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