d66e5dae504d4bf6ac4e9cfc4f91dc32410d840a
[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  */
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 <sys/bus.h>
36
37 #include <bus/pci/pcireg.h>
38 #include <bus/pci/pcivar.h>
39
40 \f
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 \f
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 \f
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         KOBJMETHOD_END
312 };
313 AC97_DECLARE(au88x0_ac97);
314
315 #define au88x0_channel(aui, dir) \
316         &(aui)->aui_chan[((dir) == PCMDIR_PLAY) ? 0 : 1]
317
318 \f
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         KOBJMETHOD_END
429 };
430 CHANNEL_DECLARE(au88x0_chan);
431
432 \f
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 \f
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 \f
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 BUS_PROBE_DEFAULT;
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         aui = kmalloc(sizeof *aui, M_DEVBUF, M_WAITOK | M_ZERO);
576         aui->aui_dev = dev;
577
578         /* Model-specific parameters */
579         aui->aui_model = pci_get_devid(dev);
580         for (auc = au88x0_chipsets; auc->auc_pci_id; ++auc)
581                 if (auc->auc_pci_id == aui->aui_model)
582                         aui->aui_chipset = auc;
583         if (aui->aui_chipset == NULL)
584                 panic("%s() called for non-au88x0 device", __func__);
585
586         /* enable pio, mmio, bus-mastering dma */
587         config = pci_read_config(dev, PCIR_COMMAND, 2);
588         config |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
589         pci_write_config(dev, PCIR_COMMAND, config, 2);
590
591         /* register mapping */
592         config = pci_read_config(dev, PCIR_COMMAND, 2);
593         if (config & PCIM_CMD_MEMEN) {
594                 /* try memory-mapped I/O */
595                 aui->aui_regid = PCIR_BAR(0);
596                 aui->aui_regtype = SYS_RES_MEMORY;
597                 aui->aui_reg = bus_alloc_resource_any(dev, aui->aui_regtype,
598                     &aui->aui_regid, RF_ACTIVE);
599         }
600         if (aui->aui_reg == NULL && (config & PCIM_CMD_PORTEN)) {
601                 /* fall back on port I/O */
602                 aui->aui_regid = PCIR_BAR(0);
603                 aui->aui_regtype = SYS_RES_IOPORT;
604                 aui->aui_reg = bus_alloc_resource_any(dev, aui->aui_regtype,
605                     &aui->aui_regid, RF_ACTIVE);
606         }
607         if (aui->aui_reg == NULL) {
608                 /* both mmio and pio failed... */
609                 device_printf(dev, "failed to map registers\n");
610                 goto failed;
611         }
612         aui->aui_spct = rman_get_bustag(aui->aui_reg);
613         aui->aui_spch = rman_get_bushandle(aui->aui_reg);
614
615         /* IRQ mapping */
616         aui->aui_irqid = 0;
617         aui->aui_irqtype = SYS_RES_IRQ;
618         aui->aui_irq = bus_alloc_resource_any(dev, aui->aui_irqtype,
619             &aui->aui_irqid, RF_ACTIVE | RF_SHAREABLE);
620         if (aui->aui_irq == 0) {
621                 device_printf(dev, "failed to map IRQ\n");
622                 goto failed;
623         }
624
625         /* install interrupt handler */
626         error = snd_setup_intr(dev, aui->aui_irq, 0, au88x0_intr,
627             aui, &aui->aui_irqh);
628         if (error != 0) {
629                 device_printf(dev, "failed to install interrupt handler\n");
630                 goto failed;
631         }
632
633         /* DMA mapping */
634         aui->aui_bufsize = pcm_getbuffersize(dev, AU88X0_BUFSIZE_MIN,
635             AU88X0_BUFSIZE_DFLT, AU88X0_BUFSIZE_MAX);
636         error = bus_dma_tag_create(NULL,
637             2, 0, /* 16-bit alignment, no boundary */
638             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* restrict to 4GB */
639             NULL, NULL, /* no filter */
640             aui->aui_bufsize, 1, aui->aui_bufsize,
641             0, busdma_lock_mutex, &Giant, &aui->aui_dmat);
642         if (error != 0) {
643                 device_printf(dev, "failed to create DMA tag\n");
644                 goto failed;
645         }
646
647         /* initialize the hardware */
648         au88x0_init(aui);
649
650         /* initialize the ac97 codec and mixer */
651         if ((aui->aui_ac97i = AC97_CREATE(dev, aui, au88x0_ac97)) == NULL) {
652                 device_printf(dev, "failed to initialize ac97 codec\n");
653                 goto failed;
654         }
655         if (mixer_init(dev, ac97_getmixerclass(), aui->aui_ac97i) != 0) {
656                 device_printf(dev, "failed to initialize ac97 mixer\n");
657                 goto failed;
658         }
659
660         /* register with the pcm driver */
661         if (pcm_register(dev, aui, 0, 0))
662                 goto failed;
663         pcm_addchan(dev, PCMDIR_PLAY, &au88x0_chan_class, aui);
664 #if 0
665         pcm_addchan(dev, PCMDIR_REC, &au88x0_chan_class, aui);
666 #endif
667         au88x0_set_status(dev);
668
669         return (0);
670 failed:
671         if (aui->aui_ac97i != NULL)
672                 ac97_destroy(aui->aui_ac97i);
673         if (aui->aui_dmat)
674                 bus_dma_tag_destroy(aui->aui_dmat);
675         if (aui->aui_irqh != NULL)
676                 bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh);
677         if (aui->aui_irq)
678                 bus_release_resource(dev, aui->aui_irqtype,
679                     aui->aui_irqid, aui->aui_irq);
680         if (aui->aui_reg)
681                 bus_release_resource(dev, aui->aui_regtype,
682                     aui->aui_regid, aui->aui_reg);
683         kfree(aui, M_DEVBUF);
684         return (ENXIO);
685 }
686
687 /*
688  * Detach
689  */
690 static int
691 au88x0_pci_detach(device_t dev)
692 {
693         struct au88x0_info *aui;
694         int error;
695
696         aui = pcm_getdevinfo(dev);
697         if ((error = pcm_unregister(dev)) != 0)
698                 return (error);
699
700         /* release resources in reverse order */
701         bus_dma_tag_destroy(aui->aui_dmat);
702         bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh);
703         bus_release_resource(dev, aui->aui_irqtype,
704             aui->aui_irqid, aui->aui_irq);
705         bus_release_resource(dev, aui->aui_regtype,
706             aui->aui_regid, aui->aui_reg);
707         kfree(aui, M_DEVBUF);
708
709         return (0);
710 }
711
712 /*
713  * Driver glue
714  */
715 static device_method_t au88x0_methods[] = {
716         DEVMETHOD(device_probe,         au88x0_pci_probe),
717         DEVMETHOD(device_attach,        au88x0_pci_attach),
718         DEVMETHOD(device_detach,        au88x0_pci_detach),
719         DEVMETHOD_END
720 };
721
722 static driver_t au88x0_driver = {
723         "pcm",
724         au88x0_methods,
725         PCM_SOFTC_SIZE,
726 };
727
728 DRIVER_MODULE(snd_au88x0, pci, au88x0_driver, pcm_devclass, NULL, NULL);
729 MODULE_DEPEND(snd_au88x0, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
730 MODULE_VERSION(snd_au88x0, 1);