root/dev/pci/fms.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fms_match
  2. fms_attach
  3. fms_read_codec
  4. fms_write_codec
  5. fms_attach_codec
  6. fms_reset_codec
  7. fms_intr
  8. fms_open
  9. fms_close
  10. fms_query_encoding
  11. fms_set_params
  12. fms_round_blocksize
  13. fms_halt_output
  14. fms_halt_input
  15. fms_getdev
  16. fms_set_port
  17. fms_get_port
  18. fms_malloc
  19. fms_free
  20. fms_mappage
  21. fms_get_props
  22. fms_query_devinfo
  23. fms_trigger_output
  24. fms_trigger_input

    1 /*      $OpenBSD: fms.c,v 1.17 2005/04/16 21:57:23 mickey Exp $ */
    2 /*      $NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $       */
    3 
    4 /*-
    5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Witold J. Wnuk.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Forte Media FM801 Audio Device Driver
   42  */
   43 
   44 #include "radio.h"
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/malloc.h>
   50 #include <sys/device.h>
   51 #include <sys/audioio.h>
   52 
   53 #include <machine/bus.h>
   54 #include <machine/cpu.h>
   55 
   56 #include <dev/pci/pcidevs.h>
   57 #include <dev/pci/pcivar.h>
   58 
   59 #include <dev/audio_if.h>
   60 #include <dev/mulaw.h>
   61 #include <dev/auconv.h>
   62 
   63 #include <dev/ic/ac97.h>
   64 #if 0
   65 #include <dev/ic/mpuvar.h>
   66 #endif
   67 
   68 #include <dev/pci/fmsreg.h>
   69 #include <dev/pci/fmsvar.h>
   70 
   71 
   72 struct fms_dma {
   73         struct fms_dma *next;
   74         caddr_t addr;
   75         size_t size;
   76         bus_dmamap_t map;
   77         bus_dma_segment_t seg;
   78 };
   79 
   80 
   81 
   82 int     fms_match(struct device *, void *, void *);
   83 void    fms_attach(struct device *, struct device *, void *);
   84 int     fms_intr(void *);
   85 
   86 int     fms_open(void *, int);
   87 void    fms_close(void *);
   88 int     fms_query_encoding(void *, struct audio_encoding *);
   89 int     fms_set_params(void *, int, int, struct audio_params *, 
   90                             struct audio_params *);
   91 int     fms_round_blocksize(void *, int);
   92 int     fms_halt_output(void *);
   93 int     fms_halt_input(void *);
   94 int     fms_getdev(void *, struct audio_device *);
   95 int     fms_set_port(void *, mixer_ctrl_t *);
   96 int     fms_get_port(void *, mixer_ctrl_t *);
   97 int     fms_query_devinfo(void *, mixer_devinfo_t *);
   98 void    *fms_malloc(void *, int, size_t, int, int);
   99 void    fms_free(void *, void *, int);
  100 paddr_t fms_mappage(void *, void *, off_t, int);
  101 int     fms_get_props(void *);
  102 int     fms_trigger_output(void *, void *, void *, int, void (*)(void *),
  103                            void *, struct audio_params *);
  104 int     fms_trigger_input(void *, void *, void *, int, void (*)(void *),
  105                           void *, struct audio_params *);
  106 
  107 struct  cfdriver fms_cd = {
  108         NULL, "fms", DV_DULL
  109 };
  110 
  111 struct cfattach fms_ca = {
  112         sizeof (struct fms_softc), fms_match, fms_attach
  113 };
  114 
  115 struct audio_device fms_device = {
  116         "Forte Media 801",
  117         "1.0",
  118         "fms"
  119 };
  120 
  121 
  122 struct audio_hw_if fms_hw_if = {
  123         fms_open,
  124         fms_close,
  125         NULL,
  126         fms_query_encoding,
  127         fms_set_params,
  128         fms_round_blocksize,
  129         NULL,
  130         NULL,
  131         NULL,
  132         NULL,
  133         NULL,
  134         fms_halt_output,
  135         fms_halt_input,
  136         NULL,
  137         fms_getdev,
  138         NULL,
  139         fms_set_port,
  140         fms_get_port,
  141         fms_query_devinfo,
  142         fms_malloc,
  143         fms_free,
  144         NULL,
  145         fms_mappage,
  146         fms_get_props,
  147         fms_trigger_output,
  148         fms_trigger_input
  149 };
  150 
  151 int     fms_attach_codec(void *, struct ac97_codec_if *);
  152 int     fms_read_codec(void *, u_int8_t, u_int16_t *);
  153 int     fms_write_codec(void *, u_int8_t, u_int16_t);
  154 void    fms_reset_codec(void *);
  155 
  156 int     fms_allocmem(struct fms_softc *, size_t, size_t,
  157                           struct fms_dma *);
  158 int     fms_freemem(struct fms_softc *, struct fms_dma *);
  159 
  160 int
  161 fms_match(parent, match, aux)
  162         struct device *parent;
  163         void *match;
  164         void *aux;
  165 {
  166         struct pci_attach_args *pa = (struct pci_attach_args *) aux;
  167 
  168         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA &&
  169             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801)
  170                 return (1);
  171         return (0);
  172 }
  173 
  174 void
  175 fms_attach(parent, self, aux)
  176         struct device *parent;
  177         struct device *self;
  178         void *aux;
  179 {
  180         struct pci_attach_args *pa = aux;
  181         struct fms_softc *sc = (struct fms_softc *) self;
  182         struct audio_attach_args aa;
  183         pci_chipset_tag_t pc = pa->pa_pc;
  184         pcitag_t pt = pa->pa_tag;
  185         pci_intr_handle_t ih;
  186         bus_size_t iosize;
  187         const char *intrstr;
  188         u_int16_t k1;
  189         int i;
  190         
  191         if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
  192             &sc->sc_ioh, NULL, &iosize, 0)) {
  193                 printf(": can't map i/o space\n");
  194                 return;
  195         }
  196         
  197         if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
  198             &sc->sc_mpu_ioh)) {
  199                 printf(": can't get mpu subregion handle\n");
  200                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  201                 return;
  202         }
  203 
  204         if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
  205             &sc->sc_opl_ioh)) {
  206                 printf(": can't get opl subregion handle\n");
  207                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  208                 return;
  209         }
  210         
  211         if (pci_intr_map(pa, &ih)) {
  212                 printf(": couldn't map interrupt\n");
  213                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  214                 return;
  215         }
  216         intrstr = pci_intr_string(pc, ih);
  217         
  218         sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc,
  219             sc->sc_dev.dv_xname);
  220         if (sc->sc_ih == NULL) {
  221                 printf(": couldn't establish interrupt");
  222                 if (intrstr != NULL)
  223                         printf(" at %s", intrstr);
  224                 printf("\n");
  225                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  226                 return;
  227         }
  228         
  229         printf(": %s\n", intrstr);
  230 
  231         sc->sc_dmat = pa->pa_dmat;
  232 
  233         /* Disable legacy audio (SBPro compatibility) */
  234         pci_conf_write(pc, pt, 0x40, 0);
  235         
  236         /* Reset codec and AC'97 */
  237         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
  238         delay(2);               /* > 1us according to AC'97 documentation */
  239         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
  240         delay(1);               /* > 168.2ns according to AC'97 documentation */
  241         
  242         /* Set up volume */
  243         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
  244         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
  245         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
  246         
  247         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
  248         
  249         /* Unmask playback, record and mpu interrupts, mask the rest */
  250         k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
  251         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK, 
  252             (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
  253              FM_INTMASK_VOL);
  254         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 
  255             FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU | 
  256             FM_INTSTATUS_VOL);
  257 
  258 #if NRADIO > 0
  259         fmsradio_attach(sc);
  260 #endif /* NRADIO > 0 */
  261         
  262         sc->host_if.arg = sc;
  263         sc->host_if.attach = fms_attach_codec;
  264         sc->host_if.read = fms_read_codec;
  265         sc->host_if.write = fms_write_codec;
  266         sc->host_if.reset = fms_reset_codec;
  267 
  268         if (ac97_attach(&sc->host_if) != 0)
  269                 return;
  270         
  271         /* Turn mute off */
  272         for (i = 0; i < 3; i++) {
  273                 static struct {
  274                         char *class, *device;
  275                 } d[] = {
  276                         { AudioCoutputs, AudioNmaster },
  277                         { AudioCinputs, AudioNdac },
  278                         { AudioCrecord, AudioNvolume }
  279                 };
  280                 struct mixer_ctrl ctl;
  281                 
  282                 ctl.type = AUDIO_MIXER_ENUM;
  283                 ctl.un.ord = 0;
  284                 ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
  285                         d[i].class, d[i].device, AudioNmute);
  286                 fms_set_port(sc, &ctl);
  287         }
  288 
  289         audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
  290 
  291         aa.type = AUDIODEV_TYPE_OPL;
  292         aa.hwif = NULL;
  293         aa.hdl = NULL;
  294         config_found(&sc->sc_dev, &aa, audioprint);
  295 
  296         aa.type = AUDIODEV_TYPE_MPU;
  297         aa.hwif = NULL;
  298         aa.hdl = NULL;
  299         sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
  300 }
  301 
  302 /*
  303  * Each AC-link frame takes 20.8us, data should be ready in next frame,
  304  * we allow more than two.
  305  */
  306 #define TIMO 50
  307 int
  308 fms_read_codec(addr, reg, val)
  309         void *addr;
  310         u_int8_t reg;
  311         u_int16_t *val;
  312 {
  313         struct fms_softc *sc = addr;
  314         int i;
  315 
  316         /* Poll until codec is ready */
  317         for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 
  318                  FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
  319                 delay(1);
  320         if (i >= TIMO) {
  321                 printf("fms: codec busy\n");
  322                 return 1;
  323         }
  324 
  325         /* Write register index, read access */
  326         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, 
  327                           reg | FM_CODEC_CMD_READ);
  328         
  329         /* Poll until we have valid data */
  330         for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh, 
  331                  FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
  332                 delay(1);
  333         if (i >= TIMO) {
  334                 printf("fms: no data from codec\n");
  335                 return 1;
  336         }
  337         
  338         /* Read data */
  339         *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
  340         return 0;
  341 }
  342 
  343 int
  344 fms_write_codec(addr, reg, val)
  345         void *addr;
  346         u_int8_t reg;
  347         u_int16_t val;
  348 {
  349         struct fms_softc *sc = addr;
  350         int i;
  351         
  352         /* Poll until codec is ready */
  353         for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh, 
  354                  FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
  355                 delay(1);
  356         if (i >= TIMO) {
  357                 printf("fms: codec busy\n");
  358                 return 1;
  359         }
  360 
  361         /* Write data */
  362         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
  363         /* Write index register, write access */
  364         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
  365         return 0;
  366 }
  367 #undef TIMO
  368 
  369 int
  370 fms_attach_codec(addr, cif)
  371         void *addr;
  372         struct ac97_codec_if *cif;
  373 {
  374         struct fms_softc *sc = addr;
  375 
  376         sc->codec_if = cif;
  377         return 0;
  378 }
  379 
  380 /* Cold Reset */
  381 void
  382 fms_reset_codec(addr)
  383         void *addr;
  384 {
  385         struct fms_softc *sc = addr;
  386         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
  387         delay(2);
  388         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
  389         delay(1);
  390 }
  391 
  392 int
  393 fms_intr(arg)
  394         void *arg;
  395 {
  396         struct fms_softc *sc = arg;
  397         u_int16_t istat;
  398         
  399         istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
  400 
  401         if (istat & FM_INTSTATUS_PLAY) {
  402                 if ((sc->sc_play_nextblk += sc->sc_play_blksize) >= 
  403                      sc->sc_play_end)
  404                         sc->sc_play_nextblk = sc->sc_play_start;
  405 
  406                 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 
  407                     sc->sc_play_flip++ & 1 ? 
  408                     FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
  409 
  410                 if (sc->sc_pintr)
  411                         sc->sc_pintr(sc->sc_parg);
  412                 else
  413                         printf("unexpected play intr\n");
  414         }
  415 
  416         if (istat & FM_INTSTATUS_REC) {
  417                 if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >= 
  418                      sc->sc_rec_end)
  419                         sc->sc_rec_nextblk = sc->sc_rec_start;
  420 
  421                 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 
  422                     sc->sc_rec_flip++ & 1 ? 
  423                     FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
  424 
  425                 if (sc->sc_rintr)
  426                         sc->sc_rintr(sc->sc_rarg);
  427                 else
  428                         printf("unexpected rec intr\n");
  429         }
  430         
  431 #if 0
  432         if (istat & FM_INTSTATUS_MPU)
  433                 mpu_intr(sc->sc_mpu_dev);
  434 #endif
  435 
  436         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS, 
  437                           istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
  438         
  439         return 1;
  440 }
  441 
  442 int
  443 fms_open(addr, flags)
  444         void *addr;
  445         int flags;      
  446 {
  447         /* UNUSED struct fms_softc *sc = addr;*/
  448         
  449         return 0;
  450 }
  451 
  452 void
  453 fms_close(addr)
  454         void *addr;
  455 {
  456         /* UNUSED struct fms_softc *sc = addr;*/
  457 }
  458 
  459 int
  460 fms_query_encoding(addr, fp)
  461         void *addr;
  462         struct audio_encoding *fp;
  463 {
  464 
  465         switch (fp->index) {
  466         case 0:
  467                 strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
  468                 fp->encoding = AUDIO_ENCODING_ULAW;
  469                 fp->precision = 8;
  470                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  471                 return 0; 
  472         case 1:
  473                 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
  474                 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
  475                 fp->precision = 16;
  476                 fp->flags = 0;
  477                 return 0;
  478         case 2:
  479                 strlcpy(fp->name, AudioEulinear, sizeof fp->name);
  480                 fp->encoding = AUDIO_ENCODING_ULINEAR;
  481                 fp->precision = 8;
  482                 fp->flags = 0;
  483                 return 0;
  484         case 3:
  485                 strlcpy(fp->name, AudioEalaw, sizeof fp->name);
  486                 fp->encoding = AUDIO_ENCODING_ALAW;
  487                 fp->precision = 8;
  488                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  489                 return 0;
  490         case 4:
  491                 strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
  492                 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
  493                 fp->precision = 16;
  494                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  495                 return 0;
  496         case 5:
  497                 strlcpy(fp->name, AudioEslinear, sizeof fp->name);
  498                 fp->encoding = AUDIO_ENCODING_SLINEAR;
  499                 fp->precision = 8;
  500                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  501                 return 0;
  502         case 6:
  503                 strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
  504                 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
  505                 fp->precision = 16;
  506                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  507                 return 0;
  508         case 7:
  509                 strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
  510                 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
  511                 fp->precision = 16;
  512                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  513                 return 0;
  514         default:
  515                 return EINVAL;
  516         }
  517 }
  518 
  519 /*
  520  * Range below -limit- is set to -rate-
  521  * What a pity FM801 does not have 24000
  522  * 24000 -> 22050 sounds rather poor
  523  */
  524 struct {
  525         int limit;
  526         int rate;
  527 } fms_rates[11] = {
  528         {  6600,  5500 },
  529         {  8750,  8000 },
  530         { 10250,  9600 },
  531         { 13200, 11025 },
  532         { 17500, 16000 },
  533         { 20500, 19200 },
  534         { 26500, 22050 },
  535         { 35000, 32000 },
  536         { 41000, 38400 },
  537         { 46000, 44100 },
  538         { 48000, 48000 },
  539         /* anything above -> 48000 */
  540 };
  541 
  542 int
  543 fms_set_params(addr, setmode, usemode, play, rec)
  544         void *addr;
  545         int setmode, usemode;
  546         struct audio_params *play, *rec;
  547 {
  548         struct fms_softc *sc = addr;
  549         int i;
  550 
  551         if (setmode & AUMODE_PLAY) {
  552                 play->factor = 1;
  553                 play->sw_code = 0;
  554                 switch(play->encoding) {
  555                 case AUDIO_ENCODING_ULAW:
  556                         play->factor = 2;
  557                         play->sw_code = mulaw_to_slinear16_le;
  558                         break;
  559                 case AUDIO_ENCODING_SLINEAR_LE:
  560                         if (play->precision == 8)
  561                                 play->sw_code = change_sign8;
  562                         break;
  563                 case AUDIO_ENCODING_ULINEAR_LE:
  564                         if (play->precision == 16)
  565                                 play->sw_code = change_sign16_le;
  566                         break;
  567                 case AUDIO_ENCODING_ALAW:
  568                         play->factor = 2;
  569                         play->sw_code = alaw_to_slinear16_le;
  570                         break;
  571                 case AUDIO_ENCODING_SLINEAR_BE:
  572                         if (play->precision == 16)
  573                                 play->sw_code = swap_bytes;
  574                         else
  575                                 play->sw_code = change_sign8;
  576                         break;
  577                 case AUDIO_ENCODING_ULINEAR_BE:
  578                         if (play->precision == 16)
  579                                 play->sw_code = change_sign16_swap_bytes_le;
  580                         break;
  581                 default:
  582                         return EINVAL;
  583                 }
  584                 for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
  585                      i++)
  586                         ;
  587                 play->sample_rate = fms_rates[i].rate;
  588                 sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
  589                     (play->precision * play->factor == 16 ? FM_PLAY_16BIT : 0) |
  590                     (i << 8);
  591         }
  592 
  593         if (setmode & AUMODE_RECORD) {
  594 
  595                 rec->factor = 1;
  596                 rec->sw_code = 0;
  597                 switch(rec->encoding) {
  598                 case AUDIO_ENCODING_ULAW:
  599                         rec->sw_code = ulinear8_to_mulaw;
  600                         break;
  601                 case AUDIO_ENCODING_SLINEAR_LE:
  602                         if (rec->precision == 8)
  603                                 rec->sw_code = change_sign8;
  604                         break;
  605                 case AUDIO_ENCODING_ULINEAR_LE:
  606                         if (rec->precision == 16)
  607                                 rec->sw_code = change_sign16_le;
  608                         break;
  609                 case AUDIO_ENCODING_ALAW:
  610                         rec->sw_code = ulinear8_to_alaw;
  611                         break;
  612                 case AUDIO_ENCODING_SLINEAR_BE:
  613                         if (play->precision == 16)
  614                                 play->sw_code = swap_bytes;
  615                         else
  616                                 play->sw_code = change_sign8;
  617                         break;
  618                 case AUDIO_ENCODING_ULINEAR_BE:
  619                         if (play->precision == 16)
  620                                 play->sw_code = swap_bytes_change_sign16_le;
  621                         break;
  622                 default:
  623                         return EINVAL;
  624                 }
  625                 for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit; 
  626                      i++)
  627                         ;
  628                 rec->sample_rate = fms_rates[i].rate;
  629                 sc->sc_rec_reg = 
  630                     (rec->channels == 2 ? FM_REC_STEREO : 0) | 
  631                     (rec->precision * rec->factor == 16 ? FM_REC_16BIT : 0) |
  632                     (i << 8);
  633         }
  634         
  635         return 0;
  636 }
  637 
  638 int
  639 fms_round_blocksize(addr, blk)
  640         void *addr;
  641         int blk;
  642 {
  643         return (blk + 0xf) & ~0xf;
  644 }
  645 
  646 int
  647 fms_halt_output(addr)
  648         void *addr;
  649 {
  650         struct fms_softc *sc = addr;
  651         u_int16_t k1;
  652         
  653         k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
  654         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 
  655                           (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) | 
  656                           FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
  657         
  658         return 0;
  659 }
  660 
  661 int
  662 fms_halt_input(addr)
  663         void *addr;
  664 {
  665         struct fms_softc *sc = addr;
  666         u_int16_t k1;
  667         
  668         k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
  669         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 
  670                           (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
  671                           FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
  672         
  673         return 0;
  674 }
  675 
  676 int
  677 fms_getdev(addr, retp)
  678         void *addr;
  679         struct audio_device *retp;
  680 {
  681         *retp = fms_device;
  682         return 0;
  683 }
  684 
  685 int
  686 fms_set_port(addr, cp)
  687         void *addr;
  688         mixer_ctrl_t *cp;
  689 {
  690         struct fms_softc *sc = addr;
  691 
  692         return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
  693 }
  694 
  695 int
  696 fms_get_port(addr, cp)
  697         void *addr;
  698         mixer_ctrl_t *cp;
  699 {
  700         struct fms_softc *sc = addr;
  701         
  702         return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
  703 }
  704 
  705 void *
  706 fms_malloc(addr, direction, size, pool, flags)
  707         void *addr;
  708         int direction;
  709         size_t size;
  710         int pool, flags;
  711 {
  712         struct fms_softc *sc = addr;
  713         struct fms_dma *p;
  714         int error;
  715         int rseg;
  716         
  717         p = malloc(sizeof(*p), pool, flags);
  718         if (!p)
  719                 return 0;
  720         
  721         p->size = size;
  722         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1, 
  723                                       &rseg, BUS_DMA_NOWAIT)) != 0) {
  724                 printf("%s: unable to allocate dma, error = %d\n", 
  725                        sc->sc_dev.dv_xname, error);
  726                 goto fail_alloc;
  727         }
  728         
  729         if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
  730                                     BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  731                 printf("%s: unable to map dma, error = %d\n", 
  732                        sc->sc_dev.dv_xname, error);
  733                 goto fail_map;
  734         }
  735         
  736         if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 
  737                                        BUS_DMA_NOWAIT, &p->map)) != 0) {
  738                 printf("%s: unable to create dma map, error = %d\n",
  739                        sc->sc_dev.dv_xname, error);
  740                 goto fail_create;
  741         }
  742         
  743         if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
  744                                      BUS_DMA_NOWAIT)) != 0) {
  745                 printf("%s: unable to load dma map, error = %d\n",
  746                        sc->sc_dev.dv_xname, error);
  747                 goto fail_load;
  748         }
  749         
  750         p->next = sc->sc_dmas;
  751         sc->sc_dmas = p;
  752 
  753         return p->addr;
  754 
  755 
  756 fail_load:
  757         bus_dmamap_destroy(sc->sc_dmat, p->map);
  758 fail_create:
  759         bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
  760 fail_map:
  761         bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  762 fail_alloc:
  763         free(p, pool);
  764         return 0;
  765 }
  766 
  767 void
  768 fms_free(addr, ptr, pool)
  769         void *addr;
  770         void *ptr;
  771         int pool;
  772 {
  773         struct fms_softc *sc = addr;
  774         struct fms_dma **pp, *p;
  775 
  776         for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
  777                 if (p->addr == ptr) {
  778                         bus_dmamap_unload(sc->sc_dmat, p->map);
  779                         bus_dmamap_destroy(sc->sc_dmat, p->map);
  780                         bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
  781                         bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  782                         
  783                         *pp = p->next;
  784                         free(p, pool);
  785                         return;
  786                 }
  787 
  788         panic("fms_free: trying to free unallocated memory");
  789 }
  790 
  791 paddr_t
  792 fms_mappage(addr, mem, off, prot)
  793         void *addr;
  794         void *mem;
  795         off_t off;
  796         int prot;
  797 {
  798         struct fms_softc *sc = addr;
  799         struct fms_dma *p;
  800         
  801         if (off < 0)
  802                 return -1;
  803         
  804         for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
  805                 ;
  806         if (!p)
  807                 return -1;
  808         
  809         return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot, 
  810                                BUS_DMA_WAITOK);
  811 }
  812 
  813 int
  814 fms_get_props(addr)
  815         void *addr;
  816 {
  817         return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | 
  818                AUDIO_PROP_FULLDUPLEX;
  819 }
  820 
  821 int
  822 fms_query_devinfo(addr, dip)
  823         void *addr;
  824         mixer_devinfo_t *dip;
  825 {
  826         struct fms_softc *sc = addr;
  827 
  828         return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
  829 }
  830 
  831 int
  832 fms_trigger_output(addr, start, end, blksize, intr, arg, param)
  833         void *addr;
  834         void *start, *end;
  835         int blksize;
  836         void (*intr)(void *);
  837         void *arg;
  838         struct audio_params *param;
  839 {
  840         struct fms_softc *sc = addr;
  841         struct fms_dma *p;
  842         
  843         sc->sc_pintr = intr;
  844         sc->sc_parg = arg;
  845         
  846         for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
  847                 ;
  848         
  849         if (!p)
  850                 panic("fms_trigger_output: request with bad start "
  851                       "address (%p)", start);
  852 
  853         sc->sc_play_start = p->map->dm_segs[0].ds_addr;
  854         sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
  855         sc->sc_play_blksize = blksize;
  856         sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;  
  857         sc->sc_play_flip = 0;
  858         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
  859         bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1, 
  860                           sc->sc_play_start);
  861         bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2, 
  862                           sc->sc_play_nextblk);
  863         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL, 
  864                           FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
  865         return 0;
  866 }
  867 
  868 
  869 int
  870 fms_trigger_input(addr, start, end, blksize, intr, arg, param)
  871         void *addr;
  872         void *start, *end;
  873         int blksize;
  874         void (*intr)(void *);
  875         void *arg;
  876         struct audio_params *param;
  877 {
  878         struct fms_softc *sc = addr;
  879         struct fms_dma *p;
  880         
  881         sc->sc_rintr = intr;
  882         sc->sc_rarg = arg;
  883         
  884         for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
  885                 ;
  886         
  887         if (!p)
  888                 panic("fms_trigger_input: request with bad start "
  889                       "address (%p)", start);
  890 
  891         sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
  892         sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
  893         sc->sc_rec_blksize = blksize;
  894         sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;     
  895         sc->sc_rec_flip = 0;
  896         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
  897         bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1, 
  898                           sc->sc_rec_start);
  899         bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2, 
  900                           sc->sc_rec_nextblk);
  901         bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL, 
  902                           FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
  903         return 0;
  904 }
  905 
  906 

/* [<][>][^][v][top][bottom][index][help] */