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