xref: /freebsd/sys/dev/sound/pci/via8233.c (revision 2b743a9e9ddc6736208dc8ca1ce06ce64ad20a19)
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 /*
30  * Credits due to:
31  *
32  * Grzybowski Rafal, Russell Davies, Mark Handley, Daniel O'Connor for
33  * comments, machine time, testing patches, and patience.  VIA for
34  * providing specs.  ALSA for helpful comments and some register poke
35  * ordering.
36  */
37 
38 #include <dev/sound/pcm/sound.h>
39 #include <dev/sound/pcm/ac97.h>
40 
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43 #include <sys/sysctl.h>
44 
45 #include <dev/sound/pci/via8233.h>
46 
47 SND_DECLARE_FILE("$FreeBSD$");
48 
49 #define VIA8233_PCI_ID 0x30591106
50 
51 #define VIA8233_REV_ID_8233PRE	0x10
52 #define VIA8233_REV_ID_8233C	0x20
53 #define VIA8233_REV_ID_8233	0x30
54 #define VIA8233_REV_ID_8233A	0x40
55 #define VIA8233_REV_ID_8235	0x50
56 #define VIA8233_REV_ID_8237	0x60
57 #define VIA8233_REV_ID_8251	0x70
58 
59 #define SEGS_PER_CHAN	2			/* Segments per channel */
60 #define NDXSCHANS	4			/* No of DXS channels */
61 #define NMSGDCHANS	1			/* No of multichannel SGD */
62 #define NWRCHANS	1			/* No of write channels */
63 #define NCHANS		(NWRCHANS + NDXSCHANS + NMSGDCHANS)
64 #define	NSEGS		NCHANS * SEGS_PER_CHAN	/* Segments in SGD table */
65 #define VIA_SEGS_MIN		2
66 #define VIA_SEGS_MAX		64
67 #define VIA_SEGS_DEFAULT	2
68 
69 #define	VIA_DEFAULT_BUFSZ	0x1000
70 
71 /* we rely on this struct being packed to 64 bits */
72 struct via_dma_op {
73 	volatile uint32_t ptr;
74 	volatile uint32_t flags;
75 #define VIA_DMAOP_EOL         0x80000000
76 #define VIA_DMAOP_FLAG        0x40000000
77 #define VIA_DMAOP_STOP        0x20000000
78 #define VIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
79 };
80 
81 struct via_info;
82 
83 struct via_chinfo {
84 	struct via_info *parent;
85 	struct pcm_channel *channel;
86 	struct snd_dbuf *buffer;
87 	struct via_dma_op *sgd_table;
88 	bus_addr_t sgd_addr;
89 	int dir, rbase, active;
90 	unsigned int blksz, blkcnt;
91 	unsigned int ptr, prevptr;
92 };
93 
94 struct via_info {
95 	bus_space_tag_t st;
96 	bus_space_handle_t sh;
97 	bus_dma_tag_t parent_dmat;
98 	bus_dma_tag_t sgd_dmat;
99 	bus_dmamap_t sgd_dmamap;
100 	bus_addr_t sgd_addr;
101 
102 	struct resource *reg, *irq;
103 	int regid, irqid;
104 	void *ih;
105 	struct ac97_info *codec;
106 
107 	unsigned int bufsz, blkcnt;
108 	int dxs_src, dma_eol_wake;
109 
110 	struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
111 	struct via_chinfo rch[NWRCHANS];
112 	struct via_dma_op *sgd_table;
113 	uint16_t codec_caps;
114 	uint16_t n_dxs_registered;
115 	struct mtx *lock;
116 	struct callout poll_timer;
117 	int poll_ticks, polling;
118 };
119 
120 static uint32_t via_fmt[] = {
121 	AFMT_U8,
122 	AFMT_STEREO | AFMT_U8,
123 	AFMT_S16_LE,
124 	AFMT_STEREO | AFMT_S16_LE,
125 	0
126 };
127 
128 static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
129 static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
130 
131 static __inline int
132 via_chan_active(struct via_info *via)
133 {
134 	int i, ret = 0;
135 
136 	if (via == NULL)
137 		return (0);
138 
139 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++)
140 		ret += via->pch[i].active;
141 
142 	for (i = 0; i < NWRCHANS; i++)
143 		ret += via->rch[i].active;
144 
145 	return (ret);
146 }
147 
148 #ifdef SND_DYNSYSCTL
149 static int
150 sysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS)
151 {
152 	struct via_info *via;
153 	device_t dev;
154 	uint32_t r;
155 	int err, new_en;
156 
157 	dev = oidp->oid_arg1;
158 	via = pcm_getdevinfo(dev);
159 	snd_mtxlock(via->lock);
160 	r = pci_read_config(dev, VIA_PCI_SPDIF, 1);
161 	snd_mtxunlock(via->lock);
162 	new_en = (r & VIA_SPDIF_EN) ? 1 : 0;
163 	err = sysctl_handle_int(oidp, &new_en, sizeof(new_en), req);
164 
165 	if (err || req->newptr == NULL)
166 		return (err);
167 	if (new_en < 0 || new_en > 1)
168 		return (EINVAL);
169 
170 	if (new_en)
171 		r |= VIA_SPDIF_EN;
172 	else
173 		r &= ~VIA_SPDIF_EN;
174 	snd_mtxlock(via->lock);
175 	pci_write_config(dev, VIA_PCI_SPDIF, r, 1);
176 	snd_mtxunlock(via->lock);
177 
178 	return (0);
179 }
180 
181 static int
182 sysctl_via8233_dxs_src(SYSCTL_HANDLER_ARGS)
183 {
184 	struct via_info *via;
185 	device_t dev;
186 	int err, val;
187 
188 	dev = oidp->oid_arg1;
189 	via = pcm_getdevinfo(dev);
190 	snd_mtxlock(via->lock);
191 	val = via->dxs_src;
192 	snd_mtxunlock(via->lock);
193 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
194 
195 	if (err || req->newptr == NULL)
196 		return (err);
197 	if (val < 0 || val > 1)
198 		return (EINVAL);
199 
200 	snd_mtxlock(via->lock);
201 	via->dxs_src = val;
202 	snd_mtxunlock(via->lock);
203 
204 	return (0);
205 }
206 
207 static int
208 sysctl_via_polling(SYSCTL_HANDLER_ARGS)
209 {
210 	struct via_info *via;
211 	device_t dev;
212 	int err, val;
213 
214 	dev = oidp->oid_arg1;
215 	via = pcm_getdevinfo(dev);
216 	if (via == NULL)
217 		return (EINVAL);
218 	snd_mtxlock(via->lock);
219 	val = via->polling;
220 	snd_mtxunlock(via->lock);
221 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
222 
223 	if (err || req->newptr == NULL)
224 		return (err);
225 	if (val < 0 || val > 1)
226 		return (EINVAL);
227 
228 	snd_mtxlock(via->lock);
229 	if (val != via->polling) {
230 		if (via_chan_active(via) != 0)
231 			err = EBUSY;
232 		else if (val == 0)
233 			via->polling = 0;
234 		else
235 			via->polling = 1;
236 	}
237 	snd_mtxunlock(via->lock);
238 
239 	return (err);
240 }
241 #endif /* SND_DYNSYSCTL */
242 
243 static void
244 via_init_sysctls(device_t dev)
245 {
246 #ifdef SND_DYNSYSCTL
247 	/* XXX: an user should be able to set this with a control tool,
248 	   if not done before 7.0-RELEASE, this needs to be converted to
249 	   a device specific sysctl "dev.pcm.X.yyy" via device_get_sysctl_*()
250 	   as discussed on multimedia@ in msg-id <861wujij2q.fsf@xps.des.no> */
251 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
252 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
253 	    "spdif_enabled",  CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
254 	    sysctl_via8233_spdif_enable, "I",
255 	    "Enable S/PDIF output on primary playback channel");
256 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
257 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
258 	    "dxs_src", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
259 	    sysctl_via8233_dxs_src, "I",
260 	    "Enable VIA DXS Sample Rate Converter");
261 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
262 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
263 	    "polling", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
264 	    sysctl_via_polling, "I",
265 	    "Enable polling mode");
266 #endif
267 }
268 
269 static __inline uint32_t
270 via_rd(struct via_info *via, int regno, int size)
271 {
272 	switch (size) {
273 	case 1:
274 		return (bus_space_read_1(via->st, via->sh, regno));
275 	case 2:
276 		return (bus_space_read_2(via->st, via->sh, regno));
277 	case 4:
278 		return (bus_space_read_4(via->st, via->sh, regno));
279 	default:
280 		return (0xFFFFFFFF);
281 	}
282 }
283 
284 static __inline void
285 via_wr(struct via_info *via, int regno, uint32_t data, int size)
286 {
287 
288 	switch (size) {
289 	case 1:
290 		bus_space_write_1(via->st, via->sh, regno, data);
291 		break;
292 	case 2:
293 		bus_space_write_2(via->st, via->sh, regno, data);
294 		break;
295 	case 4:
296 		bus_space_write_4(via->st, via->sh, regno, data);
297 		break;
298 	}
299 }
300 
301 /* -------------------------------------------------------------------- */
302 /* Codec interface */
303 
304 static int
305 via_waitready_codec(struct via_info *via)
306 {
307 	int i;
308 
309 	/* poll until codec not busy */
310 	for (i = 0; i < 1000; i++) {
311 		if ((via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_BUSY) == 0)
312 			return (0);
313 		DELAY(1);
314 	}
315 	printf("via: codec busy\n");
316 	return (1);
317 }
318 
319 static int
320 via_waitvalid_codec(struct via_info *via)
321 {
322 	int i;
323 
324 	/* poll until codec valid */
325 	for (i = 0; i < 1000; i++) {
326 		if (via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_CODEC00_VALID)
327 			return (0);
328 		DELAY(1);
329 	}
330 	printf("via: codec invalid\n");
331 	return (1);
332 }
333 
334 static int
335 via_write_codec(kobj_t obj, void *addr, int reg, uint32_t val)
336 {
337 	struct via_info *via = addr;
338 
339 	if (via_waitready_codec(via))
340 		return (-1);
341 
342 	via_wr(via, VIA_AC97_CONTROL,
343 	       VIA_AC97_CODEC00_VALID | VIA_AC97_INDEX(reg) |
344 	       VIA_AC97_DATA(val), 4);
345 
346 	return (0);
347 }
348 
349 static int
350 via_read_codec(kobj_t obj, void *addr, int reg)
351 {
352 	struct via_info *via = addr;
353 
354 	if (via_waitready_codec(via))
355 		return (-1);
356 
357 	via_wr(via, VIA_AC97_CONTROL, VIA_AC97_CODEC00_VALID |
358 	    VIA_AC97_READ | VIA_AC97_INDEX(reg), 4);
359 
360 	if (via_waitready_codec(via))
361 		return (-1);
362 
363 	if (via_waitvalid_codec(via))
364 		return (-1);
365 
366 	return (via_rd(via, VIA_AC97_CONTROL, 2));
367 }
368 
369 static kobj_method_t via_ac97_methods[] = {
370 	KOBJMETHOD(ac97_read,		via_read_codec),
371 	KOBJMETHOD(ac97_write,		via_write_codec),
372 	{ 0, 0 }
373 };
374 AC97_DECLARE(via_ac97);
375 
376 /* -------------------------------------------------------------------- */
377 
378 static int
379 via_buildsgdt(struct via_chinfo *ch)
380 {
381 	uint32_t phys_addr, flag;
382 	int i;
383 
384 	phys_addr = sndbuf_getbufaddr(ch->buffer);
385 
386 	for (i = 0; i < ch->blkcnt; i++) {
387 		flag = (i == ch->blkcnt - 1) ? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
388 		ch->sgd_table[i].ptr = phys_addr + (i * ch->blksz);
389 		ch->sgd_table[i].flags = flag | ch->blksz;
390 	}
391 
392 	return (0);
393 }
394 
395 /* -------------------------------------------------------------------- */
396 /* Format setting functions */
397 
398 static int
399 via8233wr_setformat(kobj_t obj, void *data, uint32_t format)
400 {
401 	struct via_chinfo *ch = data;
402 	struct via_info *via = ch->parent;
403 
404 	uint32_t f = WR_FORMAT_STOP_INDEX;
405 
406 	if (format & AFMT_STEREO)
407 		f |= WR_FORMAT_STEREO;
408 	if (format & AFMT_S16_LE)
409 		f |= WR_FORMAT_16BIT;
410 	snd_mtxlock(via->lock);
411 	via_wr(via, VIA_WR0_FORMAT, f, 4);
412 	snd_mtxunlock(via->lock);
413 
414 	return (0);
415 }
416 
417 static int
418 via8233dxs_setformat(kobj_t obj, void *data, uint32_t format)
419 {
420 	struct via_chinfo *ch = data;
421 	struct via_info *via = ch->parent;
422 	uint32_t r, v;
423 
424 	r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
425 	snd_mtxlock(via->lock);
426 	v = via_rd(via, r, 4);
427 
428 	v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT);
429 	if (format & AFMT_STEREO)
430 		v |= VIA8233_DXS_RATEFMT_STEREO;
431 	if (format & AFMT_16BIT)
432 		v |= VIA8233_DXS_RATEFMT_16BIT;
433 	via_wr(via, r, v, 4);
434 	snd_mtxunlock(via->lock);
435 
436 	return (0);
437 }
438 
439 static int
440 via8233msgd_setformat(kobj_t obj, void *data, uint32_t format)
441 {
442 	struct via_chinfo *ch = data;
443 	struct via_info *via = ch->parent;
444 
445 	uint32_t s = 0xff000000;
446 	uint8_t  v = (format & AFMT_S16_LE) ? MC_SGD_16BIT : MC_SGD_8BIT;
447 
448 	if (format & AFMT_STEREO) {
449 		v |= MC_SGD_CHANNELS(2);
450 		s |= SLOT3(1) | SLOT4(2);
451 	} else {
452 		v |= MC_SGD_CHANNELS(1);
453 		s |= SLOT3(1) | SLOT4(1);
454 	}
455 
456 	snd_mtxlock(via->lock);
457 	via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
458 	via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
459 	snd_mtxunlock(via->lock);
460 
461 	return (0);
462 }
463 
464 /* -------------------------------------------------------------------- */
465 /* Speed setting functions */
466 
467 static int
468 via8233wr_setspeed(kobj_t obj, void *data, uint32_t speed)
469 {
470 	struct via_chinfo *ch = data;
471 	struct via_info *via = ch->parent;
472 
473 	if (via->codec_caps & AC97_EXTCAP_VRA)
474 		return (ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed));
475 
476 	return (48000);
477 }
478 
479 static int
480 via8233dxs_setspeed(kobj_t obj, void *data, uint32_t speed)
481 {
482 	struct via_chinfo *ch = data;
483 	struct via_info *via = ch->parent;
484 	uint32_t r, v;
485 
486 	r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
487 	snd_mtxlock(via->lock);
488 	v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K;
489 
490 	/* Careful to avoid overflow (divide by 48 per vt8233c docs) */
491 
492 	v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48);
493 	via_wr(via, r, v, 4);
494 	snd_mtxunlock(via->lock);
495 
496 	return (speed);
497 }
498 
499 static int
500 via8233msgd_setspeed(kobj_t obj, void *data, uint32_t speed)
501 {
502 	struct via_chinfo *ch = data;
503 	struct via_info *via = ch->parent;
504 
505 	if (via->codec_caps & AC97_EXTCAP_VRA)
506 		return (ac97_setrate(via->codec, AC97_REGEXT_FDACRATE, speed));
507 
508 	return (48000);
509 }
510 
511 /* -------------------------------------------------------------------- */
512 /* Format probing functions */
513 
514 static struct pcmchan_caps *
515 via8233wr_getcaps(kobj_t obj, void *data)
516 {
517 	struct via_chinfo *ch = data;
518 	struct via_info *via = ch->parent;
519 
520 	/* Controlled by ac97 registers */
521 	if (via->codec_caps & AC97_EXTCAP_VRA)
522 		return (&via_vracaps);
523 	return (&via_caps);
524 }
525 
526 static struct pcmchan_caps *
527 via8233dxs_getcaps(kobj_t obj, void *data)
528 {
529 	struct via_chinfo *ch = data;
530 	struct via_info *via = ch->parent;
531 
532 	/*
533 	 * Controlled by onboard registers
534 	 *
535 	 * Apparently, few boards can do DXS sample rate
536 	 * conversion.
537 	 */
538 	if (via->dxs_src)
539 		return (&via_vracaps);
540 	return (&via_caps);
541 }
542 
543 static struct pcmchan_caps *
544 via8233msgd_getcaps(kobj_t obj, void *data)
545 {
546 	struct via_chinfo *ch = data;
547 	struct via_info *via = ch->parent;
548 
549 	/* Controlled by ac97 registers */
550 	if (via->codec_caps & AC97_EXTCAP_VRA)
551 		return (&via_vracaps);
552 	return (&via_caps);
553 }
554 
555 /* -------------------------------------------------------------------- */
556 /* Common functions */
557 
558 static int
559 via8233chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
560 {
561 	struct via_chinfo *ch = data;
562 
563 	if ((blksz * ch->blkcnt) > sndbuf_getmaxsize(ch->buffer))
564 		blksz = sndbuf_getmaxsize(ch->buffer) / ch->blkcnt;
565 
566 	if ((sndbuf_getblksz(ch->buffer) != blksz ||
567 	    sndbuf_getblkcnt(ch->buffer) != ch->blkcnt) &&
568 	    sndbuf_resize(ch->buffer, ch->blkcnt, blksz) != 0)
569 		printf("via: %s: failed blksz=%u blkcnt=%u\n",
570 		    __func__, blksz, ch->blkcnt);
571 
572 	ch->blksz = sndbuf_getblksz(ch->buffer);
573 
574 	return (ch->blksz);
575 }
576 
577 static int
578 via8233chan_getptr(kobj_t obj, void *data)
579 {
580 	struct via_chinfo *ch = data;
581 	struct via_info *via = ch->parent;
582 	uint32_t v, index, count;
583 	int ptr;
584 
585 	snd_mtxlock(via->lock);
586 	if (via->polling != 0) {
587 		ptr = ch->ptr;
588 		snd_mtxunlock(via->lock);
589 	} else {
590 		v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
591 		snd_mtxunlock(via->lock);
592 		index = v >> 24;		/* Last completed buffer */
593 		count = v & 0x00ffffff;	/* Bytes remaining */
594 		ptr = (index + 1) * ch->blksz - count;
595 		ptr %= ch->blkcnt * ch->blksz;	/* Wrap to available space */
596 	}
597 
598 	return (ptr);
599 }
600 
601 static void
602 via8233chan_reset(struct via_info *via, struct via_chinfo *ch)
603 {
604 	via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
605 	via_wr(via, ch->rbase + VIA_RP_CONTROL, 0x00, 1);
606 	via_wr(via, ch->rbase + VIA_RP_STATUS,
607 	    SGD_STATUS_EOL | SGD_STATUS_FLAG, 1);
608 }
609 
610 /* -------------------------------------------------------------------- */
611 /* Channel initialization functions */
612 
613 static void
614 via8233chan_sgdinit(struct via_info *via, struct via_chinfo *ch, int chnum)
615 {
616 	ch->sgd_table = &via->sgd_table[chnum * via->blkcnt];
617 	ch->sgd_addr = via->sgd_addr + chnum * via->blkcnt *
618 	    sizeof(struct via_dma_op);
619 }
620 
621 static void*
622 via8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
623 						struct pcm_channel *c, int dir)
624 {
625 	struct via_info *via = devinfo;
626 	struct via_chinfo *ch = &via->rch[c->num];
627 
628 	ch->parent = via;
629 	ch->channel = c;
630 	ch->buffer = b;
631 	ch->dir = dir;
632 	ch->blkcnt = via->blkcnt;
633 
634 	ch->rbase = VIA_WR_BASE(c->num);
635 	snd_mtxlock(via->lock);
636 	via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1);
637 	snd_mtxunlock(via->lock);
638 
639 	if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
640 		return (NULL);
641 
642 	snd_mtxlock(via->lock);
643 	via8233chan_sgdinit(via, ch, c->num);
644 	via8233chan_reset(via, ch);
645 	snd_mtxunlock(via->lock);
646 
647 	return (ch);
648 }
649 
650 static void*
651 via8233dxs_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
652 						struct pcm_channel *c, int dir)
653 {
654 	struct via_info *via = devinfo;
655 	struct via_chinfo *ch = &via->pch[c->num];
656 
657 	ch->parent = via;
658 	ch->channel = c;
659 	ch->buffer = b;
660 	ch->dir = dir;
661 	ch->blkcnt = via->blkcnt;
662 
663 	/*
664 	 * All cards apparently support DXS3, but not other DXS
665 	 * channels.  We therefore want to align first DXS channel to
666 	 * DXS3.
667 	 */
668 	snd_mtxlock(via->lock);
669 	ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered);
670 	via->n_dxs_registered++;
671 	snd_mtxunlock(via->lock);
672 
673 	if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
674 		return (NULL);
675 
676 	snd_mtxlock(via->lock);
677 	via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
678 	via8233chan_reset(via, ch);
679 	snd_mtxunlock(via->lock);
680 
681 	return (ch);
682 }
683 
684 static void*
685 via8233msgd_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
686 						struct pcm_channel *c, int dir)
687 {
688 	struct via_info *via = devinfo;
689 	struct via_chinfo *ch = &via->pch[c->num];
690 
691 	ch->parent = via;
692 	ch->channel = c;
693 	ch->buffer = b;
694 	ch->dir = dir;
695 	ch->rbase = VIA_MC_SGD_STATUS;
696 	ch->blkcnt = via->blkcnt;
697 
698 	if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
699 		return (NULL);
700 
701 	snd_mtxlock(via->lock);
702 	via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
703 	via8233chan_reset(via, ch);
704 	snd_mtxunlock(via->lock);
705 
706 	return (ch);
707 }
708 
709 static void
710 via8233chan_mute(struct via_info *via, struct via_chinfo *ch, int muted)
711 {
712 	if (BASE_IS_VIA_DXS_REG(ch->rbase)) {
713 		int r;
714 		muted = (muted) ? VIA8233_DXS_MUTE : 0;
715 		via_wr(via, ch->rbase + VIA8233_RP_DXS_LVOL, muted, 1);
716 		via_wr(via, ch->rbase + VIA8233_RP_DXS_RVOL, muted, 1);
717 		r = via_rd(via, ch->rbase + VIA8233_RP_DXS_LVOL, 1) &
718 		    VIA8233_DXS_MUTE;
719 		if (r != muted) {
720 			printf("via: failed to set dxs volume "
721 			       "(dxs base 0x%02x).\n", ch->rbase);
722 		}
723 	}
724 }
725 
726 static __inline int
727 via_poll_channel(struct via_chinfo *ch)
728 {
729 	struct via_info *via;
730 	uint32_t sz, delta;
731 	uint32_t v, index, count;
732 	int ptr;
733 
734 	if (ch == NULL || ch->channel == NULL || ch->active == 0)
735 		return (0);
736 
737 	via = ch->parent;
738 	sz = ch->blksz * ch->blkcnt;
739 	v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
740 	index = v >> 24;
741 	count = v & 0x00ffffff;
742 	ptr = ((index + 1) * ch->blksz) - count;
743 	ptr %= sz;
744 	ptr &= ~(ch->blksz - 1);
745 	ch->ptr = ptr;
746 	delta = (sz + ptr - ch->prevptr) % sz;
747 
748 	if (delta < ch->blksz)
749 		return (0);
750 
751 	ch->prevptr = ptr;
752 
753 	return (1);
754 }
755 
756 static void
757 via_poll_callback(void *arg)
758 {
759 	struct via_info *via = arg;
760 	uint32_t ptrigger = 0, rtrigger = 0;
761 	int i;
762 
763 	if (via == NULL)
764 		return;
765 
766 	snd_mtxlock(via->lock);
767 	if (via->polling == 0 || via_chan_active(via) == 0) {
768 		snd_mtxunlock(via->lock);
769 		return;
770 	}
771 
772 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++)
773 		ptrigger |= (via_poll_channel(&via->pch[i]) != 0) ?
774 		    (1 << i) : 0;
775 
776 	for (i = 0; i < NWRCHANS; i++)
777 		rtrigger |= (via_poll_channel(&via->rch[i]) != 0) ?
778 		    (1 << i) : 0;
779 
780 	/* XXX */
781 	callout_reset(&via->poll_timer, 1/*via->poll_ticks*/,
782 	    via_poll_callback, via);
783 
784 	snd_mtxunlock(via->lock);
785 
786 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
787 		if (ptrigger & (1 << i))
788 			chn_intr(via->pch[i].channel);
789 	}
790 	for (i = 0; i < NWRCHANS; i++) {
791 		if (rtrigger & (1 << i))
792 			chn_intr(via->rch[i].channel);
793 	}
794 }
795 
796 static int
797 via_poll_ticks(struct via_info *via)
798 {
799 	struct via_chinfo *ch;
800 	int i;
801 	int ret = hz;
802 	int pollticks;
803 
804 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
805 		ch = &via->pch[i];
806 		if (ch->channel == NULL || ch->active == 0)
807 			continue;
808 		pollticks = ((uint64_t)hz * ch->blksz) /
809 		    ((uint64_t)sndbuf_getbps(ch->buffer) *
810 		    sndbuf_getspd(ch->buffer));
811 		pollticks >>= 2;
812 		if (pollticks > hz)
813 			pollticks = hz;
814 		if (pollticks < 1)
815 			pollticks = 1;
816 		if (pollticks < ret)
817 			ret = pollticks;
818 	}
819 
820 	for (i = 0; i < NWRCHANS; i++) {
821 		ch = &via->rch[i];
822 		if (ch->channel == NULL || ch->active == 0)
823 			continue;
824 		pollticks = ((uint64_t)hz * ch->blksz) /
825 		    ((uint64_t)sndbuf_getbps(ch->buffer) *
826 		    sndbuf_getspd(ch->buffer));
827 		pollticks >>= 2;
828 		if (pollticks > hz)
829 			pollticks = hz;
830 		if (pollticks < 1)
831 			pollticks = 1;
832 		if (pollticks < ret)
833 			ret = pollticks;
834 	}
835 
836 	return (ret);
837 }
838 
839 static int
840 via8233chan_trigger(kobj_t obj, void* data, int go)
841 {
842 	struct via_chinfo *ch = data;
843 	struct via_info *via = ch->parent;
844 	int pollticks;
845 
846 	snd_mtxlock(via->lock);
847 	switch(go) {
848 	case PCMTRIG_START:
849 		via_buildsgdt(ch);
850 		via8233chan_mute(via, ch, 0);
851 		via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, ch->sgd_addr, 4);
852 		if (via->polling != 0) {
853 			ch->ptr = 0;
854 			ch->prevptr = 0;
855 			pollticks = ((uint64_t)hz * ch->blksz) /
856 			    ((uint64_t)sndbuf_getbps(ch->buffer) *
857 			    sndbuf_getspd(ch->buffer));
858 			pollticks >>= 2;
859 			if (pollticks > hz)
860 				pollticks = hz;
861 			if (pollticks < 1)
862 				pollticks = 1;
863 			if (via_chan_active(via) == 0 ||
864 			    pollticks < via->poll_ticks) {
865 			    	if (bootverbose) {
866 					if (via_chan_active(via) == 0)
867 						printf("%s: pollticks=%d\n",
868 						    __func__, pollticks);
869 					else
870 						printf("%s: "
871 						    "pollticks %d -> %d\n",
872 						    __func__, via->poll_ticks,
873 						    pollticks);
874 				}
875 				via->poll_ticks = pollticks;
876 				callout_reset(&via->poll_timer, 1,
877 				    via_poll_callback, via);
878 			}
879 		}
880 		via_wr(via, ch->rbase + VIA_RP_CONTROL,
881 		    SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
882 		    ((via->polling == 0) ?
883 		    (SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG) : 0), 1);
884 		ch->active = 1;
885 		break;
886 	case PCMTRIG_STOP:
887 	case PCMTRIG_ABORT:
888 		via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
889 		via8233chan_mute(via, ch, 1);
890 		via8233chan_reset(via, ch);
891 		ch->active = 0;
892 		if (via->polling != 0) {
893 			if (via_chan_active(via) == 0) {
894 				callout_stop(&via->poll_timer);
895 				via->poll_ticks = 1;
896 			} else {
897 				pollticks = via_poll_ticks(via);
898 				if (pollticks > via->poll_ticks) {
899 					if (bootverbose)
900 						printf("%s: pollticks "
901 						    "%d -> %d\n",
902 						    __func__, via->poll_ticks,
903 						    pollticks);
904 					via->poll_ticks = pollticks;
905 					callout_reset(&via->poll_timer,
906 					    1, via_poll_callback,
907 					    via);
908 				}
909 			}
910 		}
911 		break;
912 	default:
913 		break;
914 	}
915 	snd_mtxunlock(via->lock);
916 	return (0);
917 }
918 
919 static kobj_method_t via8233wr_methods[] = {
920 	KOBJMETHOD(channel_init,		via8233wr_init),
921 	KOBJMETHOD(channel_setformat,		via8233wr_setformat),
922 	KOBJMETHOD(channel_setspeed,		via8233wr_setspeed),
923 	KOBJMETHOD(channel_getcaps,		via8233wr_getcaps),
924 	KOBJMETHOD(channel_setblocksize,	via8233chan_setblocksize),
925 	KOBJMETHOD(channel_trigger,		via8233chan_trigger),
926 	KOBJMETHOD(channel_getptr,		via8233chan_getptr),
927 	{ 0, 0 }
928 };
929 CHANNEL_DECLARE(via8233wr);
930 
931 static kobj_method_t via8233dxs_methods[] = {
932 	KOBJMETHOD(channel_init,		via8233dxs_init),
933 	KOBJMETHOD(channel_setformat,		via8233dxs_setformat),
934 	KOBJMETHOD(channel_setspeed,		via8233dxs_setspeed),
935 	KOBJMETHOD(channel_getcaps,		via8233dxs_getcaps),
936 	KOBJMETHOD(channel_setblocksize,	via8233chan_setblocksize),
937 	KOBJMETHOD(channel_trigger,		via8233chan_trigger),
938 	KOBJMETHOD(channel_getptr,		via8233chan_getptr),
939 	{ 0, 0 }
940 };
941 CHANNEL_DECLARE(via8233dxs);
942 
943 static kobj_method_t via8233msgd_methods[] = {
944 	KOBJMETHOD(channel_init,		via8233msgd_init),
945 	KOBJMETHOD(channel_setformat,		via8233msgd_setformat),
946 	KOBJMETHOD(channel_setspeed,		via8233msgd_setspeed),
947 	KOBJMETHOD(channel_getcaps,		via8233msgd_getcaps),
948 	KOBJMETHOD(channel_setblocksize,	via8233chan_setblocksize),
949 	KOBJMETHOD(channel_trigger,		via8233chan_trigger),
950 	KOBJMETHOD(channel_getptr,		via8233chan_getptr),
951 	{ 0, 0 }
952 };
953 CHANNEL_DECLARE(via8233msgd);
954 
955 /* -------------------------------------------------------------------- */
956 
957 static void
958 via_intr(void *p)
959 {
960 	struct via_info *via = p;
961 	uint32_t ptrigger = 0, rtrigger = 0;
962 	int i, reg, stat;
963 
964 	snd_mtxlock(via->lock);
965 	if (via->polling != 0) {
966 		snd_mtxunlock(via->lock);
967 		return;
968 	}
969 	/* Poll playback channels */
970 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
971 		if (via->pch[i].channel == NULL || via->pch[i].active == 0)
972 			continue;
973 		reg = via->pch[i].rbase + VIA_RP_STATUS;
974 		stat = via_rd(via, reg, 1);
975 		if (stat & SGD_STATUS_INTR) {
976 			if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
977 			    !(stat & SGD_STATUS_ACTIVE)))
978 				via_wr(via, via->pch[i].rbase + VIA_RP_CONTROL,
979 				    SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
980 				    SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
981 			via_wr(via, reg, stat, 1);
982 			ptrigger |= 1 << i;
983 		}
984 	}
985 	/* Poll record channels */
986 	for (i = 0; i < NWRCHANS; i++) {
987 		if (via->rch[i].channel == NULL || via->rch[i].active == 0)
988 			continue;
989 		reg = via->rch[i].rbase + VIA_RP_STATUS;
990 		stat = via_rd(via, reg, 1);
991 		if (stat & SGD_STATUS_INTR) {
992 			if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
993 			    !(stat & SGD_STATUS_ACTIVE)))
994 				via_wr(via, via->rch[i].rbase + VIA_RP_CONTROL,
995 				    SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
996 				    SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
997 			via_wr(via, reg, stat, 1);
998 			rtrigger |= 1 << i;
999 		}
1000 	}
1001 	snd_mtxunlock(via->lock);
1002 
1003 	for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
1004 		if (ptrigger & (1 << i))
1005 			chn_intr(via->pch[i].channel);
1006 	}
1007 	for (i = 0; i < NWRCHANS; i++) {
1008 		if (rtrigger & (1 << i))
1009 			chn_intr(via->rch[i].channel);
1010 	}
1011 }
1012 
1013 /*
1014  *  Probe and attach the card
1015  */
1016 static int
1017 via_probe(device_t dev)
1018 {
1019 	switch(pci_get_devid(dev)) {
1020 	case VIA8233_PCI_ID:
1021 		switch(pci_get_revid(dev)) {
1022 		case VIA8233_REV_ID_8233PRE:
1023 			device_set_desc(dev, "VIA VT8233 (pre)");
1024 			return (BUS_PROBE_DEFAULT);
1025 		case VIA8233_REV_ID_8233C:
1026 			device_set_desc(dev, "VIA VT8233C");
1027 			return (BUS_PROBE_DEFAULT);
1028 		case VIA8233_REV_ID_8233:
1029 			device_set_desc(dev, "VIA VT8233");
1030 			return (BUS_PROBE_DEFAULT);
1031 		case VIA8233_REV_ID_8233A:
1032 			device_set_desc(dev, "VIA VT8233A");
1033 			return (BUS_PROBE_DEFAULT);
1034 		case VIA8233_REV_ID_8235:
1035 			device_set_desc(dev, "VIA VT8235");
1036 			return (BUS_PROBE_DEFAULT);
1037 		case VIA8233_REV_ID_8237:
1038 			device_set_desc(dev, "VIA VT8237");
1039 			return (BUS_PROBE_DEFAULT);
1040 		case VIA8233_REV_ID_8251:
1041 			device_set_desc(dev, "VIA VT8251");
1042 			return (BUS_PROBE_DEFAULT);
1043 		default:
1044 			device_set_desc(dev, "VIA VT8233X");	/* Unknown */
1045 			return (BUS_PROBE_DEFAULT);
1046 		}
1047 	}
1048 	return (ENXIO);
1049 }
1050 
1051 static void
1052 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
1053 {
1054 	struct via_info *via = (struct via_info *)p;
1055 	via->sgd_addr = bds->ds_addr;
1056 }
1057 
1058 static int
1059 via_chip_init(device_t dev)
1060 {
1061 	uint32_t data, cnt;
1062 
1063 	/* Wake up and reset AC97 if necessary */
1064 	data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
1065 
1066 	if ((data & VIA_PCI_ACLINK_C00_READY) == 0) {
1067 		/* Cold reset per ac97r2.3 spec (page 95) */
1068 		/* Assert low */
1069 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1070 		    VIA_PCI_ACLINK_EN, 1);
1071 		/* Wait T_rst_low */
1072 		DELAY(100);
1073 		/* Assert high */
1074 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1075 		    VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST, 1);
1076 		/* Wait T_rst2clk */
1077 		DELAY(5);
1078 		/* Assert low */
1079 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1080 		    VIA_PCI_ACLINK_EN, 1);
1081 	} else {
1082 		/* Warm reset */
1083 		/* Force no sync */
1084 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1085 		    VIA_PCI_ACLINK_EN, 1);
1086 		DELAY(100);
1087 		/* Sync */
1088 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1089 		    VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_SYNC, 1);
1090 		/* Wait T_sync_high */
1091 		DELAY(5);
1092 		/* Force no sync */
1093 		pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
1094 		    VIA_PCI_ACLINK_EN, 1);
1095 		/* Wait T_sync2clk */
1096 		DELAY(5);
1097 	}
1098 
1099 	/* Power everything up */
1100 	pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1);
1101 
1102 	/* Wait for codec to become ready (largest reported delay 310ms) */
1103 	for (cnt = 0; cnt < 2000; cnt++) {
1104 		data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
1105 		if (data & VIA_PCI_ACLINK_C00_READY)
1106 			return (0);
1107 		DELAY(5000);
1108 	}
1109 	device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt);
1110 	return (ENXIO);
1111 }
1112 
1113 static int
1114 via_attach(device_t dev)
1115 {
1116 	struct via_info *via = 0;
1117 	char status[SND_STATUSLEN];
1118 	int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum;
1119 	int nsegs;
1120 	uint32_t revid;
1121 
1122 	if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
1123 		device_printf(dev, "cannot allocate softc\n");
1124 		return (ENXIO);
1125 	}
1126 	via->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
1127 
1128 	callout_init(&via->poll_timer, CALLOUT_MPSAFE);
1129 	via->poll_ticks = 1;
1130 
1131 	if (resource_int_value(device_get_name(dev),
1132 	    device_get_unit(dev), "polling", &i) == 0 && i != 0)
1133 		via->polling = 1;
1134 	else
1135 		via->polling = 0;
1136 
1137 	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
1138 	pci_enable_busmaster(dev);
1139 
1140 	via->regid = PCIR_BAR(0);
1141 	via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &via->regid,
1142 					  RF_ACTIVE);
1143 	if (!via->reg) {
1144 		device_printf(dev, "cannot allocate bus resource.");
1145 		goto bad;
1146 	}
1147 	via->st = rman_get_bustag(via->reg);
1148 	via->sh = rman_get_bushandle(via->reg);
1149 
1150 	via->irqid = 0;
1151 	via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
1152 	    RF_ACTIVE | RF_SHAREABLE);
1153 	if (!via->irq ||
1154 	    snd_setup_intr(dev, via->irq, INTR_MPSAFE,
1155 	    via_intr, via, &via->ih)) {
1156 		device_printf(dev, "unable to map interrupt\n");
1157 		goto bad;
1158 	}
1159 
1160 	via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536);
1161 	if (resource_int_value(device_get_name(dev),
1162 	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
1163 		via->blkcnt = via->bufsz / i;
1164 		i = 0;
1165 		while (via->blkcnt >> i)
1166 			i++;
1167 		via->blkcnt = 1 << (i - 1);
1168 		if (via->blkcnt < VIA_SEGS_MIN)
1169 			via->blkcnt = VIA_SEGS_MIN;
1170 		else if (via->blkcnt > VIA_SEGS_MAX)
1171 			via->blkcnt = VIA_SEGS_MAX;
1172 
1173 	} else
1174 		via->blkcnt = VIA_SEGS_DEFAULT;
1175 
1176 	revid = pci_get_revid(dev);
1177 
1178 	/*
1179 	 * VIA8251 lost its interrupt after DMA EOL, and need
1180 	 * a gentle spank on its face within interrupt handler.
1181 	 */
1182 	if (revid == VIA8233_REV_ID_8251)
1183 		via->dma_eol_wake = 1;
1184 	else
1185 		via->dma_eol_wake = 0;
1186 
1187 	/*
1188 	 * Decide whether DXS had to be disabled or not
1189 	 */
1190 	if (revid == VIA8233_REV_ID_8233A) {
1191 		/*
1192 		 * DXS channel is disabled.  Reports from multiple users
1193 		 * that it plays at half-speed.  Do not see this behaviour
1194 		 * on available 8233C or when emulating 8233A register set
1195 		 * on 8233C (either with or without ac97 VRA).
1196 		 */
1197 		via_dxs_disabled = 1;
1198 	} else if (resource_int_value(device_get_name(dev),
1199 	    device_get_unit(dev), "via_dxs_disabled",
1200 	    &via_dxs_disabled) == 0)
1201 		via_dxs_disabled = (via_dxs_disabled > 0) ? 1 : 0;
1202 	else
1203 		via_dxs_disabled = 0;
1204 
1205 	if (via_dxs_disabled) {
1206 		via_dxs_chnum = 0;
1207 		via_sgd_chnum = 1;
1208 	} else {
1209 		if (resource_int_value(device_get_name(dev),
1210 		    device_get_unit(dev), "via_dxs_channels",
1211 		    &via_dxs_chnum) != 0)
1212 			via_dxs_chnum = NDXSCHANS;
1213 		if (resource_int_value(device_get_name(dev),
1214 		    device_get_unit(dev), "via_sgd_channels",
1215 		    &via_sgd_chnum) != 0)
1216 			via_sgd_chnum = NMSGDCHANS;
1217 	}
1218 	if (via_dxs_chnum > NDXSCHANS)
1219 		via_dxs_chnum = NDXSCHANS;
1220 	else if (via_dxs_chnum < 0)
1221 		via_dxs_chnum = 0;
1222 	if (via_sgd_chnum > NMSGDCHANS)
1223 		via_sgd_chnum = NMSGDCHANS;
1224 	else if (via_sgd_chnum < 0)
1225 		via_sgd_chnum = 0;
1226 	if (via_dxs_chnum + via_sgd_chnum < 1) {
1227 		/* Minimalist ? */
1228 		via_dxs_chnum = 1;
1229 		via_sgd_chnum = 0;
1230 	}
1231 	if (via_dxs_chnum > 0 && resource_int_value(device_get_name(dev),
1232 	    device_get_unit(dev), "via_dxs_src", &via_dxs_src) == 0)
1233 		via->dxs_src = (via_dxs_src > 0) ? 1 : 0;
1234 	else
1235 		via->dxs_src = 0;
1236 
1237 	nsegs = (via_dxs_chnum + via_sgd_chnum + NWRCHANS) * via->blkcnt;
1238 
1239 	/* DMA tag for buffers */
1240 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1241 		/*boundary*/0,
1242 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1243 		/*highaddr*/BUS_SPACE_MAXADDR,
1244 		/*filter*/NULL, /*filterarg*/NULL,
1245 		/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
1246 		/*flags*/0, /*lockfunc*/NULL,
1247 		/*lockarg*/NULL, &via->parent_dmat) != 0) {
1248 		device_printf(dev, "unable to create dma tag\n");
1249 		goto bad;
1250 	}
1251 
1252 	/*
1253 	 *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
1254 	 *  requires a list in memory of work to do.  We need only 16 bytes
1255 	 *  for this list, and it is wasteful to allocate 16K.
1256 	 */
1257 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
1258 		/*boundary*/0,
1259 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1260 		/*highaddr*/BUS_SPACE_MAXADDR,
1261 		/*filter*/NULL, /*filterarg*/NULL,
1262 		/*maxsize*/nsegs * sizeof(struct via_dma_op),
1263 		/*nsegments*/1, /*maxsegz*/0x3ffff,
1264 		/*flags*/0, /*lockfunc*/NULL,
1265 		/*lockarg*/NULL, &via->sgd_dmat) != 0) {
1266 		device_printf(dev, "unable to create dma tag\n");
1267 		goto bad;
1268 	}
1269 
1270 	if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
1271 	    BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
1272 		goto bad;
1273 	if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table,
1274 	    nsegs * sizeof(struct via_dma_op), dma_cb, via, 0))
1275 		goto bad;
1276 
1277 	if (via_chip_init(dev))
1278 		goto bad;
1279 
1280 	via->codec = AC97_CREATE(dev, via, via_ac97);
1281 	if (!via->codec)
1282 		goto bad;
1283 
1284 	mixer_init(dev, ac97_getmixerclass(), via->codec);
1285 
1286 	via->codec_caps = ac97_getextcaps(via->codec);
1287 
1288 	/* Try to set VRA without generating an error, VRM not reqrd yet */
1289 	if (via->codec_caps &
1290 	    (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) {
1291 		uint16_t ext = ac97_getextmode(via->codec);
1292 		ext |= (via->codec_caps &
1293 		    (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
1294 		ext &= ~AC97_EXTCAP_DRA;
1295 		ac97_setextmode(via->codec, ext);
1296 	}
1297 
1298 	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
1299 	    rman_get_start(via->reg), rman_get_start(via->irq),
1300 	    PCM_KLDSTRING(snd_via8233));
1301 
1302 	/* Register */
1303 	if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS))
1304 	      goto bad;
1305 	for (i = 0; i < via_dxs_chnum; i++)
1306 	      pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
1307 	for (i = 0; i < via_sgd_chnum; i++)
1308 	      pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
1309 	for (i = 0; i < NWRCHANS; i++)
1310 	      pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
1311 	if (via_dxs_chnum > 0)
1312 		via_init_sysctls(dev);
1313 	device_printf(dev, "<VIA DXS %sabled: DXS%s %d / SGD %d / REC %d>\n",
1314 	    (via_dxs_chnum > 0) ? "En" : "Dis", (via->dxs_src) ? "(SRC)" : "",
1315 	    via_dxs_chnum, via_sgd_chnum, NWRCHANS);
1316 
1317 	pcm_setstatus(dev, status);
1318 
1319 	return (0);
1320 bad:
1321 	if (via->codec)
1322 		ac97_destroy(via->codec);
1323 	if (via->reg)
1324 		bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
1325 	if (via->ih)
1326 		bus_teardown_intr(dev, via->irq, via->ih);
1327 	if (via->irq)
1328 		bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
1329 	if (via->parent_dmat)
1330 		bus_dma_tag_destroy(via->parent_dmat);
1331 	if (via->sgd_dmamap)
1332 		bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
1333 	if (via->sgd_dmat)
1334 		bus_dma_tag_destroy(via->sgd_dmat);
1335 	if (via->lock)
1336 		snd_mtxfree(via->lock);
1337 	if (via)
1338 		free(via, M_DEVBUF);
1339 	return (ENXIO);
1340 }
1341 
1342 static int
1343 via_detach(device_t dev)
1344 {
1345 	int r;
1346 	struct via_info *via = 0;
1347 
1348 	r = pcm_unregister(dev);
1349 	if (r)
1350 		return (r);
1351 
1352 	via = pcm_getdevinfo(dev);
1353 	bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
1354 	bus_teardown_intr(dev, via->irq, via->ih);
1355 	bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
1356 	bus_dma_tag_destroy(via->parent_dmat);
1357 	bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
1358 	bus_dma_tag_destroy(via->sgd_dmat);
1359 	snd_mtxfree(via->lock);
1360 	free(via, M_DEVBUF);
1361 	return (0);
1362 }
1363 
1364 
1365 static device_method_t via_methods[] = {
1366 	DEVMETHOD(device_probe,		via_probe),
1367 	DEVMETHOD(device_attach,	via_attach),
1368 	DEVMETHOD(device_detach,	via_detach),
1369 	{ 0, 0}
1370 };
1371 
1372 static driver_t via_driver = {
1373 	"pcm",
1374 	via_methods,
1375 	PCM_SOFTC_SIZE,
1376 };
1377 
1378 DRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, 0, 0);
1379 MODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1380 MODULE_VERSION(snd_via8233, 1);
1381