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