xref: /openbsd/sys/arch/luna88k/cbus/nec86hw.c (revision 3ad4051d)
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