Deleted Added
sdiff udiff text old ( 70345 ) new ( 70346 )
full compact
1/*
2 * Copyright (c) 2000 David Jones <dej@ox.org>
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/pci/via82c686.c 70345 2000-12-25 02:21:16Z cg $
27 */
28
29#include <dev/sound/pcm/sound.h>
30#include <dev/sound/pcm/ac97.h>
31
32#include <pci/pcireg.h>
33#include <pci/pcivar.h>
34#include <sys/sysctl.h>
35
36#include <dev/sound/pci/via82c686.h>
37
38#define VIA_PCI_ID 0x30581106
39#define NSEGS 16 /* Number of segments in SGD table */
40
41#define SEGS_PER_CHAN (NSEGS/2)
42
43#undef DEB
44#define DEB(x)
45
46struct via_info;
47
48struct via_chinfo {
49 struct via_info *parent;
50 pcm_channel *channel;
51 snd_dbuf *buffer;
52 int dir;
53};
54
55struct via_info {
56 bus_space_tag_t st;
57 bus_space_handle_t sh;
58 bus_dma_tag_t parent_dmat;
59 bus_dma_tag_t sgd_dmat;
60
61 struct resource *reg, *irq;
62 int regid, irqid;
63 void *ih;
64
65 struct via_chinfo pch, rch;
66 struct via_dma_op *sgd_table;
67 u_int16_t codec_caps;
68};
69
70static u_int32_t via_rd(struct via_info *via, int regno, int size);
71static void via_wr(struct via_info *, int regno, u_int32_t data, int size);
72
73static void via_intr(void *);
74bus_dmamap_callback_t dma_cb;
75
76static u_int32_t via_playfmt[] = {
77 AFMT_U8,
78 AFMT_STEREO | AFMT_U8,
79 AFMT_S16_LE,
80 AFMT_STEREO | AFMT_S16_LE,
81 0
82};
83static pcmchan_caps via_playcaps = {4000, 48000, via_playfmt, 0};
84
85static u_int32_t via_recfmt[] = {
86 AFMT_U8,
87 AFMT_STEREO | AFMT_U8,
88 AFMT_S16_LE,
89 AFMT_STEREO | AFMT_S16_LE,
90 0
91};
92static pcmchan_caps via_reccaps = {4000, 48000, via_recfmt, 0};
93
94static u_int32_t
95via_rd(struct via_info *via, int regno, int size)
96{
97
98 switch (size) {
99 case 1:
100 return bus_space_read_1(via->st, via->sh, regno);
101 case 2:
102 return bus_space_read_2(via->st, via->sh, regno);
103 case 4:
104 return bus_space_read_4(via->st, via->sh, regno);
105 default:
106 return 0xFFFFFFFF;
107 }
108}
109
110
111static void
112via_wr(struct via_info *via, int regno, u_int32_t data, int size)
113{
114
115 switch (size) {
116 case 1:
117 bus_space_write_1(via->st, via->sh, regno, data);
118 break;
119 case 2:
120 bus_space_write_2(via->st, via->sh, regno, data);
121 break;
122 case 4:
123 bus_space_write_4(via->st, via->sh, regno, data);
124 break;
125 }
126}
127
128/* -------------------------------------------------------------------- */
129/* Codec interface */
130
131static int
132via_waitready_codec(struct via_info *via)
133{
134 int i;
135
136 /* poll until codec not busy */
137 for (i = 0; (i < TIMEOUT) &&
138 (via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_BUSY); i++)
139 DELAY(1);
140 if (i >= TIMEOUT) {
141 printf("via: codec busy\n");
142 return 1;
143 }
144
145 return 0;
146}
147
148
149static int
150via_waitvalid_codec(struct via_info *via)
151{
152 int i;
153
154 /* poll until codec valid */
155 for (i = 0; (i < TIMEOUT) &&
156 !(via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_PRIVALID); i++)
157 DELAY(1);
158 if (i >= TIMEOUT) {
159 printf("via: codec invalid\n");
160 return 1;
161 }
162
163 return 0;
164}
165
166
167static int
168via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val)
169{
170 struct via_info *via = addr;
171
172 if (via_waitready_codec(via)) return -1;
173
174 via_wr(via, VIA_CODEC_CTL,
175 VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4);
176
177 return 0;
178}
179
180
181static int
182via_read_codec(kobj_t obj, void *addr, int reg)
183{
184 struct via_info *via = addr;
185
186 if (via_waitready_codec(via))
187 return 1;
188
189 via_wr(via, VIA_CODEC_CTL,
190 VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4);
191
192 if (via_waitready_codec(via))
193 return 1;
194
195 if (via_waitvalid_codec(via))
196 return 1;
197
198 return via_rd(via, VIA_CODEC_CTL, 2);
199}
200
201static kobj_method_t via_ac97_methods[] = {
202 KOBJMETHOD(ac97_read, via_read_codec),
203 KOBJMETHOD(ac97_write, via_write_codec),
204 { 0, 0 }
205};
206AC97_DECLARE(via_ac97);
207
208/* -------------------------------------------------------------------- */
209
210/* channel interface */
211static void *
212viachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
213{
214 struct via_info *via = devinfo;
215 struct via_chinfo *ch = (dir == PCMDIR_PLAY) ? &via->pch : &via->rch;
216
217 ch->parent = via;
218 ch->channel = c;
219 ch->buffer = b;
220
221 if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1) return NULL;
222 return ch;
223}
224
225static int
226viachan_setdir(kobj_t obj, void *data, int dir)
227{
228 struct via_chinfo *ch = data;
229 struct via_info *via = ch->parent;
230 struct via_dma_op *ado;
231 int i, chunk_size;
232 int phys_addr, flag;
233
234 ch->dir = dir;
235 /*
236 * Build the scatter/gather DMA (SGD) table.
237 * There are four slots in the table: two for play, two for record.
238 * This creates two half-buffers, one of which is playing; the other
239 * is feeding.
240 */
241 ado = via->sgd_table;
242 chunk_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
243
244 if (dir == PCMDIR_REC) {
245 ado += SEGS_PER_CHAN;
246 }
247
248 DEB(printf("SGD table located at va %p\n", ado));
249 phys_addr = vtophys(sndbuf_getbuf(ch->buffer));
250 for (i = 0; i < SEGS_PER_CHAN; i++) {
251 ado->ptr = phys_addr;
252 flag = (i == SEGS_PER_CHAN-1) ?
253 VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
254 ado->flags = flag | chunk_size;
255 DEB(printf("ado->ptr/flags = %x/%x\n", phys_addr, flag));
256 phys_addr += chunk_size;
257 ado++;
258 }
259 return 0;
260}
261
262static int
263viachan_setformat(kobj_t obj, void *data, u_int32_t format)
264{
265 struct via_chinfo *ch = data;
266 struct via_info *via = ch->parent;
267 int mode, mode_set;
268
269 mode_set = 0;
270 if (format & AFMT_STEREO)
271 mode_set |= VIA_RPMODE_STEREO;
272 if (format & AFMT_S16_LE)
273 mode_set |= VIA_RPMODE_16BIT;
274
275 /* Set up for output format */
276 if (ch->dir == PCMDIR_PLAY) {
277 DEB(printf("set play format: %x\n", format));
278 mode = via_rd(via, VIA_PLAY_MODE, 1);
279 mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
280 mode |= mode_set;
281 via_wr(via, VIA_PLAY_MODE, mode, 1);
282 }
283 else {
284 DEB(printf("set record format: %x\n", format));
285 mode = via_rd(via, VIA_RECORD_MODE, 1);
286 mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
287 mode |= mode_set;
288 via_wr(via, VIA_RECORD_MODE, mode, 1);
289 }
290
291 return 0;
292}
293
294static int
295viachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
296{
297 struct via_chinfo *ch = data;
298 struct via_info *via = ch->parent;
299
300 /*
301 * Basic AC'97 defines a 48 kHz sample rate only. For other rates,
302 * upsampling is required.
303 *
304 * The VT82C686A does not perform upsampling, and neither do we.
305 * If the codec supports variable-rate audio (i.e. does the upsampling
306 * itself), then negotiate the rate with the codec. Otherwise,
307 * return 48 kHz cuz that's all you got.
308 */
309 if (ch->dir == PCMDIR_PLAY) {
310 DEB(printf("requested play speed: %d\n", speed));
311 if (via->codec_caps & AC97_CODEC_DOES_VRA) {
312 via_write_codec(NULL, via, AC97_REG_EXT_DAC_RATE, speed);
313 speed = via_read_codec(NULL, via, AC97_REG_EXT_DAC_RATE);
314 }
315 else {
316 DEB(printf("VRA not supported!\n"));
317 speed = 48000;
318 }
319 DEB(printf("obtained play speed: %d\n", speed));
320 }
321 else {
322 DEB(printf("requested record speed: %d\n", speed));
323 if (via->codec_caps & AC97_CODEC_DOES_VRA) {
324 via_write_codec(NULL, via, AC97_REG_EXT_ADC_RATE, speed);
325 speed = via_read_codec(NULL, via, AC97_REG_EXT_ADC_RATE);
326 }
327 else {
328 DEB(printf("VRA not supported!\n"));
329 speed = 48000;
330 }
331 DEB(printf("obtained record speed: %d\n", speed));
332 }
333 return speed;
334}
335
336static int
337viachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
338{
339 struct via_chinfo *ch = data;
340
341 return sndbuf_getsize(ch->buffer) / 2;
342}
343
344static int
345viachan_trigger(kobj_t obj, void *data, int go)
346{
347 struct via_chinfo *ch = data;
348 struct via_info *via = ch->parent;
349 struct via_dma_op *ado;
350
351 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0;
352 if (ch->dir == PCMDIR_PLAY) {
353 if (go == PCMTRIG_START) {
354 ado = &via->sgd_table[0];
355 DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
356 via_wr(via, VIA_PLAY_DMAOPS_BASE, vtophys(ado),4);
357 via_wr(via, VIA_PLAY_CONTROL,
358 VIA_RPCTRL_START, 1);
359 }
360 else {
361 /* Stop DMA */
362 via_wr(via, VIA_PLAY_CONTROL,
363 VIA_RPCTRL_TERMINATE, 1);
364 }
365 } else {
366 if (go == PCMTRIG_START) {
367 ado = &via->sgd_table[SEGS_PER_CHAN];
368 DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
369 via_wr(via, VIA_RECORD_DMAOPS_BASE,
370 vtophys(ado),4);
371 via_wr(via, VIA_RECORD_CONTROL,
372 VIA_RPCTRL_START, 1);
373 }
374 else {
375 /* Stop DMA */
376 via_wr(via, VIA_RECORD_CONTROL,
377 VIA_RPCTRL_TERMINATE, 1);
378 }
379 }
380
381DEB(printf("viachan_trigger: go=%d\n", go));
382 return 0;
383}
384
385static int
386viachan_getptr(kobj_t obj, void *data)
387{
388 struct via_chinfo *ch = data;
389 struct via_info *via = ch->parent;
390 struct via_dma_op *ado;
391 int ptr, base, len, seg;
392 int base1;
393
394 if (ch->dir == PCMDIR_PLAY) {
395 ado = &via->sgd_table[0];
396 base1 = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
397 len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
398 base = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
399 if (base != base1) { /* Avoid race hazzard */
400 len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
401 }
402 DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
403
404 /* Base points to SGD segment to do, one past current */
405
406 /* Determine how many segments have been done */
407 seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
408 if (seg == 0) seg = SEGS_PER_CHAN;
409
410 /* Now work out offset: seg less count */
411 ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
412 DEB(printf("return ptr=%d\n", ptr));
413 return ptr;
414 }
415 else {
416 base1 = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
417 ado = &via->sgd_table[SEGS_PER_CHAN];
418 len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
419 base = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
420 if (base != base1) { /* Avoid race hazzard */
421 len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
422 }
423 DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
424
425 /* Base points to next block to do, one past current */
426
427 /* Determine how many segments have been done */
428 seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
429 if (seg == 0) seg = SEGS_PER_CHAN;
430
431 /* Now work out offset: seg less count */
432 ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
433
434 /* DMA appears to operate on memory 'lines' of 32 bytes */
435 /* so don't return any part line - it isn't in RAM yet */
436 ptr = ptr & ~0x1f;
437 DEB(printf("return ptr=%d\n", ptr));
438 return ptr;
439 }
440 return 0;
441}
442
443static pcmchan_caps *
444viachan_getcaps(kobj_t obj, void *data)
445{
446 struct via_chinfo *ch = data;
447 return (ch->dir == PCMDIR_PLAY) ? &via_playcaps : &via_reccaps;
448}
449
450static kobj_method_t viachan_methods[] = {
451 KOBJMETHOD(channel_init, viachan_init),
452 KOBJMETHOD(channel_setdir, viachan_setdir),
453 KOBJMETHOD(channel_setformat, viachan_setformat),
454 KOBJMETHOD(channel_setspeed, viachan_setspeed),
455 KOBJMETHOD(channel_setblocksize, viachan_setblocksize),
456 KOBJMETHOD(channel_trigger, viachan_trigger),
457 KOBJMETHOD(channel_getptr, viachan_getptr),
458 KOBJMETHOD(channel_getcaps, viachan_getcaps),
459 { 0, 0 }
460};
461CHANNEL_DECLARE(viachan);
462
463/* -------------------------------------------------------------------- */
464
465static void
466via_intr(void *p)
467{
468 struct via_info *via = p;
469 int st;
470
471 /* DEB(printf("viachan_intr\n")); */
472 /* Read channel */
473 st = via_rd(via, VIA_PLAY_STAT, 1);
474 if (st & VIA_RPSTAT_INTR) {
475 via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
476 chn_intr(via->pch.channel);
477 }
478
479 /* Write channel */
480 st = via_rd(via, VIA_RECORD_STAT, 1);
481 if (st & VIA_RPSTAT_INTR) {
482 via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
483 chn_intr(via->rch.channel);
484 }
485}
486
487/*
488 * Probe and attach the card
489 */
490static int
491via_probe(device_t dev)
492{
493 if (pci_get_devid(dev) == VIA_PCI_ID) {
494 device_set_desc(dev, "VIA VT82C686A");
495 return 0;
496 }
497 return ENXIO;
498}
499
500
501void dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
502{
503}
504
505
506static int
507via_attach(device_t dev)
508{
509 struct via_info *via = 0;
510 struct ac97_info *codec = 0;
511 char status[SND_STATUSLEN];
512
513 u_int32_t data;
514
515 u_int16_t v;
516 bus_dmamap_t sgd_dma_map;
517
518 if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT)) == NULL) {
519 device_printf(dev, "cannot allocate softc\n");
520 return ENXIO;
521 }
522 bzero(via, sizeof *via);
523
524 /* Get resources */
525 data = pci_read_config(dev, PCIR_COMMAND, 2);
526 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
527 pci_write_config(dev, PCIR_COMMAND, data, 2);
528 data = pci_read_config(dev, PCIR_COMMAND, 2);
529
530 pci_write_config(dev, VIA_PCICONF_MISC,
531 VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD |
532 VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1);
533
534 via->regid = PCIR_MAPS;
535 via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid,
536 0, ~0, 1, RF_ACTIVE);
537 if (!via->reg) {
538 device_printf(dev, "cannot allocate bus resource.");
539 goto bad;
540 }
541 via->st = rman_get_bustag(via->reg);
542 via->sh = rman_get_bushandle(via->reg);
543
544 via->irqid = 0;
545 via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid,
546 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
547 if (!via->irq
548 || bus_setup_intr(dev, via->irq, INTR_TYPE_TTY, via_intr, via, &via->ih)){
549 device_printf(dev, "unable to map interrupt\n");
550 goto bad;
551 }
552
553 via_wr(via, VIA_PLAY_MODE,
554 VIA_RPMODE_AUTOSTART |
555 VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
556 via_wr(via, VIA_RECORD_MODE,
557 VIA_RPMODE_AUTOSTART |
558 VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
559
560 codec = AC97_CREATE(dev, via, via_ac97);
561 if (!codec) goto bad;
562
563 mixer_init(dev, ac97_getmixerclass(), codec);
564
565 /*
566 * The mixer init resets the codec. So enabling VRA must be done
567 * afterwards.
568 */
569 v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_ID);
570 v &= (AC97_ENAB_VRA | AC97_ENAB_MICVRA);
571 via_write_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT, v);
572 via->codec_caps = v;
573 {
574 v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT);
575 DEB(printf("init: codec stat: %d\n", v));
576 }
577
578 if (!(v & AC97_CODEC_DOES_VRA)) {
579 /* no VRA => can do only 48 kbps */
580 via_playcaps.minspeed = 48000;
581 via_reccaps.minspeed = 48000;
582 }
583
584 /* DMA tag for buffers */
585 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
586 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
587 /*highaddr*/BUS_SPACE_MAXADDR,
588 /*filter*/NULL, /*filterarg*/NULL,
589 /*maxsize*/VIA_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
590 /*flags*/0, &via->parent_dmat) != 0) {
591 device_printf(dev, "unable to create dma tag\n");
592 goto bad;
593 }
594
595 /*
596 * DMA tag for SGD table. The 686 uses scatter/gather DMA and
597 * requires a list in memory of work to do. We need only 16 bytes
598 * for this list, and it is wasteful to allocate 16K.
599 */
600 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
601 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
602 /*highaddr*/BUS_SPACE_MAXADDR,
603 /*filter*/NULL, /*filterarg*/NULL,
604 /*maxsize*/NSEGS * sizeof(struct via_dma_op),
605 /*nsegments*/1, /*maxsegz*/0x3ffff,
606 /*flags*/0, &via->sgd_dmat) != 0) {
607 device_printf(dev, "unable to create dma tag\n");
608 goto bad;
609 }
610
611 if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
612 BUS_DMA_NOWAIT, &sgd_dma_map) == -1) goto bad;
613 if (bus_dmamap_load(via->sgd_dmat, sgd_dma_map, via->sgd_table,
614 NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) goto bad;
615
616 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld",
617 rman_get_start(via->reg), rman_get_start(via->irq));
618
619 /* Register */
620 if (pcm_register(dev, via, 1, 1)) goto bad;
621 pcm_addchan(dev, PCMDIR_PLAY, &viachan_class, via);
622 pcm_addchan(dev, PCMDIR_REC, &viachan_class, via);
623 pcm_setstatus(dev, status);
624 return 0;
625bad:
626 if (codec) ac97_destroy(codec);
627 if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
628 if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
629 if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
630 if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
631 if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
632 if (via) free(via, M_DEVBUF);
633 return ENXIO;
634}
635
636static int
637via_detach(device_t dev)
638{
639 int r;
640 struct via_info *via = 0;
641
642 r = pcm_unregister(dev);
643 if (r)
644 return r;
645
646 via = pcm_getdevinfo(dev);
647 bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
648 bus_teardown_intr(dev, via->irq, via->ih);
649 bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
650 bus_dma_tag_destroy(via->parent_dmat);
651 bus_dma_tag_destroy(via->sgd_dmat);
652 free(via, M_DEVBUF);
653 return 0;
654}
655
656
657static device_method_t via_methods[] = {
658 DEVMETHOD(device_probe, via_probe),
659 DEVMETHOD(device_attach, via_attach),
660 DEVMETHOD(device_detach, via_detach),
661 { 0, 0}
662};
663
664static driver_t via_driver = {
665 "pcm",
666 via_methods,
667 sizeof(snddev_info),
668};
669
670static devclass_t pcm_devclass;
671
672DRIVER_MODULE(via, pci, via_driver, pcm_devclass, 0, 0);
673MODULE_DEPEND(via, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
674MODULE_VERSION(via, 1);
675
676