Annotation of sys/dev/pci/cmpci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cmpci.c,v 1.14 2006/07/27 00:45:59 brad Exp $ */
2: /* $NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $ */
3:
4: /*
5: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Takuya SHIOZAKI <tshiozak@NetBSD.org> .
10: *
11: * This code is derived from software contributed to The NetBSD Foundation
12: * by ITOH Yasufumi.
13: *
14: * Redistribution and use in source and binary forms, with or without
15: * modification, are permitted provided that the following conditions
16: * are met:
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
35: */
36:
37: /*
38: * C-Media CMI8x38 Audio Chip Support.
39: *
40: * TODO:
41: * - 4ch / 6ch support.
42: * - Joystick support.
43: *
44: */
45:
46: #if 0
47: #include <sys/cdefs.h>
48: __KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.25 2004/10/26 06:32:20 xtraeme Exp $");
49: #endif
50:
51: #if defined(AUDIO_DEBUG) || defined(DEBUG)
52: #define DPRINTF(x) if (cmpcidebug) printf x
53: int cmpcidebug = 0;
54: #else
55: #define DPRINTF(x)
56: #endif
57:
58: #include <sys/param.h>
59: #include <sys/systm.h>
60: #include <sys/kernel.h>
61: #include <sys/malloc.h>
62: #include <sys/device.h>
63: #include <sys/proc.h>
64:
65: #include <dev/pci/pcidevs.h>
66: #include <dev/pci/pcivar.h>
67:
68: #include <sys/audioio.h>
69: #include <dev/audio_if.h>
70: #include <dev/midi_if.h>
71:
72: #include <dev/mulaw.h>
73: #include <dev/auconv.h>
74: #include <dev/pci/cmpcireg.h>
75: #include <dev/pci/cmpcivar.h>
76:
77: #include <dev/ic/mpuvar.h>
78: #include <machine/bus.h>
79: #include <machine/intr.h>
80:
81: /*
82: * Low-level HW interface
83: */
84: __inline uint8_t cmpci_mixerreg_read(struct cmpci_softc *,
85: uint8_t);
86: __inline void cmpci_mixerreg_write(struct cmpci_softc *,
87: uint8_t, uint8_t);
88: __inline void cmpci_reg_partial_write_1(struct cmpci_softc *,
89: int, int,
90: unsigned, unsigned);
91: __inline void cmpci_reg_partial_write_4(struct cmpci_softc *,
92: int, int,
93: uint32_t, uint32_t);
94: __inline void cmpci_reg_set_1(struct cmpci_softc *,
95: int, uint8_t);
96: __inline void cmpci_reg_clear_1(struct cmpci_softc *,
97: int, uint8_t);
98: __inline void cmpci_reg_set_4(struct cmpci_softc *,
99: int, uint32_t);
100: __inline void cmpci_reg_clear_4(struct cmpci_softc *,
101: int, uint32_t);
102: __inline void cmpci_reg_set_reg_misc(struct cmpci_softc *,
103: uint32_t);
104: __inline void cmpci_reg_clear_reg_misc(struct cmpci_softc *,
105: uint32_t);
106: int cmpci_rate_to_index(int);
107: __inline int cmpci_index_to_rate(int);
108: __inline int cmpci_index_to_divider(int);
109:
110: int cmpci_adjust(int, int);
111: void cmpci_set_mixer_gain(struct cmpci_softc *, int);
112: void cmpci_set_out_ports(struct cmpci_softc *);
113: int cmpci_set_in_ports(struct cmpci_softc *);
114:
115: /*
116: * autoconf interface
117: */
118: int cmpci_match(struct device *, void *, void *);
119: void cmpci_attach(struct device *, struct device *, void *);
120:
121: struct cfdriver cmpci_cd = {
122: NULL, "cmpci", DV_DULL
123: };
124:
125: struct cfattach cmpci_ca = {
126: sizeof (struct cmpci_softc), cmpci_match, cmpci_attach
127: };
128:
129: /* interrupt */
130: int cmpci_intr(void *);
131:
132: /*
133: * DMA stuff
134: */
135: int cmpci_alloc_dmamem(struct cmpci_softc *,
136: size_t, int,
137: int, caddr_t *);
138: int cmpci_free_dmamem(struct cmpci_softc *, caddr_t,
139: int);
140: struct cmpci_dmanode * cmpci_find_dmamem(struct cmpci_softc *,
141: caddr_t);
142:
143: /*
144: * Interface to machine independent layer
145: */
146: int cmpci_open(void *, int);
147: void cmpci_close(void *);
148: int cmpci_query_encoding(void *, struct audio_encoding *);
149: int cmpci_set_params(void *, int, int,
150: struct audio_params *,
151: struct audio_params *);
152: int cmpci_round_blocksize(void *, int);
153: int cmpci_halt_output(void *);
154: int cmpci_halt_input(void *);
155: int cmpci_getdev(void *, struct audio_device *);
156: int cmpci_set_port(void *, mixer_ctrl_t *);
157: int cmpci_get_port(void *, mixer_ctrl_t *);
158: int cmpci_query_devinfo(void *, mixer_devinfo_t *);
159: void *cmpci_malloc(void *, int, size_t, int, int);
160: void cmpci_free(void *, void *, int);
161: size_t cmpci_round_buffersize(void *, int, size_t);
162: paddr_t cmpci_mappage(void *, void *, off_t, int);
163: int cmpci_get_props(void *);
164: int cmpci_trigger_output(void *, void *, void *, int,
165: void (*)(void *), void *,
166: struct audio_params *);
167: int cmpci_trigger_input(void *, void *, void *, int,
168: void (*)(void *), void *,
169: struct audio_params *);
170:
171: struct audio_hw_if cmpci_hw_if = {
172: cmpci_open, /* open */
173: cmpci_close, /* close */
174: NULL, /* drain */
175: cmpci_query_encoding, /* query_encoding */
176: cmpci_set_params, /* set_params */
177: cmpci_round_blocksize, /* round_blocksize */
178: NULL, /* commit_settings */
179: NULL, /* init_output */
180: NULL, /* init_input */
181: NULL, /* start_output */
182: NULL, /* start_input */
183: cmpci_halt_output, /* halt_output */
184: cmpci_halt_input, /* halt_input */
185: NULL, /* speaker_ctl */
186: cmpci_getdev, /* getdev */
187: NULL, /* setfd */
188: cmpci_set_port, /* set_port */
189: cmpci_get_port, /* get_port */
190: cmpci_query_devinfo, /* query_devinfo */
191: cmpci_malloc, /* malloc */
192: cmpci_free, /* free */
193: cmpci_round_buffersize,/* round_buffersize */
194: cmpci_mappage, /* mappage */
195: cmpci_get_props, /* get_props */
196: cmpci_trigger_output, /* trigger_output */
197: cmpci_trigger_input, /* trigger_input */
198: };
199:
200: /*
201: * Low-level HW interface
202: */
203:
204: /* mixer register read/write */
205: __inline uint8_t
206: cmpci_mixerreg_read(struct cmpci_softc *sc, uint8_t no)
207: {
208: uint8_t ret;
209:
210: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no);
211: delay(10);
212: ret = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBDATA);
213: delay(10);
214: return ret;
215: }
216:
217: __inline void
218: cmpci_mixerreg_write(struct cmpci_softc *sc, uint8_t no, uint8_t val)
219: {
220: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBADDR, no);
221: delay(10);
222: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_SBDATA, val);
223: delay(10);
224: }
225:
226: /* register partial write */
227: __inline void
228: cmpci_reg_partial_write_1(struct cmpci_softc *sc, int no, int shift,
229: unsigned mask, unsigned val)
230: {
231: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
232: (val<<shift) |
233: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~(mask<<shift)));
234: delay(10);
235: }
236:
237: __inline void
238: cmpci_reg_partial_write_4(struct cmpci_softc *sc, int no, int shift,
239: uint32_t mask, uint32_t val)
240: {
241: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
242: (val<<shift) |
243: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~(mask<<shift)));
244: delay(10);
245: }
246:
247: /* register set/clear bit */
248: __inline void
249: cmpci_reg_set_1(struct cmpci_softc *sc, int no, uint8_t mask)
250: {
251: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
252: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) | mask));
253: delay(10);
254: }
255:
256: __inline void
257: cmpci_reg_clear_1(struct cmpci_softc *sc, int no, uint8_t mask)
258: {
259: bus_space_write_1(sc->sc_iot, sc->sc_ioh, no,
260: (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~mask));
261: delay(10);
262: }
263:
264: __inline void
265: cmpci_reg_set_4(struct cmpci_softc *sc, int no, uint32_t mask)
266: {
267: /* use cmpci_reg_set_reg_misc() for CMPCI_REG_MISC */
268: KDASSERT(no != CMPCI_REG_MISC);
269:
270: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
271: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask));
272: delay(10);
273: }
274:
275: __inline void
276: cmpci_reg_clear_4(struct cmpci_softc *sc, int no, uint32_t mask)
277: {
278: /* use cmpci_reg_clear_reg_misc() for CMPCI_REG_MISC */
279: KDASSERT(no != CMPCI_REG_MISC);
280:
281: bus_space_write_4(sc->sc_iot, sc->sc_ioh, no,
282: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask));
283: delay(10);
284: }
285:
286: /*
287: * The CMPCI_REG_MISC register needs special handling, since one of
288: * its bits has different read/write values.
289: */
290: __inline void
291: cmpci_reg_set_reg_misc(struct cmpci_softc *sc, uint32_t mask)
292: {
293: sc->sc_reg_misc |= mask;
294: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC,
295: sc->sc_reg_misc);
296: delay(10);
297: }
298:
299: __inline void
300: cmpci_reg_clear_reg_misc(struct cmpci_softc *sc, uint32_t mask)
301: {
302: sc->sc_reg_misc &= ~mask;
303: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MISC,
304: sc->sc_reg_misc);
305: delay(10);
306: }
307:
308: /* rate */
309: static const struct {
310: int rate;
311: int divider;
312: } cmpci_rate_table[CMPCI_REG_NUMRATE] = {
313: #define _RATE(n) { n, CMPCI_REG_RATE_ ## n }
314: _RATE(5512),
315: _RATE(8000),
316: _RATE(11025),
317: _RATE(16000),
318: _RATE(22050),
319: _RATE(32000),
320: _RATE(44100),
321: _RATE(48000)
322: #undef _RATE
323: };
324:
325: int
326: cmpci_rate_to_index(int rate)
327: {
328: int i;
329:
330: for (i = 0; i < CMPCI_REG_NUMRATE - 1; i++)
331: if (rate <=
332: (cmpci_rate_table[i].rate + cmpci_rate_table[i+1].rate) / 2)
333: return i;
334: return i; /* 48000 */
335: }
336:
337: __inline int
338: cmpci_index_to_rate(int index)
339: {
340: return cmpci_rate_table[index].rate;
341: }
342:
343: __inline int
344: cmpci_index_to_divider(int index)
345: {
346: return cmpci_rate_table[index].divider;
347: }
348:
349: const struct pci_matchid cmpci_devices[] = {
350: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338A },
351: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8338B },
352: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738 },
353: { PCI_VENDOR_CMI, PCI_PRODUCT_CMI_CMI8738B }
354: };
355:
356: /*
357: * interface to configure the device.
358: */
359:
360: int
361: cmpci_match(struct device *parent, void *match, void *aux)
362: {
363: return (pci_matchbyid((struct pci_attach_args *)aux, cmpci_devices,
364: sizeof(cmpci_devices)/sizeof(cmpci_devices[0])));
365: }
366:
367: void
368: cmpci_attach(struct device *parent, struct device *self, void *aux)
369: {
370: struct cmpci_softc *sc = (struct cmpci_softc *)self;
371: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
372: struct audio_attach_args aa;
373: pci_intr_handle_t ih;
374: char const *intrstr;
375: int i, v;
376:
377: sc->sc_id = pa->pa_id;
378: sc->sc_class = pa->pa_class;
379: switch (PCI_PRODUCT(sc->sc_id)) {
380: case PCI_PRODUCT_CMI_CMI8338A:
381: /*FALLTHROUGH*/
382: case PCI_PRODUCT_CMI_CMI8338B:
383: sc->sc_capable = CMPCI_CAP_CMI8338;
384: break;
385: case PCI_PRODUCT_CMI_CMI8738:
386: /*FALLTHROUGH*/
387: case PCI_PRODUCT_CMI_CMI8738B:
388: sc->sc_capable = CMPCI_CAP_CMI8738;
389: break;
390: }
391:
392: /* map I/O space */
393: if (pci_mapreg_map(pa, CMPCI_PCI_IOBASEREG, PCI_MAPREG_TYPE_IO, 0,
394: &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0)) {
395: printf(": failed to map I/O space\n");
396: return;
397: }
398:
399: /* interrupt */
400: if (pci_intr_map(pa, &ih)) {
401: printf(": failed to map interrupt\n");
402: return;
403: }
404: intrstr = pci_intr_string(pa->pa_pc, ih);
405: sc->sc_ih=pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, cmpci_intr, sc,
406: sc->sc_dev.dv_xname);
407: if (sc->sc_ih == NULL) {
408: printf(": failed to establish interrupt");
409: if (intrstr != NULL)
410: printf(" at %s", intrstr);
411: printf("\n");
412: return;
413: }
414: printf(": %s\n", intrstr);
415:
416: sc->sc_dmat = pa->pa_dmat;
417:
418: audio_attach_mi(&cmpci_hw_if, sc, &sc->sc_dev);
419:
420: /* attach OPL device */
421: aa.type = AUDIODEV_TYPE_OPL;
422: aa.hwif = NULL;
423: aa.hdl = NULL;
424: (void)config_found(&sc->sc_dev, &aa, audioprint);
425:
426: /* attach MPU-401 device */
427: aa.type = AUDIODEV_TYPE_MPU;
428: aa.hwif = NULL;
429: aa.hdl = NULL;
430: if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
431: CMPCI_REG_MPU_BASE, CMPCI_REG_MPU_SIZE, &sc->sc_mpu_ioh) == 0)
432: sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint);
433:
434: /* get initial value (this is 0 and may be omitted but just in case) */
435: sc->sc_reg_misc = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
436: CMPCI_REG_MISC) & ~CMPCI_REG_SPDIF48K;
437:
438: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_RESET, 0);
439: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0);
440: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0);
441: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX,
442: CMPCI_SB16_SW_CD|CMPCI_SB16_SW_MIC|CMPCI_SB16_SW_LINE);
443: for (i = 0; i < CMPCI_NDEVS; i++) {
444: switch(i) {
445: /*
446: * CMI8738 defaults are
447: * master: 0xe0 (0x00 - 0xf8)
448: * FM, DAC: 0xc0 (0x00 - 0xf8)
449: * PC speaker: 0x80 (0x00 - 0xc0)
450: * others: 0
451: */
452: /* volume */
453: case CMPCI_MASTER_VOL:
454: v = 128; /* 224 */
455: break;
456: case CMPCI_FM_VOL:
457: case CMPCI_DAC_VOL:
458: v = 192;
459: break;
460: case CMPCI_PCSPEAKER:
461: v = 128;
462: break;
463:
464: /* booleans, set to true */
465: case CMPCI_CD_MUTE:
466: case CMPCI_MIC_MUTE:
467: case CMPCI_LINE_IN_MUTE:
468: case CMPCI_AUX_IN_MUTE:
469: v = 1;
470: break;
471:
472: /* volume with inital value 0 */
473: case CMPCI_CD_VOL:
474: case CMPCI_LINE_IN_VOL:
475: case CMPCI_AUX_IN_VOL:
476: case CMPCI_MIC_VOL:
477: case CMPCI_MIC_RECVOL:
478: /* FALLTHROUGH */
479:
480: /* others are cleared */
481: case CMPCI_MIC_PREAMP:
482: case CMPCI_RECORD_SOURCE:
483: case CMPCI_PLAYBACK_MODE:
484: case CMPCI_SPDIF_IN_SELECT:
485: case CMPCI_SPDIF_IN_PHASE:
486: case CMPCI_SPDIF_LOOP:
487: case CMPCI_SPDIF_OUT_PLAYBACK:
488: case CMPCI_SPDIF_OUT_VOLTAGE:
489: case CMPCI_MONITOR_DAC:
490: case CMPCI_REAR:
491: case CMPCI_INDIVIDUAL:
492: case CMPCI_REVERSE:
493: case CMPCI_SURROUND:
494: default:
495: v = 0;
496: break;
497: }
498: sc->sc_gain[i][CMPCI_LEFT] = sc->sc_gain[i][CMPCI_RIGHT] = v;
499: cmpci_set_mixer_gain(sc, i);
500: }
501: }
502:
503: int
504: cmpci_intr(void *handle)
505: {
506: struct cmpci_softc *sc = handle;
507: uint32_t intrstat;
508:
509: intrstat = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
510: CMPCI_REG_INTR_STATUS);
511:
512: if (!(intrstat & CMPCI_REG_ANY_INTR))
513: return 0;
514:
515: delay(10);
516:
517: /* disable and reset intr */
518: if (intrstat & CMPCI_REG_CH0_INTR)
519: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL,
520: CMPCI_REG_CH0_INTR_ENABLE);
521: if (intrstat & CMPCI_REG_CH1_INTR)
522: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL,
523: CMPCI_REG_CH1_INTR_ENABLE);
524:
525: if (intrstat & CMPCI_REG_CH0_INTR) {
526: if (sc->sc_play.intr != NULL)
527: (*sc->sc_play.intr)(sc->sc_play.intr_arg);
528: }
529: if (intrstat & CMPCI_REG_CH1_INTR) {
530: if (sc->sc_rec.intr != NULL)
531: (*sc->sc_rec.intr)(sc->sc_rec.intr_arg);
532: }
533:
534: /* enable intr */
535: if (intrstat & CMPCI_REG_CH0_INTR)
536: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL,
537: CMPCI_REG_CH0_INTR_ENABLE);
538: if (intrstat & CMPCI_REG_CH1_INTR)
539: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL,
540: CMPCI_REG_CH1_INTR_ENABLE);
541:
542: #if 0
543: if (intrstat & CMPCI_REG_UART_INTR && sc->sc_mpudev != NULL)
544: mpu_intr(sc->sc_mpudev);
545: #endif
546:
547: return 1;
548: }
549:
550: /* open/close */
551: int
552: cmpci_open(void *handle, int flags)
553: {
554: return 0;
555: }
556:
557: void
558: cmpci_close(void *handle)
559: {
560: }
561:
562: int
563: cmpci_query_encoding(void *handle, struct audio_encoding *fp)
564: {
565: switch (fp->index) {
566: case 0:
567: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
568: fp->encoding = AUDIO_ENCODING_ULINEAR;
569: fp->precision = 8;
570: fp->flags = 0;
571: break;
572: case 1:
573: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
574: fp->encoding = AUDIO_ENCODING_ULAW;
575: fp->precision = 8;
576: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
577: break;
578: case 2:
579: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
580: fp->encoding = AUDIO_ENCODING_ALAW;
581: fp->precision = 8;
582: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
583: break;
584: case 3:
585: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
586: fp->encoding = AUDIO_ENCODING_SLINEAR;
587: fp->precision = 8;
588: fp->flags = 0;
589: break;
590: case 4:
591: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
592: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
593: fp->precision = 16;
594: fp->flags = 0;
595: break;
596: case 5:
597: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
598: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
599: fp->precision = 16;
600: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
601: break;
602: case 6:
603: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
604: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
605: fp->precision = 16;
606: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
607: break;
608: case 7:
609: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
610: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
611: fp->precision = 16;
612: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
613: break;
614: default:
615: return EINVAL;
616: }
617: return 0;
618: }
619:
620: int
621: cmpci_set_params(void *handle, int setmode, int usemode,
622: struct audio_params *play, struct audio_params *rec)
623: {
624: int i;
625: struct cmpci_softc *sc = handle;
626:
627: for (i = 0; i < 2; i++) {
628: int md_format;
629: int md_divide;
630: int md_index;
631: int mode;
632: struct audio_params *p;
633:
634: switch (i) {
635: case 0:
636: mode = AUMODE_PLAY;
637: p = play;
638: break;
639: case 1:
640: mode = AUMODE_RECORD;
641: p = rec;
642: break;
643: default:
644: return EINVAL;
645: }
646:
647: if (!(setmode & mode))
648: continue;
649:
650: /* format */
651: p->sw_code = NULL;
652: switch (p->channels) {
653: case 1:
654: md_format = CMPCI_REG_FORMAT_MONO;
655: break;
656: case 2:
657: md_format = CMPCI_REG_FORMAT_STEREO;
658: break;
659: default:
660: return (EINVAL);
661: }
662: switch (p->encoding) {
663: case AUDIO_ENCODING_ULAW:
664: if (p->precision != 8)
665: return (EINVAL);
666: if (mode & AUMODE_PLAY) {
667: p->factor = 2;
668: p->sw_code = mulaw_to_slinear16_le;
669: md_format |= CMPCI_REG_FORMAT_16BIT;
670: } else {
671: p->sw_code = ulinear8_to_mulaw;
672: md_format |= CMPCI_REG_FORMAT_8BIT;
673: }
674: break;
675: case AUDIO_ENCODING_ALAW:
676: if (p->precision != 8)
677: return (EINVAL);
678: if (mode & AUMODE_PLAY) {
679: p->factor = 2;
680: p->sw_code = alaw_to_slinear16_le;
681: md_format |= CMPCI_REG_FORMAT_16BIT;
682: } else {
683: p->sw_code = ulinear8_to_alaw;
684: md_format |= CMPCI_REG_FORMAT_8BIT;
685: }
686: break;
687: case AUDIO_ENCODING_SLINEAR_LE:
688: switch (p->precision) {
689: case 8:
690: p->sw_code = change_sign8;
691: md_format |= CMPCI_REG_FORMAT_8BIT;
692: break;
693: case 16:
694: md_format |= CMPCI_REG_FORMAT_16BIT;
695: break;
696: default:
697: return (EINVAL);
698: }
699: break;
700: case AUDIO_ENCODING_SLINEAR_BE:
701: switch (p->precision) {
702: case 8:
703: md_format |= CMPCI_REG_FORMAT_8BIT;
704: p->sw_code = change_sign8;
705: break;
706: case 16:
707: md_format |= CMPCI_REG_FORMAT_16BIT;
708: p->sw_code = swap_bytes;
709: break;
710: default:
711: return (EINVAL);
712: }
713: break;
714: case AUDIO_ENCODING_ULINEAR_LE:
715: switch (p->precision) {
716: case 8:
717: md_format |= CMPCI_REG_FORMAT_8BIT;
718: break;
719: case 16:
720: md_format |= CMPCI_REG_FORMAT_16BIT;
721: p->sw_code = change_sign16_le;
722: break;
723: default:
724: return (EINVAL);
725: }
726: break;
727: case AUDIO_ENCODING_ULINEAR_BE:
728: switch (p->precision) {
729: case 8:
730: md_format |= CMPCI_REG_FORMAT_8BIT;
731: break;
732: case 16:
733: md_format |= CMPCI_REG_FORMAT_16BIT;
734: if (mode & AUMODE_PLAY)
735: p->sw_code =
736: swap_bytes_change_sign16_le;
737: else
738: p->sw_code =
739: change_sign16_swap_bytes_le;
740: break;
741: default:
742: return (EINVAL);
743: }
744: break;
745: default:
746: return (EINVAL);
747: }
748: if (mode & AUMODE_PLAY)
749: cmpci_reg_partial_write_4(sc,
750: CMPCI_REG_CHANNEL_FORMAT,
751: CMPCI_REG_CH0_FORMAT_SHIFT,
752: CMPCI_REG_CH0_FORMAT_MASK, md_format);
753: else
754: cmpci_reg_partial_write_4(sc,
755: CMPCI_REG_CHANNEL_FORMAT,
756: CMPCI_REG_CH1_FORMAT_SHIFT,
757: CMPCI_REG_CH1_FORMAT_MASK, md_format);
758: /* sample rate */
759: md_index = cmpci_rate_to_index(p->sample_rate);
760: md_divide = cmpci_index_to_divider(md_index);
761: p->sample_rate = cmpci_index_to_rate(md_index);
762: DPRINTF(("%s: sample:%d, divider=%d\n",
763: sc->sc_dev.dv_xname, (int)p->sample_rate, md_divide));
764: if (mode & AUMODE_PLAY) {
765: cmpci_reg_partial_write_4(sc,
766: CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT,
767: CMPCI_REG_DAC_FS_MASK, md_divide);
768: sc->sc_play.md_divide = md_divide;
769: } else {
770: cmpci_reg_partial_write_4(sc,
771: CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT,
772: CMPCI_REG_ADC_FS_MASK, md_divide);
773: sc->sc_rec.md_divide = md_divide;
774: }
775: cmpci_set_out_ports(sc);
776: cmpci_set_in_ports(sc);
777: }
778: return 0;
779: }
780:
781: /* ARGSUSED */
782: int
783: cmpci_round_blocksize(void *handle, int block)
784: {
785: return ((block + 3) & -4);
786: }
787:
788: int
789: cmpci_halt_output(void *handle)
790: {
791: struct cmpci_softc *sc = handle;
792: int s;
793:
794: s = splaudio();
795: sc->sc_play.intr = NULL;
796: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
797: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
798: /* wait for reset DMA */
799: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
800: delay(10);
801: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
802: splx(s);
803:
804: return 0;
805: }
806:
807: int
808: cmpci_halt_input(void *handle)
809: {
810: struct cmpci_softc *sc = handle;
811: int s;
812:
813: s = splaudio();
814: sc->sc_rec.intr = NULL;
815: cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
816: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE);
817: /* wait for reset DMA */
818: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
819: delay(10);
820: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
821: splx(s);
822:
823: return 0;
824: }
825:
826: /* get audio device information */
827: int
828: cmpci_getdev(void *handle, struct audio_device *ad)
829: {
830: struct cmpci_softc *sc = handle;
831:
832: strncpy(ad->name, "CMI PCI Audio", sizeof(ad->name));
833: snprintf(ad->version, sizeof(ad->version), "0x%02x",
834: PCI_REVISION(sc->sc_class));
835: switch (PCI_PRODUCT(sc->sc_id)) {
836: case PCI_PRODUCT_CMI_CMI8338A:
837: strncpy(ad->config, "CMI8338A", sizeof(ad->config));
838: break;
839: case PCI_PRODUCT_CMI_CMI8338B:
840: strncpy(ad->config, "CMI8338B", sizeof(ad->config));
841: break;
842: case PCI_PRODUCT_CMI_CMI8738:
843: strncpy(ad->config, "CMI8738", sizeof(ad->config));
844: break;
845: case PCI_PRODUCT_CMI_CMI8738B:
846: strncpy(ad->config, "CMI8738B", sizeof(ad->config));
847: break;
848: default:
849: strncpy(ad->config, "unknown", sizeof(ad->config));
850: }
851:
852: return 0;
853: }
854:
855: /* mixer device information */
856: int
857: cmpci_query_devinfo(void *handle, mixer_devinfo_t *dip)
858: {
859: static const char *const mixer_port_names[] = {
860: AudioNdac, AudioNfmsynth, AudioNcd, AudioNline, AudioNaux,
861: AudioNmicrophone
862: };
863: static const char *const mixer_classes[] = {
864: AudioCinputs, AudioCoutputs, AudioCrecord, CmpciCplayback,
865: CmpciCspdif
866: };
867: struct cmpci_softc *sc = handle;
868: int i;
869:
870: dip->prev = dip->next = AUDIO_MIXER_LAST;
871:
872: switch (dip->index) {
873: case CMPCI_INPUT_CLASS:
874: case CMPCI_OUTPUT_CLASS:
875: case CMPCI_RECORD_CLASS:
876: case CMPCI_PLAYBACK_CLASS:
877: case CMPCI_SPDIF_CLASS:
878: dip->type = AUDIO_MIXER_CLASS;
879: dip->mixer_class = dip->index;
880: strlcpy(dip->label.name,
881: mixer_classes[dip->index - CMPCI_INPUT_CLASS],
882: sizeof dip->label.name);
883: return 0;
884:
885: case CMPCI_AUX_IN_VOL:
886: dip->un.v.delta = 1 << (8 - CMPCI_REG_AUX_VALBITS);
887: goto vol1;
888: case CMPCI_DAC_VOL:
889: case CMPCI_FM_VOL:
890: case CMPCI_CD_VOL:
891: case CMPCI_LINE_IN_VOL:
892: case CMPCI_MIC_VOL:
893: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS);
894: vol1: dip->mixer_class = CMPCI_INPUT_CLASS;
895: dip->next = dip->index + 6; /* CMPCI_xxx_MUTE */
896: strlcpy(dip->label.name, mixer_port_names[dip->index],
897: sizeof dip->label.name);
898: dip->un.v.num_channels = (dip->index == CMPCI_MIC_VOL ? 1 : 2);
899: vol:
900: dip->type = AUDIO_MIXER_VALUE;
901: strlcpy(dip->un.v.units.name, AudioNvolume,
902: sizeof dip->un.v.units.name);
903: return 0;
904:
905: case CMPCI_MIC_MUTE:
906: dip->next = CMPCI_MIC_PREAMP;
907: /* FALLTHROUGH */
908: case CMPCI_DAC_MUTE:
909: case CMPCI_FM_MUTE:
910: case CMPCI_CD_MUTE:
911: case CMPCI_LINE_IN_MUTE:
912: case CMPCI_AUX_IN_MUTE:
913: dip->prev = dip->index - 6; /* CMPCI_xxx_VOL */
914: dip->mixer_class = CMPCI_INPUT_CLASS;
915: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
916: goto on_off;
917: on_off:
918: dip->type = AUDIO_MIXER_ENUM;
919: dip->un.e.num_mem = 2;
920: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
921: sizeof dip->un.e.member[0].label.name);
922: dip->un.e.member[0].ord = 0;
923: strlcpy(dip->un.e.member[1].label.name, AudioNon,
924: sizeof dip->un.e.member[1].label.name);
925: dip->un.e.member[1].ord = 1;
926: return 0;
927:
928: case CMPCI_MIC_PREAMP:
929: dip->mixer_class = CMPCI_INPUT_CLASS;
930: dip->prev = CMPCI_MIC_MUTE;
931: strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
932: goto on_off;
933: case CMPCI_PCSPEAKER:
934: dip->mixer_class = CMPCI_INPUT_CLASS;
935: strlcpy(dip->label.name, AudioNspeaker, sizeof dip->label.name);
936: dip->un.v.num_channels = 1;
937: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_SPEAKER_VALBITS);
938: goto vol;
939: case CMPCI_RECORD_SOURCE:
940: dip->mixer_class = CMPCI_RECORD_CLASS;
941: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
942: dip->type = AUDIO_MIXER_SET;
943: dip->un.s.num_mem = 7;
944: strlcpy(dip->un.s.member[0].label.name, AudioNmicrophone,
945: sizeof dip->un.s.member[0].label.name);
946: dip->un.s.member[0].mask = CMPCI_RECORD_SOURCE_MIC;
947: strlcpy(dip->un.s.member[1].label.name, AudioNcd,
948: sizeof dip->un.s.member[1].label.name);
949: dip->un.s.member[1].mask = CMPCI_RECORD_SOURCE_CD;
950: strlcpy(dip->un.s.member[2].label.name, AudioNline,
951: sizeof dip->un.s.member[2].label.name);
952: dip->un.s.member[2].mask = CMPCI_RECORD_SOURCE_LINE_IN;
953: strlcpy(dip->un.s.member[3].label.name, AudioNaux,
954: sizeof dip->un.s.member[3].label.name);
955: dip->un.s.member[3].mask = CMPCI_RECORD_SOURCE_AUX_IN;
956: strlcpy(dip->un.s.member[4].label.name, AudioNwave,
957: sizeof dip->un.s.member[4].label.name);
958: dip->un.s.member[4].mask = CMPCI_RECORD_SOURCE_WAVE;
959: strlcpy(dip->un.s.member[5].label.name, AudioNfmsynth,
960: sizeof dip->un.s.member[5].label.name);
961: dip->un.s.member[5].mask = CMPCI_RECORD_SOURCE_FM;
962: strlcpy(dip->un.s.member[6].label.name, CmpciNspdif,
963: sizeof dip->un.s.member[6].label.name);
964: dip->un.s.member[6].mask = CMPCI_RECORD_SOURCE_SPDIF;
965: return 0;
966: case CMPCI_MIC_RECVOL:
967: dip->mixer_class = CMPCI_RECORD_CLASS;
968: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
969: dip->un.v.num_channels = 1;
970: dip->un.v.delta = 1 << (8 - CMPCI_REG_ADMIC_VALBITS);
971: goto vol;
972:
973: case CMPCI_PLAYBACK_MODE:
974: dip->mixer_class = CMPCI_PLAYBACK_CLASS;
975: dip->type = AUDIO_MIXER_ENUM;
976: strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
977: dip->un.e.num_mem = 2;
978: strlcpy(dip->un.e.member[0].label.name, AudioNdac,
979: sizeof dip->un.e.member[0].label.name);
980: dip->un.e.member[0].ord = CMPCI_PLAYBACK_MODE_WAVE;
981: strlcpy(dip->un.e.member[1].label.name, CmpciNspdif,
982: sizeof dip->un.e.member[1].label.name);
983: dip->un.e.member[1].ord = CMPCI_PLAYBACK_MODE_SPDIF;
984: return 0;
985: case CMPCI_SPDIF_IN_SELECT:
986: dip->mixer_class = CMPCI_SPDIF_CLASS;
987: dip->type = AUDIO_MIXER_ENUM;
988: dip->next = CMPCI_SPDIF_IN_PHASE;
989: strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
990: i = 0;
991: strlcpy(dip->un.e.member[i].label.name, CmpciNspdin1,
992: sizeof dip->un.e.member[i].label.name);
993: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN1;
994: if (CMPCI_ISCAP(sc, 2ND_SPDIN)) {
995: strlcpy(dip->un.e.member[i].label.name, CmpciNspdin2,
996: sizeof dip->un.e.member[i].label.name);
997: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDIN2;
998: }
999: strlcpy(dip->un.e.member[i].label.name, CmpciNspdout,
1000: sizeof dip->un.e.member[i].label.name);
1001: dip->un.e.member[i++].ord = CMPCI_SPDIF_IN_SPDOUT;
1002: dip->un.e.num_mem = i;
1003: return 0;
1004: case CMPCI_SPDIF_IN_PHASE:
1005: dip->mixer_class = CMPCI_SPDIF_CLASS;
1006: dip->prev = CMPCI_SPDIF_IN_SELECT;
1007: strlcpy(dip->label.name, CmpciNphase, sizeof dip->label.name);
1008: dip->type = AUDIO_MIXER_ENUM;
1009: dip->un.e.num_mem = 2;
1010: strlcpy(dip->un.e.member[0].label.name, CmpciNpositive,
1011: sizeof dip->un.e.member[0].label.name);
1012: dip->un.e.member[0].ord = CMPCI_SPDIF_IN_PHASE_POSITIVE;
1013: strlcpy(dip->un.e.member[1].label.name, CmpciNnegative,
1014: sizeof dip->un.e.member[1].label.name);
1015: dip->un.e.member[1].ord = CMPCI_SPDIF_IN_PHASE_NEGATIVE;
1016: return 0;
1017: case CMPCI_SPDIF_LOOP:
1018: dip->mixer_class = CMPCI_SPDIF_CLASS;
1019: dip->next = CMPCI_SPDIF_OUT_PLAYBACK;
1020: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1021: dip->type = AUDIO_MIXER_ENUM;
1022: dip->un.e.num_mem = 2;
1023: strlcpy(dip->un.e.member[0].label.name, CmpciNplayback,
1024: sizeof dip->un.e.member[0].label.name);
1025: dip->un.e.member[0].ord = CMPCI_SPDIF_LOOP_OFF;
1026: strlcpy(dip->un.e.member[1].label.name, CmpciNspdin,
1027: sizeof dip->un.e.member[1].label.name);
1028: dip->un.e.member[1].ord = CMPCI_SPDIF_LOOP_ON;
1029: return 0;
1030: case CMPCI_SPDIF_OUT_PLAYBACK:
1031: dip->mixer_class = CMPCI_SPDIF_CLASS;
1032: dip->prev = CMPCI_SPDIF_LOOP;
1033: dip->next = CMPCI_SPDIF_OUT_VOLTAGE;
1034: strlcpy(dip->label.name, CmpciNplayback, sizeof dip->label.name);
1035: dip->type = AUDIO_MIXER_ENUM;
1036: dip->un.e.num_mem = 2;
1037: strlcpy(dip->un.e.member[0].label.name, AudioNwave,
1038: sizeof dip->un.e.member[0].label.name);
1039: dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_PLAYBACK_WAVE;
1040: strlcpy(dip->un.e.member[1].label.name, CmpciNlegacy,
1041: sizeof dip->un.e.member[1].label.name);
1042: dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_PLAYBACK_LEGACY;
1043: return 0;
1044: case CMPCI_SPDIF_OUT_VOLTAGE:
1045: dip->mixer_class = CMPCI_SPDIF_CLASS;
1046: dip->prev = CMPCI_SPDIF_OUT_PLAYBACK;
1047: strlcpy(dip->label.name, CmpciNvoltage, sizeof dip->label.name);
1048: dip->type = AUDIO_MIXER_ENUM;
1049: dip->un.e.num_mem = 2;
1050: strlcpy(dip->un.e.member[0].label.name, CmpciNhigh_v,
1051: sizeof dip->un.e.member[0].label.name);
1052: dip->un.e.member[0].ord = CMPCI_SPDIF_OUT_VOLTAGE_HIGH;
1053: strlcpy(dip->un.e.member[1].label.name, CmpciNlow_v,
1054: sizeof dip->un.e.member[1].label.name);
1055: dip->un.e.member[1].ord = CMPCI_SPDIF_OUT_VOLTAGE_LOW;
1056: return 0;
1057: case CMPCI_MONITOR_DAC:
1058: dip->mixer_class = CMPCI_SPDIF_CLASS;
1059: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
1060: dip->type = AUDIO_MIXER_ENUM;
1061: dip->un.e.num_mem = 3;
1062: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
1063: sizeof dip->un.e.member[0].label.name);
1064: dip->un.e.member[0].ord = CMPCI_MONITOR_DAC_OFF;
1065: strlcpy(dip->un.e.member[1].label.name, CmpciNspdin,
1066: sizeof dip->un.e.member[1].label.name);
1067: dip->un.e.member[1].ord = CMPCI_MONITOR_DAC_SPDIN;
1068: strlcpy(dip->un.e.member[2].label.name, CmpciNspdout,
1069: sizeof dip->un.e.member[2].label.name);
1070: dip->un.e.member[2].ord = CMPCI_MONITOR_DAC_SPDOUT;
1071: return 0;
1072:
1073: case CMPCI_MASTER_VOL:
1074: dip->mixer_class = CMPCI_OUTPUT_CLASS;
1075: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
1076: dip->un.v.num_channels = 2;
1077: dip->un.v.delta = 1 << (8 - CMPCI_SB16_MIXER_VALBITS);
1078: goto vol;
1079: case CMPCI_REAR:
1080: dip->mixer_class = CMPCI_OUTPUT_CLASS;
1081: dip->next = CMPCI_INDIVIDUAL;
1082: strlcpy(dip->label.name, CmpciNrear, sizeof dip->label.name);
1083: goto on_off;
1084: case CMPCI_INDIVIDUAL:
1085: dip->mixer_class = CMPCI_OUTPUT_CLASS;
1086: dip->prev = CMPCI_REAR;
1087: dip->next = CMPCI_REVERSE;
1088: strlcpy(dip->label.name, CmpciNindividual, sizeof dip->label.name);
1089: goto on_off;
1090: case CMPCI_REVERSE:
1091: dip->mixer_class = CMPCI_OUTPUT_CLASS;
1092: dip->prev = CMPCI_INDIVIDUAL;
1093: strlcpy(dip->label.name, CmpciNreverse, sizeof dip->label.name);
1094: goto on_off;
1095: case CMPCI_SURROUND:
1096: dip->mixer_class = CMPCI_OUTPUT_CLASS;
1097: strlcpy(dip->label.name, CmpciNsurround, sizeof dip->label.name);
1098: goto on_off;
1099: }
1100:
1101: return ENXIO;
1102: }
1103:
1104: int
1105: cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, int type, int flags,
1106: caddr_t *r_addr)
1107: {
1108: int error = 0;
1109: struct cmpci_dmanode *n;
1110: int w;
1111:
1112: n = malloc(sizeof(struct cmpci_dmanode), type, flags);
1113: if (n == NULL) {
1114: error = ENOMEM;
1115: goto quit;
1116: }
1117:
1118: w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
1119: #define CMPCI_DMABUF_ALIGN 0x4
1120: #define CMPCI_DMABUF_BOUNDARY 0x0
1121: n->cd_tag = sc->sc_dmat;
1122: n->cd_size = size;
1123: error = bus_dmamem_alloc(n->cd_tag, n->cd_size,
1124: CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, n->cd_segs,
1125: sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w);
1126: if (error)
1127: goto mfree;
1128: error = bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size,
1129: &n->cd_addr, w | BUS_DMA_COHERENT);
1130: if (error)
1131: goto dmafree;
1132: error = bus_dmamap_create(n->cd_tag, n->cd_size, 1, n->cd_size, 0,
1133: w, &n->cd_map);
1134: if (error)
1135: goto unmap;
1136: error = bus_dmamap_load(n->cd_tag, n->cd_map, n->cd_addr, n->cd_size,
1137: NULL, w);
1138: if (error)
1139: goto destroy;
1140:
1141: n->cd_next = sc->sc_dmap;
1142: sc->sc_dmap = n;
1143: *r_addr = KVADDR(n);
1144: return 0;
1145:
1146: destroy:
1147: bus_dmamap_destroy(n->cd_tag, n->cd_map);
1148: unmap:
1149: bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size);
1150: dmafree:
1151: bus_dmamem_free(n->cd_tag,
1152: n->cd_segs, sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
1153: mfree:
1154: free(n, type);
1155: quit:
1156: return error;
1157: }
1158:
1159: int
1160: cmpci_free_dmamem(struct cmpci_softc *sc, caddr_t addr, int type)
1161: {
1162: struct cmpci_dmanode **nnp;
1163:
1164: for (nnp = &sc->sc_dmap; *nnp; nnp = &(*nnp)->cd_next) {
1165: if ((*nnp)->cd_addr == addr) {
1166: struct cmpci_dmanode *n = *nnp;
1167: bus_dmamap_unload(n->cd_tag, n->cd_map);
1168: bus_dmamap_destroy(n->cd_tag, n->cd_map);
1169: bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size);
1170: bus_dmamem_free(n->cd_tag, n->cd_segs,
1171: sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
1172: free(n, type);
1173: return 0;
1174: }
1175: }
1176: return -1;
1177: }
1178:
1179: struct cmpci_dmanode *
1180: cmpci_find_dmamem(struct cmpci_softc *sc, caddr_t addr)
1181: {
1182: struct cmpci_dmanode *p;
1183:
1184: for (p = sc->sc_dmap; p; p = p->cd_next) {
1185: if (KVADDR(p) == (void *)addr)
1186: break;
1187: }
1188: return p;
1189: }
1190:
1191: #if 0
1192: void cmpci_print_dmamem(struct cmpci_dmanode *p);
1193:
1194: void
1195: cmpci_print_dmamem(struct cmpci_dmanode *p)
1196: {
1197: DPRINTF(("DMA at virt:%p, dmaseg:%p, mapseg:%p, size:%p\n",
1198: (void *)p->cd_addr, (void *)p->cd_segs[0].ds_addr,
1199: (void *)DMAADDR(p), (void *)p->cd_size));
1200: }
1201: #endif /* DEBUG */
1202:
1203: void *
1204: cmpci_malloc(void *handle, int direction, size_t size, int type,
1205: int flags)
1206: {
1207: caddr_t addr;
1208:
1209: if (cmpci_alloc_dmamem(handle, size, type, flags, &addr))
1210: return NULL;
1211: return addr;
1212: }
1213:
1214: void
1215: cmpci_free(void *handle, void *addr, int type)
1216: {
1217: cmpci_free_dmamem(handle, addr, type);
1218: }
1219:
1220: #define MAXVAL 256
1221: int
1222: cmpci_adjust(int val, int mask)
1223: {
1224: val += (MAXVAL - mask) >> 1;
1225: if (val >= MAXVAL)
1226: val = MAXVAL-1;
1227: return val & mask;
1228: }
1229:
1230: void
1231: cmpci_set_mixer_gain(struct cmpci_softc *sc, int port)
1232: {
1233: int src;
1234: int bits, mask;
1235:
1236: switch (port) {
1237: case CMPCI_MIC_VOL:
1238: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_MIC,
1239: CMPCI_ADJUST_MIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
1240: return;
1241: case CMPCI_MASTER_VOL:
1242: src = CMPCI_SB16_MIXER_MASTER_L;
1243: break;
1244: case CMPCI_LINE_IN_VOL:
1245: src = CMPCI_SB16_MIXER_LINE_L;
1246: break;
1247: case CMPCI_AUX_IN_VOL:
1248: bus_space_write_1(sc->sc_iot, sc->sc_ioh, CMPCI_REG_MIXER_AUX,
1249: CMPCI_ADJUST_AUX_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT],
1250: sc->sc_gain[port][CMPCI_RIGHT]));
1251: return;
1252: case CMPCI_MIC_RECVOL:
1253: cmpci_reg_partial_write_1(sc, CMPCI_REG_MIXER25,
1254: CMPCI_REG_ADMIC_SHIFT, CMPCI_REG_ADMIC_MASK,
1255: CMPCI_ADJUST_ADMIC_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
1256: return;
1257: case CMPCI_DAC_VOL:
1258: src = CMPCI_SB16_MIXER_VOICE_L;
1259: break;
1260: case CMPCI_FM_VOL:
1261: src = CMPCI_SB16_MIXER_FM_L;
1262: break;
1263: case CMPCI_CD_VOL:
1264: src = CMPCI_SB16_MIXER_CDDA_L;
1265: break;
1266: case CMPCI_PCSPEAKER:
1267: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_SPEAKER,
1268: CMPCI_ADJUST_2_GAIN(sc, sc->sc_gain[port][CMPCI_LR]));
1269: return;
1270: case CMPCI_MIC_PREAMP:
1271: if (sc->sc_gain[port][CMPCI_LR])
1272: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
1273: CMPCI_REG_MICGAINZ);
1274: else
1275: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
1276: CMPCI_REG_MICGAINZ);
1277: return;
1278:
1279: case CMPCI_DAC_MUTE:
1280: if (sc->sc_gain[port][CMPCI_LR])
1281: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1282: CMPCI_REG_WSMUTE);
1283: else
1284: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1285: CMPCI_REG_WSMUTE);
1286: return;
1287: case CMPCI_FM_MUTE:
1288: if (sc->sc_gain[port][CMPCI_LR])
1289: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1290: CMPCI_REG_FMMUTE);
1291: else
1292: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1293: CMPCI_REG_FMMUTE);
1294: return;
1295: case CMPCI_AUX_IN_MUTE:
1296: if (sc->sc_gain[port][CMPCI_LR])
1297: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
1298: CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM);
1299: else
1300: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
1301: CMPCI_REG_VAUXRM|CMPCI_REG_VAUXLM);
1302: return;
1303: case CMPCI_CD_MUTE:
1304: mask = CMPCI_SB16_SW_CD;
1305: goto sbmute;
1306: case CMPCI_MIC_MUTE:
1307: mask = CMPCI_SB16_SW_MIC;
1308: goto sbmute;
1309: case CMPCI_LINE_IN_MUTE:
1310: mask = CMPCI_SB16_SW_LINE;
1311: sbmute:
1312: bits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_OUTMIX);
1313: if (sc->sc_gain[port][CMPCI_LR])
1314: bits = bits & ~mask;
1315: else
1316: bits = bits | mask;
1317: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_OUTMIX, bits);
1318: return;
1319:
1320: case CMPCI_SPDIF_IN_SELECT:
1321: case CMPCI_MONITOR_DAC:
1322: case CMPCI_PLAYBACK_MODE:
1323: case CMPCI_SPDIF_LOOP:
1324: case CMPCI_SPDIF_OUT_PLAYBACK:
1325: cmpci_set_out_ports(sc);
1326: return;
1327: case CMPCI_SPDIF_OUT_VOLTAGE:
1328: if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) {
1329: if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR]
1330: == CMPCI_SPDIF_OUT_VOLTAGE_HIGH)
1331: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_5V);
1332: else
1333: cmpci_reg_set_reg_misc(sc, CMPCI_REG_5V);
1334: }
1335: return;
1336: case CMPCI_SURROUND:
1337: if (CMPCI_ISCAP(sc, SURROUND)) {
1338: if (sc->sc_gain[CMPCI_SURROUND][CMPCI_LR])
1339: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1340: CMPCI_REG_SURROUND);
1341: else
1342: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1343: CMPCI_REG_SURROUND);
1344: }
1345: return;
1346: case CMPCI_REAR:
1347: if (CMPCI_ISCAP(sc, REAR)) {
1348: if (sc->sc_gain[CMPCI_REAR][CMPCI_LR])
1349: cmpci_reg_set_reg_misc(sc, CMPCI_REG_N4SPK3D);
1350: else
1351: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_N4SPK3D);
1352: }
1353: return;
1354: case CMPCI_INDIVIDUAL:
1355: if (CMPCI_ISCAP(sc, INDIVIDUAL_REAR)) {
1356: if (sc->sc_gain[CMPCI_REAR][CMPCI_LR])
1357: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1358: CMPCI_REG_INDIVIDUAL);
1359: else
1360: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1361: CMPCI_REG_INDIVIDUAL);
1362: }
1363: return;
1364: case CMPCI_REVERSE:
1365: if (CMPCI_ISCAP(sc, REVERSE_FR)) {
1366: if (sc->sc_gain[CMPCI_REVERSE][CMPCI_LR])
1367: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1368: CMPCI_REG_REVERSE_FR);
1369: else
1370: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1371: CMPCI_REG_REVERSE_FR);
1372: }
1373: return;
1374: case CMPCI_SPDIF_IN_PHASE:
1375: if (CMPCI_ISCAP(sc, SPDIN_PHASE)) {
1376: if (sc->sc_gain[CMPCI_SPDIF_IN_PHASE][CMPCI_LR]
1377: == CMPCI_SPDIF_IN_PHASE_POSITIVE)
1378: cmpci_reg_clear_1(sc, CMPCI_REG_CHANNEL_FORMAT,
1379: CMPCI_REG_SPDIN_PHASE);
1380: else
1381: cmpci_reg_set_1(sc, CMPCI_REG_CHANNEL_FORMAT,
1382: CMPCI_REG_SPDIN_PHASE);
1383: }
1384: return;
1385: default:
1386: return;
1387: }
1388:
1389: cmpci_mixerreg_write(sc, src,
1390: CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_LEFT]));
1391: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_L_TO_R(src),
1392: CMPCI_ADJUST_GAIN(sc, sc->sc_gain[port][CMPCI_RIGHT]));
1393: }
1394:
1395: void
1396: cmpci_set_out_ports(struct cmpci_softc *sc)
1397: {
1398: u_int8_t v;
1399: int enspdout = 0;
1400:
1401: if (!CMPCI_ISCAP(sc, SPDLOOP))
1402: return;
1403:
1404: /* SPDIF/out select */
1405: if (sc->sc_gain[CMPCI_SPDIF_LOOP][CMPCI_LR] == CMPCI_SPDIF_LOOP_OFF) {
1406: /* playback */
1407: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP);
1408: } else {
1409: /* monitor SPDIF/in */
1410: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP);
1411: }
1412:
1413: /* SPDIF in select */
1414: v = sc->sc_gain[CMPCI_SPDIF_IN_SELECT][CMPCI_LR];
1415: if (v & CMPCI_SPDIFIN_SPDIFIN2)
1416: cmpci_reg_set_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN);
1417: else
1418: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_2ND_SPDIFIN);
1419: if (v & CMPCI_SPDIFIN_SPDIFOUT)
1420: cmpci_reg_set_reg_misc(sc, CMPCI_REG_SPDFLOOPI);
1421: else
1422: cmpci_reg_clear_reg_misc(sc, CMPCI_REG_SPDFLOOPI);
1423:
1424: /* playback to ... */
1425: if (CMPCI_ISCAP(sc, SPDOUT) &&
1426: sc->sc_gain[CMPCI_PLAYBACK_MODE][CMPCI_LR]
1427: == CMPCI_PLAYBACK_MODE_SPDIF &&
1428: (sc->sc_play.md_divide == CMPCI_REG_RATE_44100 ||
1429: (CMPCI_ISCAP(sc, SPDOUT_48K) &&
1430: sc->sc_play.md_divide==CMPCI_REG_RATE_48000))) {
1431: /* playback to SPDIF */
1432: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF0_ENABLE);
1433: enspdout = 1;
1434: if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000)
1435: cmpci_reg_set_reg_misc(sc,
1436: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
1437: else
1438: cmpci_reg_clear_reg_misc(sc,
1439: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
1440: } else {
1441: /* playback to DAC */
1442: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1,
1443: CMPCI_REG_SPDIF0_ENABLE);
1444: if (CMPCI_ISCAP(sc, SPDOUT_48K))
1445: cmpci_reg_clear_reg_misc(sc,
1446: CMPCI_REG_SPDIFOUT_48K | CMPCI_REG_SPDIF48K);
1447: }
1448:
1449: /* legacy to SPDIF/out or not */
1450: if (CMPCI_ISCAP(sc, SPDLEGACY)) {
1451: if (sc->sc_gain[CMPCI_SPDIF_OUT_PLAYBACK][CMPCI_LR]
1452: == CMPCI_SPDIF_OUT_PLAYBACK_WAVE)
1453: cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL,
1454: CMPCI_REG_LEGACY_SPDIF_ENABLE);
1455: else {
1456: cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL,
1457: CMPCI_REG_LEGACY_SPDIF_ENABLE);
1458: enspdout = 1;
1459: }
1460: }
1461:
1462: /* enable/disable SPDIF/out */
1463: if (CMPCI_ISCAP(sc, XSPDOUT) && enspdout)
1464: cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL,
1465: CMPCI_REG_XSPDIF_ENABLE);
1466: else
1467: cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL,
1468: CMPCI_REG_XSPDIF_ENABLE);
1469:
1470: /* SPDIF monitor (digital to analog output) */
1471: if (CMPCI_ISCAP(sc, SPDIN_MONITOR)) {
1472: v = sc->sc_gain[CMPCI_MONITOR_DAC][CMPCI_LR];
1473: if (!(v & CMPCI_MONDAC_ENABLE))
1474: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1475: CMPCI_REG_SPDIN_MONITOR);
1476: if (v & CMPCI_MONDAC_SPDOUT)
1477: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1,
1478: CMPCI_REG_SPDIFOUT_DAC);
1479: else
1480: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1,
1481: CMPCI_REG_SPDIFOUT_DAC);
1482: if (v & CMPCI_MONDAC_ENABLE)
1483: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1484: CMPCI_REG_SPDIN_MONITOR);
1485: }
1486: }
1487:
1488: int
1489: cmpci_set_in_ports(struct cmpci_softc *sc)
1490: {
1491: int mask;
1492: int bitsl, bitsr;
1493:
1494: mask = sc->sc_in_mask;
1495:
1496: /*
1497: * Note CMPCI_RECORD_SOURCE_CD, CMPCI_RECORD_SOURCE_LINE_IN and
1498: * CMPCI_RECORD_SOURCE_FM are defined to the corresponding bit
1499: * of the mixer register.
1500: */
1501: bitsr = mask & (CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN |
1502: CMPCI_RECORD_SOURCE_FM);
1503:
1504: bitsl = CMPCI_SB16_MIXER_SRC_R_TO_L(bitsr);
1505: if (mask & CMPCI_RECORD_SOURCE_MIC) {
1506: bitsl |= CMPCI_SB16_MIXER_MIC_SRC;
1507: bitsr |= CMPCI_SB16_MIXER_MIC_SRC;
1508: }
1509: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, bitsl);
1510: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, bitsr);
1511:
1512: if (mask & CMPCI_RECORD_SOURCE_AUX_IN)
1513: cmpci_reg_set_1(sc, CMPCI_REG_MIXER25,
1514: CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN);
1515: else
1516: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER25,
1517: CMPCI_REG_RAUXREN | CMPCI_REG_RAUXLEN);
1518:
1519: if (mask & CMPCI_RECORD_SOURCE_WAVE)
1520: cmpci_reg_set_1(sc, CMPCI_REG_MIXER24,
1521: CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR);
1522: else
1523: cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24,
1524: CMPCI_REG_WAVEINL | CMPCI_REG_WAVEINR);
1525:
1526: if (CMPCI_ISCAP(sc, SPDIN) &&
1527: (sc->sc_rec.md_divide == CMPCI_REG_RATE_44100 ||
1528: (CMPCI_ISCAP(sc, SPDOUT_48K) &&
1529: sc->sc_rec.md_divide == CMPCI_REG_RATE_48000/* XXX? */))) {
1530: if (mask & CMPCI_RECORD_SOURCE_SPDIF) {
1531: /* enable SPDIF/in */
1532: cmpci_reg_set_4(sc,
1533: CMPCI_REG_FUNC_1,
1534: CMPCI_REG_SPDIF1_ENABLE);
1535: } else {
1536: cmpci_reg_clear_4(sc,
1537: CMPCI_REG_FUNC_1,
1538: CMPCI_REG_SPDIF1_ENABLE);
1539: }
1540: }
1541:
1542: return 0;
1543: }
1544:
1545: int
1546: cmpci_set_port(void *handle, mixer_ctrl_t *cp)
1547: {
1548: struct cmpci_softc *sc = handle;
1549: int lgain, rgain;
1550:
1551: switch (cp->dev) {
1552: case CMPCI_MIC_VOL:
1553: case CMPCI_PCSPEAKER:
1554: case CMPCI_MIC_RECVOL:
1555: if (cp->un.value.num_channels != 1)
1556: return EINVAL;
1557: /* FALLTHROUGH */
1558: case CMPCI_DAC_VOL:
1559: case CMPCI_FM_VOL:
1560: case CMPCI_CD_VOL:
1561: case CMPCI_LINE_IN_VOL:
1562: case CMPCI_AUX_IN_VOL:
1563: case CMPCI_MASTER_VOL:
1564: if (cp->type != AUDIO_MIXER_VALUE)
1565: return EINVAL;
1566: switch (cp->un.value.num_channels) {
1567: case 1:
1568: lgain = rgain =
1569: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1570: break;
1571: case 2:
1572: lgain = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1573: rgain = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1574: break;
1575: default:
1576: return EINVAL;
1577: }
1578: sc->sc_gain[cp->dev][CMPCI_LEFT] = lgain;
1579: sc->sc_gain[cp->dev][CMPCI_RIGHT] = rgain;
1580:
1581: cmpci_set_mixer_gain(sc, cp->dev);
1582: break;
1583:
1584: case CMPCI_RECORD_SOURCE:
1585: if (cp->type != AUDIO_MIXER_SET)
1586: return EINVAL;
1587:
1588: if (cp->un.mask & ~(CMPCI_RECORD_SOURCE_MIC |
1589: CMPCI_RECORD_SOURCE_CD | CMPCI_RECORD_SOURCE_LINE_IN |
1590: CMPCI_RECORD_SOURCE_AUX_IN | CMPCI_RECORD_SOURCE_WAVE |
1591: CMPCI_RECORD_SOURCE_FM | CMPCI_RECORD_SOURCE_SPDIF))
1592: return EINVAL;
1593:
1594: if (cp->un.mask & CMPCI_RECORD_SOURCE_SPDIF)
1595: cp->un.mask = CMPCI_RECORD_SOURCE_SPDIF;
1596:
1597: sc->sc_in_mask = cp->un.mask;
1598: return cmpci_set_in_ports(sc);
1599:
1600: /* boolean */
1601: case CMPCI_DAC_MUTE:
1602: case CMPCI_FM_MUTE:
1603: case CMPCI_CD_MUTE:
1604: case CMPCI_LINE_IN_MUTE:
1605: case CMPCI_AUX_IN_MUTE:
1606: case CMPCI_MIC_MUTE:
1607: case CMPCI_MIC_PREAMP:
1608: case CMPCI_PLAYBACK_MODE:
1609: case CMPCI_SPDIF_IN_PHASE:
1610: case CMPCI_SPDIF_LOOP:
1611: case CMPCI_SPDIF_OUT_PLAYBACK:
1612: case CMPCI_SPDIF_OUT_VOLTAGE:
1613: case CMPCI_REAR:
1614: case CMPCI_INDIVIDUAL:
1615: case CMPCI_REVERSE:
1616: case CMPCI_SURROUND:
1617: if (cp->type != AUDIO_MIXER_ENUM)
1618: return EINVAL;
1619: sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord != 0;
1620: cmpci_set_mixer_gain(sc, cp->dev);
1621: break;
1622:
1623: case CMPCI_SPDIF_IN_SELECT:
1624: switch (cp->un.ord) {
1625: case CMPCI_SPDIF_IN_SPDIN1:
1626: case CMPCI_SPDIF_IN_SPDIN2:
1627: case CMPCI_SPDIF_IN_SPDOUT:
1628: break;
1629: default:
1630: return EINVAL;
1631: }
1632: goto xenum;
1633: case CMPCI_MONITOR_DAC:
1634: switch (cp->un.ord) {
1635: case CMPCI_MONITOR_DAC_OFF:
1636: case CMPCI_MONITOR_DAC_SPDIN:
1637: case CMPCI_MONITOR_DAC_SPDOUT:
1638: break;
1639: default:
1640: return EINVAL;
1641: }
1642: xenum:
1643: if (cp->type != AUDIO_MIXER_ENUM)
1644: return EINVAL;
1645: sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord;
1646: cmpci_set_mixer_gain(sc, cp->dev);
1647: break;
1648:
1649: default:
1650: return EINVAL;
1651: }
1652:
1653: return 0;
1654: }
1655:
1656: int
1657: cmpci_get_port(void *handle, mixer_ctrl_t *cp)
1658: {
1659: struct cmpci_softc *sc = handle;
1660:
1661: switch (cp->dev) {
1662: case CMPCI_MIC_VOL:
1663: case CMPCI_PCSPEAKER:
1664: case CMPCI_MIC_RECVOL:
1665: if (cp->un.value.num_channels != 1)
1666: return EINVAL;
1667: /*FALLTHROUGH*/
1668: case CMPCI_DAC_VOL:
1669: case CMPCI_FM_VOL:
1670: case CMPCI_CD_VOL:
1671: case CMPCI_LINE_IN_VOL:
1672: case CMPCI_AUX_IN_VOL:
1673: case CMPCI_MASTER_VOL:
1674: switch (cp->un.value.num_channels) {
1675: case 1:
1676: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1677: sc->sc_gain[cp->dev][CMPCI_LEFT];
1678: break;
1679: case 2:
1680: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1681: sc->sc_gain[cp->dev][CMPCI_LEFT];
1682: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1683: sc->sc_gain[cp->dev][CMPCI_RIGHT];
1684: break;
1685: default:
1686: return EINVAL;
1687: }
1688: break;
1689:
1690: case CMPCI_RECORD_SOURCE:
1691: cp->un.mask = sc->sc_in_mask;
1692: break;
1693:
1694: case CMPCI_DAC_MUTE:
1695: case CMPCI_FM_MUTE:
1696: case CMPCI_CD_MUTE:
1697: case CMPCI_LINE_IN_MUTE:
1698: case CMPCI_AUX_IN_MUTE:
1699: case CMPCI_MIC_MUTE:
1700: case CMPCI_MIC_PREAMP:
1701: case CMPCI_PLAYBACK_MODE:
1702: case CMPCI_SPDIF_IN_SELECT:
1703: case CMPCI_SPDIF_IN_PHASE:
1704: case CMPCI_SPDIF_LOOP:
1705: case CMPCI_SPDIF_OUT_PLAYBACK:
1706: case CMPCI_SPDIF_OUT_VOLTAGE:
1707: case CMPCI_MONITOR_DAC:
1708: case CMPCI_REAR:
1709: case CMPCI_INDIVIDUAL:
1710: case CMPCI_REVERSE:
1711: case CMPCI_SURROUND:
1712: cp->un.ord = sc->sc_gain[cp->dev][CMPCI_LR];
1713: break;
1714:
1715: default:
1716: return EINVAL;
1717: }
1718:
1719: return 0;
1720: }
1721:
1722: /* ARGSUSED */
1723: size_t
1724: cmpci_round_buffersize(void *handle, int direction, size_t bufsize)
1725: {
1726: if (bufsize > 0x10000)
1727: bufsize = 0x10000;
1728:
1729: return bufsize;
1730: }
1731:
1732: paddr_t
1733: cmpci_mappage(void *handle, void *addr, off_t offset, int prot)
1734: {
1735: struct cmpci_softc *sc = handle;
1736: struct cmpci_dmanode *p;
1737:
1738: if (offset < 0 || NULL == (p = cmpci_find_dmamem(sc, addr)))
1739: return -1;
1740:
1741: return bus_dmamem_mmap(p->cd_tag, p->cd_segs,
1742: sizeof(p->cd_segs)/sizeof(p->cd_segs[0]),
1743: offset, prot, BUS_DMA_WAITOK);
1744: }
1745:
1746: /* ARGSUSED */
1747: int
1748: cmpci_get_props(void *handle)
1749: {
1750: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1751: }
1752:
1753: int
1754: cmpci_trigger_output(void *handle, void *start, void *end, int blksize,
1755: void (*intr)(void *), void *arg, struct audio_params *param)
1756: {
1757: struct cmpci_softc *sc = handle;
1758: struct cmpci_dmanode *p;
1759: int bps;
1760:
1761: sc->sc_play.intr = intr;
1762: sc->sc_play.intr_arg = arg;
1763: bps = param->channels * param->precision * param->factor / 8;
1764: if (!bps)
1765: return EINVAL;
1766:
1767: /* set DMA frame */
1768: if (!(p = cmpci_find_dmamem(sc, start)))
1769: return EINVAL;
1770: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BASE,
1771: DMAADDR(p));
1772: delay(10);
1773: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BYTES,
1774: ((caddr_t)end - (caddr_t)start + 1) / bps - 1);
1775: delay(10);
1776:
1777: /* set interrupt count */
1778: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_SAMPLES,
1779: (blksize + bps - 1) / bps - 1);
1780: delay(10);
1781:
1782: /* start DMA */
1783: cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); /* PLAY */
1784: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
1785: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
1786:
1787: return 0;
1788: }
1789:
1790: int
1791: cmpci_trigger_input(void *handle, void *start, void *end, int blksize,
1792: void (*intr)(void *), void *arg, struct audio_params *param)
1793: {
1794: struct cmpci_softc *sc = handle;
1795: struct cmpci_dmanode *p;
1796: int bps;
1797:
1798: sc->sc_rec.intr = intr;
1799: sc->sc_rec.intr_arg = arg;
1800: bps = param->channels*param->precision*param->factor/8;
1801: if (!bps)
1802: return EINVAL;
1803:
1804: /* set DMA frame */
1805: if (!(p = cmpci_find_dmamem(sc, start)))
1806: return EINVAL;
1807: bus_space_write_4(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BASE,
1808: DMAADDR(p));
1809: delay(10);
1810: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BYTES,
1811: ((caddr_t)end - (caddr_t)start + 1) / bps - 1);
1812: delay(10);
1813:
1814: /* set interrupt count */
1815: bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_SAMPLES,
1816: (blksize + bps - 1) / bps - 1);
1817: delay(10);
1818:
1819: /* start DMA */
1820: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); /* REC */
1821: cmpci_reg_set_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
1822: cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE);
1823:
1824: return 0;
1825: }
1826:
1827: /* end of file */
CVSweb