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