harmony.c revision 1.2 1 /* $NetBSD: harmony.c,v 1.2 2014/08/10 16:44:34 tls 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 (at) 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/rnd.h>
77
78 #include <sys/audioio.h>
79 #include <dev/audio_if.h>
80 #include <dev/auconv.h>
81
82 #include <machine/cpu.h>
83 #include <machine/intr.h>
84 #include <machine/iomod.h>
85 #include <machine/autoconf.h>
86 #include <sys/bus.h>
87
88 #include <hppa/dev/cpudevs.h>
89 #include <hppa/gsc/gscbusvar.h>
90 #include <hppa/gsc/harmonyreg.h>
91 #include <hppa/gsc/harmonyvar.h>
92
93 int harmony_open(void *, int);
94 void harmony_close(void *);
95 int harmony_query_encoding(void *, struct audio_encoding *);
96 int harmony_set_params(void *, int, int, audio_params_t *,
97 audio_params_t *, stream_filter_list_t *, stream_filter_list_t *);
98 int harmony_round_blocksize(void *, int, int, const audio_params_t *);
99
100 int harmony_control_wait(struct harmony_softc *);
101 int harmony_commit_settings(void *);
102
103 int harmony_halt_output(void *);
104 int harmony_halt_input(void *);
105 int harmony_getdev(void *, struct audio_device *);
106 int harmony_set_port(void *, mixer_ctrl_t *);
107 int harmony_get_port(void *, mixer_ctrl_t *);
108 int harmony_query_devinfo(void *, mixer_devinfo_t *);
109 void * harmony_allocm(void *, int, size_t);
110 void harmony_freem(void *, void *, size_t);
111 size_t harmony_round_buffersize(void *, int, size_t);
112 int harmony_get_props(void *);
113 int harmony_trigger_output(void *, void *, void *, int,
114 void (*)(void *), void *, const audio_params_t *);
115 int harmony_trigger_input(void *, void *, void *, int,
116 void (*)(void *), void *, const audio_params_t *);
117 void harmony_get_locks(void *, kmutex_t **, kmutex_t **);
118
119 const struct audio_hw_if harmony_sa_hw_if = {
120 harmony_open,
121 harmony_close,
122 NULL,
123 harmony_query_encoding,
124 harmony_set_params,
125 harmony_round_blocksize,
126 harmony_commit_settings,
127 NULL,
128 NULL,
129 NULL,
130 NULL,
131 harmony_halt_output,
132 harmony_halt_input,
133 NULL,
134 harmony_getdev,
135 NULL,
136 harmony_set_port,
137 harmony_get_port,
138 harmony_query_devinfo,
139 harmony_allocm,
140 harmony_freem,
141 harmony_round_buffersize,
142 NULL,
143 harmony_get_props,
144 harmony_trigger_output,
145 harmony_trigger_input,
146 NULL,
147 harmony_get_locks,
148 };
149
150 int harmony_match(device_t, struct cfdata *, void *);
151 void harmony_attach(device_t, device_t, void *);
152
153
154 CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc),
155 harmony_match, harmony_attach, NULL, NULL);
156
157 int harmony_intr(void *);
158 void harmony_intr_enable(struct harmony_softc *);
159 void harmony_intr_disable(struct harmony_softc *);
160 uint32_t harmony_speed_bits(struct harmony_softc *, u_int *);
161 int harmony_set_gainctl(struct harmony_softc *);
162 void harmony_reset_codec(struct harmony_softc *);
163 void harmony_start_cp(struct harmony_softc *, int);
164 void harmony_start_pp(struct harmony_softc *, int);
165 void harmony_tick_pb(void *);
166 void harmony_tick_cp(void *);
167 void harmony_try_more(struct harmony_softc *, int, int,
168 struct harmony_channel *);
169 static void harmony_empty_input(struct harmony_softc *);
170 static void harmony_empty_output(struct harmony_softc *);
171
172 void harmony_acc_tmo(void *);
173 #define ADD_CLKALLICA(sc) do { \
174 (sc)->sc_acc <<= 1; \
175 (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \
176 if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \
177 rnd_add_uint32(&(sc)->sc_rnd_source, \
178 (sc)->sc_acc_num ^= (sc)->sc_acc); \
179 } while(0)
180
181 int
182 harmony_match(device_t parent, struct cfdata *match, void *aux)
183 {
184 struct gsc_attach_args *ga;
185
186 ga = aux;
187 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
188 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
189 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
190 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
191 ga->ga_type.iodc_sv_model == HPPA_FIO_A2)
192 return 1;
193 }
194 return 0;
195 }
196
197 void
198 harmony_attach(device_t parent, device_t self, void *aux)
199 {
200 struct harmony_softc *sc = device_private(self);
201 struct gsc_attach_args *ga;
202 uint8_t rev;
203 uint32_t cntl;
204 int i;
205
206 sc->sc_dv = self;
207 ga = aux;
208 sc->sc_bt = ga->ga_iot;
209 sc->sc_dmat = ga->ga_dmatag;
210
211 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
212 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
213
214 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
215 &sc->sc_bh) != 0) {
216 aprint_error(": couldn't map registers\n");
217 return;
218 }
219
220 cntl = READ_REG(sc, HARMONY_ID);
221 switch ((cntl & ID_REV_MASK)) {
222 case ID_REV_TS:
223 sc->sc_teleshare = 1;
224 case ID_REV_NOTS:
225 break;
226 default:
227 aprint_error(": unknown id == 0x%02x\n",
228 (cntl & ID_REV_MASK) >> ID_REV_SHIFT);
229 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
230 return;
231 }
232
233 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
234 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
235 BUS_DMA_WAITOK) != 0) {
236 aprint_error(": could not alloc DMA memory\n");
237 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
238 return;
239 }
240 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
241 sizeof(struct harmony_empty), (void **)&sc->sc_empty_kva,
242 BUS_DMA_WAITOK) != 0) {
243 aprint_error(": couldn't map DMA memory\n");
244 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
245 sc->sc_empty_rseg);
246 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
247 return;
248 }
249 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
250 sizeof(struct harmony_empty), 0, BUS_DMA_WAITOK,
251 &sc->sc_empty_map) != 0) {
252 aprint_error(": can't create DMA map\n");
253 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
254 sizeof(struct harmony_empty));
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_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
261 sizeof(struct harmony_empty), NULL, BUS_DMA_WAITOK) != 0) {
262 aprint_error(": can't load DMA map\n");
263 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
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
272 sc->sc_playback_empty = 0;
273 for (i = 0; i < PLAYBACK_EMPTYS; i++)
274 sc->sc_playback_paddrs[i] =
275 sc->sc_empty_map->dm_segs[0].ds_addr +
276 offsetof(struct harmony_empty, playback[i][0]);
277
278 sc->sc_capture_empty = 0;
279 for (i = 0; i < CAPTURE_EMPTYS; i++)
280 sc->sc_capture_paddrs[i] =
281 sc->sc_empty_map->dm_segs[0].ds_addr +
282 offsetof(struct harmony_empty, capture[i][0]);
283
284 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
285 offsetof(struct harmony_empty, playback[0][0]),
286 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
287
288 (void) hppa_intr_establish(IPL_AUDIO, harmony_intr, sc, ga->ga_ir,
289 ga->ga_irq);
290
291 /* set defaults */
292 sc->sc_in_port = HARMONY_IN_LINE;
293 sc->sc_out_port = HARMONY_OUT_SPEAKER;
294 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
295 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
296 sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
297 sc->sc_outputgain = 0;
298
299 /* reset chip, and push default gain controls */
300 harmony_reset_codec(sc);
301
302 cntl = READ_REG(sc, HARMONY_CNTL);
303 rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
304 aprint_normal(": rev %u", rev);
305
306 if (sc->sc_teleshare)
307 printf(", teleshare");
308 aprint_normal("\n");
309
310 if ((rev & CS4215_REV_VER) >= CS4215_REV_VER_E)
311 sc->sc_hasulinear8 = 1;
312
313 strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name));
314 snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version,
315 "%u.%u;%u", ga->ga_type.iodc_sv_rev,
316 ga->ga_type.iodc_model, ga->ga_type.iodc_revision);
317 strlcpy(sc->sc_audev.config, device_xname(sc->sc_dv),
318 sizeof(sc->sc_audev.config));
319
320 audio_attach_mi(&harmony_sa_hw_if, sc, sc->sc_dv);
321
322 rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
323 RND_TYPE_UNKNOWN, RND_FLAG_DEFAULT);
324
325 callout_init(&sc->sc_acc_tmo, 0);
326 callout_setfunc(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
327 sc->sc_acc_num = 0xa5a5a5a5;
328 }
329
330 void
331 harmony_reset_codec(struct harmony_softc *sc)
332 {
333
334 /* silence */
335 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
336 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
337
338 /* start reset */
339 WRITE_REG(sc, HARMONY_RESET, RESET_RST);
340
341 DELAY(100000); /* wait at least 0.05 sec */
342
343 harmony_set_gainctl(sc);
344 WRITE_REG(sc, HARMONY_RESET, 0);
345 }
346
347 void
348 harmony_acc_tmo(void *v)
349 {
350 struct harmony_softc *sc;
351
352 sc = v;
353 ADD_CLKALLICA(sc);
354 callout_schedule(&sc->sc_acc_tmo, 1);
355 }
356
357 /*
358 * interrupt handler
359 */
360 int
361 harmony_intr(void *vsc)
362 {
363 struct harmony_softc *sc;
364 uint32_t dstatus;
365 int r;
366
367 sc = vsc;
368 r = 0;
369 ADD_CLKALLICA(sc);
370
371 mutex_spin_enter(&sc->sc_intr_lock);
372
373 harmony_intr_disable(sc);
374
375 dstatus = READ_REG(sc, HARMONY_DSTATUS);
376
377 if (dstatus & DSTATUS_PN) {
378 r = 1;
379 harmony_start_pp(sc, 0);
380 }
381
382 if (dstatus & DSTATUS_RN) {
383 r = 1;
384 harmony_start_cp(sc, 0);
385 }
386
387 if (READ_REG(sc, HARMONY_OV) & OV_OV) {
388 sc->sc_ov = 1;
389 WRITE_REG(sc, HARMONY_OV, 0);
390 } else
391 sc->sc_ov = 0;
392
393 harmony_intr_enable(sc);
394
395 mutex_spin_exit(&sc->sc_intr_lock);
396
397 return r;
398 }
399
400 void
401 harmony_intr_enable(struct harmony_softc *sc)
402 {
403
404 WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
405 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
406 }
407
408 void
409 harmony_intr_disable(struct harmony_softc *sc)
410 {
411
412 WRITE_REG(sc, HARMONY_DSTATUS, 0);
413 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
414 }
415
416 int
417 harmony_open(void *vsc, int flags)
418 {
419 struct harmony_softc *sc;
420
421 sc = vsc;
422 if (sc->sc_open)
423 return EBUSY;
424 sc->sc_open = 1;
425 return 0;
426 }
427
428 void
429 harmony_close(void *vsc)
430 {
431 struct harmony_softc *sc;
432
433 sc = vsc;
434 harmony_halt_input(sc);
435 harmony_halt_output(sc);
436 harmony_intr_disable(sc);
437 sc->sc_open = 0;
438 }
439
440 int
441 harmony_query_encoding(void *vsc, struct audio_encoding *fp)
442 {
443 struct harmony_softc *sc;
444 int err;
445
446 sc = vsc;
447 err = 0;
448 switch (fp->index) {
449 case 0:
450 strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
451 fp->encoding = AUDIO_ENCODING_ULAW;
452 fp->precision = 8;
453 fp->flags = 0;
454 break;
455 case 1:
456 strlcpy(fp->name, AudioEalaw, sizeof fp->name);
457 fp->encoding = AUDIO_ENCODING_ALAW;
458 fp->precision = 8;
459 fp->flags = 0;
460 break;
461 case 2:
462 strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
463 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
464 fp->precision = 16;
465 fp->flags = 0;
466 break;
467 case 3:
468 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
469 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
470 fp->precision = 16;
471 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
472 break;
473 case 4:
474 strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
475 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
476 fp->precision = 16;
477 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
478 break;
479 case 5:
480 strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
481 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
482 fp->precision = 16;
483 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
484 break;
485 case 6:
486 if (sc->sc_hasulinear8) {
487 strlcpy(fp->name, AudioEulinear, sizeof fp->name);
488 fp->encoding = AUDIO_ENCODING_ULINEAR;
489 fp->precision = 8;
490 fp->flags = 0;
491 break;
492 }
493 /*FALLTHROUGH*/
494 case 7:
495 if (sc->sc_hasulinear8) {
496 strlcpy(fp->name, AudioEslinear, sizeof fp->name);
497 fp->encoding = AUDIO_ENCODING_SLINEAR;
498 fp->precision = 8;
499 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
500 break;
501 }
502 /*FALLTHROUGH*/
503 default:
504 err = EINVAL;
505 }
506 return err;
507 }
508
509 int
510 harmony_set_params(void *vsc, int setmode, int usemode,
511 audio_params_t *p, audio_params_t *r,
512 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
513 {
514 audio_params_t hw;
515 struct harmony_softc *sc;
516 uint32_t bits;
517 stream_filter_factory_t *pswcode = NULL;
518 stream_filter_factory_t *rswcode = NULL;
519
520 sc = vsc;
521 /* assume p.equals(r) */
522 hw = *p;
523 switch (p->encoding) {
524 case AUDIO_ENCODING_ULAW:
525 if (p->precision != 8)
526 return EINVAL;
527 bits = CNTL_FORMAT_ULAW;
528 break;
529 case AUDIO_ENCODING_ALAW:
530 if (p->precision != 8)
531 return EINVAL;
532 bits = CNTL_FORMAT_ALAW;
533 break;
534 case AUDIO_ENCODING_SLINEAR_BE:
535 if (p->precision == 8) {
536 bits = CNTL_FORMAT_ULINEAR8;
537 hw.encoding = AUDIO_ENCODING_ULINEAR_LE;
538 rswcode = pswcode = change_sign8;
539 break;
540 }
541 if (p->precision == 16) {
542 bits = CNTL_FORMAT_SLINEAR16BE;
543 break;
544 }
545 return EINVAL;
546 case AUDIO_ENCODING_ULINEAR:
547 if (p->precision != 8)
548 return EINVAL;
549 bits = CNTL_FORMAT_ULINEAR8;
550 break;
551 case AUDIO_ENCODING_SLINEAR:
552 if (p->precision != 8)
553 return EINVAL;
554 bits = CNTL_FORMAT_ULINEAR8;
555 hw.encoding = AUDIO_ENCODING_ULINEAR_LE;
556 rswcode = pswcode = change_sign8;
557 break;
558 case AUDIO_ENCODING_SLINEAR_LE:
559 if (p->precision == 8) {
560 bits = CNTL_FORMAT_ULINEAR8;
561 hw.encoding = AUDIO_ENCODING_ULINEAR_LE;
562 rswcode = pswcode = change_sign8;
563 break;
564 }
565 if (p->precision == 16) {
566 bits = CNTL_FORMAT_SLINEAR16BE;
567 hw.encoding = AUDIO_ENCODING_SLINEAR_BE;
568 rswcode = pswcode = swap_bytes;
569 break;
570 }
571 return EINVAL;
572 case AUDIO_ENCODING_ULINEAR_BE:
573 if (p->precision == 8) {
574 bits = CNTL_FORMAT_ULINEAR8;
575 break;
576 }
577 if (p->precision == 16) {
578 bits = CNTL_FORMAT_SLINEAR16BE;
579 rswcode = pswcode = change_sign16;
580 break;
581 }
582 return EINVAL;
583 case AUDIO_ENCODING_ULINEAR_LE:
584 if (p->precision == 8) {
585 bits = CNTL_FORMAT_ULINEAR8;
586 break;
587 }
588 if (p->precision == 16) {
589 bits = CNTL_FORMAT_SLINEAR16BE;
590 hw.encoding = AUDIO_ENCODING_SLINEAR_BE;
591 rswcode = pswcode = swap_bytes_change_sign16;
592 break;
593 }
594 return EINVAL;
595 default:
596 return EINVAL;
597 }
598
599 if (sc->sc_outputgain)
600 bits |= CNTL_OLB;
601
602 if (p->channels == 1)
603 bits |= CNTL_CHANS_MONO;
604 else if (p->channels == 2)
605 bits |= CNTL_CHANS_STEREO;
606 else
607 return EINVAL;
608
609 bits |= harmony_speed_bits(sc, &p->sample_rate);
610 if (pswcode != NULL)
611 pfil->append(pfil, pswcode, &hw);
612 if (rswcode != NULL)
613 rfil->append(rfil, rswcode, &hw);
614 sc->sc_cntlbits = bits;
615 sc->sc_need_commit = 1;
616
617 return 0;
618 }
619
620 int
621 harmony_round_blocksize(void *vsc, int blk,
622 int mode, const audio_params_t *param)
623 {
624
625 return HARMONY_BUFSIZE;
626 }
627
628 int
629 harmony_control_wait(struct harmony_softc *sc)
630 {
631 uint32_t reg;
632 int j = 0;
633
634 while (j < 10) {
635 /* Wait for it to come out of control mode */
636 reg = READ_REG(sc, HARMONY_CNTL);
637 if ((reg & CNTL_C) == 0)
638 return 0;
639 DELAY(50000); /* wait 0.05 */
640 j++;
641 }
642
643 return 1;
644 }
645
646 int
647 harmony_commit_settings(void *vsc)
648 {
649 struct harmony_softc *sc;
650 uint32_t reg;
651 uint8_t quietchar;
652 int i;
653
654 sc = vsc;
655 if (sc->sc_need_commit == 0)
656 return 0;
657
658 harmony_intr_disable(sc);
659
660 for (;;) {
661 reg = READ_REG(sc, HARMONY_DSTATUS);
662 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
663 break;
664 }
665
666 /* Setting some bits in gainctl requires a reset */
667 harmony_reset_codec(sc);
668
669 /* set the silence character based on the encoding type */
670 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
671 offsetof(struct harmony_empty, playback[0][0]),
672 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
673 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
674 case CNTL_FORMAT_ULAW:
675 quietchar = 0x7f;
676 break;
677 case CNTL_FORMAT_ALAW:
678 quietchar = 0x55;
679 break;
680 case CNTL_FORMAT_SLINEAR16BE:
681 case CNTL_FORMAT_ULINEAR8:
682 default:
683 quietchar = 0;
684 break;
685 }
686 for (i = 0; i < PLAYBACK_EMPTYS; i++)
687 memset(&sc->sc_empty_kva->playback[i][0],
688 quietchar, HARMONY_BUFSIZE);
689 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
690 offsetof(struct harmony_empty, playback[0][0]),
691 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
692
693 harmony_control_wait(sc);
694
695 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
696 sc->sc_cntlbits | CNTL_C);
697
698 harmony_control_wait(sc);
699
700 sc->sc_need_commit = 0;
701
702 if (sc->sc_playing || sc->sc_capturing)
703 harmony_intr_enable(sc);
704
705 return 0;
706 }
707
708 static void
709 harmony_empty_output(struct harmony_softc *sc)
710 {
711
712 WRITE_REG(sc, HARMONY_PNXTADD,
713 sc->sc_playback_paddrs[sc->sc_playback_empty]);
714 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
715
716 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS)
717 sc->sc_playback_empty = 0;
718 }
719
720 int
721 harmony_halt_output(void *vsc)
722 {
723 struct harmony_softc *sc;
724
725 sc = vsc;
726 sc->sc_playing = 0;
727
728 harmony_empty_output(sc);
729 return 0;
730 }
731
732 static void
733 harmony_empty_input(struct harmony_softc *sc)
734 {
735
736 WRITE_REG(sc, HARMONY_RNXTADD,
737 sc->sc_capture_paddrs[sc->sc_capture_empty]);
738 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
739
740 if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
741 sc->sc_capture_empty = 0;
742 }
743
744 int
745 harmony_halt_input(void *vsc)
746 {
747 struct harmony_softc *sc;
748
749 sc = vsc;
750 sc->sc_capturing = 0;
751
752 harmony_empty_input(sc);
753 return 0;
754 }
755
756 int
757 harmony_getdev(void *vsc, struct audio_device *retp)
758 {
759 struct harmony_softc *sc;
760
761 sc = vsc;
762 *retp = sc->sc_audev;
763 return 0;
764 }
765
766 int
767 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
768 {
769 struct harmony_softc *sc;
770 int err;
771
772 sc = vsc;
773 err = EINVAL;
774 switch (cp->dev) {
775 case HARMONY_PORT_INPUT_LVL:
776 if (cp->type != AUDIO_MIXER_VALUE)
777 break;
778 if (cp->un.value.num_channels == 1)
779 sc->sc_input_lvl.left = sc->sc_input_lvl.right =
780 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
781 else if (cp->un.value.num_channels == 2) {
782 sc->sc_input_lvl.left =
783 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
784 sc->sc_input_lvl.right =
785 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
786 } else
787 break;
788 sc->sc_need_commit = 1;
789 err = 0;
790 break;
791 case HARMONY_PORT_OUTPUT_LVL:
792 if (cp->type != AUDIO_MIXER_VALUE)
793 break;
794 if (cp->un.value.num_channels == 1)
795 sc->sc_output_lvl.left = sc->sc_output_lvl.right =
796 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
797 else if (cp->un.value.num_channels == 2) {
798 sc->sc_output_lvl.left =
799 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
800 sc->sc_output_lvl.right =
801 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
802 } else
803 break;
804 sc->sc_need_commit = 1;
805 err = 0;
806 break;
807 case HARMONY_PORT_OUTPUT_GAIN:
808 if (cp->type != AUDIO_MIXER_ENUM)
809 break;
810 sc->sc_outputgain = cp->un.ord ? 1 : 0;
811 err = 0;
812 break;
813 case HARMONY_PORT_MONITOR_LVL:
814 if (cp->type != AUDIO_MIXER_VALUE)
815 break;
816 if (cp->un.value.num_channels != 1)
817 break;
818 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
819 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
820 sc->sc_need_commit = 1;
821 err = 0;
822 break;
823 case HARMONY_PORT_RECORD_SOURCE:
824 if (cp->type != AUDIO_MIXER_ENUM)
825 break;
826 if (cp->un.ord != HARMONY_IN_LINE &&
827 cp->un.ord != HARMONY_IN_MIC)
828 break;
829 sc->sc_in_port = cp->un.ord;
830 err = 0;
831 sc->sc_need_commit = 1;
832 break;
833 case HARMONY_PORT_OUTPUT_SOURCE:
834 if (cp->type != AUDIO_MIXER_ENUM)
835 break;
836 if (cp->un.ord != HARMONY_OUT_LINE &&
837 cp->un.ord != HARMONY_OUT_SPEAKER &&
838 cp->un.ord != HARMONY_OUT_HEADPHONE)
839 break;
840 sc->sc_out_port = cp->un.ord;
841 err = 0;
842 sc->sc_need_commit = 1;
843 break;
844 }
845
846 return err;
847 }
848
849 int
850 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
851 {
852 struct harmony_softc *sc;
853 int err;
854
855 sc = vsc;
856 err = EINVAL;
857 switch (cp->dev) {
858 case HARMONY_PORT_INPUT_LVL:
859 if (cp->type != AUDIO_MIXER_VALUE)
860 break;
861 if (cp->un.value.num_channels == 1) {
862 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
863 sc->sc_input_lvl.left;
864 } else if (cp->un.value.num_channels == 2) {
865 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
866 sc->sc_input_lvl.left;
867 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
868 sc->sc_input_lvl.right;
869 } else
870 break;
871 err = 0;
872 break;
873 case HARMONY_PORT_INPUT_OV:
874 if (cp->type != AUDIO_MIXER_ENUM)
875 break;
876 cp->un.ord = sc->sc_ov ? 1 : 0;
877 err = 0;
878 break;
879 case HARMONY_PORT_OUTPUT_LVL:
880 if (cp->type != AUDIO_MIXER_VALUE)
881 break;
882 if (cp->un.value.num_channels == 1) {
883 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
884 sc->sc_output_lvl.left;
885 } else if (cp->un.value.num_channels == 2) {
886 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
887 sc->sc_output_lvl.left;
888 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
889 sc->sc_output_lvl.right;
890 } else
891 break;
892 err = 0;
893 break;
894 case HARMONY_PORT_OUTPUT_GAIN:
895 if (cp->type != AUDIO_MIXER_ENUM)
896 break;
897 cp->un.ord = sc->sc_outputgain ? 1 : 0;
898 err = 0;
899 break;
900 case HARMONY_PORT_MONITOR_LVL:
901 if (cp->type != AUDIO_MIXER_VALUE)
902 break;
903 if (cp->un.value.num_channels != 1)
904 break;
905 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
906 sc->sc_monitor_lvl.left;
907 err = 0;
908 break;
909 case HARMONY_PORT_RECORD_SOURCE:
910 if (cp->type != AUDIO_MIXER_ENUM)
911 break;
912 cp->un.ord = sc->sc_in_port;
913 err = 0;
914 break;
915 case HARMONY_PORT_OUTPUT_SOURCE:
916 if (cp->type != AUDIO_MIXER_ENUM)
917 break;
918 cp->un.ord = sc->sc_out_port;
919 err = 0;
920 break;
921 }
922 return err;
923 }
924
925 int
926 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
927 {
928 int err;
929
930 err = 0;
931 switch (dip->index) {
932 case HARMONY_PORT_INPUT_LVL:
933 dip->type = AUDIO_MIXER_VALUE;
934 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
935 dip->prev = dip->next = AUDIO_MIXER_LAST;
936 strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
937 dip->un.v.num_channels = 2;
938 strlcpy(dip->un.v.units.name, AudioNvolume,
939 sizeof dip->un.v.units.name);
940 break;
941 case HARMONY_PORT_INPUT_OV:
942 dip->type = AUDIO_MIXER_ENUM;
943 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
944 dip->prev = dip->next = AUDIO_MIXER_LAST;
945 strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
946 dip->un.e.num_mem = 2;
947 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
948 sizeof dip->un.e.member[0].label.name);
949 dip->un.e.member[0].ord = 0;
950 strlcpy(dip->un.e.member[1].label.name, AudioNon,
951 sizeof dip->un.e.member[1].label.name);
952 dip->un.e.member[1].ord = 1;
953 break;
954 case HARMONY_PORT_OUTPUT_LVL:
955 dip->type = AUDIO_MIXER_VALUE;
956 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
957 dip->prev = dip->next = AUDIO_MIXER_LAST;
958 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
959 dip->un.v.num_channels = 2;
960 strlcpy(dip->un.v.units.name, AudioNvolume,
961 sizeof dip->un.v.units.name);
962 break;
963 case HARMONY_PORT_OUTPUT_GAIN:
964 dip->type = AUDIO_MIXER_ENUM;
965 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
966 dip->prev = dip->next = AUDIO_MIXER_LAST;
967 strlcpy(dip->label.name, "gain", sizeof dip->label.name);
968 dip->un.e.num_mem = 2;
969 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
970 sizeof dip->un.e.member[0].label.name);
971 dip->un.e.member[0].ord = 0;
972 strlcpy(dip->un.e.member[1].label.name, AudioNon,
973 sizeof dip->un.e.member[1].label.name);
974 dip->un.e.member[1].ord = 1;
975 break;
976 case HARMONY_PORT_MONITOR_LVL:
977 dip->type = AUDIO_MIXER_VALUE;
978 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
979 dip->prev = dip->next = AUDIO_MIXER_LAST;
980 strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
981 dip->un.v.num_channels = 1;
982 strlcpy(dip->un.v.units.name, AudioNvolume,
983 sizeof dip->un.v.units.name);
984 break;
985 case HARMONY_PORT_RECORD_SOURCE:
986 dip->type = AUDIO_MIXER_ENUM;
987 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
988 dip->prev = dip->next = AUDIO_MIXER_LAST;
989 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
990 dip->un.e.num_mem = 2;
991 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
992 sizeof dip->un.e.member[0].label.name);
993 dip->un.e.member[0].ord = HARMONY_IN_MIC;
994 strlcpy(dip->un.e.member[1].label.name, AudioNline,
995 sizeof dip->un.e.member[1].label.name);
996 dip->un.e.member[1].ord = HARMONY_IN_LINE;
997 break;
998 case HARMONY_PORT_OUTPUT_SOURCE:
999 dip->type = AUDIO_MIXER_ENUM;
1000 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
1001 dip->prev = dip->next = AUDIO_MIXER_LAST;
1002 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1003 dip->un.e.num_mem = 3;
1004 strlcpy(dip->un.e.member[0].label.name, AudioNline,
1005 sizeof dip->un.e.member[0].label.name);
1006 dip->un.e.member[0].ord = HARMONY_OUT_LINE;
1007 strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
1008 sizeof dip->un.e.member[1].label.name);
1009 dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
1010 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
1011 sizeof dip->un.e.member[2].label.name);
1012 dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
1013 break;
1014 case HARMONY_PORT_INPUT_CLASS:
1015 dip->type = AUDIO_MIXER_CLASS;
1016 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
1017 dip->prev = dip->next = AUDIO_MIXER_LAST;
1018 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1019 break;
1020 case HARMONY_PORT_OUTPUT_CLASS:
1021 dip->type = AUDIO_MIXER_CLASS;
1022 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
1023 dip->prev = dip->next = AUDIO_MIXER_LAST;
1024 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
1025 break;
1026 case HARMONY_PORT_MONITOR_CLASS:
1027 dip->type = AUDIO_MIXER_CLASS;
1028 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
1029 dip->prev = dip->next = AUDIO_MIXER_LAST;
1030 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
1031 break;
1032 case HARMONY_PORT_RECORD_CLASS:
1033 dip->type = AUDIO_MIXER_CLASS;
1034 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
1035 dip->prev = dip->next = AUDIO_MIXER_LAST;
1036 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1037 break;
1038 default:
1039 err = ENXIO;
1040 break;
1041 }
1042
1043 return err;
1044 }
1045
1046 void *
1047 harmony_allocm(void *vsc, int dir, size_t size)
1048 {
1049 struct harmony_softc *sc;
1050 struct harmony_dma *d;
1051 int rseg;
1052
1053 sc = vsc;
1054 d = kmem_alloc(sizeof(*d), KM_SLEEP);
1055 if (d == NULL)
1056 goto fail;
1057
1058 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK,
1059 &d->d_map) != 0)
1060 goto fail1;
1061
1062 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
1063 &rseg, BUS_DMA_WAITOK) != 0)
1064 goto fail2;
1065
1066 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
1067 BUS_DMA_WAITOK) != 0)
1068 goto fail3;
1069
1070 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
1071 BUS_DMA_WAITOK) != 0)
1072 goto fail4;
1073
1074 d->d_next = sc->sc_dmas;
1075 sc->sc_dmas = d;
1076 d->d_size = size;
1077 return (d->d_kva);
1078
1079 fail4:
1080 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
1081 fail3:
1082 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
1083 fail2:
1084 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
1085 fail1:
1086 kmem_free(d, sizeof(*d));
1087 fail:
1088 return (NULL);
1089 }
1090
1091 void
1092 harmony_freem(void *vsc, void *ptr, size_t size)
1093 {
1094 struct harmony_softc *sc;
1095 struct harmony_dma *d, **dd;
1096
1097 sc = vsc;
1098 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
1099 if (d->d_kva != ptr)
1100 continue;
1101 bus_dmamap_unload(sc->sc_dmat, d->d_map);
1102 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
1103 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
1104 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
1105 kmem_free(d, sizeof(*d));
1106 return;
1107 }
1108 printf("%s: free rogue pointer\n", device_xname(sc->sc_dv));
1109 }
1110
1111 size_t
1112 harmony_round_buffersize(void *vsc, int direction, size_t size)
1113 {
1114
1115 return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
1116 }
1117
1118 int
1119 harmony_get_props(void *vsc)
1120 {
1121
1122 return AUDIO_PROP_FULLDUPLEX;
1123 }
1124
1125 void
1126 harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread)
1127 {
1128 struct harmony_softc *sc;
1129
1130 sc = vsc;
1131 *intr = &sc->sc_intr_lock;
1132 *thread = &sc->sc_lock;
1133 }
1134
1135 int
1136 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
1137 void (*intr)(void *), void *intrarg, const audio_params_t *param)
1138 {
1139 struct harmony_softc *sc;
1140 struct harmony_channel *c;
1141 struct harmony_dma *d;
1142
1143 sc = vsc;
1144 c = &sc->sc_playback;
1145 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1146 continue;
1147 if (d == NULL) {
1148 printf("%s: trigger_output: bad addr: %p\n",
1149 device_xname(sc->sc_dv), start);
1150 return EINVAL;
1151 }
1152
1153 mutex_spin_enter(&sc->sc_intr_lock);
1154
1155 c->c_intr = intr;
1156 c->c_intrarg = intrarg;
1157 c->c_blksz = blksize;
1158 c->c_current = d;
1159 c->c_segsz = (char *)end - (char *)start;
1160 c->c_cnt = 0;
1161 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1162
1163 sc->sc_playing = 1;
1164
1165 harmony_start_pp(sc, 1);
1166 harmony_start_cp(sc, 0);
1167 harmony_intr_enable(sc);
1168
1169 mutex_spin_exit(&sc->sc_intr_lock);
1170
1171 return 0;
1172 }
1173
1174 void
1175 harmony_start_cp(struct harmony_softc *sc, int start)
1176 {
1177 struct harmony_channel *c;
1178 struct harmony_dma *d;
1179 bus_addr_t nextaddr;
1180 bus_size_t togo;
1181
1182 KASSERT(mutex_owned(&sc->sc_intr_lock));
1183
1184 c = &sc->sc_capture;
1185 if (sc->sc_capturing == 0)
1186 harmony_empty_input(sc);
1187 else {
1188 d = c->c_current;
1189 togo = c->c_segsz - c->c_cnt;
1190 if (togo == 0) {
1191 nextaddr = d->d_map->dm_segs[0].ds_addr;
1192 c->c_cnt = togo = c->c_blksz;
1193 } else {
1194 nextaddr = c->c_lastaddr;
1195 if (togo > c->c_blksz)
1196 togo = c->c_blksz;
1197 c->c_cnt += togo;
1198 }
1199
1200 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1201 nextaddr - d->d_map->dm_segs[0].ds_addr,
1202 c->c_blksz, BUS_DMASYNC_PREWRITE);
1203
1204 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
1205 if (start)
1206 c->c_theaddr = nextaddr;
1207 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
1208 c->c_lastaddr = nextaddr + togo;
1209
1210 harmony_try_more(sc, HARMONY_RCURADD,
1211 RCURADD_BUFMASK, &sc->sc_capture);
1212 }
1213
1214 callout_schedule(&sc->sc_acc_tmo, 1);
1215 }
1216
1217 void
1218 harmony_start_pp(struct harmony_softc *sc, int start)
1219 {
1220 struct harmony_channel *c;
1221 struct harmony_dma *d;
1222 bus_addr_t nextaddr;
1223 bus_size_t togo;
1224
1225 KASSERT(mutex_owned(&sc->sc_intr_lock));
1226
1227 c = &sc->sc_playback;
1228 if (sc->sc_playing == 0)
1229 harmony_empty_output(sc);
1230 else {
1231 d = c->c_current;
1232 togo = c->c_segsz - c->c_cnt;
1233 if (togo == 0) {
1234 nextaddr = d->d_map->dm_segs[0].ds_addr;
1235 c->c_cnt = togo = c->c_blksz;
1236 } else {
1237 nextaddr = c->c_lastaddr;
1238 if (togo > c->c_blksz)
1239 togo = c->c_blksz;
1240 c->c_cnt += togo;
1241 }
1242
1243 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1244 nextaddr - d->d_map->dm_segs[0].ds_addr,
1245 c->c_blksz, BUS_DMASYNC_PREWRITE);
1246
1247 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
1248 if (start)
1249 c->c_theaddr = nextaddr;
1250 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
1251 c->c_lastaddr = nextaddr + togo;
1252
1253 harmony_try_more(sc, HARMONY_PCURADD,
1254 PCURADD_BUFMASK, &sc->sc_playback);
1255 }
1256 }
1257
1258 int
1259 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
1260 void (*intr)(void *), void *intrarg, const audio_params_t *param)
1261 {
1262 struct harmony_softc *sc = vsc;
1263 struct harmony_channel *c = &sc->sc_capture;
1264 struct harmony_dma *d;
1265
1266 KASSERT(mutex_owned(&sc->sc_intr_lock));
1267
1268 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1269 continue;
1270 if (d == NULL) {
1271 printf("%s: trigger_input: bad addr: %p\n",
1272 device_xname(sc->sc_dv), start);
1273 return EINVAL;
1274 }
1275
1276 c->c_intr = intr;
1277 c->c_intrarg = intrarg;
1278 c->c_blksz = blksize;
1279 c->c_current = d;
1280 c->c_segsz = (char *)end - (char *)start;
1281 c->c_cnt = 0;
1282 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1283
1284 sc->sc_capturing = 1;
1285
1286 harmony_start_cp(sc, 1);
1287 harmony_intr_enable(sc);
1288
1289 return 0;
1290 }
1291
1292 static const struct speed_struct {
1293 uint32_t speed;
1294 uint32_t bits;
1295 } harmony_speeds[] = {
1296 { 5125, CNTL_RATE_5125 },
1297 { 6615, CNTL_RATE_6615 },
1298 { 8000, CNTL_RATE_8000 },
1299 { 9600, CNTL_RATE_9600 },
1300 { 11025, CNTL_RATE_11025 },
1301 { 16000, CNTL_RATE_16000 },
1302 { 18900, CNTL_RATE_18900 },
1303 { 22050, CNTL_RATE_22050 },
1304 { 27428, CNTL_RATE_27428 },
1305 { 32000, CNTL_RATE_32000 },
1306 { 33075, CNTL_RATE_33075 },
1307 { 37800, CNTL_RATE_37800 },
1308 { 44100, CNTL_RATE_44100 },
1309 { 48000, CNTL_RATE_48000 },
1310 };
1311
1312 uint32_t
1313 harmony_speed_bits(struct harmony_softc *sc, u_int *speedp)
1314 {
1315 int i, n, selected;
1316
1317 selected = -1;
1318 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
1319
1320 if ((*speedp) <= harmony_speeds[0].speed)
1321 selected = 0;
1322 else if ((*speedp) >= harmony_speeds[n - 1].speed)
1323 selected = n - 1;
1324 else {
1325 for (i = 1; selected == -1 && i < n; i++) {
1326 if ((*speedp) == harmony_speeds[i].speed)
1327 selected = i;
1328 else if ((*speedp) < harmony_speeds[i].speed) {
1329 int diff1, diff2;
1330
1331 diff1 = (*speedp) - harmony_speeds[i - 1].speed;
1332 diff2 = harmony_speeds[i].speed - (*speedp);
1333 if (diff1 < diff2)
1334 selected = i - 1;
1335 else
1336 selected = i;
1337 }
1338 }
1339 }
1340
1341 if (selected == -1)
1342 selected = 2;
1343
1344 *speedp = harmony_speeds[selected].speed;
1345 return harmony_speeds[selected].bits;
1346 }
1347
1348 int
1349 harmony_set_gainctl(struct harmony_softc *sc)
1350 {
1351 uint32_t bits, mask, val, old;
1352
1353 /* XXX leave these bits alone or the chip will not come out of CNTL */
1354 bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1355
1356 /* input level */
1357 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1358 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1359 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1360 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1361
1362 /* output level (inverted) */
1363 mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1364 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1365 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1366 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1367 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1368
1369 /* monitor level (inverted) */
1370 mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1371 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1372 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1373
1374 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1375 bits &= ~GAINCTL_IS_MASK;
1376 if (sc->sc_in_port == HARMONY_IN_MIC)
1377 bits |= GAINCTL_IS_LINE;
1378 else
1379 bits |= GAINCTL_IS_MICROPHONE;
1380
1381 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1382 bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1383 if (sc->sc_out_port == HARMONY_OUT_LINE)
1384 bits |= GAINCTL_LE;
1385 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1386 bits |= GAINCTL_SE;
1387 else
1388 bits |= GAINCTL_HE;
1389
1390 mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1391 old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1392 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1393 if ((old & mask) != (bits & mask))
1394 return 1;
1395 return 0;
1396 }
1397
1398 void
1399 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1400 struct harmony_channel *c)
1401 {
1402 struct harmony_dma *d;
1403 uint32_t cur;
1404 int i, nsegs;
1405
1406 d = c->c_current;
1407 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1408 cur &= bufmask;
1409 nsegs = 0;
1410
1411 #ifdef DIAGNOSTIC
1412 if (cur < d->d_map->dm_segs[0].ds_addr ||
1413 cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1414 panic("%s: bad current %x < %lx || %x > %lx",
1415 device_xname(sc->sc_dv), cur,
1416 d->d_map->dm_segs[0].ds_addr, cur,
1417 d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1418 #endif /* DIAGNOSTIC */
1419
1420 if (cur > c->c_theaddr) {
1421 nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1422 } else if (cur < c->c_theaddr) {
1423 nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1424 c->c_theaddr) / HARMONY_BUFSIZE;
1425 nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1426 HARMONY_BUFSIZE;
1427 }
1428
1429 if (nsegs != 0 && c->c_intr != NULL) {
1430 for (i = 0; i < nsegs; i++)
1431 (*c->c_intr)(c->c_intrarg);
1432 c->c_theaddr = cur;
1433 }
1434 }
1435