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
|