Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / pci / via8233.c
1 /*
2  * Copyright (c) 2002 Orion Hodson <orion@freebsd.org>
3  * Portions of this code derived from via82c686.c:
4  *      Copyright (c) 2000 David Jones <dej@ox.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /* Some Credits:
30  *
31  * Grzybowski Rafal, Russell Davies, Mark Handley, Daniel O'Connor for
32  * comments, machine time, testing patches, and patience.  VIA for
33  * providing specs.  ALSA for helpful comments and some register poke
34  * ordering.  
35  */
36
37 #include <dev/sound/pcm/sound.h>
38 #include <dev/sound/pcm/ac97.h>
39
40 #include <pci/pcireg.h>
41 #include <pci/pcivar.h>
42 #include <sys/sysctl.h>
43
44 #include <dev/sound/pci/via8233.h>
45
46 SND_DECLARE_FILE("$FreeBSD: src/sys/dev/sound/pci/via8233.c,v 1.2.2.2 2003/02/06 17:35:56 orion Exp $");
47
48 #define VIA8233_PCI_ID 0x30591106
49
50 #define SEGS_PER_CHAN   2                       /* Segments per channel */
51 #define NCHANS          2                       /* Lines-in,out (mic later) */
52 #define NSEGS           NCHANS * SEGS_PER_CHAN  /* Segments in SGD table */
53
54 #define VIA_DEFAULT_BUFSZ       0x1000
55
56 #undef DEB
57 #define DEB(x) x
58
59 /* we rely on this struct being packed to 64 bits */
60 struct via_dma_op {
61         u_int32_t ptr;
62         u_int32_t flags;
63 #define VIA_DMAOP_EOL         0x80000000
64 #define VIA_DMAOP_FLAG        0x40000000
65 #define VIA_DMAOP_STOP        0x20000000
66 #define VIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
67 };
68
69 struct via_info;
70
71 struct via_chinfo {
72         struct via_info *parent;
73         struct pcm_channel *channel;
74         struct snd_dbuf *buffer;
75         struct via_dma_op *sgd_table;
76         int dir, blksz;
77         int rbase;                      /* base register for channel */
78 };
79
80 struct via_info {
81         bus_space_tag_t st;
82         bus_space_handle_t sh;
83         bus_dma_tag_t parent_dmat;
84         bus_dma_tag_t sgd_dmat;
85         bus_dmamap_t sgd_dmamap;
86
87         struct resource *reg, *irq;
88         int regid, irqid;
89         void *ih;
90         struct ac97_info *codec;
91
92         unsigned int bufsz;
93
94         struct via_chinfo pch, rch;
95         struct via_dma_op *sgd_table;
96         u_int16_t codec_caps;
97 };
98
99 static u_int32_t via_fmt[] = {
100         AFMT_U8,
101         AFMT_STEREO | AFMT_U8,
102         AFMT_S16_LE,
103         AFMT_STEREO | AFMT_S16_LE,
104         0
105 };
106
107 static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
108 static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
109
110 static u_int32_t
111 via_rd(struct via_info *via, int regno, int size)
112 {
113         switch (size) {
114         case 1:
115                 return bus_space_read_1(via->st, via->sh, regno);
116         case 2:
117                 return bus_space_read_2(via->st, via->sh, regno);
118         case 4:
119                 return bus_space_read_4(via->st, via->sh, regno);
120         default:
121                 return 0xFFFFFFFF;
122         }
123 }
124
125 static void
126 via_wr(struct via_info *via, int regno, u_int32_t data, int size)
127 {
128
129         switch (size) {
130         case 1:
131                 bus_space_write_1(via->st, via->sh, regno, data);
132                 break;
133         case 2:
134                 bus_space_write_2(via->st, via->sh, regno, data);
135                 break;
136         case 4:
137                 bus_space_write_4(via->st, via->sh, regno, data);
138                 break;
139         }
140 }
141
142 /* -------------------------------------------------------------------- */
143 /* Codec interface */
144
145 static int
146 via_waitready_codec(struct via_info *via)
147 {
148         int i;
149
150         /* poll until codec not busy */
151         for (i = 0; i < 1000; i++) {
152                 if ((via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_BUSY) == 0)
153                         return 0;
154                 DELAY(1);
155         }
156         printf("via: codec busy\n");
157         return 1;
158 }
159
160 static int
161 via_waitvalid_codec(struct via_info *via)
162 {
163         int i;
164
165         /* poll until codec valid */
166         for (i = 0; i < 1000; i++) {
167                 if (via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_CODEC00_VALID)
168                         return 0;
169                 DELAY(1);
170         }
171         printf("via: codec invalid\n");
172         return 1;
173 }
174
175 static int
176 via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val)
177 {
178         struct via_info *via = addr;
179
180         if (via_waitready_codec(via)) return -1;
181
182         via_wr(via, VIA_AC97_CONTROL, 
183                VIA_AC97_CODEC00_VALID | VIA_AC97_INDEX(reg) |
184                VIA_AC97_DATA(val), 4);
185
186         return 0;
187 }
188
189 static int
190 via_read_codec(kobj_t obj, void *addr, int reg)
191 {
192         struct via_info *via = addr;
193
194         if (via_waitready_codec(via))
195                 return -1;
196
197         via_wr(via, VIA_AC97_CONTROL, VIA_AC97_CODEC00_VALID | 
198                VIA_AC97_READ | VIA_AC97_INDEX(reg), 4);
199
200         if (via_waitready_codec(via))
201                 return -1;
202
203         if (via_waitvalid_codec(via))
204                 return -1;
205
206         return via_rd(via, VIA_AC97_CONTROL, 2);
207 }
208
209 static kobj_method_t via_ac97_methods[] = {
210         KOBJMETHOD(ac97_read,           via_read_codec),
211         KOBJMETHOD(ac97_write,          via_write_codec),
212         { 0, 0 }
213 };
214 AC97_DECLARE(via_ac97);
215
216 /* -------------------------------------------------------------------- */
217
218 static int
219 via_buildsgdt(struct via_chinfo *ch)
220 {
221         u_int32_t phys_addr, flag;
222         int i, seg_size;
223
224         /*
225          *  Build the scatter/gather DMA (SGD) table.
226          *  There are four slots in the table: two for play, two for record.
227          *  This creates two half-buffers, one of which is playing; the other
228          *  is feeding.
229          */
230         seg_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
231                 
232         phys_addr = vtophys(sndbuf_getbuf(ch->buffer));
233
234         for (i = 0; i < SEGS_PER_CHAN; i++) {
235                 flag = (i == SEGS_PER_CHAN - 1) ? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
236                 ch->sgd_table[i].ptr = phys_addr + (i * seg_size);
237                 ch->sgd_table[i].flags = flag | seg_size;
238         }
239
240         return 0;
241 }
242
243 static int
244 via8233pchan_setformat(kobj_t obj, void *data, u_int32_t format)
245 {
246         struct via_chinfo *ch = data;
247         struct via_info *via = ch->parent;
248
249         u_int32_t s = 0xff000000;
250         u_int8_t  v = (format & AFMT_S16_LE) ? MC_SGD_16BIT : MC_SGD_8BIT;
251
252         if (format & AFMT_STEREO) {
253                 v |= MC_SGD_CHANNELS(2);
254                 s |= SLOT3(1) | SLOT4(2);
255         } else {
256                 v |= MC_SGD_CHANNELS(1);
257                 s |= SLOT3(1) | SLOT4(1);
258         }
259
260         via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
261         via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
262
263         return 0;
264 }
265
266 static int
267 via8233rchan_setformat(kobj_t obj, void *data, u_int32_t format)
268 {
269         struct via_chinfo *ch = data;
270         struct via_info *via = ch->parent;
271         
272         u_int32_t f = WR_FORMAT_STOP_INDEX;
273         if (format & AFMT_STEREO)
274                 f |= WR_FORMAT_STEREO;
275         if (format & AFMT_S16_LE)
276                 f |= WR_FORMAT_16BIT;
277         via_wr(via, VIA_WR0_FORMAT, f, 4);
278
279         return 0;
280 }
281
282 static int
283 via8233pchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
284 {
285         struct via_chinfo *ch = data;
286         struct via_info *via = ch->parent;
287
288         if (via->codec_caps & AC97_EXTCAP_VRA)
289                 return ac97_setrate(via->codec, AC97_REGEXT_FDACRATE, speed); 
290
291         return 48000;
292 }
293
294 static int
295 via8233rchan_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         u_int32_t spd = 48000;
301         if (via->codec_caps & AC97_EXTCAP_VRA) {
302                 spd = ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed);
303         }
304         return spd;
305 }
306
307 static int
308 via8233chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
309 {
310         struct via_chinfo *ch = data;
311
312         sndbuf_resize(ch->buffer, SEGS_PER_CHAN, blocksize);
313         ch->blksz = sndbuf_getblksz(ch->buffer);
314         return ch->blksz;
315 }
316
317 static int
318 via8233chan_getptr(kobj_t obj, void *data)
319 {
320         struct via_chinfo *ch = data;
321         struct via_info *via = ch->parent;
322
323         u_int32_t v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
324         u_int32_t index = v >> 24;              /* Last completed buffer */
325         u_int32_t count = v & 0x00ffffff;       /* Bytes remaining */
326         int ptr = (index + 1) * ch->blksz - count;
327         ptr %= SEGS_PER_CHAN * ch->blksz;       /* Wrap to available space */
328
329         return ptr;
330 }
331
332 static struct pcmchan_caps *
333 via8233chan_getcaps(kobj_t obj, void *data)
334 {
335         struct via_chinfo *ch = data;
336         struct via_info *via = ch->parent;
337         if (via->codec_caps & AC97_EXTCAP_VRA) 
338                 return &via_vracaps;
339         return &via_caps;
340 }
341
342 static void
343 via8233chan_reset(struct via_info *via, struct via_chinfo *ch)
344 {
345         via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
346         via_wr(via, ch->rbase + VIA_RP_CONTROL, 0x00, 1);
347         via_wr(via, ch->rbase + VIA_RP_STATUS, 
348                SGD_STATUS_EOL | SGD_STATUS_FLAG, 1);
349 }
350
351 static void*
352 via8233chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
353                  struct pcm_channel *c, int dir)
354 {
355         struct via_info *via = devinfo;
356         struct via_chinfo *ch = (dir == PCMDIR_PLAY)? &via->pch : &via->rch;
357
358         ch->parent = via;
359         ch->channel = c;
360         ch->buffer = b;
361         ch->dir = dir;
362         ch->sgd_table = &via->sgd_table[(dir == PCMDIR_PLAY)? 0 : SEGS_PER_CHAN];
363
364         if (ch->dir == PCMDIR_PLAY) {
365                 ch->rbase = VIA_MC_SGD_STATUS;
366         } else {
367                 ch->rbase = VIA_WR0_SGD_STATUS;
368                 via_wr(via, VIA_WR0_SGD_FORMAT, WR_FIFO_ENABLE, 1);
369         }
370
371         if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) == -1)
372                 return NULL;
373
374         via8233chan_reset(via, ch);
375
376         return ch;
377 }
378
379 static int
380 via8233chan_trigger(kobj_t obj, void* data, int go)
381 {
382         struct via_chinfo *ch = data;
383         struct via_info *via = ch->parent;
384         struct via_dma_op *ado = ch->sgd_table;
385
386         switch(go) {
387         case PCMTRIG_START:
388                 via_buildsgdt(ch);
389                 via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, vtophys(ado), 4);
390                 via_wr(via, ch->rbase + VIA_RP_CONTROL,
391                        SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
392                        SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
393                 break;
394         case PCMTRIG_STOP:
395         case PCMTRIG_ABORT:
396                 via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
397                 via8233chan_reset(via, ch);
398                 break;
399         }
400         return 0;
401 }
402
403 static kobj_method_t via8233pchan_methods[] = {
404         KOBJMETHOD(channel_init,                via8233chan_init),
405         KOBJMETHOD(channel_setformat,           via8233pchan_setformat),
406         KOBJMETHOD(channel_setspeed,            via8233pchan_setspeed),
407         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
408         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
409         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
410         KOBJMETHOD(channel_getcaps,             via8233chan_getcaps),
411         { 0, 0 }
412 };
413 CHANNEL_DECLARE(via8233pchan);
414
415 static kobj_method_t via8233rchan_methods[] = {
416         KOBJMETHOD(channel_init,                via8233chan_init),
417         KOBJMETHOD(channel_setformat,           via8233rchan_setformat),
418         KOBJMETHOD(channel_setspeed,            via8233rchan_setspeed),
419         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
420         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
421         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
422         KOBJMETHOD(channel_getcaps,             via8233chan_getcaps),
423         { 0, 0 }
424 };
425 CHANNEL_DECLARE(via8233rchan);
426
427 /* -------------------------------------------------------------------- */
428
429 static void
430 via_intr(void *p)
431 {
432         struct via_info *via = p;
433         int r = via_rd(via, VIA_MC_SGD_STATUS, 1);
434         if (r & SGD_STATUS_INTR) {
435                 via_wr(via, VIA_MC_SGD_STATUS, SGD_STATUS_INTR, 1);
436                 chn_intr(via->pch.channel);
437         }
438
439         r = via_rd(via, VIA_WR0_SGD_STATUS, 1);
440         if (r & SGD_STATUS_INTR) {
441                 via_wr(via, VIA_WR0_SGD_STATUS, SGD_STATUS_INTR, 1);
442                 chn_intr(via->rch.channel);
443         }
444 }
445
446 /*
447  *  Probe and attach the card
448  */
449 static int
450 via_probe(device_t dev)
451 {
452         switch(pci_get_devid(dev)) {
453         case VIA8233_PCI_ID:
454                 switch(pci_get_revid(dev)) {
455                 case 0x10: 
456                         device_set_desc(dev, "VIA VT8233 (pre)");
457                         return 0;
458                 case 0x20:
459                         device_set_desc(dev, "VIA VT8233C");
460                         return 0;
461                 case 0x30:
462                         device_set_desc(dev, "VIA VT8233");
463                         return 0;
464                 case 0x40:
465                         device_set_desc(dev, "VIA VT8233A");
466                         return 0;
467                 case 0x50:
468                         device_set_desc(dev, "VIA VT8235");
469                         return 0;
470                 default:
471                         device_set_desc(dev, "VIA VT8233X");    /* Unknown */
472                         return 0;
473                 }                       
474         }
475         return ENXIO;
476 }
477
478 static void
479 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
480 {
481 }
482
483 static int
484 via_chip_init(device_t dev)
485 {
486         int i, s;
487
488         pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 0, 1);       
489         DELAY(100);
490
491         /* assert ACLink reset */
492         pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_NRST, 1);
493         DELAY(2);
494
495         /* deassert ACLink reset, force SYNC (warm AC'97 reset) */
496         pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
497                          VIA_PCI_ACLINK_NRST | VIA_PCI_ACLINK_SYNC, 1);
498
499         /* ACLink on, deassert ACLink reset, VSR, SGD data out */
500         pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
501                          VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST
502                          | VIA_PCI_ACLINK_VRATE | VIA_PCI_ACLINK_SGD, 1);
503
504         for (i = 0; i < 100; i++) {
505                 s = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
506                 if (s & VIA_PCI_ACLINK_C00_READY) {
507                         s = pci_read_config(dev, VIA_PCI_ACLINK_CTRL, 1);
508                         return 0;
509                 }
510                 DELAY(10);
511         }
512         device_printf(dev, "primary codec not ready (s = 0x%02x)\n", s);
513         return ENXIO;
514 }
515
516 static int
517 via_attach(device_t dev)
518 {
519         struct via_info *via = 0;
520         char status[SND_STATUSLEN];
521
522         if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
523                 device_printf(dev, "cannot allocate softc\n");
524                 return ENXIO;
525         }
526
527         pci_enable_io(dev, SYS_RES_IOPORT);
528         pci_set_powerstate(dev, PCI_POWERSTATE_D0);
529         pci_enable_busmaster(dev);
530         
531         via->regid = PCIR_MAPS;
532         via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid, 0, ~0,
533                                       1, RF_ACTIVE);
534         if (!via->reg) {
535                 device_printf(dev, "cannot allocate bus resource.");
536                 goto bad;
537         }
538         via->st = rman_get_bustag(via->reg);
539         via->sh = rman_get_bushandle(via->reg);
540
541         via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536);
542
543         via->irqid = 0;
544         via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid, 0, ~0, 1,
545                                       RF_ACTIVE | RF_SHAREABLE);
546         if (!via->irq || 
547             snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) {
548                 device_printf(dev, "unable to map interrupt\n");
549                 goto bad;
550         }
551
552         /* DMA tag for buffers */
553         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
554                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
555                 /*highaddr*/BUS_SPACE_MAXADDR,
556                 /*filter*/NULL, /*filterarg*/NULL,
557                 /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
558                 /*flags*/0, &via->parent_dmat) != 0) {
559                 device_printf(dev, "unable to create dma tag\n");
560                 goto bad;
561         }
562
563         /*
564          *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
565          *  requires a list in memory of work to do.  We need only 16 bytes
566          *  for this list, and it is wasteful to allocate 16K.
567          */
568         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
569                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
570                 /*highaddr*/BUS_SPACE_MAXADDR,
571                 /*filter*/NULL, /*filterarg*/NULL,
572                 /*maxsize*/NSEGS * sizeof(struct via_dma_op),
573                 /*nsegments*/1, /*maxsegz*/0x3ffff,
574                 /*flags*/0, &via->sgd_dmat) != 0) {
575                 device_printf(dev, "unable to create dma tag\n");
576                 goto bad;
577         }
578
579         if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, 
580                              BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
581                 goto bad;
582         if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, 
583                             NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0))
584                 goto bad;
585
586         if (via_chip_init(dev))
587                 goto bad;
588
589         via->codec = AC97_CREATE(dev, via, via_ac97);
590         if (!via->codec)
591                 goto bad;
592
593         mixer_init(dev, ac97_getmixerclass(), via->codec);
594
595         via->codec_caps = ac97_getextcaps(via->codec);
596
597         /* Try to set VRA without generating an error, VRM not reqrd yet */
598         if (via->codec_caps & 
599             (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) {
600                 u_int16_t ext = ac97_getextmode(via->codec);
601                 ext |= (via->codec_caps & 
602                         (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
603                 ext &= ~AC97_EXTCAP_DRA;
604                 ac97_setextmode(via->codec, ext);
605         }
606
607         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", 
608                  rman_get_start(via->reg), rman_get_start(via->irq));
609
610         /* Register */
611         if (pcm_register(dev, via, 1, 1)) goto bad;
612
613         pcm_addchan(dev, PCMDIR_PLAY, &via8233pchan_class, via);
614         pcm_addchan(dev, PCMDIR_REC, &via8233rchan_class, via);
615
616         pcm_setstatus(dev, status);
617
618         return 0;
619 bad:
620         if (via->codec) ac97_destroy(via->codec);
621         if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
622         if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
623         if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
624         if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
625         if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
626         if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
627         if (via) free(via, M_DEVBUF);
628         return ENXIO;
629 }
630
631 static int
632 via_detach(device_t dev)
633 {
634         int r;
635         struct via_info *via = 0;
636
637         r = pcm_unregister(dev);
638         if (r) return r;
639
640         via = pcm_getdevinfo(dev);
641         bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
642         bus_teardown_intr(dev, via->irq, via->ih);
643         bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
644         bus_dma_tag_destroy(via->parent_dmat);
645         bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
646         bus_dma_tag_destroy(via->sgd_dmat);
647         free(via, M_DEVBUF);
648         return 0;
649 }
650
651
652 static device_method_t via_methods[] = {
653         DEVMETHOD(device_probe,         via_probe),
654         DEVMETHOD(device_attach,        via_attach),
655         DEVMETHOD(device_detach,        via_detach),
656         { 0, 0}
657 };
658
659 static driver_t via_driver = {
660         "pcm",
661         via_methods,
662         PCM_SOFTC_SIZE,
663 };
664
665 DRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, 0, 0);
666 MODULE_DEPEND(snd_via8233, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
667 MODULE_VERSION(snd_via8233, 1);