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