kernel: Don't pass the size of the var as arg2 to sysctl_handle_int().
[dragonfly.git] / sys / dev / sound / pci / via8233.c
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  * $FreeBSD: src/sys/dev/sound/pci/via8233.c,v 1.20.2.3 2007/04/26 08:21:44 ariff Exp $
29  */
30
31 /*
32  * Credits due to:
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
43 #include <bus/pci/pcireg.h>
44 #include <bus/pci/pcivar.h>
45 #include <sys/sysctl.h>
46
47 #include <dev/sound/pci/via8233.h>
48
49 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/via8233.c,v 1.10 2007/06/16 20:07:19 dillon Exp $");
50
51 #define VIA8233_PCI_ID 0x30591106
52
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
61 #define SEGS_PER_CHAN   2                       /* Segments per channel */
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)
66 #define NSEGS           NCHANS * SEGS_PER_CHAN  /* Segments in SGD table */
67
68 #define VIA_DEFAULT_BUFSZ       0x1000
69
70 /* we rely on this struct being packed to 64 bits */
71 struct via_dma_op {
72         volatile u_int32_t ptr;
73         volatile u_int32_t flags;
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
80 struct via_info;
81
82 struct via_chinfo {
83         struct via_info *parent;
84         struct pcm_channel *channel;
85         struct snd_dbuf *buffer;
86         struct via_dma_op *sgd_table;
87         bus_addr_t sgd_addr;
88         int dir, blksz;
89         int rbase;
90 };
91
92 struct 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;
98         bus_addr_t sgd_addr;
99
100         struct resource *reg, *irq;
101         int regid, irqid;
102         void *ih;
103         struct ac97_info *codec;
104
105         unsigned int bufsz;
106         int dxs_src, dma_eol_wake;
107
108         struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
109         struct via_chinfo rch[NWRCHANS];
110         struct via_dma_op *sgd_table;
111         u_int16_t codec_caps;
112         u_int16_t n_dxs_registered;
113         sndlock_t       lock;
114 };
115
116 static 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
124 static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
125 static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
126
127 #ifdef SND_DYNSYSCTL
128 static int
129 sysctl_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, 0, 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
161 static int
162 sysctl_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, 0, 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
189 static void
190 via_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
210 static __inline u_int32_t
211 via_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
225 static __inline void
226 via_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
245 static int
246 via_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         }
256         kprintf("via: codec busy\n");
257         return 1;
258 }
259
260 static int
261 via_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         }
271         kprintf("via: codec invalid\n");
272         return 1;
273 }
274
275 static int
276 via_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
289 static int
290 via_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
309 static kobj_method_t via_ac97_methods[] = {
310         KOBJMETHOD(ac97_read,           via_read_codec),
311         KOBJMETHOD(ac97_write,          via_write_codec),
312         KOBJMETHOD_END
313 };
314 AC97_DECLARE(via_ac97);
315
316 /* -------------------------------------------------------------------- */
317
318 static int
319 via_buildsgdt(struct via_chinfo *ch)
320 {
321         u_int32_t phys_addr, flag;
322         int i, seg_size;
323
324         seg_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
325         phys_addr = sndbuf_getbufaddr(ch->buffer);
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
336 /* -------------------------------------------------------------------- */
337 /* Format setting functions */
338
339 static int
340 via8233wr_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
358 static int
359 via8233dxs_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
380 static int
381 via8233msgd_setformat(kobj_t obj, void *data, u_int32_t format)
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
397         snd_mtxlock(via->lock);
398         via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
399         via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
400         snd_mtxunlock(via->lock);
401
402         return 0;
403 }
404
405 /* -------------------------------------------------------------------- */
406 /* Speed setting functions */
407
408 static int
409 via8233wr_setspeed(kobj_t obj, void *data, u_int32_t speed)
410 {
411         struct via_chinfo *ch = data;
412         struct via_info *via = ch->parent;
413
414         if (via->codec_caps & AC97_EXTCAP_VRA)
415                 return ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed);
416
417         return 48000;
418 }
419
420 static int
421 via8233dxs_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;
438 }
439
440 static int
441 via8233msgd_setspeed(kobj_t obj, void *data, u_int32_t speed)
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
452 /* -------------------------------------------------------------------- */
453 /* Format probing functions */
454
455 static struct pcmchan_caps *
456 via8233wr_getcaps(kobj_t obj, void *data)
457 {
458         struct via_chinfo *ch = data;
459         struct via_info *via = ch->parent;
460
461         /* Controlled by ac97 registers */
462         if (via->codec_caps & AC97_EXTCAP_VRA)
463                 return &via_vracaps;
464         return &via_caps;
465 }
466
467 static struct pcmchan_caps *
468 via8233dxs_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
484 static struct pcmchan_caps *
485 via8233msgd_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
499 static int
500 via8233chan_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
509 static int
510 via8233chan_getptr(kobj_t obj, void *data)
511 {
512         struct via_chinfo *ch = data;
513         struct via_info *via = ch->parent;
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;
523         ptr %= SEGS_PER_CHAN * ch->blksz;       /* Wrap to available space */
524
525         return ptr;
526 }
527
528 static void
529 via8233chan_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
537 /* -------------------------------------------------------------------- */
538 /* Channel initialization functions */
539
540 static void
541 via8233chan_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
547 static void*
548 via8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
549                struct pcm_channel *c, int dir)
550 {
551         struct via_info *via = devinfo;
552         struct via_chinfo *ch = &via->rch[c->num];
553
554         ch->parent = via;
555         ch->channel = c;
556         ch->buffer = b;
557         ch->dir = dir;
558
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
575 static void*
576 via8233dxs_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 }
607
608 static void*
609 via8233msgd_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)
622                 return NULL;
623
624         snd_mtxlock(via->lock);
625         via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
626         via8233chan_reset(via, ch);
627         snd_mtxunlock(via->lock);
628
629         return ch;
630 }
631
632 static void
633 via8233chan_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
648 static int
649 via8233chan_trigger(kobj_t obj, void* data, int go)
650 {
651         struct via_chinfo *ch = data;
652         struct via_info *via = ch->parent;
653
654         snd_mtxlock(via->lock);
655         switch(go) {
656         case PCMTRIG_START:
657                 via_buildsgdt(ch);
658                 via8233chan_mute(via, ch, 0);
659                 via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, ch->sgd_addr, 4);
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);
667                 via8233chan_mute(via, ch, 1);
668                 via8233chan_reset(via, ch);
669                 break;
670         }
671         snd_mtxunlock(via->lock);
672         return 0;
673 }
674
675 static 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         KOBJMETHOD_END
684 };
685 CHANNEL_DECLARE(via8233wr);
686
687 static 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),
692         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
693         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
694         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
695         KOBJMETHOD_END
696 };
697 CHANNEL_DECLARE(via8233dxs);
698
699 static 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),
704         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
705         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
706         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
707         KOBJMETHOD_END
708 };
709 CHANNEL_DECLARE(via8233msgd);
710
711 /* -------------------------------------------------------------------- */
712
713 static void
714 via_intr(void *p)
715 {
716         struct via_info *via = p;
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                 }
741         }
742
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                 }
764         }
765         snd_mtxunlock(via->lock);
766 }
767
768 /*
769  *  Probe and attach the card
770  */
771 static int
772 via_probe(device_t dev)
773 {
774         switch(pci_get_devid(dev)) {
775         case VIA8233_PCI_ID:
776                 switch(pci_get_revid(dev)) {
777                 case VIA8233_REV_ID_8233PRE: 
778                         device_set_desc(dev, "VIA VT8233 (pre)");
779                         return BUS_PROBE_DEFAULT;
780                 case VIA8233_REV_ID_8233C:
781                         device_set_desc(dev, "VIA VT8233C");
782                         return BUS_PROBE_DEFAULT;
783                 case VIA8233_REV_ID_8233:
784                         device_set_desc(dev, "VIA VT8233");
785                         return BUS_PROBE_DEFAULT;
786                 case VIA8233_REV_ID_8233A:
787                         device_set_desc(dev, "VIA VT8233A");
788                         return BUS_PROBE_DEFAULT;
789                 case VIA8233_REV_ID_8235:
790                         device_set_desc(dev, "VIA VT8235");
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;
798                 default:
799                         device_set_desc(dev, "VIA VT8233X");    /* Unknown */
800                         return BUS_PROBE_DEFAULT;
801                 }                       
802         }
803         return ENXIO;
804 }
805
806 static void
807 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
808 {
809         struct via_info *via = (struct via_info *)p;
810         via->sgd_addr = bds->ds_addr;
811 }
812
813 static int
814 via_chip_init(device_t dev)
815 {
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         }
853
854         /* Power everything up */
855         pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1);
856
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) {
861                         return 0;
862                 }
863                 DELAY(5000);
864         }
865         device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt);
866         return ENXIO;
867 }
868
869 static int
870 via_attach(device_t dev)
871 {
872         struct via_info *via = NULL;
873         char status[SND_STATUSLEN];
874         int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum;
875         uint32_t revid;
876
877         via = kmalloc(sizeof *via, M_DEVBUF, M_WAITOK | M_ZERO);
878         via->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
879
880         pci_set_powerstate(dev, PCI_POWERSTATE_D0);
881         pci_enable_busmaster(dev);
882
883         via->regid = PCIR_BAR(0);
884         via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &via->regid,
885                                           RF_ACTIVE);
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;
896         via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
897                                           RF_ACTIVE | RF_SHAREABLE);
898         if (!via->irq || 
899             snd_setup_intr(dev, via->irq, INTR_MPSAFE, via_intr, via, &via->ih)) {
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,
910                 /*flags*/0,
911                 &via->parent_dmat) != 0) {
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,
927                 /*flags*/0,
928                 &via->sgd_dmat) != 0) {
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, 
937                             NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0))
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
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));
963
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;
974
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);
1040
1041         pcm_setstatus(dev, status);
1042
1043         return 0;
1044 bad:
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);
1051         if (via->sgd_table) bus_dmamem_free(via->sgd_dmat, via->sgd_table, 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) kfree(via, M_DEVBUF);
1055         return ENXIO;
1056 }
1057
1058 static int
1059 via_detach(device_t dev)
1060 {
1061         int r;
1062         struct via_info *via = NULL;
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_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap);
1074         bus_dma_tag_destroy(via->sgd_dmat);
1075         snd_mtxfree(via->lock);
1076         kfree(via, M_DEVBUF);
1077         return 0;
1078 }
1079
1080
1081 static device_method_t via_methods[] = {
1082         DEVMETHOD(device_probe,         via_probe),
1083         DEVMETHOD(device_attach,        via_attach),
1084         DEVMETHOD(device_detach,        via_detach),
1085         DEVMETHOD_END
1086 };
1087
1088 static driver_t via_driver = {
1089         "pcm",
1090         via_methods,
1091         PCM_SOFTC_SIZE,
1092 };
1093
1094 DRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, NULL, NULL);
1095 MODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
1096 MODULE_VERSION(snd_via8233, 1);