1 /* $NetBSD: harmony.c,v 1.11 2022/05/15 00:25:15 gutteridge Exp $ */
2
3 /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */
4
5 /*-
6 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Matt Fleming.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Copyright (c) 2003 Jason L. Wright (jason@thought.net)
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
49 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
51 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
56 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59
60 /*
61 * Harmony (CS4215/AD1849 LASI) audio interface.
62 */
63
64
65
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/ioctl.h>
71 #include <sys/device.h>
72 #include <sys/proc.h>
73 #include <sys/kmem.h>
74 #include <uvm/uvm_extern.h>
75
76 #include <sys/rndsource.h>
77
78 #include <sys/audioio.h>
79 #include <dev/audio/audio_if.h>
80
81 #include <machine/cpu.h>
82 #include <machine/intr.h>
83 #include <machine/iomod.h>
84 #include <machine/autoconf.h>
85 #include <sys/bus.h>
86
87 #include <hppa/dev/cpudevs.h>
88 #include <hppa/gsc/gscbusvar.h>
89 #include <hppa/gsc/harmonyreg.h>
90 #include <hppa/gsc/harmonyvar.h>
91
92 void harmony_close(void *);
93 int harmony_query_format(void *, audio_format_query_t *);
94 int harmony_set_format(void *, int,
95 const audio_params_t *, const audio_params_t *,
96 audio_filter_reg_t *, audio_filter_reg_t *);
97 int harmony_round_blocksize(void *, int, int, const audio_params_t *);
98
99 int harmony_control_wait(struct harmony_softc *);
100 int harmony_commit_settings(void *);
101
102 int harmony_halt_output(void *);
103 int harmony_halt_input(void *);
104 int harmony_getdev(void *, struct audio_device *);
105 int harmony_set_port(void *, mixer_ctrl_t *);
106 int harmony_get_port(void *, mixer_ctrl_t *);
107 int harmony_query_devinfo(void *, mixer_devinfo_t *);
108 void * harmony_allocm(void *, int, size_t);
109 void harmony_freem(void *, void *, size_t);
110 size_t harmony_round_buffersize(void *, int, size_t);
111 int harmony_get_props(void *);
112 int harmony_trigger_output(void *, void *, void *, int,
113 void (*)(void *), void *, const audio_params_t *);
114 int harmony_trigger_input(void *, void *, void *, int,
115 void (*)(void *), void *, const audio_params_t *);
116 void harmony_get_locks(void *, kmutex_t **, kmutex_t **);
117
118 const struct audio_hw_if harmony_sa_hw_if = {
119 .close = harmony_close,
120 .query_format = harmony_query_format,
121 .set_format = harmony_set_format,
122 .round_blocksize = harmony_round_blocksize,
123 .commit_settings = harmony_commit_settings,
124 .halt_output = harmony_halt_output,
125 .halt_input = harmony_halt_input,
126 .getdev = harmony_getdev,
127 .set_port = harmony_set_port,
128 .get_port = harmony_get_port,
129 .query_devinfo = harmony_query_devinfo,
130 .allocm = harmony_allocm,
131 .freem = harmony_freem,
132 .round_buffersize = harmony_round_buffersize,
133 .get_props = harmony_get_props,
134 .trigger_output = harmony_trigger_output,
135 .trigger_input = harmony_trigger_input,
136 .get_locks = harmony_get_locks,
137 };
138
139 /*
140 * The HW actually supports more frequencies, but these are the standard ones.
141 * For the full list, see the definition of harmony_speeds below.
142 */
143 #define HARMONY_FORMAT(enc, prec) \
144 { \
145 .mode = AUMODE_PLAY | AUMODE_RECORD, \
146 .encoding = (enc), \
147 .validbits = (prec), \
148 .precision = (prec), \
149 .channels = 2, \
150 .channel_mask = AUFMT_STEREO, \
151 .frequency_type = 4, \
152 .frequency = { 16000, 32000, 44100, 48000 }, \
153 }
154 static struct audio_format harmony_formats[] = {
155 HARMONY_FORMAT(AUDIO_ENCODING_ULAW, 8),
156 HARMONY_FORMAT(AUDIO_ENCODING_ALAW, 8),
157 HARMONY_FORMAT(AUDIO_ENCODING_SLINEAR_BE, 16),
158 };
159 #define HARMONY_NFORMATS __arraycount(harmony_formats)
160
161 int harmony_match(device_t, struct cfdata *, void *);
162 void harmony_attach(device_t, device_t, void *);
163
164
165 CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc),
166 harmony_match, harmony_attach, NULL, NULL);
167
168 int harmony_intr(void *);
169 void harmony_intr_enable(struct harmony_softc *);
170 void harmony_intr_disable(struct harmony_softc *);
171 uint32_t harmony_speed_bits(struct harmony_softc *, u_int);
172 int harmony_set_gainctl(struct harmony_softc *);
173 void harmony_reset_codec(struct harmony_softc *);
174 void harmony_start_cp(struct harmony_softc *, int);
175 void harmony_start_pp(struct harmony_softc *, int);
176 void harmony_tick_pb(void *);
177 void harmony_tick_cp(void *);
178 void harmony_try_more(struct harmony_softc *, int, int,
179 struct harmony_channel *);
180 static void harmony_empty_input(struct harmony_softc *);
181 static void harmony_empty_output(struct harmony_softc *);
182
183 void harmony_acc_tmo(void *);
184 #define ADD_CLKALLICA(sc) do { \
185 (sc)->sc_acc <<= 1; \
186 (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \
187 if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \
188 rnd_add_uint32(&(sc)->sc_rnd_source, \
189 (sc)->sc_acc_num ^= (sc)->sc_acc); \
190 } while(0)
191
192 int
harmony_match(device_t parent,struct cfdata * match,void * aux)193 harmony_match(device_t parent, struct cfdata *match, void *aux)
194 {
195 struct gsc_attach_args *ga;
196
197 ga = aux;
198 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
199 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
200 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
201 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
202 ga->ga_type.iodc_sv_model == HPPA_FIO_A2)
203 return 1;
204 }
205 return 0;
206 }
207
208 void
harmony_attach(device_t parent,device_t self,void * aux)209 harmony_attach(device_t parent, device_t self, void *aux)
210 {
211 struct harmony_softc *sc = device_private(self);
212 struct gsc_attach_args *ga;
213 uint8_t rev;
214 uint32_t cntl;
215 int i;
216
217 sc->sc_dv = self;
218 ga = aux;
219 sc->sc_bt = ga->ga_iot;
220 sc->sc_dmat = ga->ga_dmatag;
221
222 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
223 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
224
225 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
226 &sc->sc_bh) != 0) {
227 aprint_error(": couldn't map registers\n");
228 return;
229 }
230
231 cntl = READ_REG(sc, HARMONY_ID);
232 switch ((cntl & ID_REV_MASK)) {
233 case ID_REV_TS:
234 sc->sc_teleshare = 1;
235 case ID_REV_NOTS:
236 break;
237 default:
238 aprint_error(": unknown id == 0x%02x\n",
239 (cntl & ID_REV_MASK) >> ID_REV_SHIFT);
240 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
241 return;
242 }
243
244 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
245 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
246 BUS_DMA_WAITOK) != 0) {
247 aprint_error(": could not alloc DMA memory\n");
248 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
249 return;
250 }
251 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
252 sizeof(struct harmony_empty), (void **)&sc->sc_empty_kva,
253 BUS_DMA_WAITOK) != 0) {
254 aprint_error(": couldn't map DMA memory\n");
255 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
256 sc->sc_empty_rseg);
257 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
258 return;
259 }
260 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
261 sizeof(struct harmony_empty), 0, BUS_DMA_WAITOK,
262 &sc->sc_empty_map) != 0) {
263 aprint_error(": can't create DMA map\n");
264 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
265 sizeof(struct harmony_empty));
266 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
267 sc->sc_empty_rseg);
268 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
269 return;
270 }
271 if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
272 sizeof(struct harmony_empty), NULL, BUS_DMA_WAITOK) != 0) {
273 aprint_error(": can't load DMA map\n");
274 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
275 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
276 sizeof(struct harmony_empty));
277 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
278 sc->sc_empty_rseg);
279 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
280 return;
281 }
282
283 sc->sc_playback_empty = 0;
284 for (i = 0; i < PLAYBACK_EMPTYS; i++)
285 sc->sc_playback_paddrs[i] =
286 sc->sc_empty_map->dm_segs[0].ds_addr +
287 offsetof(struct harmony_empty, playback[i][0]);
288
289 sc->sc_capture_empty = 0;
290 for (i = 0; i < CAPTURE_EMPTYS; i++)
291 sc->sc_capture_paddrs[i] =
292 sc->sc_empty_map->dm_segs[0].ds_addr +
293 offsetof(struct harmony_empty, capture[i][0]);
294
295 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
296 offsetof(struct harmony_empty, playback[0][0]),
297 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
298
299 (void) hppa_intr_establish(IPL_AUDIO, harmony_intr, sc, ga->ga_ir,
300 ga->ga_irq);
301
302 /* set defaults */
303 sc->sc_in_port = HARMONY_IN_LINE;
304 sc->sc_out_port = HARMONY_OUT_SPEAKER;
305 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
306 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
307 sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
308 sc->sc_outputgain = 0;
309
310 /* reset chip, and push default gain controls */
311 harmony_reset_codec(sc);
312
313 cntl = READ_REG(sc, HARMONY_CNTL);
314 rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
315 aprint_normal(": rev %u", rev);
316
317 if (sc->sc_teleshare)
318 printf(", teleshare");
319 aprint_normal("\n");
320
321 strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name));
322 snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version,
323 "%u.%u;%u", ga->ga_type.iodc_sv_rev,
324 ga->ga_type.iodc_model, ga->ga_type.iodc_revision);
325 strlcpy(sc->sc_audev.config, device_xname(sc->sc_dv),
326 sizeof(sc->sc_audev.config));
327
328 audio_attach_mi(&harmony_sa_hw_if, sc, sc->sc_dv);
329
330 rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
331 RND_TYPE_UNKNOWN, RND_FLAG_DEFAULT);
332
333 callout_init(&sc->sc_acc_tmo, 0);
334 callout_setfunc(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
335 sc->sc_acc_num = 0xa5a5a5a5;
336 }
337
338 void
harmony_reset_codec(struct harmony_softc * sc)339 harmony_reset_codec(struct harmony_softc *sc)
340 {
341
342 /* silence */
343 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
344 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
345
346 /* start reset */
347 WRITE_REG(sc, HARMONY_RESET, RESET_RST);
348
349 DELAY(100000); /* wait at least 0.1 sec */
350
351 harmony_set_gainctl(sc);
352 WRITE_REG(sc, HARMONY_RESET, 0);
353 }
354
355 void
harmony_acc_tmo(void * v)356 harmony_acc_tmo(void *v)
357 {
358 struct harmony_softc *sc;
359
360 sc = v;
361 ADD_CLKALLICA(sc);
362 callout_schedule(&sc->sc_acc_tmo, 1);
363 }
364
365 /*
366 * interrupt handler
367 */
368 int
harmony_intr(void * vsc)369 harmony_intr(void *vsc)
370 {
371 struct harmony_softc *sc;
372 uint32_t dstatus;
373 int r;
374
375 sc = vsc;
376 r = 0;
377 ADD_CLKALLICA(sc);
378
379 mutex_spin_enter(&sc->sc_intr_lock);
380
381 harmony_intr_disable(sc);
382
383 dstatus = READ_REG(sc, HARMONY_DSTATUS);
384
385 if (dstatus & DSTATUS_PN) {
386 r = 1;
387 harmony_start_pp(sc, 0);
388 }
389
390 if (dstatus & DSTATUS_RN) {
391 r = 1;
392 harmony_start_cp(sc, 0);
393 }
394
395 if (READ_REG(sc, HARMONY_OV) & OV_OV) {
396 sc->sc_ov = 1;
397 WRITE_REG(sc, HARMONY_OV, 0);
398 } else
399 sc->sc_ov = 0;
400
401 harmony_intr_enable(sc);
402
403 mutex_spin_exit(&sc->sc_intr_lock);
404
405 return r;
406 }
407
408 void
harmony_intr_enable(struct harmony_softc * sc)409 harmony_intr_enable(struct harmony_softc *sc)
410 {
411
412 WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
413 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
414 }
415
416 void
harmony_intr_disable(struct harmony_softc * sc)417 harmony_intr_disable(struct harmony_softc *sc)
418 {
419
420 WRITE_REG(sc, HARMONY_DSTATUS, 0);
421 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
422 }
423
424 void
harmony_close(void * vsc)425 harmony_close(void *vsc)
426 {
427 struct harmony_softc *sc;
428
429 sc = vsc;
430 harmony_intr_disable(sc);
431 }
432
433 int
harmony_query_format(void * vsc,audio_format_query_t * afp)434 harmony_query_format(void *vsc, audio_format_query_t *afp)
435 {
436
437 return audio_query_format(harmony_formats, HARMONY_NFORMATS, afp);
438 }
439
440 int
harmony_set_format(void * vsc,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)441 harmony_set_format(void *vsc, int setmode,
442 const audio_params_t *play, const audio_params_t *rec,
443 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
444 {
445 struct harmony_softc *sc;
446 uint32_t bits;
447
448 sc = vsc;
449
450 /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
451 switch (play->encoding) {
452 case AUDIO_ENCODING_ULAW:
453 bits = CNTL_FORMAT_ULAW;
454 break;
455 case AUDIO_ENCODING_ALAW:
456 bits = CNTL_FORMAT_ALAW;
457 break;
458 case AUDIO_ENCODING_SLINEAR_BE:
459 bits = CNTL_FORMAT_SLINEAR16BE;
460 break;
461 default:
462 return EINVAL;
463 }
464
465 if (sc->sc_outputgain)
466 bits |= CNTL_OLB;
467
468 bits |= CNTL_CHANS_STEREO;
469 bits |= harmony_speed_bits(sc, play->sample_rate);
470 sc->sc_cntlbits = bits;
471 sc->sc_need_commit = 1;
472
473 return 0;
474 }
475
476 int
harmony_round_blocksize(void * vsc,int blk,int mode,const audio_params_t * param)477 harmony_round_blocksize(void *vsc, int blk,
478 int mode, const audio_params_t *param)
479 {
480
481 return HARMONY_BUFSIZE;
482 }
483
484 int
harmony_control_wait(struct harmony_softc * sc)485 harmony_control_wait(struct harmony_softc *sc)
486 {
487 uint32_t reg;
488 int j = 0;
489
490 while (j < 10) {
491 /* Wait for it to come out of control mode */
492 reg = READ_REG(sc, HARMONY_CNTL);
493 if ((reg & CNTL_C) == 0)
494 return 0;
495 DELAY(50000); /* wait 0.05 */
496 j++;
497 }
498
499 return 1;
500 }
501
502 int
harmony_commit_settings(void * vsc)503 harmony_commit_settings(void *vsc)
504 {
505 struct harmony_softc *sc;
506 uint32_t reg;
507 uint8_t quietchar;
508 int i;
509
510 sc = vsc;
511 if (sc->sc_need_commit == 0)
512 return 0;
513
514 harmony_intr_disable(sc);
515
516 for (;;) {
517 reg = READ_REG(sc, HARMONY_DSTATUS);
518 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
519 break;
520 }
521
522 /* Setting some bits in gainctl requires a reset */
523 harmony_reset_codec(sc);
524
525 /* set the silence character based on the encoding type */
526 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
527 offsetof(struct harmony_empty, playback[0][0]),
528 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
529 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
530 case CNTL_FORMAT_ULAW:
531 quietchar = 0x7f;
532 break;
533 case CNTL_FORMAT_ALAW:
534 quietchar = 0x55;
535 break;
536 case CNTL_FORMAT_SLINEAR16BE:
537 case CNTL_FORMAT_ULINEAR8:
538 default:
539 quietchar = 0;
540 break;
541 }
542 for (i = 0; i < PLAYBACK_EMPTYS; i++)
543 memset(&sc->sc_empty_kva->playback[i][0],
544 quietchar, HARMONY_BUFSIZE);
545 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
546 offsetof(struct harmony_empty, playback[0][0]),
547 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
548
549 harmony_control_wait(sc);
550
551 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
552 sc->sc_cntlbits | CNTL_C);
553
554 harmony_control_wait(sc);
555
556 sc->sc_need_commit = 0;
557
558 if (sc->sc_playing || sc->sc_capturing)
559 harmony_intr_enable(sc);
560
561 return 0;
562 }
563
564 static void
harmony_empty_output(struct harmony_softc * sc)565 harmony_empty_output(struct harmony_softc *sc)
566 {
567
568 WRITE_REG(sc, HARMONY_PNXTADD,
569 sc->sc_playback_paddrs[sc->sc_playback_empty]);
570 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
571
572 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS)
573 sc->sc_playback_empty = 0;
574 }
575
576 int
harmony_halt_output(void * vsc)577 harmony_halt_output(void *vsc)
578 {
579 struct harmony_softc *sc;
580
581 sc = vsc;
582 sc->sc_playing = 0;
583
584 harmony_empty_output(sc);
585 return 0;
586 }
587
588 static void
harmony_empty_input(struct harmony_softc * sc)589 harmony_empty_input(struct harmony_softc *sc)
590 {
591
592 WRITE_REG(sc, HARMONY_RNXTADD,
593 sc->sc_capture_paddrs[sc->sc_capture_empty]);
594 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
595
596 if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
597 sc->sc_capture_empty = 0;
598 }
599
600 int
harmony_halt_input(void * vsc)601 harmony_halt_input(void *vsc)
602 {
603 struct harmony_softc *sc;
604
605 sc = vsc;
606 sc->sc_capturing = 0;
607
608 harmony_empty_input(sc);
609 return 0;
610 }
611
612 int
harmony_getdev(void * vsc,struct audio_device * retp)613 harmony_getdev(void *vsc, struct audio_device *retp)
614 {
615 struct harmony_softc *sc;
616
617 sc = vsc;
618 *retp = sc->sc_audev;
619 return 0;
620 }
621
622 int
harmony_set_port(void * vsc,mixer_ctrl_t * cp)623 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
624 {
625 struct harmony_softc *sc;
626 int err;
627
628 sc = vsc;
629 err = EINVAL;
630 switch (cp->dev) {
631 case HARMONY_PORT_INPUT_LVL:
632 if (cp->type != AUDIO_MIXER_VALUE)
633 break;
634 if (cp->un.value.num_channels == 1)
635 sc->sc_input_lvl.left = sc->sc_input_lvl.right =
636 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
637 else if (cp->un.value.num_channels == 2) {
638 sc->sc_input_lvl.left =
639 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
640 sc->sc_input_lvl.right =
641 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
642 } else
643 break;
644 sc->sc_need_commit = 1;
645 err = 0;
646 break;
647 case HARMONY_PORT_OUTPUT_LVL:
648 if (cp->type != AUDIO_MIXER_VALUE)
649 break;
650 if (cp->un.value.num_channels == 1)
651 sc->sc_output_lvl.left = sc->sc_output_lvl.right =
652 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
653 else if (cp->un.value.num_channels == 2) {
654 sc->sc_output_lvl.left =
655 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
656 sc->sc_output_lvl.right =
657 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
658 } else
659 break;
660 sc->sc_need_commit = 1;
661 err = 0;
662 break;
663 case HARMONY_PORT_OUTPUT_GAIN:
664 if (cp->type != AUDIO_MIXER_ENUM)
665 break;
666 sc->sc_outputgain = cp->un.ord ? 1 : 0;
667 err = 0;
668 break;
669 case HARMONY_PORT_MONITOR_LVL:
670 if (cp->type != AUDIO_MIXER_VALUE)
671 break;
672 if (cp->un.value.num_channels != 1)
673 break;
674 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
675 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
676 sc->sc_need_commit = 1;
677 err = 0;
678 break;
679 case HARMONY_PORT_RECORD_SOURCE:
680 if (cp->type != AUDIO_MIXER_ENUM)
681 break;
682 if (cp->un.ord != HARMONY_IN_LINE &&
683 cp->un.ord != HARMONY_IN_MIC)
684 break;
685 sc->sc_in_port = cp->un.ord;
686 err = 0;
687 sc->sc_need_commit = 1;
688 break;
689 case HARMONY_PORT_OUTPUT_SOURCE:
690 if (cp->type != AUDIO_MIXER_ENUM)
691 break;
692 if (cp->un.ord != HARMONY_OUT_LINE &&
693 cp->un.ord != HARMONY_OUT_SPEAKER &&
694 cp->un.ord != HARMONY_OUT_HEADPHONE)
695 break;
696 sc->sc_out_port = cp->un.ord;
697 err = 0;
698 sc->sc_need_commit = 1;
699 break;
700 }
701
702 return err;
703 }
704
705 int
harmony_get_port(void * vsc,mixer_ctrl_t * cp)706 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
707 {
708 struct harmony_softc *sc;
709 int err;
710
711 sc = vsc;
712 err = EINVAL;
713 switch (cp->dev) {
714 case HARMONY_PORT_INPUT_LVL:
715 if (cp->type != AUDIO_MIXER_VALUE)
716 break;
717 if (cp->un.value.num_channels == 1) {
718 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
719 sc->sc_input_lvl.left;
720 } else if (cp->un.value.num_channels == 2) {
721 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
722 sc->sc_input_lvl.left;
723 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
724 sc->sc_input_lvl.right;
725 } else
726 break;
727 err = 0;
728 break;
729 case HARMONY_PORT_INPUT_OV:
730 if (cp->type != AUDIO_MIXER_ENUM)
731 break;
732 cp->un.ord = sc->sc_ov ? 1 : 0;
733 err = 0;
734 break;
735 case HARMONY_PORT_OUTPUT_LVL:
736 if (cp->type != AUDIO_MIXER_VALUE)
737 break;
738 if (cp->un.value.num_channels == 1) {
739 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
740 sc->sc_output_lvl.left;
741 } else if (cp->un.value.num_channels == 2) {
742 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
743 sc->sc_output_lvl.left;
744 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
745 sc->sc_output_lvl.right;
746 } else
747 break;
748 err = 0;
749 break;
750 case HARMONY_PORT_OUTPUT_GAIN:
751 if (cp->type != AUDIO_MIXER_ENUM)
752 break;
753 cp->un.ord = sc->sc_outputgain ? 1 : 0;
754 err = 0;
755 break;
756 case HARMONY_PORT_MONITOR_LVL:
757 if (cp->type != AUDIO_MIXER_VALUE)
758 break;
759 if (cp->un.value.num_channels != 1)
760 break;
761 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
762 sc->sc_monitor_lvl.left;
763 err = 0;
764 break;
765 case HARMONY_PORT_RECORD_SOURCE:
766 if (cp->type != AUDIO_MIXER_ENUM)
767 break;
768 cp->un.ord = sc->sc_in_port;
769 err = 0;
770 break;
771 case HARMONY_PORT_OUTPUT_SOURCE:
772 if (cp->type != AUDIO_MIXER_ENUM)
773 break;
774 cp->un.ord = sc->sc_out_port;
775 err = 0;
776 break;
777 }
778 return err;
779 }
780
781 int
harmony_query_devinfo(void * vsc,mixer_devinfo_t * dip)782 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
783 {
784 int err;
785
786 err = 0;
787 switch (dip->index) {
788 case HARMONY_PORT_INPUT_LVL:
789 dip->type = AUDIO_MIXER_VALUE;
790 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
791 dip->prev = dip->next = AUDIO_MIXER_LAST;
792 strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
793 dip->un.v.num_channels = 2;
794 strlcpy(dip->un.v.units.name, AudioNvolume,
795 sizeof dip->un.v.units.name);
796 break;
797 case HARMONY_PORT_INPUT_OV:
798 dip->type = AUDIO_MIXER_ENUM;
799 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
800 dip->prev = dip->next = AUDIO_MIXER_LAST;
801 strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
802 dip->un.e.num_mem = 2;
803 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
804 sizeof dip->un.e.member[0].label.name);
805 dip->un.e.member[0].ord = 0;
806 strlcpy(dip->un.e.member[1].label.name, AudioNon,
807 sizeof dip->un.e.member[1].label.name);
808 dip->un.e.member[1].ord = 1;
809 break;
810 case HARMONY_PORT_OUTPUT_LVL:
811 dip->type = AUDIO_MIXER_VALUE;
812 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
813 dip->prev = dip->next = AUDIO_MIXER_LAST;
814 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
815 dip->un.v.num_channels = 2;
816 strlcpy(dip->un.v.units.name, AudioNvolume,
817 sizeof dip->un.v.units.name);
818 break;
819 case HARMONY_PORT_OUTPUT_GAIN:
820 dip->type = AUDIO_MIXER_ENUM;
821 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
822 dip->prev = dip->next = AUDIO_MIXER_LAST;
823 strlcpy(dip->label.name, "gain", sizeof dip->label.name);
824 dip->un.e.num_mem = 2;
825 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
826 sizeof dip->un.e.member[0].label.name);
827 dip->un.e.member[0].ord = 0;
828 strlcpy(dip->un.e.member[1].label.name, AudioNon,
829 sizeof dip->un.e.member[1].label.name);
830 dip->un.e.member[1].ord = 1;
831 break;
832 case HARMONY_PORT_MONITOR_LVL:
833 dip->type = AUDIO_MIXER_VALUE;
834 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
835 dip->prev = dip->next = AUDIO_MIXER_LAST;
836 strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
837 dip->un.v.num_channels = 1;
838 strlcpy(dip->un.v.units.name, AudioNvolume,
839 sizeof dip->un.v.units.name);
840 break;
841 case HARMONY_PORT_RECORD_SOURCE:
842 dip->type = AUDIO_MIXER_ENUM;
843 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
844 dip->prev = dip->next = AUDIO_MIXER_LAST;
845 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
846 dip->un.e.num_mem = 2;
847 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
848 sizeof dip->un.e.member[0].label.name);
849 dip->un.e.member[0].ord = HARMONY_IN_MIC;
850 strlcpy(dip->un.e.member[1].label.name, AudioNline,
851 sizeof dip->un.e.member[1].label.name);
852 dip->un.e.member[1].ord = HARMONY_IN_LINE;
853 break;
854 case HARMONY_PORT_OUTPUT_SOURCE:
855 dip->type = AUDIO_MIXER_ENUM;
856 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
857 dip->prev = dip->next = AUDIO_MIXER_LAST;
858 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
859 dip->un.e.num_mem = 3;
860 strlcpy(dip->un.e.member[0].label.name, AudioNline,
861 sizeof dip->un.e.member[0].label.name);
862 dip->un.e.member[0].ord = HARMONY_OUT_LINE;
863 strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
864 sizeof dip->un.e.member[1].label.name);
865 dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
866 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
867 sizeof dip->un.e.member[2].label.name);
868 dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
869 break;
870 case HARMONY_PORT_INPUT_CLASS:
871 dip->type = AUDIO_MIXER_CLASS;
872 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
873 dip->prev = dip->next = AUDIO_MIXER_LAST;
874 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
875 break;
876 case HARMONY_PORT_OUTPUT_CLASS:
877 dip->type = AUDIO_MIXER_CLASS;
878 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
879 dip->prev = dip->next = AUDIO_MIXER_LAST;
880 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
881 break;
882 case HARMONY_PORT_MONITOR_CLASS:
883 dip->type = AUDIO_MIXER_CLASS;
884 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
885 dip->prev = dip->next = AUDIO_MIXER_LAST;
886 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
887 break;
888 case HARMONY_PORT_RECORD_CLASS:
889 dip->type = AUDIO_MIXER_CLASS;
890 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
891 dip->prev = dip->next = AUDIO_MIXER_LAST;
892 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
893 break;
894 default:
895 err = ENXIO;
896 break;
897 }
898
899 return err;
900 }
901
902 void *
harmony_allocm(void * vsc,int dir,size_t size)903 harmony_allocm(void *vsc, int dir, size_t size)
904 {
905 struct harmony_softc *sc;
906 struct harmony_dma *d;
907 int rseg;
908
909 sc = vsc;
910 d = kmem_alloc(sizeof(*d), KM_SLEEP);
911
912 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK,
913 &d->d_map) != 0)
914 goto fail1;
915
916 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
917 &rseg, BUS_DMA_WAITOK) != 0)
918 goto fail2;
919
920 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
921 BUS_DMA_WAITOK) != 0)
922 goto fail3;
923
924 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
925 BUS_DMA_WAITOK) != 0)
926 goto fail4;
927
928 d->d_next = sc->sc_dmas;
929 sc->sc_dmas = d;
930 d->d_size = size;
931 return (d->d_kva);
932
933 fail4:
934 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
935 fail3:
936 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
937 fail2:
938 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
939 fail1:
940 kmem_free(d, sizeof(*d));
941 return (NULL);
942 }
943
944 void
harmony_freem(void * vsc,void * ptr,size_t size)945 harmony_freem(void *vsc, void *ptr, size_t size)
946 {
947 struct harmony_softc *sc;
948 struct harmony_dma *d, **dd;
949
950 sc = vsc;
951 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
952 if (d->d_kva != ptr)
953 continue;
954 bus_dmamap_unload(sc->sc_dmat, d->d_map);
955 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
956 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
957 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
958 kmem_free(d, sizeof(*d));
959 return;
960 }
961 printf("%s: free rogue pointer\n", device_xname(sc->sc_dv));
962 }
963
964 size_t
harmony_round_buffersize(void * vsc,int direction,size_t size)965 harmony_round_buffersize(void *vsc, int direction, size_t size)
966 {
967
968 return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
969 }
970
971 int
harmony_get_props(void * vsc)972 harmony_get_props(void *vsc)
973 {
974
975 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
976 AUDIO_PROP_FULLDUPLEX;
977 }
978
979 void
harmony_get_locks(void * vsc,kmutex_t ** intr,kmutex_t ** thread)980 harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread)
981 {
982 struct harmony_softc *sc;
983
984 sc = vsc;
985 *intr = &sc->sc_intr_lock;
986 *thread = &sc->sc_lock;
987 }
988
989 int
harmony_trigger_output(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)990 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
991 void (*intr)(void *), void *intrarg, const audio_params_t *param)
992 {
993 struct harmony_softc *sc;
994 struct harmony_channel *c;
995 struct harmony_dma *d;
996
997 sc = vsc;
998 c = &sc->sc_playback;
999 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1000 continue;
1001 if (d == NULL) {
1002 printf("%s: trigger_output: bad addr: %p\n",
1003 device_xname(sc->sc_dv), start);
1004 return EINVAL;
1005 }
1006
1007 c->c_intr = intr;
1008 c->c_intrarg = intrarg;
1009 c->c_blksz = blksize;
1010 c->c_current = d;
1011 c->c_segsz = (char *)end - (char *)start;
1012 c->c_cnt = 0;
1013 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1014
1015 sc->sc_playing = 1;
1016
1017 harmony_start_pp(sc, 1);
1018 harmony_start_cp(sc, 0);
1019 harmony_intr_enable(sc);
1020
1021 return 0;
1022 }
1023
1024 void
harmony_start_cp(struct harmony_softc * sc,int start)1025 harmony_start_cp(struct harmony_softc *sc, int start)
1026 {
1027 struct harmony_channel *c;
1028 struct harmony_dma *d;
1029 bus_addr_t nextaddr;
1030 bus_size_t togo;
1031
1032 KASSERT(mutex_owned(&sc->sc_intr_lock));
1033
1034 c = &sc->sc_capture;
1035 if (sc->sc_capturing == 0)
1036 harmony_empty_input(sc);
1037 else {
1038 d = c->c_current;
1039 togo = c->c_segsz - c->c_cnt;
1040 if (togo == 0) {
1041 nextaddr = d->d_map->dm_segs[0].ds_addr;
1042 c->c_cnt = togo = c->c_blksz;
1043 } else {
1044 nextaddr = c->c_lastaddr;
1045 if (togo > c->c_blksz)
1046 togo = c->c_blksz;
1047 c->c_cnt += togo;
1048 }
1049
1050 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1051 nextaddr - d->d_map->dm_segs[0].ds_addr,
1052 c->c_blksz, BUS_DMASYNC_PREWRITE);
1053
1054 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
1055 if (start)
1056 c->c_theaddr = nextaddr;
1057 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
1058 c->c_lastaddr = nextaddr + togo;
1059
1060 harmony_try_more(sc, HARMONY_RCURADD,
1061 RCURADD_BUFMASK, &sc->sc_capture);
1062 }
1063
1064 callout_schedule(&sc->sc_acc_tmo, 1);
1065 }
1066
1067 void
harmony_start_pp(struct harmony_softc * sc,int start)1068 harmony_start_pp(struct harmony_softc *sc, int start)
1069 {
1070 struct harmony_channel *c;
1071 struct harmony_dma *d;
1072 bus_addr_t nextaddr;
1073 bus_size_t togo;
1074
1075 KASSERT(mutex_owned(&sc->sc_intr_lock));
1076
1077 c = &sc->sc_playback;
1078 if (sc->sc_playing == 0)
1079 harmony_empty_output(sc);
1080 else {
1081 d = c->c_current;
1082 togo = c->c_segsz - c->c_cnt;
1083 if (togo == 0) {
1084 nextaddr = d->d_map->dm_segs[0].ds_addr;
1085 c->c_cnt = togo = c->c_blksz;
1086 } else {
1087 nextaddr = c->c_lastaddr;
1088 if (togo > c->c_blksz)
1089 togo = c->c_blksz;
1090 c->c_cnt += togo;
1091 }
1092
1093 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1094 nextaddr - d->d_map->dm_segs[0].ds_addr,
1095 c->c_blksz, BUS_DMASYNC_PREWRITE);
1096
1097 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
1098 if (start)
1099 c->c_theaddr = nextaddr;
1100 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
1101 c->c_lastaddr = nextaddr + togo;
1102
1103 harmony_try_more(sc, HARMONY_PCURADD,
1104 PCURADD_BUFMASK, &sc->sc_playback);
1105 }
1106 }
1107
1108 int
harmony_trigger_input(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)1109 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
1110 void (*intr)(void *), void *intrarg, const audio_params_t *param)
1111 {
1112 struct harmony_softc *sc = vsc;
1113 struct harmony_channel *c = &sc->sc_capture;
1114 struct harmony_dma *d;
1115
1116 KASSERT(mutex_owned(&sc->sc_intr_lock));
1117
1118 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1119 continue;
1120 if (d == NULL) {
1121 printf("%s: trigger_input: bad addr: %p\n",
1122 device_xname(sc->sc_dv), start);
1123 return EINVAL;
1124 }
1125
1126 c->c_intr = intr;
1127 c->c_intrarg = intrarg;
1128 c->c_blksz = blksize;
1129 c->c_current = d;
1130 c->c_segsz = (char *)end - (char *)start;
1131 c->c_cnt = 0;
1132 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1133
1134 sc->sc_capturing = 1;
1135
1136 harmony_start_cp(sc, 1);
1137 harmony_intr_enable(sc);
1138
1139 return 0;
1140 }
1141
1142 static const struct speed_struct {
1143 uint32_t speed;
1144 uint32_t bits;
1145 } harmony_speeds[] = {
1146 { 5125, CNTL_RATE_5125 },
1147 { 6615, CNTL_RATE_6615 },
1148 { 8000, CNTL_RATE_8000 },
1149 { 9600, CNTL_RATE_9600 },
1150 { 11025, CNTL_RATE_11025 },
1151 { 16000, CNTL_RATE_16000 },
1152 { 18900, CNTL_RATE_18900 },
1153 { 22050, CNTL_RATE_22050 },
1154 { 27428, CNTL_RATE_27428 },
1155 { 32000, CNTL_RATE_32000 },
1156 { 33075, CNTL_RATE_33075 },
1157 { 37800, CNTL_RATE_37800 },
1158 { 44100, CNTL_RATE_44100 },
1159 { 48000, CNTL_RATE_48000 },
1160 };
1161
1162 uint32_t
harmony_speed_bits(struct harmony_softc * sc,u_int speed)1163 harmony_speed_bits(struct harmony_softc *sc, u_int speed)
1164 {
1165 int i;
1166
1167 for (i = 0; i < __arraycount(harmony_speeds); i++) {
1168 if (speed == harmony_speeds[i].speed) {
1169 return harmony_speeds[i].bits;
1170 }
1171 }
1172 /* If this happens, harmony_formats[] is wrong */
1173 panic("speed %u not supported", speed);
1174 }
1175
1176 int
harmony_set_gainctl(struct harmony_softc * sc)1177 harmony_set_gainctl(struct harmony_softc *sc)
1178 {
1179 uint32_t bits, mask, val, old;
1180
1181 /* XXX leave these bits alone or the chip will not come out of CNTL */
1182 bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1183
1184 /* input level */
1185 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1186 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1187 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1188 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1189
1190 /* output level (inverted) */
1191 mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1192 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1193 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1194 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1195 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1196
1197 /* monitor level (inverted) */
1198 mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1199 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1200 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1201
1202 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1203 bits &= ~GAINCTL_IS_MASK;
1204 if (sc->sc_in_port == HARMONY_IN_MIC)
1205 bits |= GAINCTL_IS_LINE;
1206 else
1207 bits |= GAINCTL_IS_MICROPHONE;
1208
1209 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1210 bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1211 if (sc->sc_out_port == HARMONY_OUT_LINE)
1212 bits |= GAINCTL_LE;
1213 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1214 bits |= GAINCTL_SE;
1215 else
1216 bits |= GAINCTL_HE;
1217
1218 mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1219 old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1220 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1221 if ((old & mask) != (bits & mask))
1222 return 1;
1223 return 0;
1224 }
1225
1226 void
harmony_try_more(struct harmony_softc * sc,int curadd,int bufmask,struct harmony_channel * c)1227 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1228 struct harmony_channel *c)
1229 {
1230 struct harmony_dma *d;
1231 uint32_t cur;
1232 int i, nsegs;
1233
1234 d = c->c_current;
1235 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1236 cur &= bufmask;
1237 nsegs = 0;
1238
1239 #ifdef DIAGNOSTIC
1240 if (cur < d->d_map->dm_segs[0].ds_addr ||
1241 cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1242 panic("%s: bad current %x < %lx || %x > %lx",
1243 device_xname(sc->sc_dv), cur,
1244 d->d_map->dm_segs[0].ds_addr, cur,
1245 d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1246 #endif /* DIAGNOSTIC */
1247
1248 if (cur > c->c_theaddr) {
1249 nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1250 } else if (cur < c->c_theaddr) {
1251 nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1252 c->c_theaddr) / HARMONY_BUFSIZE;
1253 nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1254 HARMONY_BUFSIZE;
1255 }
1256
1257 if (nsegs != 0 && c->c_intr != NULL) {
1258 for (i = 0; i < nsegs; i++)
1259 (*c->c_intr)(c->c_intrarg);
1260 c->c_theaddr = cur;
1261 }
1262 }
1263