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