1 /* $OpenBSD: nec86hw.c,v 1.9 2022/11/02 10:41:34 kn 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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