repulse.c revision 1.10 1 /* $NetBSD: repulse.c,v 1.10 2004/10/29 12:57:16 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ignatios Souvatzis.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: repulse.c,v 1.10 2004/10/29 12:57:16 yamt Exp $");
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/device.h>
47 #include <sys/fcntl.h> /* FREAD */
48
49 #include <machine/bus.h>
50
51 #include <sys/audioio.h>
52 #include <dev/audio_if.h>
53 #include <dev/mulaw.h>
54
55 #include <dev/ic/ac97reg.h>
56 #include <dev/ic/ac97var.h>
57
58 #include <amiga/dev/zbusvar.h>
59 #include <amiga/amiga/isr.h>
60
61 #include <amiga/dev/repulse_firmware.h>
62
63 #ifndef vu_int8_t
64 #define vu_int8_t volatile u_int8_t
65 #endif
66 #ifndef vu_int16_t
67 #define vu_int16_t volatile u_int16_t
68 #endif
69 #ifndef vu_int32_t
70 #define vu_int32_t volatile u_int32_t
71 #endif
72
73 /* ac97 attachment functions */
74
75 int repac_attach(void *, struct ac97_codec_if *);
76 int repac_read(void *, u_int8_t, u_int16_t *);
77 int repac_write(void *, u_int8_t, u_int16_t);
78 int repac_reset(void *);
79 enum ac97_host_flag repac_flags(void *);
80
81 /* audio attachment functions */
82
83 int rep_open(void *, int);
84 void rep_close(void *);
85 int rep_getdev(void *, struct audio_device *);
86 int rep_get_props(void *);
87 int rep_halt_output(void *);
88 int rep_halt_input(void *);
89 int rep_query_encoding(void *, struct audio_encoding *);
90 int rep_set_params(void *, int, int, struct audio_params *,
91 struct audio_params *);
92 int rep_round_blocksize(void *, int);
93 int rep_set_port(void *, mixer_ctrl_t *);
94 int rep_get_port(void *, mixer_ctrl_t *);
95 int rep_query_devinfo(void *, mixer_devinfo_t *);
96 size_t rep_round_buffersize(void *, int, size_t);
97
98 int rep_start_input(void *, void *, int, void (*)(void *), void *);
99 int rep_start_output(void *, void *, int, void (*)(void *), void *);
100
101 int rep_intr(void *tag);
102
103
104 /* audio attachment */
105
106 const struct audio_hw_if rep_hw_if = {
107 rep_open,
108 rep_close,
109 /* drain */ 0,
110 rep_query_encoding,
111 rep_set_params,
112 rep_round_blocksize,
113 /* commit_setting */ 0,
114 /* init_output */ 0,
115 /* init_input */ 0,
116 rep_start_output,
117 rep_start_input,
118 rep_halt_output,
119 rep_halt_input,
120 /* speaker_ctl */ 0,
121 rep_getdev,
122 /* getfd */ 0,
123 rep_set_port,
124 rep_get_port,
125 rep_query_devinfo,
126 /* allocm */ 0,
127 /* freem */ 0,
128 rep_round_buffersize,
129 /* mappage */ 0,
130 rep_get_props,
131 /* trigger_output */ 0,
132 /* trigger_input */ 0,
133 /* dev_ioctl */ 0,
134 };
135
136 /* hardware registers */
137
138 struct repulse_hw {
139 vu_int16_t rhw_status;
140 vu_int16_t rhw_fifostatus; /* 0xrrrrpppp0000flag */
141 vu_int16_t rhw_reg_address;
142 vu_int16_t rhw_reg_data;
143 /* 0x08 */
144 vu_int16_t rhw_fifo_lh;
145 vu_int16_t rhw_fifo_ll;
146 vu_int16_t rhw_fifo_rh;
147 vu_int16_t rhw_fifo_rl;
148 /* 0x10 */
149 vu_int16_t rhw_fifo_pack;
150 vu_int16_t rhw_play_fifosz;
151 vu_int32_t rhw_spdifin_stat;
152 #define rhw_spdifout_stat rhw_spdifin_stat;
153
154 /* 0x18 */
155 vu_int16_t rhw_capt_fifosz;
156 vu_int16_t rhw_version;
157 vu_int16_t rhw_dummy1;
158 vu_int8_t rhw_firmwareload;
159 /* 0x1F */
160 vu_int8_t rhw_dummy2[66 - 31];
161 /* 0x42 */
162 vu_int16_t rhw_reset;
163 } /* __attribute__((packed)) */;
164
165 #define REPSTATUS_PLAY 0x0001
166 #define REPSTATUS_RECORD 0x0002
167 #define REPSTATUS_PLAYFIFORST 0x0004
168 #define REPSTATUS_RECFIFORST 0x0008
169
170 #define REPSTATUS_REGSENDBUSY 0x0010
171 #define REPSTATUS_LOOPBACK 0x0020
172 #define REPSTATUS_ENSPDIFIN 0x0040
173 #define REPSTATUS_ENSPDIFOUT 0x0080
174
175 #define REPSTATUS_CODECRESET 0x0200
176 #define REPSTATUS_SPDIFOUT24 0x0400
177 #define REPSTATUS_SPDIFIN24 0x0800
178
179 #define REPSTATUS_RECIRQENABLE 0x1000
180 #define REPSTATUS_RECIRQACK 0x2000
181 #define REPSTATUS_PLAYIRQENABLE 0x4000
182 #define REPSTATUS_PLAYIRQACK 0x8000
183
184 #define REPFIFO_PLAYFIFOFULL 0x0001
185 #define REPFIFO_PLAYFIFOEMPTY 0x0002
186 #define REPFIFO_RECFIFOFULL 0x0004
187 #define REPFIFO_RECFIFOEMPTY 0x0008
188 #define REPFIFO_PLAYFIFOGAUGE(x) ((x << 4) & 0xf000)
189 #define REPFIFO_RECFIFOGAUGE(x) (x & 0xf000)
190
191 /* ac97 data stream transfer functions */
192 void rep_read_16_stereo(struct repulse_hw *, u_int8_t *, int, unsigned);
193 void rep_read_16_mono(struct repulse_hw *, u_int8_t *, int, unsigned);
194 void rep_write_16_stereo(struct repulse_hw *, u_int8_t *, int, unsigned);
195 void rep_write_16_mono(struct repulse_hw *, u_int8_t *, int, unsigned);
196 void rep_read_8_stereo(struct repulse_hw *, u_int8_t *, int, unsigned);
197 void rep_read_8_mono(struct repulse_hw *, u_int8_t *, int, unsigned);
198 void rep_write_8_stereo(struct repulse_hw *, u_int8_t *, int, unsigned);
199 void rep_write_8_mono(struct repulse_hw *, u_int8_t *, int, unsigned);
200
201 /* AmigaDOS Delay() ticks */
202
203 #define USECPERTICK (1000000/50)
204
205 /* NetBSD device attachment */
206
207 struct repulse_softc {
208 struct device sc_dev;
209 struct isr sc_isr;
210 struct ac97_host_if sc_achost;
211 struct ac97_codec_if *sc_codec_if;
212
213 struct repulse_hw *sc_boardp;
214
215 void (*sc_captmore)(void *);
216 void *sc_captarg;
217
218 void (*sc_captfun)(struct repulse_hw *, u_int8_t *, int, unsigned);
219 void *sc_captbuf;
220 int sc_captscale;
221 int sc_captbufsz;
222 unsigned sc_captflags;
223
224
225 void (*sc_playmore)(void *);
226 void *sc_playarg;
227 void (*sc_playfun)(struct repulse_hw *, u_int8_t *, int, unsigned);
228 int sc_playscale;
229 unsigned sc_playflags;
230
231 };
232
233 int repulse_match (struct device *, struct cfdata *, void *);
234 void repulse_attach (struct device *, struct device *, void *);
235
236 CFATTACH_DECL(repulse, sizeof(struct repulse_softc),
237 repulse_match, repulse_attach, NULL, NULL);
238
239 int
240 repulse_match(struct device *parent, struct cfdata *cfp, void *aux) {
241 struct zbus_args *zap;
242
243 zap = aux;
244
245 if (zap->manid != 0x4144)
246 return (0);
247
248 if (zap->prodid != 0)
249 return (0);
250
251 return (1);
252 }
253
254 void
255 repulse_attach(struct device *parent, struct device *self, void *aux) {
256 struct repulse_softc *sc;
257 struct zbus_args *zap;
258 struct repulse_hw *bp;
259 struct mixer_ctrl ctl;
260 u_int8_t *fwp;
261 int needs_firmware;
262 int i;
263
264 u_int16_t a;
265
266 sc = (struct repulse_softc *)self;
267 zap = aux;
268 bp = (struct repulse_hw *)zap->va;
269 sc->sc_boardp = bp;
270
271 needs_firmware = 0;
272 if (bp->rhw_fifostatus & 0x00f0)
273 needs_firmware = 1;
274 else {
275 bp->rhw_status = 0x000c;
276 if (bp->rhw_status != 0 || bp->rhw_fifostatus != 0x0f0a)
277 needs_firmware = 1;
278 }
279
280 printf(": ");
281 if (needs_firmware) {
282 printf("loading ");
283 bp->rhw_reset = 0;
284
285 delay(1 * USECPERTICK);
286
287 for (fwp = (u_int8_t *)repulse_firmware;
288 fwp < (repulse_firmware_size +
289 (u_int8_t *)repulse_firmware); fwp++)
290 bp->rhw_firmwareload = *fwp;
291
292 delay(1 * USECPERTICK);
293
294 if (bp->rhw_fifostatus & 0x00f0)
295 goto Initerr;
296
297 a = /* bp->rhw_status;
298 a |= */ REPSTATUS_CODECRESET;
299 bp->rhw_status = a;
300
301 a = bp->rhw_status;
302 if ((a & REPSTATUS_CODECRESET) == 0)
303 goto Initerr;
304
305 (void)bp->rhw_status;
306 (void)bp->rhw_status;
307 (void)bp->rhw_status;
308 a = bp->rhw_status;
309 a &= ~REPSTATUS_CODECRESET;
310 bp->rhw_status = a;
311 }
312
313 printf("firmware version 0x%x\n", bp->rhw_version);
314
315 sc->sc_achost.arg = sc;
316
317 sc->sc_achost.reset = repac_reset;
318 sc->sc_achost.read = repac_read;
319 sc->sc_achost.write = repac_write;
320 sc->sc_achost.attach = repac_attach;
321 sc->sc_achost.flags = 0;
322
323 if (ac97_attach(&sc->sc_achost)) {
324 printf("%s: error attaching codec\n", self->dv_xname);
325 return;
326 }
327
328 #ifdef DIAGNOSTIC
329 /*
330 * Print a warning if the codec doesn't support hardware variable
331 * rate audio. As the initial incarnations of the Repulse board
332 * are AC'97 2.1, it is epxected that we'll always have VRA.
333 */
334 /*
335 * XXX this should be a panic(). OTOH, audio codec speed is not
336 * important enough to do this.
337 */
338 a = sc->sc_codec_if->vtbl->get_extcaps(sc->sc_codec_if);
339 if (!(a & AC97_EXT_AUDIO_VRA)) {
340 printf("%s: warning: codec doesn't support "
341 "hardware AC'97 2.0 Variable Rate Audio\n",
342 sc->sc_dev.dv_xname);
343 }
344 #endif
345
346 /*
347 * from auvia.c: disable mutes ...
348 * XXX maybe this should happen in MI code?
349 */
350
351 for (i = 0; i < 5; i++) {
352 static struct {
353 char *class, *device;
354 } d[] = {
355 { AudioCoutputs, AudioNmaster},
356 { AudioCinputs, AudioNdac},
357 { AudioCinputs, AudioNcd},
358 { AudioCinputs, AudioNline},
359 { AudioCrecord, AudioNvolume},
360 };
361
362 ctl.type = AUDIO_MIXER_ENUM;
363 ctl.un.ord = 0;
364 ctl.dev = sc->sc_codec_if->vtbl->get_portnum_by_name(
365 sc->sc_codec_if, d[i].class, d[i].device, AudioNmute);
366 rep_set_port(sc, &ctl);
367 }
368
369 sc->sc_isr.isr_ipl = 2;
370 sc->sc_isr.isr_arg = sc;
371 sc->sc_isr.isr_intr = rep_intr;
372 add_isr(&sc->sc_isr);
373
374 audio_attach_mi(&rep_hw_if, sc, &sc->sc_dev);
375
376 return;
377
378 Initerr:
379 printf("\n%s: firmware not successfully loaded\n", self->dv_xname);
380 return;
381
382 }
383
384 int repac_reset(void *arg) {
385 struct repulse_softc *sc = arg;
386 struct repulse_hw *bp = sc->sc_boardp;
387
388 u_int16_t a;
389
390 a = bp->rhw_status;
391 a |= REPSTATUS_CODECRESET;
392 bp->rhw_status = a;
393
394 a = bp->rhw_status;
395 #ifdef DIAGNOSTIC
396 if ((a & REPSTATUS_CODECRESET) == 0)
397 panic("%s: cannot set reset bit", sc->sc_dev.dv_xname);
398 #endif
399
400 a = bp->rhw_status;
401 a = bp->rhw_status;
402 a = bp->rhw_status;
403 a = bp->rhw_status;
404 a &= ~REPSTATUS_CODECRESET;
405 bp->rhw_status = a;
406 return 0;
407 }
408
409 int repac_read(void *arg, u_int8_t reg, u_int16_t *valuep) {
410 struct repulse_softc *sc = arg;
411 struct repulse_hw *bp = sc->sc_boardp;
412
413 while (bp->rhw_status & REPSTATUS_REGSENDBUSY);
414 bp->rhw_reg_address = (reg & 0x7F) | 0x80;
415
416 while (bp->rhw_status & REPSTATUS_REGSENDBUSY);
417
418 *valuep = bp->rhw_reg_data;
419
420 return 0;
421 }
422
423 int repac_write(void *arg, u_int8_t reg, u_int16_t value) {
424 struct repulse_softc *sc = arg;
425 struct repulse_hw *bp = sc->sc_boardp;
426
427 bp->rhw_reg_data = value;
428 bp->rhw_reg_address = reg & 0x7F;
429
430 while (bp->rhw_status & REPSTATUS_REGSENDBUSY);
431
432 return 0;
433 }
434
435 int repac_attach(void *arg, struct ac97_codec_if *acip){
436
437 struct repulse_softc *sc;
438
439 sc = arg;
440 sc->sc_codec_if = acip;
441
442 return 0;
443 }
444
445 /* audio(9) support stuff which is not ac97-constant */
446
447 int
448 rep_open(void *arg, int flags)
449 {
450 return 0;
451 }
452
453 void
454 rep_close(void *arg)
455 {
456 struct repulse_softc *sc = arg;
457
458 rep_halt_output(sc);
459 rep_halt_input(sc);
460 }
461
462 int
463 rep_getdev(void *arg, struct audio_device *retp)
464 {
465 struct repulse_softc *sc = arg;
466 struct repulse_hw *bp = sc->sc_boardp;
467
468 if (retp) {
469 strncpy(retp->name, "Repulse", sizeof(retp->name));
470 snprintf(retp->version, sizeof(retp->version), "0x%x",
471 bp->rhw_version);
472 strncpy(retp->config, "", sizeof(retp->config));
473 }
474
475 return 0;
476 }
477
478 int
479 rep_get_props(void *v)
480 {
481 return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
482 }
483
484 int
485 rep_halt_output(void *arg)
486 {
487 struct repulse_softc *sc = arg;
488 struct repulse_hw *bp = sc->sc_boardp;
489
490 bp->rhw_status &= ~(REPSTATUS_PLAYIRQENABLE|REPSTATUS_PLAY);
491
492
493 return 0;
494 }
495
496 int
497 rep_halt_input(void *arg)
498 {
499 struct repulse_softc *sc = arg;
500 struct repulse_hw *bp = sc->sc_boardp;
501
502 bp->rhw_status &= ~(REPSTATUS_RECIRQENABLE|REPSTATUS_RECORD);
503
504 return 0;
505 }
506
507 /*
508 * Encoding support.
509 *
510 * TODO: add 24bit and 32bit modes here and in setparams.
511 */
512
513 const struct repulse_encoding_query {
514 const char *name;
515 int encoding, precision, flags;
516 } rep_encoding_queries[] = {
517 { AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0},
518 { AudioEmulaw, AUDIO_ENCODING_ULAW, 8, AUDIO_ENCODINGFLAG_EMULATED},
519 { AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED},
520 { AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0},
521 { AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0},
522 { AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0},
523 { AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0},
524 { AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0},
525 };
526
527 int
528 rep_query_encoding(void *arg, struct audio_encoding *fp)
529 {
530 int i;
531 const struct repulse_encoding_query *p;
532
533 i = fp->index;
534
535 if (i >= sizeof(rep_encoding_queries) /
536 sizeof(struct repulse_encoding_query))
537 return (EINVAL);
538
539 p = &rep_encoding_queries[i];
540
541 strncpy (fp->name, p->name, sizeof(fp->name));
542 fp->encoding = p->encoding;
543 fp->precision = p->precision;
544 fp->flags = p->flags;
545
546 return (0);
547 }
548
549 /*
550 * XXX the following three functions need to be enhanced for the FPGA s/pdif
551 * mode. Generic ac97 versions for now.
552 */
553
554 int
555 rep_get_port(void *arg, mixer_ctrl_t *cp)
556 {
557 struct repulse_softc *sc = arg;
558
559 return (sc->sc_codec_if->vtbl->mixer_get_port(sc->sc_codec_if, cp));
560 }
561
562 int
563 rep_set_port(void *arg, mixer_ctrl_t *cp)
564 {
565 struct repulse_softc *sc = arg;
566
567 return (sc->sc_codec_if->vtbl->mixer_set_port(sc->sc_codec_if, cp));
568 }
569
570 int
571 rep_query_devinfo (void *arg, mixer_devinfo_t *dip)
572 {
573 struct repulse_softc *sc = arg;
574
575 return (sc->sc_codec_if->vtbl->query_devinfo(sc->sc_codec_if, dip));
576 }
577
578 int
579 rep_round_blocksize(void *arg, int blk)
580 {
581 int b1;
582
583 b1 = (blk & -32);
584
585 if (b1 > 65536 / 2 / 2 /* channels */ / 4 /* bytes per channel */)
586 b1 = 65536 / 2 / 2 / 4;
587 return (b1);
588 }
589
590 size_t
591 rep_round_buffersize(void *arg, int direction, size_t size)
592 {
593 return size;
594 }
595
596
597 int
598 rep_set_params(void *addr, int setmode, int usemode,
599 struct audio_params *play, struct audio_params *rec)
600 {
601 struct repulse_softc *sc = addr;
602 struct audio_params *p;
603 int mode, reg;
604 unsigned flags;
605 u_int16_t a;
606
607 /* for mode in (RECORD, PLAY) */
608 for (mode = AUMODE_RECORD; mode != -1;
609 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
610
611 if ((setmode & mode) == 0)
612 continue;
613
614 p = mode == AUMODE_PLAY ? play : rec;
615
616 /* TODO XXX we can do upto 32bit, 96000 */
617 if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
618 (p->precision != 8 && p->precision != 16) ||
619 (p->channels != 1 && p->channels != 2))
620 return (EINVAL);
621
622 reg = mode == AUMODE_PLAY ?
623 AC97_REG_PCM_FRONT_DAC_RATE : AC97_REG_PCM_LR_ADC_RATE;
624
625 repac_write(sc, reg, (u_int16_t) p->sample_rate);
626 repac_read(sc, reg, &a);
627 p->sample_rate = a;
628
629 if (mode == AUMODE_PLAY)
630 sc->sc_playscale = p->channels * p->precision / 8;
631 else
632 sc->sc_captscale = p->channels * p->precision / 8;
633
634 p->factor = 1;
635 p->sw_code = 0;
636
637 /* everything else is software, alas... */
638 /* XXX TBD signed/unsigned, *law, etc */
639
640 flags = 0;
641 if (p->encoding == AUDIO_ENCODING_ULINEAR_LE ||
642 p->encoding == AUDIO_ENCODING_ULINEAR_BE ||
643 p->encoding == AUDIO_ENCODING_ULINEAR)
644 flags |= 1;
645
646 if (p->encoding == AUDIO_ENCODING_SLINEAR_LE ||
647 p->encoding == AUDIO_ENCODING_ULINEAR_LE)
648 flags |= 2;
649
650 if (mode == AUMODE_PLAY) {
651 sc->sc_playflags = flags;
652 if (p->encoding == AUDIO_ENCODING_ULAW) {
653 sc->sc_playfun = p->channels == 1 ?
654 rep_write_16_mono :
655 rep_write_16_stereo;
656 sc->sc_playflags = 0;
657 sc->sc_playscale = p->channels * 2;
658 p->sw_code = mulaw_to_slinear16_be;
659 p->factor = 2;
660 } else
661 if (p->encoding == AUDIO_ENCODING_ALAW) {
662 sc->sc_playfun = p->channels == 1 ?
663 rep_write_16_mono :
664 rep_write_16_stereo;
665 sc->sc_playflags = 0;
666 sc->sc_playscale = p->channels * 2;
667 p->sw_code = alaw_to_slinear16_be;
668 p->factor = 2;
669 } else
670 if (p->precision == 8 && p->channels == 1)
671 sc->sc_playfun = rep_write_8_mono;
672 else if (p->precision == 8 && p->channels == 2)
673 sc->sc_playfun = rep_write_8_stereo;
674 else if (p->precision == 16 && p->channels == 1)
675 sc->sc_playfun = rep_write_16_mono;
676 else if (p->precision == 16 && p->channels == 2)
677 sc->sc_playfun = rep_write_16_stereo;
678 } else {
679 sc->sc_captflags = flags;
680 if (p->encoding == AUDIO_ENCODING_ULAW) {
681 sc->sc_captfun = p->channels == 1 ?
682 rep_read_8_mono :
683 rep_read_8_stereo;
684 sc->sc_captflags = 0;
685 p->sw_code = slinear8_to_mulaw;
686 p->factor = 1;
687 } else
688 if (p->encoding == AUDIO_ENCODING_ALAW) {
689 sc->sc_captfun = p->channels == 1 ?
690 rep_read_8_mono :
691 rep_read_8_stereo;
692 sc->sc_captflags = 0;
693 p->sw_code = slinear8_to_alaw;
694 p->factor = 1;
695 } else
696 if (p->precision == 8 && p->channels == 1)
697 sc->sc_captfun = rep_read_8_mono;
698 else if (p->precision == 8 && p->channels == 2)
699 sc->sc_captfun = rep_read_8_stereo;
700 else if (p->precision == 16 && p->channels == 1)
701 sc->sc_captfun = rep_read_16_mono;
702 else if (p->precision == 16 && p->channels == 2)
703 sc->sc_captfun = rep_read_16_stereo;
704 }
705 /* TBD: mu-law, A-law */
706 }
707 return 0;
708 }
709
710 void
711 rep_write_8_mono(struct repulse_hw *bp, u_int8_t *p, int length,
712 unsigned flags)
713 {
714 u_int16_t sample;
715 u_int16_t xor;
716
717 xor = flags & 1 ? 0x8000 : 0;
718
719 bp->rhw_fifo_pack = 0;
720
721 while (length-- > 0) {
722 sample = ((*p++) << 8) ^ xor;
723 bp->rhw_fifo_lh = sample;
724 bp->rhw_fifo_rh = sample;
725 }
726 }
727
728 void
729 rep_write_8_stereo(struct repulse_hw *bp, u_int8_t *p, int length,
730 unsigned flags)
731 {
732 u_int16_t xor;
733
734 xor = flags & 1 ? 0x8000 : 0;
735
736 bp->rhw_fifo_pack = 0;
737
738 while (length-- > 0) {
739 bp->rhw_fifo_lh = ((*p++) << 8) ^ xor;
740 bp->rhw_fifo_rh = ((*p++) << 8) ^ xor;
741 }
742 }
743
744 void
745 rep_write_16_mono(struct repulse_hw *bp, u_int8_t *p, int length,
746 unsigned flags)
747 {
748 u_int16_t *q = (u_int16_t *)p;
749 u_int16_t sample;
750 u_int16_t xor;
751
752 xor = flags & 1 ? 0x8000 : 0;
753
754 bp->rhw_fifo_pack = 0;
755
756 if (flags & 2) {
757 while (length > 0) {
758 sample = bswap16(*q++) ^ xor;
759 bp->rhw_fifo_lh = sample;
760 bp->rhw_fifo_rh = sample;
761 length -= 2;
762 }
763 return;
764 }
765
766 while (length > 0) {
767 sample = (*q++) ^ xor;
768 bp->rhw_fifo_lh = sample;
769 bp->rhw_fifo_rh = sample;
770 length -= 2;
771 }
772 }
773
774 void
775 rep_write_16_stereo(struct repulse_hw *bp, u_int8_t *p, int length,
776 unsigned flags)
777 {
778 u_int16_t *q = (u_int16_t *)p;
779 u_int16_t xor;
780
781 xor = flags & 1 ? 0x8000 : 0;
782
783 bp->rhw_fifo_pack = 0;
784
785 if (flags & 2) {
786 while (length > 0) {
787 bp->rhw_fifo_lh = bswap16(*q++) ^ xor;
788 bp->rhw_fifo_rh = bswap16(*q++) ^ xor;
789 length -= 4;
790 }
791 return;
792 }
793 while (length > 0) {
794 bp->rhw_fifo_lh = (*q++) ^ xor;
795 bp->rhw_fifo_rh = (*q++) ^ xor;
796 length -= 4;
797 }
798 }
799
800 void
801 rep_read_8_mono(struct repulse_hw *bp, u_int8_t *p, int length,
802 unsigned flags)
803 {
804 u_int16_t v;
805 u_int16_t xor;
806
807 xor = flags & 1 ? 0x8000 : 0;
808
809 while (length > 0) {
810 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8;
811 v = bp->rhw_fifo_rh;
812 length--;
813 }
814 }
815
816 void
817 rep_read_16_mono(struct repulse_hw *bp, u_int8_t *p, int length,
818 unsigned flags)
819 {
820 u_int16_t *q = (u_int16_t *)p;
821 u_int16_t v;
822 u_int16_t xor;
823
824 xor = flags & 1 ? 0x8000 : 0;
825
826 if (flags & 2) {
827 while (length > 0) {
828 *q++ = bswap16(bp->rhw_fifo_lh ^ xor);
829 v = bp->rhw_fifo_rh;
830 length -= 2;
831 }
832 return;
833 }
834
835 while (length > 0) {
836 *q++ = bp->rhw_fifo_lh ^ xor;
837 v = bp->rhw_fifo_rh;
838 length -= 2;
839 }
840 }
841
842 void
843 rep_read_8_stereo(struct repulse_hw *bp, u_int8_t *p, int length,
844 unsigned flags)
845 {
846 u_int16_t xor;
847
848 xor = flags & 1 ? 0x8000 : 0;
849 while (length > 0) {
850 *p++ = (bp->rhw_fifo_lh ^ xor) >> 8;
851 *p++ = (bp->rhw_fifo_rh ^ xor) >> 8;
852 length -= 2;
853 }
854 }
855
856 void
857 rep_read_16_stereo(struct repulse_hw *bp, u_int8_t *p, int length,
858 unsigned flags)
859 {
860 u_int16_t *q = (u_int16_t *)p;
861 u_int16_t xor;
862
863 xor = flags & 1 ? 0x8000 : 0;
864
865 if (flags & 2) {
866 while (length > 0) {
867 *q++ = bswap16(bp->rhw_fifo_lh ^ xor);
868 *q++ = bswap16(bp->rhw_fifo_rh ^ xor);
869 length -= 4;
870 }
871 return;
872 }
873 while (length > 0) {
874 *q++ = bp->rhw_fifo_lh ^ xor;
875 *q++ = bp->rhw_fifo_rh ^ xor;
876 length -= 4;
877 }
878 }
879
880 /*
881 * At this point the transfer function is set.
882 */
883
884 int
885 rep_start_output(void *addr, void *block, int blksize,
886 void (*intr)(void*), void *intrarg) {
887
888 struct repulse_softc *sc;
889 u_int8_t *buf;
890 struct repulse_hw *bp;
891 u_int16_t status;
892
893
894 sc = addr;
895 bp = sc->sc_boardp;
896 buf = block;
897
898 /* TODO: prepare hw if necessary */
899 status = bp->rhw_status;
900 if (!(status & REPSTATUS_PLAY))
901 bp->rhw_status = status |
902 REPSTATUS_PLAY | REPSTATUS_PLAYFIFORST;
903
904 /* copy data */
905 (*sc->sc_playfun)(bp, buf, blksize, sc->sc_playflags);
906
907 /* TODO: set hw if necessary */
908 if (intr) {
909 bp->rhw_status |= REPSTATUS_PLAYIRQENABLE;
910 bp->rhw_play_fifosz = blksize / sc->sc_playscale / 2;
911 /* /2: give us time to return on the first call */
912 }
913
914 /* save callback function */
915 sc->sc_playarg = intrarg;
916 sc->sc_playmore = intr;
917
918 return 0;
919 }
920
921 int
922 rep_start_input(void *addr, void *block, int blksize,
923 void (*intr)(void*), void *intrarg) {
924
925 struct repulse_softc *sc;
926 struct repulse_hw *bp;
927 u_int16_t status;
928
929 sc = addr;
930 bp = sc->sc_boardp;
931
932 sc->sc_captbuf = block;
933 sc->sc_captbufsz = blksize;
934 sc->sc_captarg = intrarg;
935 sc->sc_captmore = intr;
936
937 status = bp->rhw_status;
938 if (!(status & REPSTATUS_RECORD))
939 bp->rhw_status = status | REPSTATUS_RECORD
940 | REPSTATUS_RECFIFORST;
941
942 bp->rhw_status |= REPSTATUS_RECIRQENABLE;
943 bp->rhw_capt_fifosz = blksize / sc->sc_captscale;
944
945 return 0;
946 }
947
948 /* irq handler */
949
950 int
951 rep_intr(void *tag) {
952 struct repulse_softc *sc;
953 struct repulse_hw *bp;
954 int foundone;
955 u_int16_t status;
956
957 foundone = 0;
958
959 sc = tag;
960 bp = sc->sc_boardp;
961 status = bp->rhw_status;
962
963 if (status & REPSTATUS_PLAYIRQACK) {
964 foundone = 1;
965 status &= ~REPSTATUS_PLAYIRQENABLE;
966 bp->rhw_status = status;
967 (*sc->sc_playmore)(sc->sc_playarg);
968 }
969
970 if (status & REPSTATUS_RECIRQACK) {
971 foundone = 1;
972 status &= ~REPSTATUS_RECIRQENABLE;
973 bp->rhw_status = status;
974 (*sc->sc_captfun)(bp, sc->sc_captbuf, sc->sc_captbufsz,
975 sc->sc_captflags);
976 (*sc->sc_captmore)(sc->sc_captarg);
977 }
978
979 return foundone;
980 }
981