via8233.c revision 164614
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
47SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/via8233.c 164614 2006-11-26 12:24:06Z ariff $");
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		128
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 */
72struct 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
81struct via_info;
82
83struct 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
94struct 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
120static 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
128static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
129static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
130
131static __inline int
132via_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
149static int
150sysctl_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
181static int
182sysctl_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
207static int
208sysctl_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
243static void
244via_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
269static __inline uint32_t
270via_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
284static __inline void
285via_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
304static int
305via_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
319static int
320via_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
334static int
335via_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
349static int
350via_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
369static kobj_method_t via_ac97_methods[] = {
370	KOBJMETHOD(ac97_read,		via_read_codec),
371	KOBJMETHOD(ac97_write,		via_write_codec),
372	{ 0, 0 }
373};
374AC97_DECLARE(via_ac97);
375
376/* -------------------------------------------------------------------- */
377
378static int
379via_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
398static int
399via8233wr_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
417static int
418via8233dxs_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
439static int
440via8233msgd_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
467static int
468via8233wr_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
479static int
480via8233dxs_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
499static int
500via8233msgd_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
514static struct pcmchan_caps *
515via8233wr_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
526static struct pcmchan_caps *
527via8233dxs_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
543static struct pcmchan_caps *
544via8233msgd_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
558static int
559via8233chan_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
577static int
578via8233chan_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
601static void
602via8233chan_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
613static void
614via8233chan_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
621static void*
622via8233wr_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
650static void*
651via8233dxs_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
684static void*
685via8233msgd_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
709static void
710via8233chan_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
726static __inline int
727via_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
756static void
757via_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
796static int
797via_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
839static int
840via8233chan_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
919static 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};
929CHANNEL_DECLARE(via8233wr);
930
931static 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};
941CHANNEL_DECLARE(via8233dxs);
942
943static 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};
953CHANNEL_DECLARE(via8233msgd);
954
955/* -------------------------------------------------------------------- */
956
957static void
958via_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 */
1016static int
1017via_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
1051static void
1052dma_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
1058static int
1059via_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
1113static int
1114via_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) * via->blkcnt;
1238
1239	/* DMA tag for buffers */
1240	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
1241		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1242		/*highaddr*/BUS_SPACE_MAXADDR,
1243		/*filter*/NULL, /*filterarg*/NULL,
1244		/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
1245		/*flags*/0, /*lockfunc*/NULL,
1246		/*lockarg*/NULL, &via->parent_dmat) != 0) {
1247		device_printf(dev, "unable to create dma tag\n");
1248		goto bad;
1249	}
1250
1251	/*
1252	 *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
1253	 *  requires a list in memory of work to do.  We need only 16 bytes
1254	 *  for this list, and it is wasteful to allocate 16K.
1255	 */
1256	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
1257		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
1258		/*highaddr*/BUS_SPACE_MAXADDR,
1259		/*filter*/NULL, /*filterarg*/NULL,
1260		/*maxsize*/nsegs * sizeof(struct via_dma_op),
1261		/*nsegments*/1, /*maxsegz*/0x3ffff,
1262		/*flags*/0, /*lockfunc*/NULL,
1263		/*lockarg*/NULL, &via->sgd_dmat) != 0) {
1264		device_printf(dev, "unable to create dma tag\n");
1265		goto bad;
1266	}
1267
1268	if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
1269	    BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
1270		goto bad;
1271	if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table,
1272	    nsegs * sizeof(struct via_dma_op), dma_cb, via, 0))
1273		goto bad;
1274
1275	if (via_chip_init(dev))
1276		goto bad;
1277
1278	via->codec = AC97_CREATE(dev, via, via_ac97);
1279	if (!via->codec)
1280		goto bad;
1281
1282	mixer_init(dev, ac97_getmixerclass(), via->codec);
1283
1284	via->codec_caps = ac97_getextcaps(via->codec);
1285
1286	/* Try to set VRA without generating an error, VRM not reqrd yet */
1287	if (via->codec_caps &
1288	    (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) {
1289		uint16_t ext = ac97_getextmode(via->codec);
1290		ext |= (via->codec_caps &
1291		    (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
1292		ext &= ~AC97_EXTCAP_DRA;
1293		ac97_setextmode(via->codec, ext);
1294	}
1295
1296	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
1297	    rman_get_start(via->reg), rman_get_start(via->irq),
1298	    PCM_KLDSTRING(snd_via8233));
1299
1300	/* Register */
1301	if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS))
1302	      goto bad;
1303	for (i = 0; i < via_dxs_chnum; i++)
1304	      pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
1305	for (i = 0; i < via_sgd_chnum; i++)
1306	      pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
1307	for (i = 0; i < NWRCHANS; i++)
1308	      pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
1309	if (via_dxs_chnum > 0)
1310		via_init_sysctls(dev);
1311	device_printf(dev, "<VIA DXS %sabled: DXS%s %d / SGD %d / REC %d>\n",
1312	    (via_dxs_chnum > 0) ? "En" : "Dis", (via->dxs_src) ? "(SRC)" : "",
1313	    via_dxs_chnum, via_sgd_chnum, NWRCHANS);
1314
1315	pcm_setstatus(dev, status);
1316
1317	return (0);
1318bad:
1319	if (via->codec)
1320		ac97_destroy(via->codec);
1321	if (via->reg)
1322		bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
1323	if (via->ih)
1324		bus_teardown_intr(dev, via->irq, via->ih);
1325	if (via->irq)
1326		bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
1327	if (via->parent_dmat)
1328		bus_dma_tag_destroy(via->parent_dmat);
1329	if (via->sgd_dmamap)
1330		bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
1331	if (via->sgd_dmat)
1332		bus_dma_tag_destroy(via->sgd_dmat);
1333	if (via->lock)
1334		snd_mtxfree(via->lock);
1335	if (via)
1336		free(via, M_DEVBUF);
1337	return (ENXIO);
1338}
1339
1340static int
1341via_detach(device_t dev)
1342{
1343	int r;
1344	struct via_info *via = 0;
1345
1346	r = pcm_unregister(dev);
1347	if (r)
1348		return (r);
1349
1350	via = pcm_getdevinfo(dev);
1351	bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
1352	bus_teardown_intr(dev, via->irq, via->ih);
1353	bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
1354	bus_dma_tag_destroy(via->parent_dmat);
1355	bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
1356	bus_dma_tag_destroy(via->sgd_dmat);
1357	snd_mtxfree(via->lock);
1358	free(via, M_DEVBUF);
1359	return (0);
1360}
1361
1362
1363static device_method_t via_methods[] = {
1364	DEVMETHOD(device_probe,		via_probe),
1365	DEVMETHOD(device_attach,	via_attach),
1366	DEVMETHOD(device_detach,	via_detach),
1367	{ 0, 0}
1368};
1369
1370static driver_t via_driver = {
1371	"pcm",
1372	via_methods,
1373	PCM_SOFTC_SIZE,
1374};
1375
1376DRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, 0, 0);
1377MODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1378MODULE_VERSION(snd_via8233, 1);
1379