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