1 /* $OpenBSD: nec86hw.c,v 1.10 2024/05/02 09:38:59 aoyama Exp $ */
2 /* $NecBSD: nec86hw.c,v 1.13 1998/03/14 07:04:54 kmatsuda Exp $ */
3 /* $NetBSD$ */
4
5 /*
6 * [NetBSD for NEC PC-98 series]
7 * Copyright (c) 1996, 1997, 1998
8 * NetBSD/pc98 porting staff. All rights reserved.
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. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * nec86hw.c
36 *
37 * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
38 * Written by NAGAO Tadaaki, Feb 10, 1996.
39 *
40 * Modified by N. Honda, Mar 7, 1998
41 */
42 /*
43 * TODO:
44 * - Add PC-9801-73 support.
45 * - Fake the mixer device with electric volumes.
46 */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/errno.h>
51 #include <sys/ioctl.h>
52 #include <sys/syslog.h>
53 #include <sys/device.h>
54 #include <sys/proc.h>
55 #include <sys/fcntl.h>
56
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59
60 #include <sys/audioio.h>
61 #include <dev/audio_if.h>
62
63 #if 0
64 #include <dev/ic/ym2203reg.h>
65 #endif
66 #include <luna88k/cbus/nec86reg.h>
67 #include <luna88k/cbus/nec86hwvar.h>
68 #include <luna88k/cbus/nec86var.h>
69
70 #ifdef AUDIO_DEBUG
71 extern void Dprintf(const char *, ...);
72 #define DPRINTF(x) if (nec86hwdebug) printf x
73 #define DPRINTF2(l, x) if (nec86hwdebug >= l) printf x
74 int nec86hwdebug = 3;
75 #else /* !AUDIO_DEBUG */
76 #define DPRINTF(x)
77 #define DPRINTF2(l, x)
78 #endif /* AUDIO_DEBUG */
79
80 #ifndef VOLUME_DELAY
81 /*
82 * XXX - Delaytime in microsecond after an access
83 * to the volume I/O port.
84 */
85 #define VOLUME_DELAY 10
86 #endif /* !VOLUME_DELAY */
87
88 /*
89 * Sampling rates supported by the hardware.
90 */
91 static int nec86hw_rate_table[NEC86HW_NRATE_TYPE][NEC86_NRATE] = {
92 /* NEC PC-9801-86 or its full compatibles */
93 { 44100, 33075, 22050, 16538, 11025, 8269, 5513, 4134 },
94 /* Some earlier versions of Q-Vision's WaveMaster */
95 { 44100, 33075, 22050, 16000, 11025, 8000, 5513, 4000 },
96 };
97
98 static struct audio_params nec86hw_audio_default =
99 {44100, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};
100
101 int nec86hw_set_output_block(struct nec86hw_softc *, int);
102 int nec86hw_set_input_block(struct nec86hw_softc *, int);
103
104 /*
105 * Function tables.
106 */
107 static struct nec86hw_functable_entry nec86hw_functable[] = {
108 /* precision, channels,
109 output function, input function (without resampling),
110 output function, input function (with resampling) */
111 { 8, 1,
112 nec86fifo_output_mono_8_direct, nec86fifo_input_mono_8_direct },
113 { 16, 1,
114 nec86fifo_output_mono_16_direct, nec86fifo_input_mono_16_direct },
115 { 8, 2,
116 nec86fifo_output_stereo_8_direct, nec86fifo_input_stereo_8_direct },
117 { 16, 2,
118 nec86fifo_output_stereo_16_direct, nec86fifo_input_stereo_16_direct },
119 };
120 #define NFUNCTABLEENTRY (sizeof(nec86hw_functable) / sizeof(nec86hw_functable[0]))
121
122 /*
123 * Attach hardware to driver, attach hardware driver to audio
124 * pseudo-device driver.
125 */
126 void
nec86hw_attach(struct nec86hw_softc * sc)127 nec86hw_attach(struct nec86hw_softc *sc)
128 {
129 bus_space_tag_t iot = sc->sc_iot;
130 bus_space_handle_t ioh = sc->sc_ioh;
131 u_int8_t data;
132
133 /* Set default encoding. */
134 sc->func_fifo_output = nec86fifo_output_mono_8_direct;
135 sc->func_fifo_input = nec86fifo_input_mono_8_direct;
136 (void) nec86hw_set_params(sc, AUMODE_RECORD, 0,
137 &nec86hw_audio_default, &nec86hw_audio_default);
138 (void) nec86hw_set_params(sc, AUMODE_PLAY, 0,
139 &nec86hw_audio_default, &nec86hw_audio_default);
140
141 /* Set default ports. */
142 (void) nec86hw_set_in_port(sc, NEC86HW_INPUT_MIXER);
143 (void) nec86hw_set_out_port(sc, NEC86HW_OUTPUT_MIXER);
144
145 /* Set default gains. */
146 nec86hw_set_volume(sc, NEC86_VOLUME_PORT_OPNAD, NEC86_MAXVOL);
147 nec86hw_set_volume(sc, NEC86_VOLUME_PORT_OPNAI, NEC86_MAXVOL);
148 nec86hw_set_volume(sc, NEC86_VOLUME_PORT_LINED, NEC86_MAXVOL);
149 nec86hw_set_volume(sc, NEC86_VOLUME_PORT_LINEI, NEC86_MAXVOL);
150 nec86hw_set_volume(sc, NEC86_VOLUME_PORT_PCMD, NEC86_MAXVOL);
151
152 /* Internal Speaker ON */
153 nec86hw_speaker_ctl(sc, SPKR_ON);
154
155 /* Set miscellaneous stuffs. */
156 data = bus_space_read_1(iot, ioh, NEC86_CTRL);
157 data &= NEC86_CTRL_MASK_PAN | NEC86_CTRL_MASK_PORT;
158 data |= NEC86_CTRL_PAN_L | NEC86_CTRL_PAN_R;
159 data |= NEC86_CTRL_PORT_STD;
160 bus_space_write_1(iot, ioh, NEC86_CTRL, data);
161 }
162
163 /*
164 * Various routines to interface to higher level audio driver.
165 */
166
167 int
nec86hw_open(void * arg,int flags)168 nec86hw_open(void *arg, int flags)
169 {
170 struct nec86hw_softc *sc = arg;
171 DPRINTF(("nec86hw_open: sc=%p\n", sc));
172
173 if ((flags & (FWRITE | FREAD)) == (FWRITE | FREAD))
174 return ENXIO;
175
176 if (sc->sc_open != 0 || nec86hw_reset(sc) != 0)
177 return ENXIO;
178
179 nec86hw_speaker_ctl(sc, (flags & FWRITE) ? SPKR_ON : SPKR_OFF);
180
181 sc->sc_open = 1;
182 sc->sc_intr = NULL;
183 sc->sc_arg = NULL;
184
185 sc->conv_acc = 0;
186 sc->conv_last0 = 0;
187 sc->conv_last0_l = 0;
188 sc->conv_last0_r = 0;
189 sc->conv_last1 = 0;
190 sc->conv_last1_l = 0;
191 sc->conv_last1_r = 0;
192
193 /*
194 * Leave most things including sampling format and rate as they were.
195 * (See audio_open() in audio.c)
196 */
197
198 DPRINTF(("nec86hw_open: opened\n"));
199
200 return 0;
201 }
202
203 void
nec86hw_close(void * addr)204 nec86hw_close(void *addr)
205 {
206 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
207
208 DPRINTF(("nec86hw_close: sc=%p\n", sc));
209
210 sc->sc_open = 0;
211 sc->sc_intr = NULL;
212 (void) nec86hw_reset(sc);
213
214 DPRINTF(("nec86hw_close: closed\n"));
215 }
216
217 int
nec86hw_set_params(void * addr,int mode,int usemode,struct audio_params * p,struct audio_params * r)218 nec86hw_set_params(void *addr, int mode, int usemode, struct audio_params *p,
219 struct audio_params *r)
220 {
221 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
222 int rate_type = NEC86HW_RATE_TYPE(sc->sc_cfgflags);
223
224 if ((p->channels != 1) && (p->channels != 2))
225 return EINVAL;
226
227 if (p->precision == 8)
228 p->encoding = AUDIO_ENCODING_ULINEAR_LE;
229 else {
230 p->precision = 16;
231 p->encoding = AUDIO_ENCODING_SLINEAR_LE;
232 }
233 sc->channels = p->channels;
234 sc->precision = p->precision;
235 sc->encoding = p->encoding;
236 sc->hw_orate_bits = nec86hw_rate_bits(sc, p->sample_rate);
237 sc->sc_orate = p->sample_rate = sc->hw_orate =
238 nec86hw_rate_table[rate_type][sc->hw_orate_bits];
239 sc->hw_irate_bits = nec86hw_rate_bits(sc, r->sample_rate);
240 sc->sc_irate = r->sample_rate = sc->hw_irate =
241 nec86hw_rate_table[rate_type][sc->hw_irate_bits];
242 return 0;
243 }
244
245 int
nec86hw_round_blocksize(void * addr,int blk)246 nec86hw_round_blocksize(void *addr, int blk)
247 {
248 u_int base = NEC86_INTRBLK_UNIT;
249
250 if (blk < NEC86_INTRBLK_UNIT * 2)
251 return NEC86_INTRBLK_UNIT * 2;
252
253 for ( ; base <= blk; base *= 2)
254 ;
255 return base / 2;
256 }
257
258 int
nec86hw_set_out_port(void * addr,int port)259 nec86hw_set_out_port(void *addr, int port)
260 {
261 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
262
263 DPRINTF(("nec86hw_set_out_port:\n"));
264
265 if (port != NEC86HW_OUTPUT_MIXER)
266 return EINVAL;
267
268 sc->out_port = port;
269
270 return 0;
271 }
272
273 int
nec86hw_get_out_port(void * addr)274 nec86hw_get_out_port(void *addr)
275 {
276 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
277
278 DPRINTF(("nec86hw_get_out_port:\n"));
279
280 return sc->out_port;
281 }
282
283 int
nec86hw_set_in_port(void * addr,int port)284 nec86hw_set_in_port(void *addr, int port)
285 {
286 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
287
288 DPRINTF(("nec86hw_set_in_port:\n"));
289
290 if (port != NEC86HW_INPUT_MIXER)
291 return EINVAL;
292
293 sc->in_port = port;
294
295 return 0;
296 }
297
298 int
nec86hw_get_in_port(void * addr)299 nec86hw_get_in_port(void *addr)
300 {
301 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
302
303 DPRINTF(("nec86hw_get_in_port:\n"));
304
305 return sc->in_port;
306 }
307
308 int
nec86hw_commit_settings(void * addr)309 nec86hw_commit_settings(void *addr)
310 {
311 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
312 int i;
313
314 /*
315 * Determine which function should be used to write to/read from
316 * the FIFO ring buffer.
317 */
318
319 for (i = 0; i < NFUNCTABLEENTRY; i++) {
320 if ((nec86hw_functable[i].precision == sc->precision)
321 && (nec86hw_functable[i].channels == sc->channels))
322 break;
323 }
324
325 if (i >= NFUNCTABLEENTRY) {
326 /* ??? - This should never happen. */
327 return EINVAL;
328 }
329
330 sc->func_fifo_output =
331 nec86hw_functable[i].func_fifo_output_direct;
332 sc->func_fifo_input =
333 nec86hw_functable[i].func_fifo_input_direct;
334 return 0;
335 }
336
337 int
nec86hw_mixer_set_port(void * addr,mixer_ctrl_t * cp)338 nec86hw_mixer_set_port(void *addr, mixer_ctrl_t *cp)
339 {
340 DPRINTF(("nec86hw_mixer_set_port:\n"));
341
342 /* not yet implemented */
343 return ENXIO;
344 }
345
346 int
nec86hw_mixer_get_port(void * addr,mixer_ctrl_t * cp)347 nec86hw_mixer_get_port(void *addr, mixer_ctrl_t *cp)
348 {
349 DPRINTF(("nec86hw_mixer_get_port:\n"));
350
351 /* not yet implemented */
352 return ENXIO;
353 }
354
355 int
nec86hw_mixer_query_devinfo(void * addr,mixer_devinfo_t * dip)356 nec86hw_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
357 {
358 DPRINTF(("nec86hw_mixer_query_devinfo:\n"));
359
360 /* not yet implemented */
361 return ENXIO;
362 }
363
364 int
nec86hw_set_output_block(struct nec86hw_softc * sc,int cc)365 nec86hw_set_output_block(struct nec86hw_softc *sc, int cc)
366 {
367 int bpf, hw_blocksize, watermark;
368
369 bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
370 sc->pdma_count = cc / bpf;
371
372 /* Size of the block */
373 hw_blocksize = sc->pdma_count * (sc->precision / NBBY * 2);
374
375 /* How many chunks the block should be divided into. */
376 sc->pdma_nchunk =
377 ((hw_blocksize * (WATERMARK_MAX_RATIO + WATERMARK_RATIO_OUT))
378 + (NEC86_BUFFSIZE * WATERMARK_MAX_RATIO - 1))
379 / (NEC86_BUFFSIZE * WATERMARK_MAX_RATIO);
380
381 /* Calculate the watermark. */
382 watermark =
383 (hw_blocksize * WATERMARK_RATIO_OUT)
384 / (sc->pdma_nchunk * WATERMARK_MAX_RATIO);
385 sc->pdma_watermark = nec86hw_round_watermark(watermark);
386
387 /*
388 * If the formula (*1) does not hold, watermark may be less
389 * than the minimum watermark (NEC86_INTRBLK_UNIT) and then
390 * nec86hw_round_watermark() returns that minimum value.
391 * In this case, the ring buffer on the hardware will potentially
392 * overflow.
393 * To avoid such a case, here calculate pdma_nchunk again.
394 *
395 * (*1) NEC86_BUFFSIZE / NEC86_INTRBLK_UNIT
396 * >= WATERMARK_MAX_RATIO / WATERMARK_RATIO_OUT + 1
397 */
398 if (hw_blocksize + sc->pdma_watermark > NEC86_BUFFSIZE) {
399 sc->pdma_nchunk =
400 (hw_blocksize + (NEC86_BUFFSIZE - sc->pdma_watermark - 1))
401 / (NEC86_BUFFSIZE - sc->pdma_watermark);
402 }
403
404 DPRINTF2(2, ("nec86hw_pdma_output: cc=%d count=%d hw_blocksize=%d "
405 "watermark=%d nchunk=%d ptr=%p\n",
406 cc, sc->pdma_count, hw_blocksize, sc->pdma_watermark,
407 sc->pdma_nchunk, sc->pdma_ptr));
408 return 0;
409 }
410
411 int
nec86hw_set_input_block(struct nec86hw_softc * sc,int cc)412 nec86hw_set_input_block(struct nec86hw_softc *sc, int cc)
413 {
414 int bpf, hw_blocksize, watermark, maxwatermark;
415
416 bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
417 sc->pdma_count = cc / bpf;
418
419 /* Maximum watermark. */
420 watermark =
421 (NEC86_BUFFSIZE * WATERMARK_RATIO_IN) / WATERMARK_MAX_RATIO;
422 maxwatermark = nec86hw_round_watermark(watermark);
423
424 /* Size of the block */
425 hw_blocksize = sc->pdma_count * (sc->precision / NBBY * 2);
426
427 /* How many chunks the block should be divided into. */
428 sc->pdma_nchunk = (hw_blocksize + (maxwatermark - 1)) / maxwatermark;
429
430 /* Calculate the watermark. */
431 watermark = (hw_blocksize / sc->pdma_nchunk) + (NEC86_INTRBLK_UNIT - 1);
432 sc->pdma_watermark = nec86hw_round_watermark(watermark);
433
434 DPRINTF2(2, ("nec86hw_pdma_input: cc=%d count=%d hw_blocksize=%d "
435 "watermark=%d nchunk=%d ptr=%p\n",
436 cc, sc->pdma_count, hw_blocksize, sc->pdma_watermark,
437 sc->pdma_nchunk, sc->pdma_ptr));
438 return 0;
439 }
440
441 int
nec86hw_pdma_init_output(void * addr,void * buf,int cc)442 nec86hw_pdma_init_output(void *addr, void *buf, int cc)
443 {
444 struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
445
446 nec86hw_halt_pdma(addr);
447 nec86hw_reset_fifo(sc);
448 nec86hw_set_mode_playing(sc);
449 nec86hw_set_rate_real(sc, sc->hw_orate_bits);
450 nec86hw_set_precision_real(sc, sc->precision);
451
452 nec86hw_set_output_block(sc, cc);
453 nec86hw_reset_fifo(sc);
454
455 nec86hw_enable_fifointr(sc);
456 nec86hw_set_watermark(sc, sc->pdma_watermark);
457 nec86hw_disable_fifointr(sc);
458
459 return 0;
460 }
461
462 int
nec86hw_pdma_init_input(void * addr,void * buf,int cc)463 nec86hw_pdma_init_input(void *addr, void *buf, int cc)
464 {
465 struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
466
467 nec86hw_halt_pdma(addr);
468 nec86hw_reset_fifo(sc);
469 nec86hw_set_mode_recording(sc);
470 nec86hw_set_rate_real(sc, sc->hw_irate_bits);
471 nec86hw_set_precision_real(sc, sc->precision);
472
473 nec86hw_set_input_block(sc, cc);
474 nec86hw_reset_fifo(sc);
475
476 nec86hw_enable_fifointr(sc);
477 nec86hw_set_watermark(sc, sc->pdma_watermark);
478 nec86hw_disable_fifointr(sc);
479
480 return 0;
481 }
482
483 int
nec86hw_pdma_output(void * addr,void * p,int cc,void (* intr)(void *),void * arg)484 nec86hw_pdma_output(void *addr, void *p, int cc, void (*intr)(void *),
485 void *arg)
486 {
487 struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
488 int bpf;
489
490 bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
491 if ((cc % bpf) != 0) {
492 DPRINTF(("nec86hw_pdma_output: odd bytes\n"));
493 return EIO;
494 }
495
496 sc->sc_intr = intr;
497 sc->sc_arg = arg;
498
499 /*
500 * We divide the data block into some relatively small chunks if the
501 * block is so large that the ring buffer on the hardware would
502 * overflow.
503 * In this case, we send the first chunk now and the rest in the
504 * interrupt handler.
505 */
506
507 /* Set up for pseudo-DMA. */
508 sc->pdma_ptr = (u_char *) p;
509 sc->pdma_padded = 0;
510 sc->pdma_mode = PDMA_MODE_OUTPUT;
511 if (sc->pdma_count != cc / bpf)
512 nec86hw_set_output_block(sc, cc);
513
514 if (!sc->intr_busy) {
515 nec86hw_set_precision_real(sc, sc->precision);
516 nec86hw_set_rate_real(sc, sc->hw_orate_bits);
517 nec86hw_set_mode_playing(sc);
518 nec86hw_reset_fifo(sc);
519 }
520
521 /*
522 * Send the first chunk. The rest will be sent in the interrupt
523 * handler nec86hw_intr(), if any.
524 */
525 nec86hw_disable_fifointr(sc);
526 nec86hw_output_chunk(sc);
527 nec86hw_enable_fifointr(sc);
528
529 if (!sc->intr_busy) {
530 /* Now start playing. */
531 nec86hw_start_fifo(sc);
532
533 sc->intr_busy = 1;
534 }
535
536 nec86hw_set_watermark(sc, sc->pdma_watermark);
537 return 0;
538 }
539
540 int
nec86hw_pdma_input(void * addr,void * p,int cc,void (* intr)(void *),void * arg)541 nec86hw_pdma_input(void *addr, void *p, int cc, void (*intr)(void *),
542 void *arg)
543 {
544 struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
545 int bpf;
546
547 bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
548 if ((cc % bpf) != 0) {
549 DPRINTF(("nec86hw_pdma_input: odd bytes\n"));
550 return EIO;
551 }
552
553 sc->sc_intr = intr;
554 sc->sc_arg = arg;
555
556 /* Set up for pseudo-DMA. */
557 sc->pdma_ptr = (u_int8_t *) p;
558 sc->pdma_padded = 0; /* Never padded in recording, though. */
559 sc->pdma_mode = PDMA_MODE_INPUT;
560
561 if (sc->pdma_count != cc / bpf)
562 nec86hw_set_input_block(sc, cc);
563
564 if (!sc->intr_busy) {
565 nec86hw_set_precision_real(sc, sc->precision);
566 nec86hw_set_rate_real(sc, sc->hw_irate_bits);
567 nec86hw_set_mode_recording(sc);
568 nec86hw_reset_fifo(sc);
569
570 /* Now start recording. */
571 nec86hw_enable_fifointr(sc);
572 nec86hw_start_fifo(sc);
573
574 sc->intr_busy = 1;
575 }
576
577 nec86hw_set_watermark(sc, sc->pdma_watermark);
578
579 return 0;
580 }
581
582 int
nec86hw_halt_pdma(void * addr)583 nec86hw_halt_pdma(void *addr)
584 {
585 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
586
587 DPRINTF(("nec86hw_halt_pdma: sc=%p\n", sc));
588
589 nec86hw_stop_fifo(sc);
590 nec86hw_disable_fifointr(sc);
591
592 sc->intr_busy = 0;
593
594 return 0;
595 }
596
597 int
nec86hw_cont_pdma(void * addr)598 nec86hw_cont_pdma(void *addr)
599 {
600 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
601
602 DPRINTF(("nec86hw_cont_pdma: sc=%p\n", sc));
603
604 nec86hw_enable_fifointr(sc);
605 nec86hw_start_fifo(sc);
606
607 sc->intr_busy = 1;
608
609 return 0;
610 }
611
612 int
nec86hw_speaker_ctl(void * addr,int onoff)613 nec86hw_speaker_ctl(void *addr, int onoff)
614 {
615 register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
616 bus_space_tag_t iot = sc->sc_iot;
617 bus_space_handle_t ioh = sc->sc_ioh;
618
619 DPRINTF(("nec86hw_speaker_ctl:\n"));
620
621 switch (onoff) {
622 case SPKR_ON:
623 bus_space_write_1(iot, ioh, NEC86_VOLUME, 0x0d1);
624 delay(VOLUME_DELAY);
625 break;
626 case SPKR_OFF:
627 bus_space_write_1(iot, ioh, NEC86_VOLUME, 0x0d0);
628 delay(VOLUME_DELAY);
629 break;
630 default:
631 return EINVAL;
632 }
633
634 return 0;
635 }
636
637 u_int8_t
nec86hw_rate_bits(struct nec86hw_softc * sc,u_long sr)638 nec86hw_rate_bits(struct nec86hw_softc *sc, u_long sr)
639 {
640 int i;
641 u_long rval, hr, min;
642 int rate_type = NEC86HW_RATE_TYPE(sc->sc_cfgflags);
643
644 /* Look for the minimum hardware rate equal to or more than sr. */
645 min = 0;
646 rval = 0;
647 for (i = 0; i < NEC86_NRATE; i++) {
648 hr = nec86hw_rate_table[rate_type][i];
649 if ((hr >= sr) && ((min == 0) || (min > hr))) {
650 min = hr;
651 rval = (u_int8_t) i;
652 }
653 }
654
655 return rval;
656 }
657
658 int
nec86hw_round_watermark(int wm)659 nec86hw_round_watermark(int wm)
660 {
661 wm = (wm / NEC86_INTRBLK_UNIT) * NEC86_INTRBLK_UNIT;
662
663 if (wm < NEC86_INTRBLK_UNIT)
664 wm = NEC86_INTRBLK_UNIT;
665
666 return wm;
667 }
668
669 /*
670 * Lower-level routines.
671 */
672
673 int
nec86hw_reset(struct nec86hw_softc * sc)674 nec86hw_reset(struct nec86hw_softc *sc)
675 {
676 nec86hw_stop_fifo(sc);
677 nec86hw_disable_fifointr(sc);
678 nec86hw_clear_intrflg(sc);
679 nec86hw_reset_fifo(sc);
680
681 sc->intr_busy = 0;
682 sc->pdma_mode = PDMA_MODE_NONE;
683
684 if (nec86hw_seeif_intrflg(sc))
685 return -1; /* The hardware vanished? */
686
687 return 0;
688 }
689
690 /*
691 * Set the mode for playing/recording.
692 */
693 void
nec86hw_set_mode_playing(struct nec86hw_softc * sc)694 nec86hw_set_mode_playing(struct nec86hw_softc *sc)
695 {
696 bus_space_tag_t iot = sc->sc_iot;
697 bus_space_handle_t ioh = sc->sc_ioh;
698 u_int8_t data;
699
700 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
701 data &= ~NEC86_FIFOCTL_RECMODE;
702 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
703 }
704
705 void
nec86hw_set_mode_recording(struct nec86hw_softc * sc)706 nec86hw_set_mode_recording(struct nec86hw_softc *sc)
707 {
708 bus_space_tag_t iot = sc->sc_iot;
709 bus_space_handle_t ioh = sc->sc_ioh;
710 u_int8_t data;
711
712 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
713 data |= NEC86_FIFOCTL_RECMODE;
714 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
715 }
716
717 /*
718 * Set the electric volumes.
719 */
720 void
nec86hw_set_volume(struct nec86hw_softc * sc,int port,u_int8_t vol)721 nec86hw_set_volume(struct nec86hw_softc *sc, int port, u_int8_t vol)
722 {
723 bus_space_tag_t iot = sc->sc_iot;
724 bus_space_handle_t ioh = sc->sc_ioh;
725
726 bus_space_write_1(iot, ioh, NEC86_VOLUME,
727 NEC86_VOL_TO_BITS(port, vol));
728 delay(VOLUME_DELAY);
729 }
730
731 /*
732 * Control the FIFO ring buffer on the board.
733 */
734 void
nec86hw_start_fifo(struct nec86hw_softc * sc)735 nec86hw_start_fifo(struct nec86hw_softc *sc)
736 {
737 bus_space_tag_t iot = sc->sc_iot;
738 bus_space_handle_t ioh = sc->sc_ioh;
739 u_int8_t data;
740
741 /* Start playing/recording. */
742 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
743 data |= NEC86_FIFOCTL_RUN;
744 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
745 }
746
747 void
nec86hw_stop_fifo(struct nec86hw_softc * sc)748 nec86hw_stop_fifo(struct nec86hw_softc *sc)
749 {
750 bus_space_tag_t iot = sc->sc_iot;
751 bus_space_handle_t ioh = sc->sc_ioh;
752 u_int8_t data;
753
754 /* Stop playing/recording. */
755 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
756 data &= ~NEC86_FIFOCTL_RUN;
757 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
758 }
759
760 void
nec86hw_enable_fifointr(struct nec86hw_softc * sc)761 nec86hw_enable_fifointr(struct nec86hw_softc *sc)
762 {
763 bus_space_tag_t iot = sc->sc_iot;
764 bus_space_handle_t ioh = sc->sc_ioh;
765 u_int8_t data;
766
767 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
768 data |= NEC86_FIFOCTL_ENBLINTR;
769 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
770 }
771
772 void
nec86hw_disable_fifointr(struct nec86hw_softc * sc)773 nec86hw_disable_fifointr(struct nec86hw_softc *sc)
774 {
775 bus_space_tag_t iot = sc->sc_iot;
776 bus_space_handle_t ioh = sc->sc_ioh;
777 u_int8_t data;
778
779 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
780 data &= ~NEC86_FIFOCTL_ENBLINTR;
781 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
782 }
783
784 int
nec86hw_seeif_intrflg(struct nec86hw_softc * sc)785 nec86hw_seeif_intrflg(struct nec86hw_softc *sc)
786 {
787 bus_space_tag_t iot = sc->sc_iot;
788 bus_space_handle_t ioh = sc->sc_ioh;
789 u_int8_t data;
790
791 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
792
793 return (data & NEC86_FIFOCTL_INTRFLG);
794 }
795
796 void
nec86hw_clear_intrflg(struct nec86hw_softc * sc)797 nec86hw_clear_intrflg(struct nec86hw_softc *sc)
798 {
799 bus_space_tag_t iot = sc->sc_iot;
800 bus_space_handle_t ioh = sc->sc_ioh;
801 u_int8_t data;
802
803 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
804 data &= ~NEC86_FIFOCTL_INTRFLG;
805 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
806 data |= NEC86_FIFOCTL_INTRFLG;
807 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
808 }
809
810 void
nec86hw_reset_fifo(struct nec86hw_softc * sc)811 nec86hw_reset_fifo(struct nec86hw_softc *sc)
812 {
813 bus_space_tag_t iot = sc->sc_iot;
814 bus_space_handle_t ioh = sc->sc_ioh;
815 u_int8_t data;
816
817 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
818 data |= NEC86_FIFOCTL_INIT;
819 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
820 data &= ~NEC86_FIFOCTL_INIT;
821 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
822 }
823
824 void
nec86hw_set_watermark(struct nec86hw_softc * sc,int wm)825 nec86hw_set_watermark(struct nec86hw_softc *sc, int wm)
826 {
827 bus_space_tag_t iot = sc->sc_iot;
828 bus_space_handle_t ioh = sc->sc_ioh;
829 /*
830 * Must be called after nec86hw_start_fifo() and
831 * nec86hw_enable_fifointr() are both called.
832 */
833
834 #ifdef DIAGNOSTIC
835 if ((wm < NEC86_INTRBLK_UNIT) || (wm > NEC86_BUFFSIZE)
836 || ((wm % NEC86_INTRBLK_UNIT) != 0))
837 printf("nec86hw_set_watermark: invalid watermark %d\n", wm);
838 #endif /* DIAGNOSTIC */
839
840 /*
841 * The interrupt occurs when the number of bytes in the FIFO ring
842 * buffer exceeds this watarmark.
843 */
844 bus_space_write_1(iot, ioh, NEC86_FIFOINTRBLK,
845 (wm / NEC86_INTRBLK_UNIT) - 1);
846 }
847
848 void
nec86hw_set_precision_real(struct nec86hw_softc * sc,u_int prec)849 nec86hw_set_precision_real(struct nec86hw_softc *sc, u_int prec)
850 {
851 bus_space_tag_t iot = sc->sc_iot;
852 bus_space_handle_t ioh = sc->sc_ioh;
853 u_int8_t data;
854
855 data = bus_space_read_1(iot, ioh, NEC86_CTRL);
856 data &= ~NEC86_CTRL_8BITS;
857 if (prec == 8)
858 data |= NEC86_CTRL_8BITS;
859 bus_space_write_1(iot, ioh, NEC86_CTRL, data);
860 }
861
862 void
nec86hw_set_rate_real(struct nec86hw_softc * sc,u_int8_t bits)863 nec86hw_set_rate_real(struct nec86hw_softc *sc, u_int8_t bits)
864 {
865 bus_space_tag_t iot = sc->sc_iot;
866 bus_space_handle_t ioh = sc->sc_ioh;
867 u_int8_t data;
868
869 data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
870 data &= ~NEC86_FIFOCTL_MASK_RATE;
871 data |= bits & NEC86_FIFOCTL_MASK_RATE;
872 bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
873 }
874
875 /*
876 * Write data to the FIFO ring buffer on the board.
877 */
878 void
nec86hw_output_chunk(struct nec86hw_softc * sc)879 nec86hw_output_chunk(struct nec86hw_softc *sc)
880 {
881 int cc, nbyte;
882
883 if (sc->pdma_nchunk > 0) {
884 /* Update chunksize and then send the chunk to the board. */
885
886 /* chunksize in frames */
887 cc = sc->pdma_count / sc->pdma_nchunk;
888
889 nbyte = (*sc->func_fifo_output)(sc, cc);
890
891 DPRINTF2(3, ("nec86hw_output_chunk: sc->pdma_count=%d "
892 "sc->pdma_nchunk=%d cc=%d nbyte=%d ptr=%p\n",
893 sc->pdma_count, sc->pdma_nchunk, cc, nbyte, sc->pdma_ptr));
894
895 sc->pdma_nchunk--;
896 sc->pdma_count -= cc;
897 sc->pdma_ptr += nbyte;
898 } else {
899 /* ??? - This should never happen. */
900 nbyte = 0;
901 DPRINTF(("nec86hw_output_chunk: sc->pdma_nchunk=%d\n",
902 sc->pdma_nchunk));
903 }
904
905 /*
906 * If size of the sent chunk is not enough, then pad out the buffer
907 * with zero's.
908 */
909 if (nbyte <= sc->pdma_watermark) {
910 nec86fifo_padding(sc, sc->pdma_watermark);
911 sc->pdma_padded = 1;
912
913 DPRINTF(("nec86hw_output_chunk: write padding zero's\n"));
914 }
915 }
916
917 /*
918 * Routines to write data directly.
919 */
920 int
nec86fifo_output_mono_8_direct(struct nec86hw_softc * sc,int cc)921 nec86fifo_output_mono_8_direct(struct nec86hw_softc *sc, int cc)
922 {
923 bus_space_tag_t iot = sc->sc_iot;
924 bus_space_handle_t ioh = sc->sc_ioh;
925 u_int8_t *p = sc->pdma_ptr;
926 int i;
927 register u_int8_t d;
928
929 for (i = 0; i < cc; i++) {
930 d = *p++;
931 d ^= 0x80; /* unsigned -> signed */
932 /* Fake monoral playing by duplicating a sample. */
933 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
934 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
935 }
936
937 return cc * 2;
938 }
939
940 int
nec86fifo_output_mono_16_direct(struct nec86hw_softc * sc,int cc)941 nec86fifo_output_mono_16_direct(struct nec86hw_softc *sc, int cc)
942 {
943 bus_space_tag_t iot = sc->sc_iot;
944 bus_space_handle_t ioh = sc->sc_ioh;
945 u_int8_t *p = sc->pdma_ptr;
946 int i;
947
948 for (i = 0; i < cc; i++) {
949 /* Fake monoral playing by duplicating a sample. */
950 #if BYTE_ORDER == BIG_ENDIAN
951 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
952 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
953 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
954 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
955 #else /* little endian -> big endian */
956 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
957 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
958 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
959 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
960 #endif
961 p += 2;
962 }
963
964 return cc * 4;
965 }
966
967 int
nec86fifo_output_stereo_8_direct(struct nec86hw_softc * sc,int cc)968 nec86fifo_output_stereo_8_direct(struct nec86hw_softc *sc, int cc)
969 {
970 bus_space_tag_t iot = sc->sc_iot;
971 bus_space_handle_t ioh = sc->sc_ioh;
972 u_int8_t *p = sc->pdma_ptr;
973 int i;
974
975 for (i = 0; i < cc; i++) {
976 /* unsigned -> signed (L) */
977 bus_space_write_1(iot, ioh, NEC86_FIFODATA, (*p++) ^ 0x80);
978 /* unsigned -> signed (R) */
979 bus_space_write_1(iot, ioh, NEC86_FIFODATA, (*p++) ^ 0x80);
980 }
981
982 return cc * 2;
983 }
984
985 int
nec86fifo_output_stereo_16_direct(struct nec86hw_softc * sc,int cc)986 nec86fifo_output_stereo_16_direct(struct nec86hw_softc *sc, int cc)
987 {
988 bus_space_tag_t iot = sc->sc_iot;
989 bus_space_handle_t ioh = sc->sc_ioh;
990 u_int8_t *p = sc->pdma_ptr;
991 int i;
992
993 for (i = 0; i < cc; i++) {
994 #if BYTE_ORDER == BIG_ENDIAN
995 /* (L) */
996 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
997 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
998 p += 2;
999 /* (R) */
1000 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
1001 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
1002 p += 2;
1003 #else
1004 /* little endian -> big endian */
1005 /* (L) */
1006 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
1007 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
1008 p += 2;
1009 /* (R) */
1010 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
1011 bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
1012 p += 2;
1013 #endif
1014 }
1015
1016 return cc * 4;
1017 }
1018
1019 /*
1020 * Routines to write data with resampling. (linear interpolation)
1021 */
1022 int
nec86fifo_output_mono_8_resamp(struct nec86hw_softc * sc,int cc)1023 nec86fifo_output_mono_8_resamp(struct nec86hw_softc *sc, int cc)
1024 {
1025 bus_space_tag_t iot = sc->sc_iot;
1026 bus_space_handle_t ioh = sc->sc_ioh;
1027 u_int8_t *p = sc->pdma_ptr;
1028 int i;
1029 register int rval;
1030 register u_int8_t d;
1031 register u_int8_t d0, d1;
1032 register u_long acc, orate, hw_orate;
1033
1034 rval = 0;
1035
1036 orate = sc->sc_orate;
1037 hw_orate = sc->hw_orate;
1038 acc = sc->conv_acc;
1039 d0 = (u_int8_t) sc->conv_last0;
1040 d1 = (u_int8_t) sc->conv_last1;
1041
1042 for (i = 0; i < cc; i++) {
1043 d0 = d1;
1044 d1 = *p++;
1045
1046 while (acc <= hw_orate) {
1047 /* Linear interpolation. */
1048 d = ((d0 * (hw_orate - acc)) + (d1 * acc)) / hw_orate;
1049 /* unsigned -> signed */
1050 d ^= 0x80;
1051
1052 /* Fake monoral playing by duplicating a sample. */
1053 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
1054 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
1055
1056 acc += orate;
1057 rval += 2;
1058 }
1059
1060 acc -= hw_orate;
1061 }
1062
1063 sc->conv_acc = acc;
1064 sc->conv_last0 = (u_short) d0;
1065 sc->conv_last1 = (u_short) d1;
1066
1067 return rval;
1068 }
1069
1070 int
nec86fifo_output_mono_16_resamp(struct nec86hw_softc * sc,int cc)1071 nec86fifo_output_mono_16_resamp(struct nec86hw_softc *sc, int cc)
1072 {
1073 bus_space_tag_t iot = sc->sc_iot;
1074 bus_space_handle_t ioh = sc->sc_ioh;
1075 u_int8_t *p = sc->pdma_ptr;
1076 int i;
1077 register int rval;
1078 register u_short d, d0, d1;
1079 register u_long acc, orate, hw_orate;
1080
1081 rval = 0;
1082
1083 orate = sc->sc_orate;
1084 hw_orate = sc->hw_orate;
1085 acc = sc->conv_acc;
1086 d0 = sc->conv_last0;
1087 d1 = sc->conv_last1;
1088
1089 for (i = 0; i < cc; i++) {
1090 d0 = d1;
1091 /* little endian signed -> unsigned */
1092 d1 = (*p | (*(p + 1) << 8)) ^ 0x8000;
1093 p += 2;
1094
1095 while (acc <= hw_orate) {
1096 /* Linear interpolation. */
1097 d = ((d0 * (hw_orate - acc)) + (d1 * acc)) / hw_orate;
1098 /* unsigned -> signed */
1099 d ^= 0x8000;
1100
1101 /* Fake monoral playing by duplicating a sample. */
1102 bus_space_write_1(iot, ioh, NEC86_FIFODATA,
1103 (d >> 8) & 0xff); /* -> big endian */
1104 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
1105 bus_space_write_1(iot, ioh, NEC86_FIFODATA,
1106 (d >> 8) & 0xff);
1107 bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
1108
1109 acc += orate;
1110 rval += 4;
1111 }
1112
1113 acc -= hw_orate;
1114 }
1115
1116 sc->conv_acc = acc;
1117 sc->conv_last0 = d0;
1118 sc->conv_last1 = d1;
1119
1120 return rval;
1121 }
1122
1123 /*
1124 * Read data from the FIFO ring buffer on the board.
1125 */
1126 void
nec86hw_input_chunk(struct nec86hw_softc * sc)1127 nec86hw_input_chunk(struct nec86hw_softc *sc)
1128 {
1129 int cc, bpf;
1130
1131 bpf = (sc->channels * sc->precision) / NBBY;
1132 if (sc->pdma_nchunk > 0) {
1133 /* Update chunksize and then receive the chunk from the board. */
1134 /* chunksize in frames */
1135 cc = sc->pdma_count / sc->pdma_nchunk;
1136 (*sc->func_fifo_input)(sc, cc);
1137
1138 DPRINTF2(3, ("nec86hw_input_chunk: sc->pdma_count=%d "
1139 "sc->pdma_nchunk=%d cc=%d ptr=%p\n",
1140 sc->pdma_count, sc->pdma_nchunk, cc, sc->pdma_ptr));
1141
1142 sc->pdma_nchunk--;
1143 sc->pdma_count -= cc;
1144 sc->pdma_ptr += (cc * bpf);
1145 } else {
1146 /* ??? - This should never happen. */
1147 cc = 0;
1148 DPRINTF(("nec86hw_input_chunk: ??? sc->pdma_nchunk=%d ???",
1149 sc->pdma_nchunk));
1150 }
1151 }
1152
1153 /*
1154 * Routines to read data directly.
1155 */
1156 void
nec86fifo_input_mono_8_direct(struct nec86hw_softc * sc,int cc)1157 nec86fifo_input_mono_8_direct(struct nec86hw_softc *sc, int cc)
1158 {
1159 bus_space_tag_t iot = sc->sc_iot;
1160 bus_space_handle_t ioh = sc->sc_ioh;
1161 u_int8_t *p = sc->pdma_ptr;
1162 int i;
1163 register u_int8_t d_l, d_r;
1164
1165 for (i = 0; i < cc; i++) {
1166 /* signed -> unsigned (L) */
1167 d_l = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
1168 /* signed -> unsigned (R) */
1169 d_r = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
1170
1171 /* Fake monoral recording by taking arithmetical mean. */
1172 *p++ = (d_l + d_r) / 2;
1173 }
1174 }
1175
1176 void
nec86fifo_input_mono_16_direct(struct nec86hw_softc * sc,int cc)1177 nec86fifo_input_mono_16_direct(struct nec86hw_softc *sc, int cc)
1178 {
1179 bus_space_tag_t iot = sc->sc_iot;
1180 bus_space_handle_t ioh = sc->sc_ioh;
1181 u_int8_t *p = sc->pdma_ptr;
1182 int i;
1183 register u_short d, d_l, d_r;
1184
1185 for (i = 0; i < cc; i++) {
1186 /* big endian signed -> unsigned (L) */
1187 d_l = (bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80) << 8;
1188 d_l |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1189 /* big endian signed -> unsigned (R) */
1190 d_r = (bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80) << 8;
1191 d_r |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1192
1193 /* Fake monoral recording by taking arithmetical mean. */
1194 d = (d_l + d_r) / 2;
1195
1196 #if BYTE_ORDER == BIG_ENDIAN
1197 /* -> big endian signed */
1198 *p++ = ((d >> 8) & 0xff) ^ 0x80;
1199 *p++ = d & 0xff;
1200 #else
1201 /* -> little endian signed */
1202 *p++ = d & 0xff;
1203 *p++ = ((d >> 8) & 0xff) ^ 0x80;
1204 #endif
1205 }
1206 }
1207
1208 void
nec86fifo_input_stereo_8_direct(struct nec86hw_softc * sc,int cc)1209 nec86fifo_input_stereo_8_direct(struct nec86hw_softc *sc, int cc)
1210 {
1211 bus_space_tag_t iot = sc->sc_iot;
1212 bus_space_handle_t ioh = sc->sc_ioh;
1213 u_int8_t *p = sc->pdma_ptr;
1214 int i;
1215
1216 for (i = 0; i < cc; i++) {
1217 /* signed -> unsigned (L) */
1218 *p++ = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
1219 /* signed -> unsigned (R) */
1220 *p++ = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
1221 }
1222 }
1223
1224 void
nec86fifo_input_stereo_16_direct(struct nec86hw_softc * sc,int cc)1225 nec86fifo_input_stereo_16_direct(struct nec86hw_softc *sc, int cc)
1226 {
1227 bus_space_tag_t iot = sc->sc_iot;
1228 bus_space_handle_t ioh = sc->sc_ioh;
1229 u_int8_t *p = sc->pdma_ptr;
1230 int i;
1231
1232 for (i = 0; i < cc; i++) {
1233 #if BYTE_ORDER == BIG_ENDIAN
1234 *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (L) */
1235 *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1236 p += 2;
1237 *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (R) */
1238 *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1239 p += 2;
1240 #else /* big endian -> little endian */
1241 *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (L) */
1242 *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1243 p += 2;
1244 *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (R) */
1245 *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
1246 p += 2;
1247 #endif
1248 }
1249 }
1250
1251 /*
1252 * Write padding zero's to the FIFO ring buffer on the board.
1253 */
1254 void
nec86fifo_padding(struct nec86hw_softc * sc,int cc)1255 nec86fifo_padding(struct nec86hw_softc *sc, int cc)
1256 {
1257 bus_space_tag_t iot = sc->sc_iot;
1258 bus_space_handle_t ioh = sc->sc_ioh;
1259 register int i;
1260
1261 DPRINTF2(2, ("nec86fifo_padding: %d\n", cc));
1262
1263 for (i = 0; i < cc; i++)
1264 bus_space_write_1(iot, ioh, NEC86_FIFODATA, 0);
1265 }
1266
1267 /*
1268 * Interrupt handler.
1269 */
1270 int
nec86hw_intr(void * arg)1271 nec86hw_intr(void *arg)
1272 {
1273 struct nec86hw_softc *sc = (struct nec86hw_softc *) arg;
1274
1275 if (!nec86hw_seeif_intrflg(sc)) {
1276 /* Seems to be an FM sound interrupt. */
1277 DPRINTF(("nec86hw_intr: ??? FM sound interrupt ???\n"));
1278 return 0;
1279 }
1280
1281 mtx_enter(&audio_lock);
1282 nec86hw_clear_intrflg(sc);
1283
1284 switch(sc->pdma_mode) {
1285 case PDMA_MODE_OUTPUT:
1286 if (sc->pdma_padded) {
1287 /* Clear the padding zero's. */
1288 nec86hw_reset_fifo(sc);
1289 sc->pdma_padded = 0;
1290 DPRINTF(("nec86hw_intr: clear padding zero's\n"));
1291 }
1292 if (sc->pdma_count > 0) {
1293 /* Send the next chunk. */
1294 nec86hw_disable_fifointr(sc);
1295 nec86hw_output_chunk(sc);
1296 nec86hw_enable_fifointr(sc);
1297 } else
1298 (*sc->sc_intr)(sc->sc_arg);
1299 break;
1300 case PDMA_MODE_INPUT:
1301 if (sc->pdma_count > 0) {
1302 /* Receive the next chunk. */
1303 nec86hw_disable_fifointr(sc);
1304 nec86hw_input_chunk(sc);
1305 nec86hw_enable_fifointr(sc);
1306 }
1307 if (sc->pdma_count <= 0)
1308 (*sc->sc_intr)(sc->sc_arg);
1309 break;
1310 default:
1311 /* This should never happen. */
1312 nec86hw_stop_fifo(sc);
1313 nec86hw_disable_fifointr(sc);
1314 sc->intr_busy = 0;
1315
1316 DPRINTF(("nec86hw_intr: ??? unexpected interrupt ???\n"));
1317
1318 mtx_leave(&audio_lock);
1319 return 0;
1320 }
1321
1322 mtx_leave(&audio_lock);
1323 return 1;
1324 }
1325