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