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