The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pci/au88x0.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include <dev/sound/pcm/sound.h>
   32 #include <dev/sound/pcm/ac97.h>
   33 #include <dev/sound/pci/au88x0.h>
   34 
   35 #include <machine/bus.h>
   36 
   37 #include <dev/pci/pcireg.h>
   38 #include <dev/pci/pcivar.h>
   39 
   40 
   41 /***************************************************************************\
   42  *                                                                         *
   43  *                          SUPPORTED CHIPSETS                             *
   44  *                                                                         *
   45 \***************************************************************************/
   46 
   47 static struct au88x0_chipset au88x0_chipsets[] = {
   48         {
   49                 .auc_name               = "Aureal Vortex (8820)",
   50                 .auc_pci_id             = 0x000112eb,
   51 
   52                 .auc_control            = 0x1280c,
   53 
   54                 .auc_irq_source         = 0x12800,
   55                 .auc_irq_mask           = 0x12804,
   56                 .auc_irq_control        = 0x12808,
   57                 .auc_irq_status         = 0x1199c,
   58 
   59                 .auc_dma_control        = 0x1060c,
   60 
   61                 .auc_fifo_size          = 0x20,
   62                 .auc_wt_fifos           = 32,
   63                 .auc_wt_fifo_base       = 0x0e800,
   64                 .auc_wt_fifo_ctl        = 0x0f800,
   65                 .auc_wt_dma_ctl         = 0x10500,
   66                 .auc_adb_fifos          = 16,
   67                 .auc_adb_fifo_base      = 0x0e000,
   68                 .auc_adb_fifo_ctl       = 0x0f840,
   69                 .auc_adb_dma_ctl        = 0x10580,
   70 
   71                 .auc_adb_route_base     = 0x10800,
   72                 .auc_adb_route_bits     = 7,
   73                 .auc_adb_codec_in       = 0x48,
   74                 .auc_adb_codec_out      = 0x58,
   75         },
   76         {
   77                 .auc_name               = "Aureal Vortex 2 (8830)",
   78                 .auc_pci_id             = 0x000212eb,
   79 
   80                 .auc_control            = 0x2a00c,
   81 
   82                 .auc_irq_source         = 0x2a000,
   83                 .auc_irq_mask           = 0x2a004,
   84                 .auc_irq_control        = 0x2a008,
   85                 .auc_irq_status         = 0x2919c,
   86 
   87                 .auc_dma_control        = 0x27ae8,
   88 
   89                 .auc_fifo_size          = 0x40,
   90                 .auc_wt_fifos           = 64,
   91                 .auc_wt_fifo_base       = 0x10000,
   92                 .auc_wt_fifo_ctl        = 0x16000,
   93                 .auc_wt_dma_ctl         = 0x27900,
   94                 .auc_adb_fifos          = 32,
   95                 .auc_adb_fifo_base      = 0x14000,
   96                 .auc_adb_fifo_ctl       = 0x16100,
   97                 .auc_adb_dma_ctl        = 0x27a00,
   98 
   99                 .auc_adb_route_base     = 0x28000,
  100                 .auc_adb_route_bits     = 8,
  101                 .auc_adb_codec_in       = 0x70,
  102                 .auc_adb_codec_out      = 0x88,
  103         },
  104         {
  105                 .auc_name               = "Aureal Vortex Advantage (8810)",
  106                 .auc_pci_id             = 0x000312eb,
  107 
  108                 .auc_control            = 0x2a00c,
  109 
  110                 .auc_irq_source         = 0x2a000,
  111                 .auc_irq_mask           = 0x2a004,
  112                 .auc_irq_control        = 0x2a008,
  113                 .auc_irq_status         = 0x2919c,
  114 
  115                 .auc_dma_control        = 0x27ae8,
  116 
  117                 .auc_fifo_size          = 0x20,
  118                 .auc_wt_fifos           = 32,
  119                 .auc_wt_fifo_base       = 0x10000,
  120                 .auc_wt_fifo_ctl        = 0x16000,
  121                 .auc_wt_dma_ctl         = 0x27fd8,
  122                 .auc_adb_fifos          = 16,
  123                 .auc_adb_fifo_base      = 0x14000,
  124                 .auc_adb_fifo_ctl       = 0x16100,
  125                 .auc_adb_dma_ctl        = 0x27180,
  126 
  127                 .auc_adb_route_base     = 0x28000,
  128                 .auc_adb_route_bits     = 8,
  129                 .auc_adb_codec_in       = 0x70,
  130                 .auc_adb_codec_out      = 0x88,
  131         },
  132         {
  133                 .auc_pci_id             = 0,
  134         }
  135 };
  136 
  137 
  138 /***************************************************************************\
  139  *                                                                         *
  140  *                       FORMATS AND CAPABILITIES                          *
  141  *                                                                         *
  142 \***************************************************************************/
  143 
  144 static u_int32_t au88x0_formats[] = {
  145         AFMT_U8,
  146         AFMT_STEREO | AFMT_U8,
  147         AFMT_S16_LE,
  148         AFMT_STEREO | AFMT_S16_LE,
  149         0
  150 };
  151 
  152 static struct pcmchan_caps au88x0_capabilities = {
  153         4000,                   /* minimum sample rate */
  154         48000,                  /* maximum sample rate */
  155         au88x0_formats,         /* supported formats */
  156         0                       /* no particular capabilities */
  157 };
  158 
  159 
  160 /***************************************************************************\
  161  *                                                                         *
  162  *                           CODEC INTERFACE                               *
  163  *                                                                         *
  164 \***************************************************************************/
  165 
  166 /*
  167  * Read from the au88x0 register space
  168  */
  169 #if 1
  170 /* all our writes are 32-bit */
  171 #define au88x0_read(aui, reg, n) \
  172         bus_space_read_4((aui)->aui_spct, (aui)->aui_spch, (reg))
  173 #define au88x0_write(aui, reg, data, n) \
  174         bus_space_write_4((aui)->aui_spct, (aui)->aui_spch, (reg), (data))
  175 #else
  176 static uint32_t
  177 au88x0_read(struct au88x0_info *aui, int reg, int size)
  178 {
  179         uint32_t data;
  180 
  181         switch (size) {
  182         case 1:
  183                 data = bus_space_read_1(aui->aui_spct, aui->aui_spch, reg);
  184                 break;
  185         case 2:
  186                 data = bus_space_read_2(aui->aui_spct, aui->aui_spch, reg);
  187                 break;
  188         case 4:
  189                 data = bus_space_read_4(aui->aui_spct, aui->aui_spch, reg);
  190                 break;
  191         default:
  192                 panic("unsupported read size %d", size);
  193         }
  194         return (data);
  195 }
  196 
  197 /*
  198  * Write to the au88x0 register space
  199  */
  200 static void
  201 au88x0_write(struct au88x0_info *aui, int reg, uint32_t data, int size)
  202 {
  203 
  204         switch (size) {
  205         case 1:
  206                 bus_space_write_1(aui->aui_spct, aui->aui_spch, reg, data);
  207                 break;
  208         case 2:
  209                 bus_space_write_2(aui->aui_spct, aui->aui_spch, reg, data);
  210                 break;
  211         case 4:
  212                 bus_space_write_4(aui->aui_spct, aui->aui_spch, reg, data);
  213                 break;
  214         default:
  215                 panic("unsupported write size %d", size);
  216         }
  217 }
  218 #endif
  219 
  220 /*
  221  * Reset and initialize the codec
  222  */
  223 static void
  224 au88x0_codec_init(struct au88x0_info *aui)
  225 {
  226         uint32_t data;
  227         int i;
  228 
  229         /* wave that chicken */
  230         au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x8068, 4);
  231         DELAY(AU88X0_SETTLE_DELAY);
  232         au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x00e8, 4);
  233         DELAY(1000);
  234         for (i = 0; i < 32; ++i) {
  235                 au88x0_write(aui, AU88X0_CODEC_CHANNEL + i * 4, 0, 4);
  236                 DELAY(AU88X0_SETTLE_DELAY);
  237         }
  238         au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x00e8, 4);
  239         DELAY(AU88X0_SETTLE_DELAY);
  240 
  241         /* enable both codec channels */
  242         data = au88x0_read(aui, AU88X0_CODEC_ENABLE, 4);
  243         data |= (1 << (8 + 0)) | (1 << (8 + 1));
  244         au88x0_write(aui, AU88X0_CODEC_ENABLE, data, 4);
  245         DELAY(AU88X0_SETTLE_DELAY);
  246 }
  247 
  248 /*
  249  * Wait for the codec to get ready to accept a register write
  250  * Should be called at spltty
  251  */
  252 static int
  253 au88x0_codec_wait(struct au88x0_info *aui)
  254 {
  255         uint32_t data;
  256         int i;
  257 
  258         for (i = 0; i < AU88X0_RETRY_COUNT; ++i) {
  259                 data = au88x0_read(aui, AU88X0_CODEC_CONTROL, 4);
  260                 if (data & AU88X0_CDCTL_WROK)
  261                         return (0);
  262                 DELAY(AU88X0_SETTLE_DELAY);
  263         }
  264         device_printf(aui->aui_dev, "timeout while waiting for codec\n");
  265         return (-1);
  266 }
  267 
  268 /*
  269  * Read from the ac97 codec
  270  */
  271 static int
  272 au88x0_codec_read(kobj_t obj, void *arg, int reg)
  273 {
  274         struct au88x0_info *aui = arg;
  275         uint32_t data;
  276         int sl;
  277 
  278         sl = spltty();
  279         au88x0_codec_wait(aui);
  280         au88x0_write(aui, AU88X0_CODEC_IO, AU88X0_CDIO_READ(reg), 4);
  281         DELAY(1000);
  282         data = au88x0_read(aui, AU88X0_CODEC_IO, 4);
  283         splx(sl);
  284         data &= AU88X0_CDIO_DATA_MASK;
  285         data >>= AU88X0_CDIO_DATA_SHIFT;
  286         return (data);
  287 }
  288 
  289 /*
  290  * Write to the ac97 codec
  291  */
  292 static int
  293 au88x0_codec_write(kobj_t obj, void *arg, int reg, uint32_t data)
  294 {
  295         struct au88x0_info *aui = arg;
  296         int sl;
  297 
  298         sl = spltty();
  299         au88x0_codec_wait(aui);
  300         au88x0_write(aui, AU88X0_CODEC_IO, AU88X0_CDIO_WRITE(reg, data), 4);
  301         splx(sl);
  302         return 0;
  303 }
  304 
  305 /*
  306  * Codec interface glue
  307  */
  308 static kobj_method_t au88x0_ac97_methods[] = {
  309         KOBJMETHOD(ac97_read, au88x0_codec_read),
  310         KOBJMETHOD(ac97_write, au88x0_codec_write),
  311         { 0, 0 }
  312 };
  313 AC97_DECLARE(au88x0_ac97);
  314 
  315 #define au88x0_channel(aui, dir) \
  316         &(aui)->aui_chan[((dir) == PCMDIR_PLAY) ? 0 : 1]
  317 
  318 
  319 /***************************************************************************\
  320  *                                                                         *
  321  *                          CHANNEL INTERFACE                              *
  322  *                                                                         *
  323 \***************************************************************************/
  324 
  325 /*
  326  * Initialize a PCM channel
  327  */
  328 static void *
  329 au88x0_chan_init(kobj_t obj, void *arg,
  330     struct snd_dbuf *buf, struct pcm_channel *chan, int dir)
  331 {
  332         struct au88x0_info *aui = arg;
  333         struct au88x0_chan_info *auci = au88x0_channel(aui, dir);
  334 
  335         if (sndbuf_alloc(buf, aui->aui_dmat, aui->aui_bufsize) != 0)
  336                 return (NULL);
  337         auci->auci_aui = aui;
  338         auci->auci_pcmchan = chan;
  339         auci->auci_buf = buf;
  340         auci->auci_dir = dir;
  341         return (auci);
  342 }
  343 
  344 /*
  345  * Set the data format for a PCM channel
  346  */
  347 static int
  348 au88x0_chan_setformat(kobj_t obj, void *arg, u_int32_t format)
  349 {
  350 
  351         /* XXX */
  352         return (ENXIO);
  353 }
  354 
  355 /*
  356  * Set the sample rate for a PCM channel
  357  */
  358 static int
  359 au88x0_chan_setspeed(kobj_t obj, void *arg, u_int32_t speed)
  360 {
  361 
  362         /* XXX */
  363         return (speed);
  364 }
  365 
  366 /*
  367  * Set the block size for a PCM channel
  368  */
  369 static int
  370 au88x0_chan_setblocksize(kobj_t obj, void *arg, u_int32_t blocksize)
  371 {
  372 
  373         /* XXX */
  374         return (blocksize);
  375 }
  376 
  377 /*
  378  * Initiate a data transfer
  379  */
  380 static int
  381 au88x0_chan_trigger(kobj_t obj, void *arg, int trigger)
  382 {
  383         struct au88x0_chan_info *auci = arg;
  384 
  385         (void)auci;
  386         switch (trigger) {
  387         case PCMTRIG_START:
  388                 break;
  389         case PCMTRIG_STOP:
  390         case PCMTRIG_ABORT:
  391                 break;
  392         }
  393         return (0);
  394 }
  395 
  396 /*
  397  *
  398  */
  399 static int
  400 au88x0_chan_getptr(kobj_t obj, void *arg)
  401 {
  402 
  403         /* XXX */
  404         return (0);
  405 }
  406 
  407 /*
  408  * Return the capabilities of a PCM channel
  409  */
  410 static struct pcmchan_caps *
  411 au88x0_chan_getcaps(kobj_t obj, void *arg)
  412 {
  413 
  414         return (&au88x0_capabilities);
  415 }
  416 
  417 /*
  418  * Channel interface glue
  419  */
  420 static kobj_method_t au88x0_chan_methods[] = {
  421         KOBJMETHOD(channel_init,                au88x0_chan_init),
  422         KOBJMETHOD(channel_setformat,           au88x0_chan_setformat),
  423         KOBJMETHOD(channel_setspeed,            au88x0_chan_setspeed),
  424         KOBJMETHOD(channel_setblocksize,        au88x0_chan_setblocksize),
  425         KOBJMETHOD(channel_trigger,             au88x0_chan_trigger),
  426         KOBJMETHOD(channel_getptr,              au88x0_chan_getptr),
  427         KOBJMETHOD(channel_getcaps,             au88x0_chan_getcaps),
  428         { 0, 0 }
  429 };
  430 CHANNEL_DECLARE(au88x0_chan);
  431 
  432 
  433 /***************************************************************************\
  434  *                                                                         *
  435  *                          INTERRUPT HANDLER                              *
  436  *                                                                         *
  437 \***************************************************************************/
  438 
  439 static void
  440 au88x0_intr(void *arg)
  441 {
  442         struct au88x0_info *aui = arg;
  443         struct au88x0_chipset *auc = aui->aui_chipset;
  444         int pending, source;
  445 
  446         pending = au88x0_read(aui, auc->auc_irq_control, 4);
  447         if ((pending & AU88X0_IRQ_PENDING_BIT) == 0)
  448                 return;
  449         source = au88x0_read(aui, auc->auc_irq_source, 4);
  450         if (source & AU88X0_IRQ_FATAL_ERR)
  451                 device_printf(aui->aui_dev,
  452                     "fatal error interrupt received\n");
  453         if (source & AU88X0_IRQ_PARITY_ERR)
  454                 device_printf(aui->aui_dev,
  455                     "parity error interrupt received\n");
  456         /* XXX handle the others... */
  457 
  458         /* acknowledge the interrupts we just handled */
  459         au88x0_write(aui, auc->auc_irq_source, source, 4);
  460         au88x0_read(aui, auc->auc_irq_source, 4);
  461 }
  462 
  463 
  464 /***************************************************************************\
  465  *                                                                         *
  466  *                            INITIALIZATION                               *
  467  *                                                                         *
  468 \***************************************************************************/
  469 
  470 /*
  471  * Reset and initialize the ADB and WT FIFOs
  472  *
  473  *  - need to find out what the magic values 0x42000 and 0x2000 mean.
  474  */
  475 static void
  476 au88x0_fifo_init(struct au88x0_info *aui)
  477 {
  478         struct au88x0_chipset *auc = aui->aui_chipset;
  479         int i;
  480 
  481         /* reset, then clear the ADB FIFOs */
  482         for (i = 0; i < auc->auc_adb_fifos; ++i)
  483                 au88x0_write(aui, auc->auc_adb_fifo_ctl + i * 4, 0x42000, 4);
  484         for (i = 0; i < auc->auc_adb_fifos * auc->auc_fifo_size; ++i)
  485                 au88x0_write(aui, auc->auc_adb_fifo_base + i * 4, 0, 4);
  486 
  487         /* reset, then clear the WT FIFOs */
  488         for (i = 0; i < auc->auc_wt_fifos; ++i)
  489                 au88x0_write(aui, auc->auc_wt_fifo_ctl + i * 4, 0x42000, 4);
  490         for (i = 0; i < auc->auc_wt_fifos * auc->auc_fifo_size; ++i)
  491                 au88x0_write(aui, auc->auc_wt_fifo_base + i * 4, 0, 4);
  492 }
  493 
  494 /*
  495  * Hardware initialization
  496  */
  497 static void
  498 au88x0_init(struct au88x0_info *aui)
  499 {
  500         struct au88x0_chipset *auc = aui->aui_chipset;
  501 
  502         /* reset the chip */
  503         au88x0_write(aui, auc->auc_control, 0xffffffff, 4);
  504         DELAY(10000);
  505 
  506         /* clear all interrupts */
  507         au88x0_write(aui, auc->auc_irq_source, 0xffffffff, 4);
  508         au88x0_read(aui, auc->auc_irq_source, 4);
  509         au88x0_read(aui, auc->auc_irq_status, 4);
  510 
  511         /* initialize the codec */
  512         au88x0_codec_init(aui);
  513 
  514         /* initialize the fifos */
  515         au88x0_fifo_init(aui);
  516 
  517         /* initialize the DMA engine */
  518         /* XXX chicken-waving! */
  519         au88x0_write(aui, auc->auc_dma_control, 0x1380000, 4);
  520 }
  521 
  522 /*
  523  * Construct and set status string
  524  */
  525 static void
  526 au88x0_set_status(device_t dev)
  527 {
  528         char status[SND_STATUSLEN];
  529         struct au88x0_info *aui;
  530 
  531         aui = pcm_getdevinfo(dev);
  532         snprintf(status, sizeof status, "at %s 0x%lx irq %ld %s",
  533             (aui->aui_regtype == SYS_RES_IOPORT)? "io" : "memory",
  534             rman_get_start(aui->aui_reg), rman_get_start(aui->aui_irq),PCM_KLDSTRING(snd_au88x0));
  535         pcm_setstatus(dev, status);
  536 }
  537 
  538 
  539 /***************************************************************************\
  540  *                                                                         *
  541  *                            PCI INTERFACE                                *
  542  *                                                                         *
  543 \***************************************************************************/
  544 
  545 /*
  546  * Probe
  547  */
  548 static int
  549 au88x0_pci_probe(device_t dev)
  550 {
  551         struct au88x0_chipset *auc;
  552         uint32_t pci_id;
  553 
  554         pci_id = pci_get_devid(dev);
  555         for (auc = au88x0_chipsets; auc->auc_pci_id; ++auc) {
  556                 if (auc->auc_pci_id == pci_id) {
  557                         device_set_desc(dev, auc->auc_name);
  558                         return (0);
  559                 }
  560         }
  561         return (ENXIO);
  562 }
  563 
  564 /*
  565  * Attach
  566  */
  567 static int
  568 au88x0_pci_attach(device_t dev)
  569 {
  570         struct au88x0_chipset *auc;
  571         struct au88x0_info *aui = NULL;
  572         uint32_t config;
  573         int error;
  574 
  575         if ((aui = malloc(sizeof *aui, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
  576                 device_printf(dev, "failed to allocate softc\n");
  577                 return (ENXIO);
  578         }
  579         aui->aui_dev = dev;
  580 
  581         /* Model-specific parameters */
  582         aui->aui_model = pci_get_devid(dev);
  583         for (auc = au88x0_chipsets; auc->auc_pci_id; ++auc)
  584                 if (auc->auc_pci_id == aui->aui_model)
  585                         aui->aui_chipset = auc;
  586         if (aui->aui_chipset == NULL)
  587                 panic("%s() called for non-au88x0 device", __func__);
  588 
  589         /* enable pio, mmio, bus-mastering dma */
  590         config = pci_read_config(dev, PCIR_COMMAND, 2);
  591         config |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
  592         pci_write_config(dev, PCIR_COMMAND, config, 2);
  593 
  594         /* register mapping */
  595         config = pci_read_config(dev, PCIR_COMMAND, 2);
  596         if (config & PCIM_CMD_MEMEN) {
  597                 /* try memory-mapped I/O */
  598                 aui->aui_regid = PCIR_BAR(0);
  599                 aui->aui_regtype = SYS_RES_MEMORY;
  600                 aui->aui_reg = bus_alloc_resource_any(dev, aui->aui_regtype,
  601                     &aui->aui_regid, RF_ACTIVE);
  602         }
  603         if (aui->aui_reg == NULL && (config & PCIM_CMD_PORTEN)) {
  604                 /* fall back on port I/O */
  605                 aui->aui_regid = PCIR_BAR(0);
  606                 aui->aui_regtype = SYS_RES_IOPORT;
  607                 aui->aui_reg = bus_alloc_resource_any(dev, aui->aui_regtype,
  608                     &aui->aui_regid, RF_ACTIVE);
  609         }
  610         if (aui->aui_reg == NULL) {
  611                 /* both mmio and pio failed... */
  612                 device_printf(dev, "failed to map registers\n");
  613                 goto failed;
  614         }
  615         aui->aui_spct = rman_get_bustag(aui->aui_reg);
  616         aui->aui_spch = rman_get_bushandle(aui->aui_reg);
  617 
  618         /* IRQ mapping */
  619         aui->aui_irqid = 0;
  620         aui->aui_irqtype = SYS_RES_IRQ;
  621         aui->aui_irq = bus_alloc_resource_any(dev, aui->aui_irqtype,
  622             &aui->aui_irqid, RF_ACTIVE | RF_SHAREABLE);
  623         if (aui->aui_irq == 0) {
  624                 device_printf(dev, "failed to map IRQ\n");
  625                 goto failed;
  626         }
  627 
  628         /* install interrupt handler */
  629         error = snd_setup_intr(dev, aui->aui_irq, 0, au88x0_intr,
  630             aui, &aui->aui_irqh);
  631         if (error != 0) {
  632                 device_printf(dev, "failed to install interrupt handler\n");
  633                 goto failed;
  634         }
  635 
  636         /* DMA mapping */
  637         aui->aui_bufsize = pcm_getbuffersize(dev, AU88X0_BUFSIZE_MIN,
  638             AU88X0_BUFSIZE_DFLT, AU88X0_BUFSIZE_MAX);
  639         error = bus_dma_tag_create(NULL,
  640             2, 0, /* 16-bit alignment, no boundary */
  641             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* restrict to 4GB */
  642             NULL, NULL, /* no filter */
  643             aui->aui_bufsize, 1, aui->aui_bufsize,
  644             0, busdma_lock_mutex, &Giant, &aui->aui_dmat);
  645         if (error != 0) {
  646                 device_printf(dev, "failed to create DMA tag\n");
  647                 goto failed;
  648         }
  649 
  650         /* initialize the hardware */
  651         au88x0_init(aui);
  652 
  653         /* initialize the ac97 codec and mixer */
  654         if ((aui->aui_ac97i = AC97_CREATE(dev, aui, au88x0_ac97)) == NULL) {
  655                 device_printf(dev, "failed to initialize ac97 codec\n");
  656                 goto failed;
  657         }
  658         if (mixer_init(dev, ac97_getmixerclass(), aui->aui_ac97i) != 0) {
  659                 device_printf(dev, "failed to initialize ac97 mixer\n");
  660                 goto failed;
  661         }
  662 
  663         /* register with the pcm driver */
  664         if (pcm_register(dev, aui, 0, 0))
  665                 goto failed;
  666         pcm_addchan(dev, PCMDIR_PLAY, &au88x0_chan_class, aui);
  667 #if 0
  668         pcm_addchan(dev, PCMDIR_REC, &au88x0_chan_class, aui);
  669 #endif
  670         au88x0_set_status(dev);
  671 
  672         return (0);
  673 failed:
  674         if (aui->aui_ac97i != NULL)
  675                 ac97_destroy(aui->aui_ac97i);
  676         if (aui->aui_dmat)
  677                 bus_dma_tag_destroy(aui->aui_dmat);
  678         if (aui->aui_irqh != NULL)
  679                 bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh);
  680         if (aui->aui_irq)
  681                 bus_release_resource(dev, aui->aui_irqtype,
  682                     aui->aui_irqid, aui->aui_irq);
  683         if (aui->aui_reg)
  684                 bus_release_resource(dev, aui->aui_regtype,
  685                     aui->aui_regid, aui->aui_reg);
  686         free(aui, M_DEVBUF);
  687         return (ENXIO);
  688 }
  689 
  690 /*
  691  * Detach
  692  */
  693 static int
  694 au88x0_pci_detach(device_t dev)
  695 {
  696         struct au88x0_info *aui;
  697         int error;
  698 
  699         aui = pcm_getdevinfo(dev);
  700         if ((error = pcm_unregister(dev)) != 0)
  701                 return (error);
  702 
  703         /* release resources in reverse order */
  704         bus_dma_tag_destroy(aui->aui_dmat);
  705         bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh);
  706         bus_release_resource(dev, aui->aui_irqtype,
  707             aui->aui_irqid, aui->aui_irq);
  708         bus_release_resource(dev, aui->aui_regtype,
  709             aui->aui_regid, aui->aui_reg);
  710         free(aui, M_DEVBUF);
  711 
  712         return (0);
  713 }
  714 
  715 /*
  716  * Driver glue
  717  */
  718 static device_method_t au88x0_methods[] = {
  719         DEVMETHOD(device_probe,         au88x0_pci_probe),
  720         DEVMETHOD(device_attach,        au88x0_pci_attach),
  721         DEVMETHOD(device_detach,        au88x0_pci_detach),
  722         { 0, 0 }
  723 };
  724 
  725 static driver_t au88x0_driver = {
  726         "pcm",
  727         au88x0_methods,
  728         PCM_SOFTC_SIZE,
  729 };
  730 
  731 DRIVER_MODULE(snd_au88x0, pci, au88x0_driver, pcm_devclass, 0, 0);
  732 MODULE_DEPEND(snd_au88x0, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  733 MODULE_VERSION(snd_au88x0, 1);

Cache object: fd39538bc69bfa81558b3cb13368bf99


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.