Annotation of sys/dev/pci/auvia.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: auvia.c,v 1.33 2005/05/06 01:45:22 miod Exp $ */
2: /* $NetBSD: auvia.c,v 1.7 2000/11/15 21:06:33 jdolecek Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Tyler C. Sarna
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * VIA Technologies VT82C686A Southbridge Audio Driver
42: *
43: * Documentation links:
44: *
45: * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf
46: */
47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/malloc.h>
51: #include <sys/device.h>
52: #include <sys/audioio.h>
53:
54: #include <dev/pci/pcidevs.h>
55: #include <dev/pci/pcivar.h>
56:
57: #include <dev/audio_if.h>
58: #include <dev/mulaw.h>
59: #include <dev/auconv.h>
60:
61: #include <dev/ic/ac97.h>
62:
63: #include <dev/pci/auviavar.h>
64:
65: struct auvia_dma {
66: struct auvia_dma *next;
67: caddr_t addr;
68: size_t size;
69: bus_dmamap_t map;
70: bus_dma_segment_t seg;
71: };
72:
73: struct auvia_dma_op {
74: u_int32_t ptr;
75: u_int32_t flags;
76: #define AUVIA_DMAOP_EOL 0x80000000
77: #define AUVIA_DMAOP_FLAG 0x40000000
78: #define AUVIA_DMAOP_STOP 0x20000000
79: #define AUVIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF)
80: };
81:
82: /* rev. H and later seem to support only fixed rate 44.1 kHz */
83: #define AUVIA_FIXED_RATE 44100
84:
85: int auvia_match(struct device *, void *, void *);
86: void auvia_attach(struct device *, struct device *, void *);
87: int auvia_open(void *, int);
88: void auvia_close(void *);
89: int auvia_query_encoding(void *addr, struct audio_encoding *fp);
90: int auvia_set_params(void *, int, int, struct audio_params *,
91: struct audio_params *);
92: int auvia_round_blocksize(void *, int);
93: int auvia_halt_output(void *);
94: int auvia_halt_input(void *);
95: int auvia_getdev(void *, struct audio_device *);
96: int auvia_set_port(void *, mixer_ctrl_t *);
97: int auvia_get_port(void *, mixer_ctrl_t *);
98: int auvia_query_devinfo(void *, mixer_devinfo_t *);
99: void * auvia_malloc(void *, int, size_t, int, int);
100: void auvia_free(void *, void *, int);
101: paddr_t auvia_mappage(void *, void *, off_t, int);
102: int auvia_get_props(void *);
103: int auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *,
104: struct auvia_dma *, void *, void *, int);
105: int auvia_trigger_output(void *, void *, void *, int, void (*)(void *),
106: void *, struct audio_params *);
107: int auvia_trigger_input(void *, void *, void *, int, void (*)(void *),
108: void *, struct audio_params *);
109:
110: int auvia_intr(void *);
111:
112: struct cfdriver auvia_cd = {
113: NULL, "auvia", DV_DULL
114: };
115:
116: struct cfattach auvia_ca = {
117: sizeof (struct auvia_softc), auvia_match, auvia_attach
118: };
119:
120: #define AUVIA_PCICONF_JUNK 0x40
121: #define AUVIA_PCICONF_ENABLES 0x00FF0000 /* reg 42 mask */
122: #define AUVIA_PCICONF_ACLINKENAB 0x00008000 /* ac link enab */
123: #define AUVIA_PCICONF_ACNOTRST 0x00004000 /* ~(ac reset) */
124: #define AUVIA_PCICONF_ACSYNC 0x00002000 /* ac sync */
125: #define AUVIA_PCICONF_ACVSR 0x00000800 /* var. samp. rate */
126: #define AUVIA_PCICONF_ACSGD 0x00000400 /* SGD enab */
127: #define AUVIA_PCICONF_ACFM 0x00000200 /* FM enab */
128: #define AUVIA_PCICONF_ACSB 0x00000100 /* SB enab */
129: #define AUVIA_PCICONF_PRIVALID 0x00000001 /* primary codec rdy */
130:
131: #define AUVIA_PLAY_BASE 0x00
132: #define AUVIA_RECORD_BASE 0x10
133:
134: #define AUVIA_RP_STAT 0x00
135: #define AUVIA_RPSTAT_INTR 0x03
136: #define AUVIA_RP_CONTROL 0x01
137: #define AUVIA_RPCTRL_START 0x80
138: #define AUVIA_RPCTRL_TERMINATE 0x40
139: #define AUVIA_RPCTRL_AUTOSTART 0x20
140: /* The following are 8233 specific */
141: #define AUVIA_RPCTRL_STOP 0x04
142: #define AUVIA_RPCTRL_EOL 0x02
143: #define AUVIA_RPCTRL_FLAG 0x01
144: #define AUVIA_RP_MODE 0x02
145: #define AUVIA_RPMODE_INTR_FLAG 0x01
146: #define AUVIA_RPMODE_INTR_EOL 0x02
147: #define AUVIA_RPMODE_STEREO 0x10
148: #define AUVIA_RPMODE_16BIT 0x20
149: #define AUVIA_RPMODE_AUTOSTART 0x80
150: #define AUVIA_RP_DMAOPS_BASE 0x04
151:
152: #define VIA8233_RP_DXS_LVOL 0x02
153: #define VIA8233_RP_DXS_RVOL 0x03
154: #define VIA8233_RP_RATEFMT 0x08
155: #define VIA8233_RATEFMT_48K 0xfffff
156: #define VIA8233_RATEFMT_STEREO 0x00100000
157: #define VIA8233_RATEFMT_16BIT 0x00200000
158:
159: #define VIA_RP_DMAOPS_COUNT 0x0C
160:
161: #define AUVIA_CODEC_CTL 0x80
162: #define AUVIA_CODEC_READ 0x00800000
163: #define AUVIA_CODEC_BUSY 0x01000000
164: #define AUVIA_CODEC_PRIVALID 0x02000000
165: #define AUVIA_CODEC_INDEX(x) ((x)<<16)
166:
167: #define TIMEOUT 50
168:
169: struct audio_hw_if auvia_hw_if = {
170: auvia_open,
171: auvia_close,
172: NULL, /* drain */
173: auvia_query_encoding,
174: auvia_set_params,
175: auvia_round_blocksize,
176: NULL, /* commit_settings */
177: NULL, /* init_output */
178: NULL, /* init_input */
179: NULL, /* start_output */
180: NULL, /* start_input */
181: auvia_halt_output,
182: auvia_halt_input,
183: NULL, /* speaker_ctl */
184: auvia_getdev,
185: NULL, /* setfd */
186: auvia_set_port,
187: auvia_get_port,
188: auvia_query_devinfo,
189: auvia_malloc,
190: auvia_free,
191: NULL, /* auvia_round_buffersize */
192: auvia_mappage,
193: auvia_get_props,
194: auvia_trigger_output,
195: auvia_trigger_input
196: };
197:
198: int auvia_attach_codec(void *, struct ac97_codec_if *);
199: int auvia_write_codec(void *, u_int8_t, u_int16_t);
200: int auvia_read_codec(void *, u_int8_t, u_int16_t *);
201: void auvia_reset_codec(void *);
202: int auvia_waitready_codec(struct auvia_softc *sc);
203: int auvia_waitvalid_codec(struct auvia_softc *sc);
204:
205: const struct pci_matchid auvia_devices[] = {
206: { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_AC97 },
207: { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_AC97 },
208: };
209:
210: int
211: auvia_match(struct device *parent, void *match, void *aux)
212: {
213: return (pci_matchbyid((struct pci_attach_args *)aux, auvia_devices,
214: sizeof(auvia_devices)/sizeof(auvia_devices[0])));
215: }
216:
217:
218: void
219: auvia_attach(struct device *parent, struct device *self, void *aux)
220: {
221: struct pci_attach_args *pa = aux;
222: struct auvia_softc *sc = (struct auvia_softc *) self;
223: const char *intrstr = NULL;
224: struct mixer_ctrl ctl;
225: pci_chipset_tag_t pc = pa->pa_pc;
226: pcitag_t pt = pa->pa_tag;
227: pci_intr_handle_t ih;
228: bus_size_t iosize;
229: pcireg_t pr;
230: int r, i;
231:
232: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97)
233: sc->sc_flags |= AUVIA_FLAGS_VT8233;
234:
235: if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
236: &sc->sc_ioh, NULL, &iosize, 0)) {
237: printf(": can't map i/o space\n");
238: return;
239: }
240:
241: sc->sc_dmat = pa->pa_dmat;
242: sc->sc_pc = pc;
243: sc->sc_pt = pt;
244:
245: if (pci_intr_map(pa, &ih)) {
246: printf(": couldn't map interrupt\n");
247: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
248: return;
249: }
250: intrstr = pci_intr_string(pc, ih);
251:
252: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc,
253: sc->sc_dev.dv_xname);
254: if (sc->sc_ih == NULL) {
255: printf(": couldn't establish interrupt");
256: if (intrstr != NULL)
257: printf(" at %s", intrstr);
258: printf("\n");
259: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
260: return;
261: }
262:
263: printf(": %s\n", intrstr);
264:
265: /* disable SBPro compat & others */
266: pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
267:
268: pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
269: /* XXX what to do about MIDI, FM, joystick? */
270:
271: pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST |
272: AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
273:
274: pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
275:
276: pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
277:
278: sc->host_if.arg = sc;
279: sc->host_if.attach = auvia_attach_codec;
280: sc->host_if.read = auvia_read_codec;
281: sc->host_if.write = auvia_write_codec;
282: sc->host_if.reset = auvia_reset_codec;
283:
284: if ((r = ac97_attach(&sc->host_if)) != 0) {
285: printf("%s: can't attach codec (error 0x%X)\n",
286: sc->sc_dev.dv_xname, r);
287: pci_intr_disestablish(pc, sc->sc_ih);
288: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
289: return;
290: }
291:
292: /* disable mutes */
293: for (i = 0; i < 4; i++) {
294: static struct {
295: char *class, *device;
296: } d[] = {
297: { AudioCoutputs, AudioNmaster},
298: { AudioCinputs, AudioNdac},
299: { AudioCinputs, AudioNcd},
300: { AudioCrecord, AudioNvolume},
301: };
302:
303: ctl.type = AUDIO_MIXER_ENUM;
304: ctl.un.ord = 0;
305:
306: ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
307: d[i].class, d[i].device, AudioNmute);
308: auvia_set_port(sc, &ctl);
309: }
310:
311: /* set a reasonable default volume */
312:
313: ctl.type = AUDIO_MIXER_VALUE;
314: ctl.un.value.num_channels = 2;
315: ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
316: ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199;
317:
318: ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
319: AudioCoutputs, AudioNmaster, NULL);
320: auvia_set_port(sc, &ctl);
321:
322: audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
323: }
324:
325:
326: int
327: auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
328: {
329: struct auvia_softc *sc = addr;
330:
331: sc->codec_if = cif;
332:
333: return 0;
334: }
335:
336:
337: void
338: auvia_reset_codec(void *addr)
339: {
340: int i;
341: struct auvia_softc *sc = addr;
342: pcireg_t r;
343:
344: /* perform a codec cold reset */
345:
346: r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
347:
348: r &= ~AUVIA_PCICONF_ACNOTRST; /* enable RESET (active low) */
349: pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
350: delay(2);
351:
352: r |= AUVIA_PCICONF_ACNOTRST; /* disable RESET (inactive high) */
353: pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
354: delay(200);
355:
356: for (i = 500000; i != 0 && !(pci_conf_read(sc->sc_pc, sc->sc_pt,
357: AUVIA_PCICONF_JUNK) & AUVIA_PCICONF_PRIVALID); i--)
358: DELAY(1);
359: if (i == 0)
360: printf("%s: codec reset timed out\n", sc->sc_dev.dv_xname);
361: }
362:
363:
364: int
365: auvia_waitready_codec(struct auvia_softc *sc)
366: {
367: int i;
368:
369: /* poll until codec not busy */
370: for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
371: AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
372: delay(1);
373:
374: if (i >= TIMEOUT) {
375: printf("%s: codec busy\n", sc->sc_dev.dv_xname);
376: return 1;
377: }
378:
379: return 0;
380: }
381:
382:
383: int
384: auvia_waitvalid_codec(struct auvia_softc *sc)
385: {
386: int i;
387:
388: /* poll until codec valid */
389: for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
390: AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
391: delay(1);
392:
393: if (i >= TIMEOUT) {
394: printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
395: return 1;
396: }
397:
398: return 0;
399: }
400:
401:
402: int
403: auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
404: {
405: struct auvia_softc *sc = addr;
406:
407: if (auvia_waitready_codec(sc))
408: return 1;
409:
410: bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
411: AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
412:
413: return 0;
414: }
415:
416:
417: int
418: auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
419: {
420: struct auvia_softc *sc = addr;
421:
422: if (auvia_waitready_codec(sc))
423: return 1;
424:
425: bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
426: AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
427:
428: if (auvia_waitready_codec(sc))
429: return 1;
430:
431: if (auvia_waitvalid_codec(sc))
432: return 1;
433:
434: *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
435:
436: return 0;
437: }
438:
439:
440: int
441: auvia_open(void *addr, int flags)
442: {
443: return 0;
444: }
445:
446:
447: void
448: auvia_close(void *addr)
449: {
450: struct auvia_softc *sc = addr;
451:
452: auvia_halt_output(sc);
453: auvia_halt_input(sc);
454:
455: sc->sc_play.sc_intr = NULL;
456: sc->sc_record.sc_intr = NULL;
457: }
458:
459:
460: int
461: auvia_query_encoding(void *addr, struct audio_encoding *fp)
462: {
463: switch (fp->index) {
464: case 0:
465: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
466: fp->encoding = AUDIO_ENCODING_ULINEAR;
467: fp->precision = 8;
468: fp->flags = 0;
469: return (0);
470: case 1:
471: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
472: fp->encoding = AUDIO_ENCODING_ULAW;
473: fp->precision = 8;
474: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
475: return (0);
476: case 2:
477: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
478: fp->encoding = AUDIO_ENCODING_ALAW;
479: fp->precision = 8;
480: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
481: return (0);
482: case 3:
483: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
484: fp->encoding = AUDIO_ENCODING_SLINEAR;
485: fp->precision = 8;
486: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
487: return (0);
488: case 4:
489: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
490: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
491: fp->precision = 16;
492: fp->flags = 0;
493: return (0);
494: case 5:
495: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
496: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
497: fp->precision = 16;
498: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
499: return (0);
500: case 6:
501: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
502: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
503: fp->precision = 16;
504: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
505: return (0);
506: case 7:
507: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
508: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
509: fp->precision = 16;
510: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
511: return (0);
512: default:
513: return (EINVAL);
514: }
515: }
516:
517:
518: int
519: auvia_set_params(void *addr, int setmode, int usemode,
520: struct audio_params *play, struct audio_params *rec)
521: {
522: struct auvia_softc *sc = addr;
523: struct audio_params *p;
524: u_int16_t regval;
525: int mode, base;
526:
527: /* for mode in (RECORD, PLAY) */
528: for (mode = AUMODE_RECORD; mode != -1;
529: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
530: if ((setmode & mode) == 0)
531: continue;
532:
533: if (mode == AUMODE_PLAY) {
534: p = play;
535: base = AUVIA_PLAY_BASE;
536: } else {
537: p = rec;
538: base = AUVIA_RECORD_BASE;
539: }
540:
541: if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
542: u_int32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
543: base + VIA8233_RP_RATEFMT) & ~(VIA8233_RATEFMT_48K
544: | VIA8233_RATEFMT_STEREO | VIA8233_RATEFMT_16BIT);
545:
546: v |= VIA8233_RATEFMT_48K *
547: (p->sample_rate / 20) / (48000 / 20);
548:
549: if (p->channels == 2)
550: v |= VIA8233_RATEFMT_STEREO;
551: if (p->precision == 16)
552: v |= VIA8233_RATEFMT_16BIT;
553:
554: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
555: base + VIA8233_RP_RATEFMT, v);
556: }
557:
558: if (ac97_set_rate(sc->codec_if, p, mode))
559: return (EINVAL);
560:
561: if ((p->precision != 8 && p->precision != 16) ||
562: (p->channels != 1 && p->channels != 2))
563: return (EINVAL);
564:
565: p->factor = 1;
566: p->sw_code = 0;
567: switch (p->encoding) {
568: case AUDIO_ENCODING_SLINEAR_BE:
569: if (p->precision == 16)
570: p->sw_code = swap_bytes;
571: else
572: p->sw_code = change_sign8;
573: break;
574: case AUDIO_ENCODING_SLINEAR_LE:
575: if (p->precision != 16)
576: p->sw_code = change_sign8;
577: break;
578: case AUDIO_ENCODING_ULINEAR_BE:
579: if (p->precision == 16)
580: p->sw_code = mode == AUMODE_PLAY?
581: swap_bytes_change_sign16_le :
582: change_sign16_swap_bytes_le;
583: break;
584: case AUDIO_ENCODING_ULINEAR_LE:
585: if (p->precision == 16)
586: p->sw_code = change_sign16_le;
587: break;
588: case AUDIO_ENCODING_ULAW:
589: if (mode == AUMODE_PLAY) {
590: p->factor = 2;
591: p->sw_code = mulaw_to_slinear16_le;
592: } else
593: p->sw_code = ulinear8_to_mulaw;
594: break;
595: case AUDIO_ENCODING_ALAW:
596: if (mode == AUMODE_PLAY) {
597: p->factor = 2;
598: p->sw_code = alaw_to_slinear16_le;
599: } else
600: p->sw_code = ulinear8_to_alaw;
601: break;
602: case AUDIO_ENCODING_SLINEAR:
603: case AUDIO_ENCODING_ULINEAR:
604: break;
605: default:
606: return (EINVAL);
607: }
608:
609: regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
610: | (p->precision * p->factor == 16 ?
611: AUVIA_RPMODE_16BIT : 0)
612: | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
613: | AUVIA_RPMODE_AUTOSTART;
614:
615: if (mode == AUMODE_PLAY)
616: sc->sc_play.sc_reg = regval;
617: else
618: sc->sc_record.sc_reg = regval;
619: }
620:
621: return 0;
622: }
623:
624:
625: int
626: auvia_round_blocksize(void *addr, int blk)
627: {
628: return ((blk + 31) & -32);
629: }
630:
631:
632: int
633: auvia_halt_output(void *addr)
634: {
635: struct auvia_softc *sc = addr;
636:
637: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
638: AUVIA_PLAY_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
639:
640: return 0;
641: }
642:
643:
644: int
645: auvia_halt_input(void *addr)
646: {
647: struct auvia_softc *sc = addr;
648:
649: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
650: AUVIA_RECORD_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
651:
652: return 0;
653: }
654:
655:
656: int
657: auvia_getdev(void *addr, struct audio_device *retp)
658: {
659: struct auvia_softc *sc = addr;
660:
661: if (retp) {
662: strncpy(retp->name,
663: sc->sc_flags & AUVIA_FLAGS_VT8233? "VIA VT8233" :
664: "VIA VT82C686A", sizeof(retp->name));
665: strncpy(retp->version, sc->sc_revision, sizeof(retp->version));
666: strncpy(retp->config, "auvia", sizeof(retp->config));
667: }
668:
669: return 0;
670: }
671:
672:
673: int
674: auvia_set_port(void *addr, mixer_ctrl_t *cp)
675: {
676: struct auvia_softc *sc = addr;
677:
678: return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
679: }
680:
681:
682: int
683: auvia_get_port(void *addr, mixer_ctrl_t *cp)
684: {
685: struct auvia_softc *sc = addr;
686:
687: return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
688: }
689:
690:
691: int
692: auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
693: {
694: struct auvia_softc *sc = addr;
695:
696: return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
697: }
698:
699:
700: void *
701: auvia_malloc(void *addr, int direction, size_t size, int pool, int flags)
702: {
703: struct auvia_softc *sc = addr;
704: struct auvia_dma *p;
705: int error;
706: int rseg;
707:
708: p = malloc(sizeof(*p), pool, flags);
709: if (!p)
710: return 0;
711:
712: p->size = size;
713: if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
714: 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
715: printf("%s: unable to allocate dma, error = %d\n",
716: sc->sc_dev.dv_xname, error);
717: goto fail_alloc;
718: }
719:
720: if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
721: BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
722: printf("%s: unable to map dma, error = %d\n",
723: sc->sc_dev.dv_xname, error);
724: goto fail_map;
725: }
726:
727: if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
728: BUS_DMA_NOWAIT, &p->map)) != 0) {
729: printf("%s: unable to create dma map, error = %d\n",
730: sc->sc_dev.dv_xname, error);
731: goto fail_create;
732: }
733:
734: if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
735: BUS_DMA_NOWAIT)) != 0) {
736: printf("%s: unable to load dma map, error = %d\n",
737: sc->sc_dev.dv_xname, error);
738: goto fail_load;
739: }
740:
741: p->next = sc->sc_dmas;
742: sc->sc_dmas = p;
743:
744: return p->addr;
745:
746:
747: fail_load:
748: bus_dmamap_destroy(sc->sc_dmat, p->map);
749: fail_create:
750: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
751: fail_map:
752: bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
753: fail_alloc:
754: free(p, pool);
755: return 0;
756: }
757:
758:
759: void
760: auvia_free(void *addr, void *ptr, int pool)
761: {
762: struct auvia_softc *sc = addr;
763: struct auvia_dma **pp, *p;
764:
765: for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
766: if (p->addr == ptr) {
767: bus_dmamap_unload(sc->sc_dmat, p->map);
768: bus_dmamap_destroy(sc->sc_dmat, p->map);
769: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
770: bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
771:
772: *pp = p->next;
773: free(p, pool);
774: return;
775: }
776:
777: panic("auvia_free: trying to free unallocated memory");
778: }
779:
780: paddr_t
781: auvia_mappage(void *addr, void *mem, off_t off, int prot)
782: {
783: struct auvia_softc *sc = addr;
784: struct auvia_dma *p;
785:
786: if (off < 0)
787: return -1;
788:
789: for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
790: ;
791:
792: if (!p)
793: return -1;
794:
795: return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
796: BUS_DMA_WAITOK);
797: }
798:
799:
800: int
801: auvia_get_props(void *addr)
802: {
803: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
804: AUDIO_PROP_FULLDUPLEX);
805: }
806:
807:
808: int
809: auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
810: struct auvia_dma *p, void *start, void *end, int blksize)
811: {
812: struct auvia_dma_op *op;
813: struct auvia_dma *dp;
814: bus_addr_t s;
815: size_t l;
816: int segs;
817:
818: s = p->map->dm_segs[0].ds_addr;
819: l = (vaddr_t)end - (vaddr_t)start;
820: segs = howmany(l, blksize);
821:
822: if (segs > ch->sc_dma_op_count) {
823: /* if old list was too small, free it */
824: if (ch->sc_dma_ops)
825: auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
826:
827: ch->sc_dma_ops = auvia_malloc(sc, 0,
828: sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
829:
830: for (dp = sc->sc_dmas; dp &&
831: dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next)
832: ;
833:
834: if (!dp)
835: panic("%s: build_dma_ops: where'd my memory go??? "
836: "address (%p)", sc->sc_dev.dv_xname,
837: ch->sc_dma_ops);
838:
839: ch->sc_dma_op_count = segs;
840: ch->sc_dma_ops_dma = dp;
841: }
842:
843: dp = ch->sc_dma_ops_dma;
844: op = ch->sc_dma_ops;
845:
846: while (l) {
847: op->ptr = htole32(s);
848: l = l - min(l, blksize);
849: /* if last block */
850: op->flags = htole32((l? AUVIA_DMAOP_FLAG : AUVIA_DMAOP_EOL) | blksize);
851: s += blksize;
852: op++;
853: }
854:
855: return 0;
856: }
857:
858:
859: int
860: auvia_trigger_output(void *addr, void *start, void *end, int blksize,
861: void (*intr)(void *), void *arg, struct audio_params *param)
862: {
863: struct auvia_softc *sc = addr;
864: struct auvia_softc_chan *ch = &(sc->sc_play);
865: struct auvia_dma *p;
866:
867: for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
868: ;
869:
870: if (!p)
871: panic("auvia_trigger_output: request with bad start "
872: "address (%p)", start);
873:
874: if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
875: return 1;
876: }
877:
878: ch->sc_intr = intr;
879: ch->sc_arg = arg;
880:
881: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
882: AUVIA_PLAY_BASE + AUVIA_RP_DMAOPS_BASE,
883: ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
884:
885: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
886: AUVIA_PLAY_BASE + AUVIA_RP_MODE, ch->sc_reg);
887:
888: if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
889: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
890: AUVIA_PLAY_BASE + VIA8233_RP_DXS_LVOL, 0);
891: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
892: AUVIA_PLAY_BASE + VIA8233_RP_DXS_RVOL, 0);
893: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
894: AUVIA_PLAY_BASE + AUVIA_RP_CONTROL,
895: AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
896: AUVIA_RPCTRL_STOP | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
897: } else
898: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
899: AUVIA_PLAY_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
900:
901: return 0;
902: }
903:
904:
905: int
906: auvia_trigger_input(void *addr, void *start, void *end, int blksize,
907: void (*intr)(void *), void *arg, struct audio_params *param)
908: {
909: struct auvia_softc *sc = addr;
910: struct auvia_softc_chan *ch = &(sc->sc_record);
911: struct auvia_dma *p;
912:
913: for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
914: ;
915:
916: if (!p)
917: panic("auvia_trigger_input: request with bad start "
918: "address (%p)", start);
919:
920: if (auvia_build_dma_ops(sc, ch, p, start, end, blksize))
921: return 1;
922:
923: ch->sc_intr = intr;
924: ch->sc_arg = arg;
925:
926: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
927: AUVIA_RECORD_BASE + AUVIA_RP_DMAOPS_BASE,
928: ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
929: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
930: AUVIA_RECORD_BASE + AUVIA_RP_MODE, ch->sc_reg);
931:
932: if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
933: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
934: AUVIA_RECORD_BASE + VIA8233_RP_DXS_LVOL, 0);
935: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
936: AUVIA_RECORD_BASE + VIA8233_RP_DXS_RVOL, 0);
937: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
938: AUVIA_RECORD_BASE + AUVIA_RP_CONTROL,
939: AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
940: AUVIA_RPCTRL_STOP | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
941: } else
942: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
943: AUVIA_RECORD_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
944:
945: return 0;
946: }
947:
948:
949: int
950: auvia_intr(void *arg)
951: {
952: struct auvia_softc *sc = arg;
953: u_int8_t r;
954: int i = 0;
955:
956: r = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
957: AUVIA_RECORD_BASE + AUVIA_RP_STAT);
958: if (r & AUVIA_RPSTAT_INTR) {
959: if (sc->sc_record.sc_intr)
960: sc->sc_record.sc_intr(sc->sc_record.sc_arg);
961:
962: /* clear interrupts */
963: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
964: AUVIA_RECORD_BASE + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
965:
966: i++;
967: }
968: r = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
969: AUVIA_PLAY_BASE + AUVIA_RP_STAT);
970: if (r & AUVIA_RPSTAT_INTR) {
971: if (sc->sc_play.sc_intr)
972: sc->sc_play.sc_intr(sc->sc_play.sc_arg);
973:
974: /* clear interrupts */
975: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
976: AUVIA_PLAY_BASE + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
977:
978: i++;
979: }
980:
981: return (i? 1 : 0);
982: }
CVSweb