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