1 /* $OpenBSD: cs4231.c,v 1.44 2022/10/26 20:19:09 kn Exp $ */
2
3 /*
4 * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
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 ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Effort sponsored in part by the Defense Advanced Research Projects
29 * Agency (DARPA) and Air Force Research Laboratory, Air Force
30 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31 *
32 */
33
34 /*
35 * Driver for CS4231 based audio found in some sun4m systems (cs4231)
36 * based on ideas from the S/Linux project and the NetBSD project.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/device.h>
44 #include <sys/proc.h>
45 #include <sys/malloc.h>
46
47 #include <machine/bus.h>
48 #include <machine/intr.h>
49 #include <machine/autoconf.h>
50
51 #include <sys/audioio.h>
52 #include <dev/audio_if.h>
53
54 #include <dev/ic/ad1848reg.h>
55 #include <dev/ic/cs4231reg.h>
56 #include <dev/ic/apcdmareg.h>
57 #include <dev/sbus/sbusvar.h>
58 #include <dev/sbus/cs4231var.h>
59
60 #define CSAUDIO_DAC_LVL 0
61 #define CSAUDIO_LINE_IN_LVL 1
62 #define CSAUDIO_MIC_LVL 2
63 #define CSAUDIO_CD_LVL 3
64 #define CSAUDIO_MONITOR_LVL 4
65 #define CSAUDIO_OUTPUT_LVL 5
66 #define CSAUDIO_LINE_IN_MUTE 6
67 #define CSAUDIO_DAC_MUTE 7
68 #define CSAUDIO_CD_MUTE 8
69 #define CSAUDIO_MIC_MUTE 9
70 #define CSAUDIO_MONITOR_MUTE 10
71 #define CSAUDIO_OUTPUT_MUTE 11
72 #define CSAUDIO_REC_LVL 12
73 #define CSAUDIO_RECORD_SOURCE 13
74 #define CSAUDIO_OUTPUT 14
75 #define CSAUDIO_INPUT_CLASS 15
76 #define CSAUDIO_OUTPUT_CLASS 16
77 #define CSAUDIO_RECORD_CLASS 17
78 #define CSAUDIO_MONITOR_CLASS 18
79
80 #define CSPORT_AUX2 0
81 #define CSPORT_AUX1 1
82 #define CSPORT_DAC 2
83 #define CSPORT_LINEIN 3
84 #define CSPORT_MONO 4
85 #define CSPORT_MONITOR 5
86 #define CSPORT_SPEAKER 6
87 #define CSPORT_LINEOUT 7
88 #define CSPORT_HEADPHONE 8
89 #define CSPORT_MICROPHONE 9
90
91 #define MIC_IN_PORT 0
92 #define LINE_IN_PORT 1
93 #define AUX1_IN_PORT 2
94 #define DAC_IN_PORT 3
95
96 #ifdef AUDIO_DEBUG
97 #define DPRINTF(x) printf x
98 #else
99 #define DPRINTF(x)
100 #endif
101
102 #define CS_TIMEOUT 90000
103
104 #define CS_PC_LINEMUTE XCTL0_ENABLE
105 #define CS_PC_HDPHMUTE XCTL1_ENABLE
106 #define CS_AFS_TI 0x40 /* timer interrupt */
107 #define CS_AFS_CI 0x20 /* capture interrupt */
108 #define CS_AFS_PI 0x10 /* playback interrupt */
109 #define CS_AFS_CU 0x08 /* capture underrun */
110 #define CS_AFS_CO 0x04 /* capture overrun */
111 #define CS_AFS_PO 0x02 /* playback overrun */
112 #define CS_AFS_PU 0x01 /* playback underrun */
113
114 #define CS_WRITE(sc,r,v) \
115 bus_space_write_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2, (v))
116 #define CS_READ(sc,r) \
117 bus_space_read_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2)
118
119 #define APC_WRITE(sc,r,v) \
120 bus_space_write_4(sc->sc_bustag, sc->sc_regs, r, v)
121 #define APC_READ(sc,r) \
122 bus_space_read_4(sc->sc_bustag, sc->sc_regs, r)
123
124 int cs4231_match(struct device *, void *, void *);
125 void cs4231_attach(struct device *, struct device *, void *);
126 int cs4231_intr(void *);
127
128 int cs4231_set_speed(struct cs4231_softc *, u_long *);
129 void cs4231_setup_output(struct cs4231_softc *sc);
130
131 void cs4231_write(struct cs4231_softc *, u_int8_t, u_int8_t);
132 u_int8_t cs4231_read(struct cs4231_softc *, u_int8_t);
133
134 /* Audio interface */
135 int cs4231_open(void *, int);
136 void cs4231_close(void *);
137 int cs4231_set_params(void *, int, int, struct audio_params *,
138 struct audio_params *);
139 int cs4231_round_blocksize(void *, int);
140 int cs4231_commit_settings(void *);
141 int cs4231_halt_output(void *);
142 int cs4231_halt_input(void *);
143 int cs4231_set_port(void *, mixer_ctrl_t *);
144 int cs4231_get_port(void *, mixer_ctrl_t *);
145 int cs4231_query_devinfo(void *, mixer_devinfo_t *);
146 void * cs4231_alloc(void *, int, size_t, int, int);
147 void cs4231_free(void *, void *, int);
148 int cs4231_trigger_output(void *, void *, void *, int,
149 void (*)(void *), void *, struct audio_params *);
150 int cs4231_trigger_input(void *, void *, void *, int,
151 void (*)(void *), void *, struct audio_params *);
152
153 const struct audio_hw_if cs4231_sa_hw_if = {
154 .open = cs4231_open,
155 .close = cs4231_close,
156 .set_params = cs4231_set_params,
157 .round_blocksize = cs4231_round_blocksize,
158 .commit_settings = cs4231_commit_settings,
159 .halt_output = cs4231_halt_output,
160 .halt_input = cs4231_halt_input,
161 .set_port = cs4231_set_port,
162 .get_port = cs4231_get_port,
163 .query_devinfo = cs4231_query_devinfo,
164 .allocm = cs4231_alloc,
165 .freem = cs4231_free,
166 .trigger_output = cs4231_trigger_output,
167 .trigger_input = cs4231_trigger_input,
168 };
169
170 const struct cfattach audiocs_ca = {
171 sizeof (struct cs4231_softc), cs4231_match, cs4231_attach
172 };
173
174 struct cfdriver audiocs_cd = {
175 NULL, "audiocs", DV_DULL
176 };
177
178 int
cs4231_match(struct device * parent,void * vcf,void * aux)179 cs4231_match(struct device *parent, void *vcf, void *aux)
180 {
181 struct sbus_attach_args *sa = aux;
182
183 return (strcmp("SUNW,CS4231", sa->sa_name) == 0);
184 }
185
186 void
cs4231_attach(struct device * parent,struct device * self,void * aux)187 cs4231_attach(struct device *parent, struct device *self, void *aux)
188 {
189 struct sbus_attach_args *sa = aux;
190 struct cs4231_softc *sc = (struct cs4231_softc *)self;
191 int node;
192 u_int32_t sbusburst, burst;
193
194 node = sa->sa_node;
195
196 /* Pass on the bus tags */
197 sc->sc_bustag = sa->sa_bustag;
198 sc->sc_dmatag = sa->sa_dmatag;
199
200 /* Make sure things are sane. */
201 if (sa->sa_nintr != 1) {
202 printf(": expected 1 interrupt, got %d\n", sa->sa_nintr);
203 return;
204 }
205 if (sa->sa_nreg != 1) {
206 printf(": expected 1 register set, got %d\n",
207 sa->sa_nreg);
208 return;
209 }
210
211 if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_AUDIO, 0,
212 cs4231_intr, sc, self->dv_xname) == NULL) {
213 printf(": couldn't establish interrupt, pri %d\n",
214 INTLEV(sa->sa_pri));
215 return;
216 }
217
218 if (sbus_bus_map(sa->sa_bustag,
219 sa->sa_reg[0].sbr_slot,
220 (bus_addr_t)sa->sa_reg[0].sbr_offset,
221 (bus_size_t)sa->sa_reg[0].sbr_size,
222 BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regs) != 0) {
223 printf(": couldn't map registers\n");
224 return;
225 }
226
227 sbusburst = ((struct sbus_softc *)parent)->sc_burst;
228 if (sbusburst == 0)
229 sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
230 burst = getpropint(node, "burst-sizes", -1);
231 if (burst == -1)
232 burst = sbusburst;
233 sc->sc_burst = burst & sbusburst;
234
235 printf("\n");
236
237 audio_attach_mi(&cs4231_sa_hw_if, sc, NULL, &sc->sc_dev);
238
239 /* Default to speaker, unmuted, reasonable volume */
240 sc->sc_out_port = CSPORT_SPEAKER;
241 sc->sc_in_port = CSPORT_MICROPHONE;
242 sc->sc_mute[CSPORT_SPEAKER] = 1;
243 sc->sc_mute[CSPORT_MONITOR] = 1;
244 sc->sc_volume[CSPORT_SPEAKER].left = 192;
245 sc->sc_volume[CSPORT_SPEAKER].right = 192;
246 }
247
248 /*
249 * Write to one of the indexed registers of cs4231.
250 */
251 void
cs4231_write(struct cs4231_softc * sc,u_int8_t r,u_int8_t v)252 cs4231_write(struct cs4231_softc *sc, u_int8_t r, u_int8_t v)
253 {
254 CS_WRITE(sc, AD1848_IADDR, r);
255 CS_WRITE(sc, AD1848_IDATA, v);
256 }
257
258 /*
259 * Read from one of the indexed registers of cs4231.
260 */
261 u_int8_t
cs4231_read(struct cs4231_softc * sc,u_int8_t r)262 cs4231_read(struct cs4231_softc *sc, u_int8_t r)
263 {
264 CS_WRITE(sc, AD1848_IADDR, r);
265 return (CS_READ(sc, AD1848_IDATA));
266 }
267
268 int
cs4231_set_speed(struct cs4231_softc * sc,u_long * argp)269 cs4231_set_speed(struct cs4231_softc *sc, u_long *argp)
270 {
271 /*
272 * The available speeds are in the following table. Keep the speeds in
273 * the increasing order.
274 */
275 typedef struct {
276 int speed;
277 u_char bits;
278 } speed_struct;
279 u_long arg = *argp;
280
281 static const speed_struct speed_table[] = {
282 {5510, (0 << 1) | CLOCK_XTAL2},
283 {5510, (0 << 1) | CLOCK_XTAL2},
284 {6620, (7 << 1) | CLOCK_XTAL2},
285 {8000, (0 << 1) | CLOCK_XTAL1},
286 {9600, (7 << 1) | CLOCK_XTAL1},
287 {11025, (1 << 1) | CLOCK_XTAL2},
288 {16000, (1 << 1) | CLOCK_XTAL1},
289 {18900, (2 << 1) | CLOCK_XTAL2},
290 {22050, (3 << 1) | CLOCK_XTAL2},
291 {27420, (2 << 1) | CLOCK_XTAL1},
292 {32000, (3 << 1) | CLOCK_XTAL1},
293 {33075, (6 << 1) | CLOCK_XTAL2},
294 {33075, (4 << 1) | CLOCK_XTAL2},
295 {44100, (5 << 1) | CLOCK_XTAL2},
296 {48000, (6 << 1) | CLOCK_XTAL1},
297 };
298
299 int i, n, selected = -1;
300
301 n = sizeof(speed_table) / sizeof(speed_struct);
302
303 if (arg < speed_table[0].speed)
304 selected = 0;
305 if (arg > speed_table[n - 1].speed)
306 selected = n - 1;
307
308 for (i = 1; selected == -1 && i < n; i++) {
309 if (speed_table[i].speed == arg)
310 selected = i;
311 else if (speed_table[i].speed > arg) {
312 int diff1, diff2;
313
314 diff1 = arg - speed_table[i - 1].speed;
315 diff2 = speed_table[i].speed - arg;
316 if (diff1 < diff2)
317 selected = i - 1;
318 else
319 selected = i;
320 }
321 }
322
323 if (selected == -1)
324 selected = 3;
325
326 sc->sc_speed_bits = speed_table[selected].bits;
327 sc->sc_need_commit = 1;
328 *argp = speed_table[selected].speed;
329
330 return (0);
331 }
332
333 /*
334 * Audio interface functions
335 */
336 int
cs4231_open(void * vsc,int flags)337 cs4231_open(void *vsc, int flags)
338 {
339 struct cs4231_softc *sc = vsc;
340 int tries;
341
342 if (sc->sc_open)
343 return (EBUSY);
344 sc->sc_open = 1;
345
346 sc->sc_capture.cs_intr = NULL;
347 sc->sc_capture.cs_arg = NULL;
348 sc->sc_capture.cs_locked = 0;
349
350 sc->sc_playback.cs_intr = NULL;
351 sc->sc_playback.cs_arg = NULL;
352 sc->sc_playback.cs_locked = 0;
353
354 APC_WRITE(sc, APC_CSR, APC_CSR_RESET);
355 DELAY(10);
356 APC_WRITE(sc, APC_CSR, 0);
357 DELAY(10);
358 APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) | APC_CSR_CODEC_RESET);
359
360 DELAY(20);
361
362 APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & (~APC_CSR_CODEC_RESET));
363
364 for (tries = CS_TIMEOUT;
365 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
366 DELAY(10);
367 if (tries == 0)
368 printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
369
370 /* Turn on cs4231 mode */
371 cs4231_write(sc, SP_MISC_INFO,
372 cs4231_read(sc, SP_MISC_INFO) | MODE2);
373
374 cs4231_setup_output(sc);
375
376 cs4231_write(sc, SP_PIN_CONTROL,
377 cs4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
378
379 return (0);
380 }
381
382 void
cs4231_setup_output(struct cs4231_softc * sc)383 cs4231_setup_output(struct cs4231_softc *sc)
384 {
385 u_int8_t pc, mi, rm, lm;
386
387 pc = cs4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
388
389 mi = cs4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
390
391 lm = cs4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
392 lm &= ~OUTPUT_ATTEN_BITS;
393 lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
394 OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
395
396 rm = cs4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
397 rm &= ~OUTPUT_ATTEN_BITS;
398 rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
399 OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
400
401 if (sc->sc_mute[CSPORT_MONITOR]) {
402 lm &= ~OUTPUT_MUTE;
403 rm &= ~OUTPUT_MUTE;
404 }
405
406 switch (sc->sc_out_port) {
407 case CSPORT_HEADPHONE:
408 if (sc->sc_mute[CSPORT_SPEAKER])
409 pc &= ~CS_PC_HDPHMUTE;
410 break;
411 case CSPORT_SPEAKER:
412 if (sc->sc_mute[CSPORT_SPEAKER])
413 mi &= ~MONO_OUTPUT_MUTE;
414 break;
415 case CSPORT_LINEOUT:
416 if (sc->sc_mute[CSPORT_SPEAKER])
417 pc &= ~CS_PC_LINEMUTE;
418 break;
419 }
420
421 cs4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
422 cs4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
423 cs4231_write(sc, SP_PIN_CONTROL, pc);
424 cs4231_write(sc, CS_MONO_IO_CONTROL, mi);
425
426 /* XXX doesn't really belong here... */
427 switch (sc->sc_in_port) {
428 case CSPORT_LINEIN:
429 pc = LINE_INPUT;
430 break;
431 case CSPORT_AUX1:
432 pc = AUX_INPUT;
433 break;
434 case CSPORT_DAC:
435 pc = MIXED_DAC_INPUT;
436 break;
437 case CSPORT_MICROPHONE:
438 default:
439 pc = MIC_INPUT;
440 break;
441 }
442 lm = cs4231_read(sc, SP_LEFT_INPUT_CONTROL);
443 rm = cs4231_read(sc, SP_RIGHT_INPUT_CONTROL);
444 lm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
445 rm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
446 lm |= pc | (sc->sc_adc.left >> 4);
447 rm |= pc | (sc->sc_adc.right >> 4);
448 cs4231_write(sc, SP_LEFT_INPUT_CONTROL, lm);
449 cs4231_write(sc, SP_RIGHT_INPUT_CONTROL, rm);
450 }
451
452 void
cs4231_close(void * vsc)453 cs4231_close(void *vsc)
454 {
455 struct cs4231_softc *sc = vsc;
456
457 cs4231_halt_input(sc);
458 cs4231_halt_output(sc);
459 cs4231_write(sc, SP_PIN_CONTROL,
460 cs4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
461 sc->sc_open = 0;
462 }
463
464 int
cs4231_set_params(void * vsc,int setmode,int usemode,struct audio_params * p,struct audio_params * r)465 cs4231_set_params(void *vsc, int setmode, int usemode,
466 struct audio_params *p, struct audio_params *r)
467 {
468 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
469 int err, bits, enc = p->encoding;
470
471 switch (enc) {
472 case AUDIO_ENCODING_ULAW:
473 if (p->precision != 8)
474 return (EINVAL);
475 bits = FMT_ULAW >> 5;
476 break;
477 case AUDIO_ENCODING_ALAW:
478 if (p->precision != 8)
479 return (EINVAL);
480 bits = FMT_ALAW >> 5;
481 break;
482 case AUDIO_ENCODING_SLINEAR_LE:
483 if (p->precision == 16)
484 bits = FMT_TWOS_COMP >> 5;
485 else
486 return (EINVAL);
487 break;
488 case AUDIO_ENCODING_SLINEAR_BE:
489 if (p->precision == 16)
490 bits = FMT_TWOS_COMP_BE >> 5;
491 else
492 return (EINVAL);
493 break;
494 case AUDIO_ENCODING_ULINEAR_LE:
495 case AUDIO_ENCODING_ULINEAR_BE:
496 if (p->precision == 8)
497 bits = FMT_PCM8 >> 5;
498 else
499 return (EINVAL);
500 break;
501 default:
502 return (EINVAL);
503 }
504
505 if (p->channels != 1 && p->channels != 2)
506 return (EINVAL);
507
508 err = cs4231_set_speed(sc, &p->sample_rate);
509 if (err)
510 return (err);
511
512 p->bps = AUDIO_BPS(p->precision);
513 r->bps = AUDIO_BPS(r->precision);
514 p->msb = r->msb = 1;
515
516 sc->sc_format_bits = bits;
517 sc->sc_channels = p->channels;
518 sc->sc_precision = p->precision;
519 sc->sc_need_commit = 1;
520 return (0);
521 }
522
523 int
cs4231_round_blocksize(void * vsc,int blk)524 cs4231_round_blocksize(void *vsc, int blk)
525 {
526 return ((blk + 3) & (-4));
527 }
528
529 int
cs4231_commit_settings(void * vsc)530 cs4231_commit_settings(void *vsc)
531 {
532 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
533 int tries;
534 u_int8_t r, fs;
535
536 if (sc->sc_need_commit == 0)
537 return (0);
538
539 fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
540 if (sc->sc_channels == 2)
541 fs |= FMT_STEREO;
542
543 /* XXX: this is called before DMA is setup, useful ? */
544 mtx_enter(&audio_lock);
545
546 r = cs4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
547 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
548 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
549 CS_WRITE(sc, AD1848_IDATA, r);
550
551 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
552 CS_WRITE(sc, AD1848_IDATA, fs);
553 CS_READ(sc, AD1848_IDATA);
554 CS_READ(sc, AD1848_IDATA);
555 tries = CS_TIMEOUT;
556 for (tries = CS_TIMEOUT;
557 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
558 DELAY(10);
559 if (tries == 0)
560 printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
561
562 CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
563 CS_WRITE(sc, AD1848_IDATA, fs);
564 CS_READ(sc, AD1848_IDATA);
565 CS_READ(sc, AD1848_IDATA);
566 for (tries = CS_TIMEOUT;
567 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
568 DELAY(10);
569 if (tries == 0)
570 printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
571
572 CS_WRITE(sc, AD1848_IADDR, 0);
573 for (tries = CS_TIMEOUT;
574 tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
575 DELAY(10);
576 if (tries == 0)
577 printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
578
579 CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
580 for (tries = CS_TIMEOUT;
581 tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
582 DELAY(10);
583 if (tries == 0)
584 printf("%s: timeout waiting for autocalibration\n",
585 sc->sc_dev.dv_xname);
586
587 mtx_leave(&audio_lock);
588
589 sc->sc_need_commit = 0;
590 return (0);
591 }
592
593 int
cs4231_halt_output(void * vsc)594 cs4231_halt_output(void *vsc)
595 {
596 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
597
598 /* XXX Kills some capture bits */
599 mtx_enter(&audio_lock);
600 APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) &
601 ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE |
602 APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE));
603 cs4231_write(sc, SP_INTERFACE_CONFIG,
604 cs4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
605 sc->sc_playback.cs_locked = 0;
606 mtx_leave(&audio_lock);
607 return (0);
608 }
609
610 int
cs4231_halt_input(void * vsc)611 cs4231_halt_input(void *vsc)
612 {
613 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
614
615 /* XXX Kills some playback bits */
616 mtx_enter(&audio_lock);
617 APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE);
618 cs4231_write(sc, SP_INTERFACE_CONFIG,
619 cs4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
620 sc->sc_capture.cs_locked = 0;
621 mtx_leave(&audio_lock);
622 return (0);
623 }
624
625 int
cs4231_set_port(void * vsc,mixer_ctrl_t * cp)626 cs4231_set_port(void *vsc, mixer_ctrl_t *cp)
627 {
628 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
629 int error = EINVAL;
630
631 DPRINTF(("cs4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
632
633 switch (cp->dev) {
634 case CSAUDIO_DAC_LVL:
635 if (cp->type != AUDIO_MIXER_VALUE)
636 break;
637 if (cp->un.value.num_channels == 1)
638 cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
639 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
640 LINE_INPUT_ATTEN_BITS);
641 else if (cp->un.value.num_channels == 2) {
642 cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
643 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
644 LINE_INPUT_ATTEN_BITS);
645 cs4231_write(sc, SP_RIGHT_AUX1_CONTROL,
646 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
647 LINE_INPUT_ATTEN_BITS);
648 } else
649 break;
650 error = 0;
651 break;
652 case CSAUDIO_LINE_IN_LVL:
653 if (cp->type != AUDIO_MIXER_VALUE)
654 break;
655 if (cp->un.value.num_channels == 1)
656 cs4231_write(sc, CS_LEFT_LINE_CONTROL,
657 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
658 AUX_INPUT_ATTEN_BITS);
659 else if (cp->un.value.num_channels == 2) {
660 cs4231_write(sc, CS_LEFT_LINE_CONTROL,
661 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
662 AUX_INPUT_ATTEN_BITS);
663 cs4231_write(sc, CS_RIGHT_LINE_CONTROL,
664 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
665 AUX_INPUT_ATTEN_BITS);
666 } else
667 break;
668 error = 0;
669 break;
670 case CSAUDIO_MIC_LVL:
671 if (cp->type != AUDIO_MIXER_VALUE)
672 break;
673 if (cp->un.value.num_channels == 1) {
674 #if 0
675 cs4231_write(sc, CS_MONO_IO_CONTROL,
676 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
677 MONO_INPUT_ATTEN_BITS);
678 #endif
679 } else
680 break;
681 error = 0;
682 break;
683 case CSAUDIO_CD_LVL:
684 if (cp->type != AUDIO_MIXER_VALUE)
685 break;
686 if (cp->un.value.num_channels == 1) {
687 cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
688 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
689 LINE_INPUT_ATTEN_BITS);
690 } else if (cp->un.value.num_channels == 2) {
691 cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
692 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
693 LINE_INPUT_ATTEN_BITS);
694 cs4231_write(sc, SP_RIGHT_AUX2_CONTROL,
695 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
696 LINE_INPUT_ATTEN_BITS);
697 } else
698 break;
699 error = 0;
700 break;
701 case CSAUDIO_MONITOR_LVL:
702 if (cp->type != AUDIO_MIXER_VALUE)
703 break;
704 if (cp->un.value.num_channels == 1)
705 cs4231_write(sc, SP_DIGITAL_MIX,
706 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
707 else
708 break;
709 error = 0;
710 break;
711 case CSAUDIO_OUTPUT_LVL:
712 if (cp->type != AUDIO_MIXER_VALUE)
713 break;
714 if (cp->un.value.num_channels == 1) {
715 sc->sc_volume[CSPORT_SPEAKER].left =
716 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
717 sc->sc_volume[CSPORT_SPEAKER].right =
718 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
719 }
720 else if (cp->un.value.num_channels == 2) {
721 sc->sc_volume[CSPORT_SPEAKER].left =
722 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
723 sc->sc_volume[CSPORT_SPEAKER].right =
724 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
725 }
726 else
727 break;
728
729 cs4231_setup_output(sc);
730 error = 0;
731 break;
732 case CSAUDIO_OUTPUT:
733 if (cp->type != AUDIO_MIXER_ENUM)
734 break;
735 if (cp->un.ord != CSPORT_LINEOUT &&
736 cp->un.ord != CSPORT_SPEAKER &&
737 cp->un.ord != CSPORT_HEADPHONE)
738 return (EINVAL);
739 sc->sc_out_port = cp->un.ord;
740 cs4231_setup_output(sc);
741 error = 0;
742 break;
743 case CSAUDIO_LINE_IN_MUTE:
744 if (cp->type != AUDIO_MIXER_ENUM)
745 break;
746 sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
747 error = 0;
748 break;
749 case CSAUDIO_DAC_MUTE:
750 if (cp->type != AUDIO_MIXER_ENUM)
751 break;
752 sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
753 error = 0;
754 break;
755 case CSAUDIO_CD_MUTE:
756 if (cp->type != AUDIO_MIXER_ENUM)
757 break;
758 sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
759 error = 0;
760 break;
761 case CSAUDIO_MIC_MUTE:
762 if (cp->type != AUDIO_MIXER_ENUM)
763 break;
764 sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
765 error = 0;
766 break;
767 case CSAUDIO_MONITOR_MUTE:
768 if (cp->type != AUDIO_MIXER_ENUM)
769 break;
770 sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
771 error = 0;
772 break;
773 case CSAUDIO_OUTPUT_MUTE:
774 if (cp->type != AUDIO_MIXER_ENUM)
775 break;
776 sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
777 cs4231_setup_output(sc);
778 error = 0;
779 break;
780 case CSAUDIO_REC_LVL:
781 if (cp->type != AUDIO_MIXER_VALUE)
782 break;
783 if (cp->un.value.num_channels == 1) {
784 sc->sc_adc.left =
785 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
786 sc->sc_adc.right =
787 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
788 } else if (cp->un.value.num_channels == 2) {
789 sc->sc_adc.left =
790 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
791 sc->sc_adc.right =
792 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
793 } else
794 break;
795 cs4231_setup_output(sc);
796 error = 0;
797 break;
798 case CSAUDIO_RECORD_SOURCE:
799 if (cp->type != AUDIO_MIXER_ENUM)
800 break;
801 if (cp->un.ord == CSPORT_MICROPHONE ||
802 cp->un.ord == CSPORT_LINEIN ||
803 cp->un.ord == CSPORT_AUX1 ||
804 cp->un.ord == CSPORT_DAC) {
805 sc->sc_in_port = cp->un.ord;
806 error = 0;
807 cs4231_setup_output(sc);
808 }
809 break;
810 }
811
812 return (error);
813 }
814
815 int
cs4231_get_port(void * vsc,mixer_ctrl_t * cp)816 cs4231_get_port(void *vsc, mixer_ctrl_t *cp)
817 {
818 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
819 int error = EINVAL;
820
821 DPRINTF(("cs4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
822
823 switch (cp->dev) {
824 case CSAUDIO_DAC_LVL:
825 if (cp->type != AUDIO_MIXER_VALUE)
826 break;
827 if (cp->un.value.num_channels == 1)
828 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
829 cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
830 LINE_INPUT_ATTEN_BITS;
831 else if (cp->un.value.num_channels == 2) {
832 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
833 cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
834 LINE_INPUT_ATTEN_BITS;
835 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
836 cs4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
837 LINE_INPUT_ATTEN_BITS;
838 } else
839 break;
840 error = 0;
841 break;
842 case CSAUDIO_LINE_IN_LVL:
843 if (cp->type != AUDIO_MIXER_VALUE)
844 break;
845 if (cp->un.value.num_channels == 1)
846 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
847 cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
848 else if (cp->un.value.num_channels == 2) {
849 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
850 cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
851 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
852 cs4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
853 } else
854 break;
855 error = 0;
856 break;
857 case CSAUDIO_MIC_LVL:
858 if (cp->type != AUDIO_MIXER_VALUE)
859 break;
860 if (cp->un.value.num_channels == 1) {
861 #if 0
862 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
863 cs4231_read(sc, CS_MONO_IO_CONTROL) &
864 MONO_INPUT_ATTEN_BITS;
865 #endif
866 } else
867 break;
868 error = 0;
869 break;
870 case CSAUDIO_CD_LVL:
871 if (cp->type != AUDIO_MIXER_VALUE)
872 break;
873 if (cp->un.value.num_channels == 1)
874 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
875 cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
876 LINE_INPUT_ATTEN_BITS;
877 else if (cp->un.value.num_channels == 2) {
878 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
879 cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
880 LINE_INPUT_ATTEN_BITS;
881 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
882 cs4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
883 LINE_INPUT_ATTEN_BITS;
884 }
885 else
886 break;
887 error = 0;
888 break;
889 case CSAUDIO_MONITOR_LVL:
890 if (cp->type != AUDIO_MIXER_VALUE)
891 break;
892 if (cp->un.value.num_channels != 1)
893 break;
894 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
895 cs4231_read(sc, SP_DIGITAL_MIX) >> 2;
896 error = 0;
897 break;
898 case CSAUDIO_OUTPUT_LVL:
899 if (cp->type != AUDIO_MIXER_VALUE)
900 break;
901 if (cp->un.value.num_channels == 1)
902 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
903 sc->sc_volume[CSPORT_SPEAKER].left;
904 else if (cp->un.value.num_channels == 2) {
905 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
906 sc->sc_volume[CSPORT_SPEAKER].left;
907 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
908 sc->sc_volume[CSPORT_SPEAKER].right;
909 }
910 else
911 break;
912 error = 0;
913 break;
914 case CSAUDIO_LINE_IN_MUTE:
915 if (cp->type != AUDIO_MIXER_ENUM)
916 break;
917 cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
918 error = 0;
919 break;
920 case CSAUDIO_DAC_MUTE:
921 if (cp->type != AUDIO_MIXER_ENUM)
922 break;
923 cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
924 error = 0;
925 break;
926 case CSAUDIO_CD_MUTE:
927 if (cp->type != AUDIO_MIXER_ENUM)
928 break;
929 cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
930 error = 0;
931 break;
932 case CSAUDIO_MIC_MUTE:
933 if (cp->type != AUDIO_MIXER_ENUM)
934 break;
935 cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
936 error = 0;
937 break;
938 case CSAUDIO_MONITOR_MUTE:
939 if (cp->type != AUDIO_MIXER_ENUM)
940 break;
941 cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
942 error = 0;
943 break;
944 case CSAUDIO_OUTPUT_MUTE:
945 if (cp->type != AUDIO_MIXER_ENUM)
946 break;
947 cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
948 error = 0;
949 break;
950 case CSAUDIO_REC_LVL:
951 if (cp->type != AUDIO_MIXER_VALUE)
952 break;
953 if (cp->un.value.num_channels == 1) {
954 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
955 sc->sc_adc.left;
956 } else if (cp->un.value.num_channels == 2) {
957 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
958 sc->sc_adc.left;
959 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
960 sc->sc_adc.right;
961 } else
962 break;
963 error = 0;
964 break;
965 case CSAUDIO_RECORD_SOURCE:
966 if (cp->type != AUDIO_MIXER_ENUM)
967 break;
968 cp->un.ord = sc->sc_in_port;
969 error = 0;
970 break;
971 case CSAUDIO_OUTPUT:
972 if (cp->type != AUDIO_MIXER_ENUM)
973 break;
974 cp->un.ord = sc->sc_out_port;
975 error = 0;
976 break;
977 }
978 return (error);
979 }
980
981 int
cs4231_query_devinfo(void * vsc,mixer_devinfo_t * dip)982 cs4231_query_devinfo(void *vsc, mixer_devinfo_t *dip)
983 {
984 int err = 0;
985
986 switch (dip->index) {
987 case CSAUDIO_MIC_LVL: /* mono/microphone mixer */
988 dip->type = AUDIO_MIXER_VALUE;
989 dip->mixer_class = CSAUDIO_INPUT_CLASS;
990 dip->prev = AUDIO_MIXER_LAST;
991 dip->next = CSAUDIO_MIC_MUTE;
992 strlcpy(dip->label.name, AudioNmicrophone,
993 sizeof dip->label.name);
994 dip->un.v.num_channels = 1;
995 strlcpy(dip->un.v.units.name, AudioNvolume,
996 sizeof dip->un.v.units.name);
997 break;
998 case CSAUDIO_DAC_LVL: /* dacout */
999 dip->type = AUDIO_MIXER_VALUE;
1000 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1001 dip->prev = AUDIO_MIXER_LAST;
1002 dip->next = CSAUDIO_DAC_MUTE;
1003 strlcpy(dip->label.name, AudioNdac,
1004 sizeof dip->label.name);
1005 dip->un.v.num_channels = 2;
1006 strlcpy(dip->un.v.units.name, AudioNvolume,
1007 sizeof dip->un.v.units.name);
1008 break;
1009 case CSAUDIO_LINE_IN_LVL: /* line */
1010 dip->type = AUDIO_MIXER_VALUE;
1011 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1012 dip->prev = AUDIO_MIXER_LAST;
1013 dip->next = CSAUDIO_LINE_IN_MUTE;
1014 strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
1015 dip->un.v.num_channels = 2;
1016 strlcpy(dip->un.v.units.name, AudioNvolume,
1017 sizeof dip->un.v.units.name);
1018 break;
1019 case CSAUDIO_CD_LVL: /* cd */
1020 dip->type = AUDIO_MIXER_VALUE;
1021 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1022 dip->prev = AUDIO_MIXER_LAST;
1023 dip->next = CSAUDIO_CD_MUTE;
1024 strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
1025 dip->un.v.num_channels = 2;
1026 strlcpy(dip->un.v.units.name, AudioNvolume,
1027 sizeof dip->un.v.units.name);
1028 break;
1029 case CSAUDIO_MONITOR_LVL: /* monitor level */
1030 dip->type = AUDIO_MIXER_VALUE;
1031 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1032 dip->prev = AUDIO_MIXER_LAST;
1033 dip->next = CSAUDIO_MONITOR_MUTE;
1034 strlcpy(dip->label.name, AudioNmonitor,
1035 sizeof dip->label.name);
1036 dip->un.v.num_channels = 1;
1037 strlcpy(dip->un.v.units.name, AudioNvolume,
1038 sizeof dip->un.v.units.name);
1039 break;
1040 case CSAUDIO_OUTPUT_LVL:
1041 dip->type = AUDIO_MIXER_VALUE;
1042 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1043 dip->prev = AUDIO_MIXER_LAST;
1044 dip->next = CSAUDIO_OUTPUT_MUTE;
1045 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1046 dip->un.v.num_channels = 2;
1047 strlcpy(dip->un.v.units.name, AudioNvolume,
1048 sizeof dip->un.v.units.name);
1049 break;
1050 case CSAUDIO_LINE_IN_MUTE:
1051 dip->type = AUDIO_MIXER_ENUM;
1052 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1053 dip->prev = CSAUDIO_LINE_IN_LVL;
1054 dip->next = AUDIO_MIXER_LAST;
1055 goto mute;
1056 case CSAUDIO_DAC_MUTE:
1057 dip->type = AUDIO_MIXER_ENUM;
1058 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1059 dip->prev = CSAUDIO_DAC_LVL;
1060 dip->next = AUDIO_MIXER_LAST;
1061 goto mute;
1062 case CSAUDIO_CD_MUTE:
1063 dip->type = AUDIO_MIXER_ENUM;
1064 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1065 dip->prev = CSAUDIO_CD_LVL;
1066 dip->next = AUDIO_MIXER_LAST;
1067 goto mute;
1068 case CSAUDIO_MIC_MUTE:
1069 dip->type = AUDIO_MIXER_ENUM;
1070 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1071 dip->prev = CSAUDIO_MIC_LVL;
1072 dip->next = AUDIO_MIXER_LAST;
1073 goto mute;
1074 case CSAUDIO_MONITOR_MUTE:
1075 dip->type = AUDIO_MIXER_ENUM;
1076 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1077 dip->prev = CSAUDIO_MONITOR_LVL;
1078 dip->next = AUDIO_MIXER_LAST;
1079 goto mute;
1080 case CSAUDIO_OUTPUT_MUTE:
1081 dip->type = AUDIO_MIXER_ENUM;
1082 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1083 dip->prev = CSAUDIO_OUTPUT_LVL;
1084 dip->next = AUDIO_MIXER_LAST;
1085 goto mute;
1086
1087 mute:
1088 strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
1089 dip->un.e.num_mem = 2;
1090 strlcpy(dip->un.e.member[0].label.name, AudioNon,
1091 sizeof dip->un.e.member[0].label.name);
1092 dip->un.e.member[0].ord = 0;
1093 strlcpy(dip->un.e.member[1].label.name, AudioNoff,
1094 sizeof dip->un.e.member[1].label.name);
1095 dip->un.e.member[1].ord = 1;
1096 break;
1097 case CSAUDIO_REC_LVL: /* record level */
1098 dip->type = AUDIO_MIXER_VALUE;
1099 dip->mixer_class = CSAUDIO_RECORD_CLASS;
1100 dip->prev = AUDIO_MIXER_LAST;
1101 dip->next = CSAUDIO_RECORD_SOURCE;
1102 strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
1103 dip->un.v.num_channels = 2;
1104 strlcpy(dip->un.v.units.name, AudioNvolume,
1105 sizeof dip->un.v.units.name);
1106 break;
1107 case CSAUDIO_RECORD_SOURCE:
1108 dip->type = AUDIO_MIXER_ENUM;
1109 dip->mixer_class = CSAUDIO_RECORD_CLASS;
1110 dip->prev = CSAUDIO_REC_LVL;
1111 dip->next = AUDIO_MIXER_LAST;
1112 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1113 dip->un.e.num_mem = 4;
1114 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
1115 sizeof dip->un.e.member[0].label.name);
1116 dip->un.e.member[0].ord = CSPORT_MICROPHONE;
1117 strlcpy(dip->un.e.member[1].label.name, AudioNline,
1118 sizeof dip->un.e.member[1].label.name);
1119 dip->un.e.member[1].ord = CSPORT_LINEIN;
1120 strlcpy(dip->un.e.member[2].label.name, AudioNcd,
1121 sizeof dip->un.e.member[2].label.name);
1122 dip->un.e.member[2].ord = CSPORT_AUX1;
1123 strlcpy(dip->un.e.member[3].label.name, AudioNdac,
1124 sizeof dip->un.e.member[3].label.name);
1125 dip->un.e.member[3].ord = CSPORT_DAC;
1126 break;
1127 case CSAUDIO_OUTPUT:
1128 dip->type = AUDIO_MIXER_ENUM;
1129 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1130 dip->prev = dip->next = AUDIO_MIXER_LAST;
1131 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1132 dip->un.e.num_mem = 3;
1133 strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
1134 sizeof dip->un.e.member[0].label.name);
1135 dip->un.e.member[0].ord = CSPORT_SPEAKER;
1136 strlcpy(dip->un.e.member[1].label.name, AudioNline,
1137 sizeof dip->un.e.member[1].label.name);
1138 dip->un.e.member[1].ord = CSPORT_LINEOUT;
1139 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
1140 sizeof dip->un.e.member[2].label.name);
1141 dip->un.e.member[2].ord = CSPORT_HEADPHONE;
1142 break;
1143 case CSAUDIO_INPUT_CLASS: /* input class descriptor */
1144 dip->type = AUDIO_MIXER_CLASS;
1145 dip->mixer_class = CSAUDIO_INPUT_CLASS;
1146 dip->prev = AUDIO_MIXER_LAST;
1147 dip->next = AUDIO_MIXER_LAST;
1148 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1149 break;
1150 case CSAUDIO_OUTPUT_CLASS: /* output class descriptor */
1151 dip->type = AUDIO_MIXER_CLASS;
1152 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1153 dip->prev = AUDIO_MIXER_LAST;
1154 dip->next = AUDIO_MIXER_LAST;
1155 strlcpy(dip->label.name, AudioCoutputs,
1156 sizeof dip->label.name);
1157 break;
1158 case CSAUDIO_MONITOR_CLASS: /* monitor class descriptor */
1159 dip->type = AUDIO_MIXER_CLASS;
1160 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1161 dip->prev = AUDIO_MIXER_LAST;
1162 dip->next = AUDIO_MIXER_LAST;
1163 strlcpy(dip->label.name, AudioCmonitor,
1164 sizeof dip->label.name);
1165 break;
1166 case CSAUDIO_RECORD_CLASS: /* record class descriptor */
1167 dip->type = AUDIO_MIXER_CLASS;
1168 dip->mixer_class = CSAUDIO_RECORD_CLASS;
1169 dip->prev = AUDIO_MIXER_LAST;
1170 dip->next = AUDIO_MIXER_LAST;
1171 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1172 break;
1173 default:
1174 err = ENXIO;
1175 }
1176
1177 return (err);
1178 }
1179
1180 /*
1181 * Hardware interrupt handler
1182 */
1183 int
cs4231_intr(void * vsc)1184 cs4231_intr(void *vsc)
1185 {
1186 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1187 u_int32_t csr;
1188 u_int8_t reg, status;
1189 struct cs_dma *p;
1190 int r = 0;
1191
1192 mtx_enter(&audio_lock);
1193 csr = APC_READ(sc, APC_CSR);
1194 APC_WRITE(sc, APC_CSR, csr);
1195
1196 if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
1197 printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
1198 r = 1;
1199 }
1200
1201 if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
1202 /* playback interrupt */
1203 r = 1;
1204 }
1205
1206 if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
1207 /* general interrupt */
1208 status = CS_READ(sc, AD1848_STATUS);
1209 if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
1210 reg = cs4231_read(sc, CS_IRQ_STATUS);
1211 if (reg & CS_AFS_PI) {
1212 cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1213 cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1214 }
1215 if (reg & CS_AFS_CI) {
1216 cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1217 cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1218 }
1219 CS_WRITE(sc, AD1848_STATUS, 0);
1220 }
1221 r = 1;
1222 }
1223
1224
1225 if (csr & (APC_CSR_PI|APC_CSR_PMI|APC_CSR_PIE|APC_CSR_PD))
1226 r = 1;
1227
1228 if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
1229 struct cs_channel *chan = &sc->sc_playback;
1230 u_long nextaddr, togo;
1231
1232 p = chan->cs_curdma;
1233 togo = chan->cs_segsz - chan->cs_cnt;
1234 if (togo == 0) {
1235 nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1236 chan->cs_cnt = togo = chan->cs_blksz;
1237 } else {
1238 nextaddr = APC_READ(sc, APC_PNVA) + chan->cs_blksz;
1239 if (togo > chan->cs_blksz)
1240 togo = chan->cs_blksz;
1241 chan->cs_cnt += togo;
1242 }
1243
1244 APC_WRITE(sc, APC_PNVA, nextaddr);
1245 APC_WRITE(sc, APC_PNC, togo);
1246
1247 if (chan->cs_intr != NULL)
1248 (*chan->cs_intr)(chan->cs_arg);
1249 r = 1;
1250 }
1251
1252 if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
1253 if (csr & APC_CSR_CD) {
1254 struct cs_channel *chan = &sc->sc_capture;
1255 u_long nextaddr, togo;
1256
1257 p = chan->cs_curdma;
1258 togo = chan->cs_segsz - chan->cs_cnt;
1259 if (togo == 0) {
1260 nextaddr =
1261 (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1262 chan->cs_cnt = togo = chan->cs_blksz;
1263 } else {
1264 nextaddr = APC_READ(sc, APC_CNVA) +
1265 chan->cs_blksz;
1266 if (togo > chan->cs_blksz)
1267 togo = chan->cs_blksz;
1268 chan->cs_cnt += togo;
1269 }
1270
1271 APC_WRITE(sc, APC_CNVA, nextaddr);
1272 APC_WRITE(sc, APC_CNC, togo);
1273
1274 if (chan->cs_intr != NULL)
1275 (*chan->cs_intr)(chan->cs_arg);
1276 }
1277 r = 1;
1278 }
1279
1280 if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
1281 /* capture empty */
1282 r = 1;
1283 }
1284
1285 mtx_leave(&audio_lock);
1286 return (r);
1287 }
1288
1289 void *
cs4231_alloc(void * vsc,int direction,size_t size,int pool,int flags)1290 cs4231_alloc(void *vsc, int direction, size_t size, int pool, int flags)
1291 {
1292 struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
1293 bus_dma_tag_t dmat = sc->sc_dmatag;
1294 struct cs_dma *p;
1295
1296 p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1297 if (p == NULL)
1298 return (NULL);
1299
1300 if (bus_dmamap_create(dmat, size, 1, size, 0,
1301 BUS_DMA_NOWAIT, &p->dmamap) != 0)
1302 goto fail;
1303
1304 p->size = size;
1305
1306 if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
1307 nitems(p->segs), &p->nsegs,
1308 BUS_DMA_NOWAIT) != 0)
1309 goto fail1;
1310
1311 if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
1312 &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
1313 goto fail2;
1314
1315 if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
1316 BUS_DMA_NOWAIT) != 0)
1317 goto fail3;
1318
1319 p->next = sc->sc_dmas;
1320 sc->sc_dmas = p;
1321 return (p->addr);
1322
1323 fail3:
1324 bus_dmamem_unmap(dmat, p->addr, p->size);
1325 fail2:
1326 bus_dmamem_free(dmat, p->segs, p->nsegs);
1327 fail1:
1328 bus_dmamap_destroy(dmat, p->dmamap);
1329 fail:
1330 free(p, pool, 0);
1331 return (NULL);
1332 }
1333
1334 void
cs4231_free(void * vsc,void * ptr,int pool)1335 cs4231_free(void *vsc, void *ptr, int pool)
1336 {
1337 struct cs4231_softc *sc = vsc;
1338 bus_dma_tag_t dmat = sc->sc_dmatag;
1339 struct cs_dma *p, **pp;
1340
1341 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1342 if (p->addr != ptr)
1343 continue;
1344 bus_dmamap_unload(dmat, p->dmamap);
1345 bus_dmamem_unmap(dmat, p->addr, p->size);
1346 bus_dmamem_free(dmat, p->segs, p->nsegs);
1347 bus_dmamap_destroy(dmat, p->dmamap);
1348 *pp = p->next;
1349 free(p, pool, 0);
1350 return;
1351 }
1352 printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1353 }
1354
1355 int
cs4231_trigger_output(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * arg,struct audio_params * param)1356 cs4231_trigger_output(void *vsc, void *start, void *end, int blksize,
1357 void (*intr)(void *), void *arg, struct audio_params *param)
1358 {
1359 struct cs4231_softc *sc = vsc;
1360 struct cs_channel *chan = &sc->sc_playback;
1361 struct cs_dma *p;
1362 u_int32_t csr;
1363 u_long n;
1364
1365 if (chan->cs_locked != 0) {
1366 printf("%s: trigger_output: already running\n",
1367 sc->sc_dev.dv_xname);
1368 return (EINVAL);
1369 }
1370
1371 chan->cs_locked = 1;
1372 chan->cs_intr = intr;
1373 chan->cs_arg = arg;
1374
1375 for (p = sc->sc_dmas; p->addr != start; p = p->next)
1376 /*EMPTY*/;
1377 if (p == NULL) {
1378 printf("%s: trigger_output: bad addr: %p\n",
1379 sc->sc_dev.dv_xname, start);
1380 return (EINVAL);
1381 }
1382
1383 n = (char *)end - (char *)start;
1384
1385 /*
1386 * Do only `blksize' at a time, so audio_pint() is kept
1387 * synchronous with us...
1388 */
1389 chan->cs_blksz = blksize;
1390 chan->cs_curdma = p;
1391 chan->cs_segsz = n;
1392
1393 if (n > chan->cs_blksz)
1394 n = chan->cs_blksz;
1395
1396 chan->cs_cnt = n;
1397
1398 mtx_enter(&audio_lock);
1399 csr = APC_READ(sc, APC_CSR);
1400
1401 APC_WRITE(sc, APC_PNVA, (u_long)p->dmamap->dm_segs[0].ds_addr);
1402 APC_WRITE(sc, APC_PNC, (u_long)n);
1403
1404 if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
1405 APC_WRITE(sc, APC_CSR,
1406 APC_READ(sc, APC_CSR) & ~(APC_CSR_PIE | APC_CSR_PPAUSE));
1407 APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) |
1408 APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE |
1409 APC_CSR_PMIE | APC_CSR_PDMA_GO);
1410 cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
1411 cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
1412 cs4231_write(sc, SP_INTERFACE_CONFIG,
1413 cs4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
1414 }
1415 mtx_leave(&audio_lock);
1416 return (0);
1417 }
1418
1419 int
cs4231_trigger_input(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * arg,struct audio_params * param)1420 cs4231_trigger_input(void *vsc, void *start, void *end, int blksize,
1421 void (*intr)(void *), void *arg, struct audio_params *param)
1422 {
1423 struct cs4231_softc *sc = vsc;
1424 struct cs_channel *chan = &sc->sc_capture;
1425 struct cs_dma *p;
1426 u_int32_t csr;
1427 u_long n;
1428
1429 if (chan->cs_locked != 0) {
1430 printf("%s: trigger_input: already running\n",
1431 sc->sc_dev.dv_xname);
1432 return (EINVAL);
1433 }
1434 chan->cs_locked = 1;
1435 chan->cs_intr = intr;
1436 chan->cs_arg = arg;
1437
1438 for (p = sc->sc_dmas; p->addr != start; p = p->next)
1439 /*EMPTY*/;
1440 if (p == NULL) {
1441 printf("%s: trigger_input: bad addr: %p\n",
1442 sc->sc_dev.dv_xname, start);
1443 return (EINVAL);
1444 }
1445
1446 n = (char *)end - (char *)start;
1447
1448 /*
1449 * Do only `blksize' at a time, so audio_cint() is kept
1450 * synchronous with us...
1451 */
1452 chan->cs_blksz = blksize;
1453 chan->cs_curdma = p;
1454 chan->cs_segsz = n;
1455
1456 if (n > chan->cs_blksz)
1457 n = chan->cs_blksz;
1458 chan->cs_cnt = n;
1459
1460 mtx_enter(&audio_lock);
1461 APC_WRITE(sc, APC_CNVA, p->dmamap->dm_segs[0].ds_addr);
1462 APC_WRITE(sc, APC_CNC, (u_long)n);
1463
1464 csr = APC_READ(sc, APC_CSR);
1465 if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
1466 csr &= APC_CSR_CPAUSE;
1467 csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
1468 APC_CSR_CDMA_GO;
1469 APC_WRITE(sc, APC_CSR, csr);
1470 cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1471 cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1472 cs4231_write(sc, SP_INTERFACE_CONFIG,
1473 cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1474 }
1475
1476 if (APC_READ(sc, APC_CSR) & APC_CSR_CD) {
1477 u_long nextaddr, togo;
1478
1479 p = chan->cs_curdma;
1480 togo = chan->cs_segsz - chan->cs_cnt;
1481 if (togo == 0) {
1482 nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
1483 chan->cs_cnt = togo = chan->cs_blksz;
1484 } else {
1485 nextaddr = APC_READ(sc, APC_CNVA) + chan->cs_blksz;
1486 if (togo > chan->cs_blksz)
1487 togo = chan->cs_blksz;
1488 chan->cs_cnt += togo;
1489 }
1490
1491 APC_WRITE(sc, APC_CNVA, nextaddr);
1492 APC_WRITE(sc, APC_CNC, togo);
1493 }
1494
1495 mtx_leave(&audio_lock);
1496 return (0);
1497 }
1498