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