1 /* $NetBSD: vraiu.c,v 1.15 2012/10/27 17:17:55 chs Exp $ */ 2 3 /* 4 * Copyright (c) 2001 HAMAJIMA Katsuomi. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.15 2012/10/27 17:17:55 chs Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/device.h> 34 #include <sys/bswap.h> 35 36 #include <machine/cpu.h> 37 #include <machine/intr.h> 38 #include <machine/bus.h> 39 #include <machine/platid.h> 40 #include <machine/platid_mask.h> 41 #include <machine/config_hook.h> 42 43 #include <sys/audioio.h> 44 #include <dev/audio_if.h> 45 46 #include <hpcmips/vr/vr.h> 47 #include <hpcmips/vr/vripif.h> 48 #include <hpcmips/vr/icureg.h> 49 #include <hpcmips/vr/cmureg.h> 50 #include <hpcmips/vr/vraiureg.h> 51 52 #ifdef VRAIU_DEBUG 53 int vraiu_debug = VRAIU_DEBUG; 54 #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x; 55 #else 56 #define DPRINTFN(n,x) 57 #endif 58 59 #define AUDIO_BUF_SIZE 2048 60 61 struct vraiu_softc { 62 device_t sc_dev; 63 kmutex_t sc_lock; 64 kmutex_t sc_intr_lock; 65 bus_space_tag_t sc_iot; 66 bus_space_handle_t sc_ioh; 67 bus_dma_tag_t sc_dmat; 68 bus_dmamap_t sc_dmap; 69 vrip_chipset_tag_t sc_vrip; 70 vrdcu_chipset_tag_t sc_dc; 71 vrdmaau_chipset_tag_t sc_ac; 72 vrcmu_chipset_tag_t sc_cc; 73 void *sc_handler; 74 u_short *sc_buf; /* DMA buffer pointer */ 75 int sc_status; /* status */ 76 u_int sc_rate; /* sampling rate */ 77 u_int sc_channels; /* # of channels used */ 78 u_int sc_encoding; /* encoding type */ 79 int sc_precision; /* 8 or 16 bits */ 80 /* pointer to format conversion routine */ 81 u_char sc_volume; /* volume */ 82 void (*sc_decodefunc)(struct vraiu_softc *, u_short *, void *, int); 83 void (*sc_intr)(void *); /* interrupt routine */ 84 void *sc_intrdata; /* interrupt data */ 85 }; 86 87 int vraiu_match(device_t, cfdata_t, void *); 88 void vraiu_attach(device_t, device_t, void *); 89 int vraiu_intr(void *); 90 91 CFATTACH_DECL_NEW(vraiu, sizeof(struct vraiu_softc), 92 vraiu_match, vraiu_attach, NULL, NULL); 93 94 struct audio_device aiu_device = { 95 "VR4121 AIU", 96 "0.1", 97 "aiu" 98 }; 99 100 /* 101 * Define our interface to the higher level audio driver. 102 */ 103 int vraiu_open(void *, int); 104 void vraiu_close(void *); 105 int vraiu_query_encoding(void *, struct audio_encoding *); 106 int vraiu_round_blocksize(void *, int, int, const audio_params_t *); 107 int vraiu_commit_settings(void *); 108 int vraiu_init_output(void *, void*, int); 109 int vraiu_start_output(void *, void *, int, void (*)(void *), void *); 110 int vraiu_start_input(void *, void *, int, void (*)(void *), void *); 111 int vraiu_halt_output(void *); 112 int vraiu_halt_input(void *); 113 int vraiu_getdev(void *, struct audio_device *); 114 int vraiu_set_port(void *, mixer_ctrl_t *); 115 int vraiu_get_port(void *, mixer_ctrl_t *); 116 int vraiu_query_devinfo(void *, mixer_devinfo_t *); 117 int vraiu_set_params(void *, int, int, audio_params_t *, audio_params_t *, 118 stream_filter_list_t *, stream_filter_list_t *); 119 int vraiu_get_props(void *); 120 void vraiu_get_locks(void *, kmutex_t **, kmutex_t **); 121 122 const struct audio_hw_if vraiu_hw_if = { 123 vraiu_open, 124 vraiu_close, 125 NULL, 126 vraiu_query_encoding, 127 vraiu_set_params, 128 vraiu_round_blocksize, 129 vraiu_commit_settings, 130 vraiu_init_output, 131 NULL, 132 vraiu_start_output, 133 vraiu_start_input, 134 vraiu_halt_output, 135 vraiu_halt_input, 136 NULL, 137 vraiu_getdev, 138 NULL, 139 vraiu_set_port, 140 vraiu_get_port, 141 vraiu_query_devinfo, 142 NULL, 143 NULL, 144 NULL, 145 NULL, 146 vraiu_get_props, 147 NULL, 148 NULL, 149 NULL, 150 vraiu_get_locks, 151 }; 152 153 /* 154 * convert to 1ch 10bit unsigned PCM data. 155 */ 156 static void vraiu_slinear8_1(struct vraiu_softc *, u_short *, void *, int); 157 static void vraiu_slinear8_2(struct vraiu_softc *, u_short *, void *, int); 158 static void vraiu_ulinear8_1(struct vraiu_softc *, u_short *, void *, int); 159 static void vraiu_ulinear8_2(struct vraiu_softc *, u_short *, void *, int); 160 static void vraiu_mulaw_1(struct vraiu_softc *, u_short *, void *, int); 161 static void vraiu_mulaw_2(struct vraiu_softc *, u_short *, void *, int); 162 static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int); 163 static void vraiu_slinear16_2(struct vraiu_softc *, u_short *, void *, int); 164 static void vraiu_slinear16sw_1(struct vraiu_softc *, u_short *, void *, int); 165 static void vraiu_slinear16sw_2(struct vraiu_softc *, u_short *, void *, int); 166 /* 167 * software volume control 168 */ 169 static void vraiu_volume(struct vraiu_softc *, u_short *, void *, int); 170 171 int 172 vraiu_match(device_t parent, cfdata_t cf, void *aux) 173 { 174 return 1; 175 } 176 177 void 178 vraiu_attach(device_t parent, device_t self, void *aux) 179 { 180 struct vrip_attach_args *va; 181 struct vraiu_softc *sc; 182 bus_dma_segment_t segs; 183 int rsegs; 184 185 va = aux; 186 sc = device_private(self); 187 sc->sc_dev = self; 188 sc->sc_status = ENXIO; 189 sc->sc_intr = NULL; 190 sc->sc_iot = va->va_iot; 191 sc->sc_vrip = va->va_vc; 192 sc->sc_cc = va->va_cc; 193 sc->sc_dc = va->va_dc; 194 sc->sc_ac = va->va_ac; 195 sc->sc_dmat = &vrdcu_bus_dma_tag; 196 sc->sc_volume = 127; 197 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 198 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 199 200 if (!sc->sc_cc) { 201 printf(" not configured: cmu not found\n"); 202 return; 203 } 204 if (!sc->sc_dc) { 205 printf(" not configured: dcu not found\n"); 206 return; 207 } 208 if (!sc->sc_ac) { 209 printf(" not configured: dmaau not found\n"); 210 return; 211 } 212 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 213 0 /* no flags */, &sc->sc_ioh)) { 214 printf(": can't map i/o space\n"); 215 return; 216 } 217 218 /* install interrupt handler and enable interrupt */ 219 if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit, 220 0, IPL_AUDIO, vraiu_intr, sc))) { 221 printf(": can't map interrupt line.\n"); 222 return; 223 } 224 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \ 225 AIUINT_INTM | \ 226 AIUINT_INTMIDLE | \ 227 AIUINT_INTMST | \ 228 AIUINT_INTSEND | \ 229 AIUINT_INTS | \ 230 AIUINT_INTSIDLE), 0); 231 232 if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1, 233 &rsegs, BUS_DMA_WAITOK)) { 234 printf(": can't allocate memory.\n"); 235 return; 236 } 237 if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE, 238 (void **)&sc->sc_buf, 239 BUS_DMA_WAITOK | BUS_DMA_COHERENT)) { 240 printf(": can't map memory.\n"); 241 bus_dmamem_free(sc->sc_dmat, &segs, rsegs); 242 return; 243 } 244 if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE, 245 0, BUS_DMA_WAITOK, &sc->sc_dmap)) { 246 printf(": can't create DMA map.\n"); 247 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf, 248 AUDIO_BUF_SIZE); 249 bus_dmamem_free(sc->sc_dmat, &segs, rsegs); 250 return; 251 } 252 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf, 253 AUDIO_BUF_SIZE, NULL, BUS_DMA_WAITOK)) { 254 printf(": can't load DMA map.\n"); 255 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap); 256 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf, 257 AUDIO_BUF_SIZE); 258 bus_dmamem_free(sc->sc_dmat, &segs, rsegs); 259 return; 260 } 261 if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) { 262 printf(": can't set DMA address.\n"); 263 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap); 264 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap); 265 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf, 266 AUDIO_BUF_SIZE); 267 bus_dmamem_free(sc->sc_dmat, &segs, rsegs); 268 return; 269 } 270 printf("\n"); 271 272 sc->sc_status = 0; 273 sc->sc_rate = SPS8000; 274 sc->sc_channels = 1; 275 sc->sc_precision = 8; 276 sc->sc_encoding = AUDIO_ENCODING_ULAW; 277 sc->sc_decodefunc = vraiu_mulaw_1; 278 DPRINTFN(1, ("vraiu_attach: reset AIU\n")) 279 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST); 280 /* attach audio subsystem */ 281 audio_attach_mi(&vraiu_hw_if, sc, self); 282 } 283 284 int 285 vraiu_open(void *self, int flags) 286 { 287 struct vraiu_softc *sc; 288 289 DPRINTFN(1, ("vraiu_open\n")); 290 sc = self; 291 if (sc->sc_status) { 292 DPRINTFN(0, ("vraiu_open: device error\n")); 293 return sc->sc_status; 294 } 295 sc->sc_status = EBUSY; 296 return 0; 297 } 298 299 void 300 vraiu_close(void *self) 301 { 302 struct vraiu_softc *sc; 303 304 DPRINTFN(1, ("vraiu_close\n")); 305 sc = self; 306 vraiu_halt_output(self); 307 sc->sc_status = 0; 308 } 309 310 int 311 vraiu_query_encoding(void *self, struct audio_encoding *ae) 312 { 313 DPRINTFN(3, ("vraiu_query_encoding\n")); 314 315 switch (ae->index) { 316 case 0: 317 strcpy(ae->name, AudioEslinear); 318 ae->encoding = AUDIO_ENCODING_SLINEAR; 319 ae->precision = 8; 320 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 321 break; 322 case 1: 323 strcpy(ae->name, AudioEmulaw); 324 ae->encoding = AUDIO_ENCODING_ULAW; 325 ae->precision = 8; 326 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 327 break; 328 case 2: 329 strcpy(ae->name, AudioEulinear); 330 ae->encoding = AUDIO_ENCODING_ULINEAR; 331 ae->precision = 8; 332 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 333 break; 334 case 3: 335 strcpy(ae->name, AudioEslinear); 336 ae->encoding = AUDIO_ENCODING_SLINEAR; 337 ae->precision = 16; 338 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 339 break; 340 case 4: 341 strcpy(ae->name, AudioEslinear_be); 342 ae->encoding = AUDIO_ENCODING_SLINEAR_BE; 343 ae->precision = 16; 344 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 345 break; 346 case 5: 347 strcpy(ae->name, AudioEslinear_le); 348 ae->encoding = AUDIO_ENCODING_SLINEAR_LE; 349 ae->precision = 16; 350 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 351 break; 352 case 6: 353 strcpy(ae->name, AudioEslinear); 354 ae->encoding = AUDIO_ENCODING_ULINEAR; 355 ae->precision = 16; 356 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 357 break; 358 case 7: 359 strcpy(ae->name, AudioEslinear_be); 360 ae->encoding = AUDIO_ENCODING_ULINEAR_BE; 361 ae->precision = 16; 362 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 363 break; 364 case 8: 365 strcpy(ae->name, AudioEslinear_le); 366 ae->encoding = AUDIO_ENCODING_ULINEAR_LE; 367 ae->precision = 16; 368 ae->flags = AUDIO_ENCODINGFLAG_EMULATED; 369 break; 370 default: 371 DPRINTFN(0, ("vraiu_query_encoding: param error" 372 " (%d)\n", ae->index)); 373 return EINVAL; 374 } 375 return 0; 376 } 377 378 int 379 vraiu_set_params(void *self, int setmode, int usemode, 380 audio_params_t *play, audio_params_t *rec, 381 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 382 { 383 struct vraiu_softc *sc; 384 385 DPRINTFN(1, ("vraiu_set_params: %ubit, %uch, %uHz, encoding %u\n", 386 play->precision, play->channels, play->sample_rate, 387 play->encoding)); 388 sc = self; 389 switch (play->sample_rate) { 390 case 8000: 391 sc->sc_rate = SPS8000; 392 break; 393 case 11025: 394 sc->sc_rate = SPS11025; 395 break; 396 case 22050: 397 sc->sc_rate = SPS22050; 398 break; 399 case 44100: 400 sc->sc_rate = SPS44100; 401 break; 402 default: 403 DPRINTFN(0, ("vraiu_set_params: rate error (%ld)\n", 404 play->sample_rate)); 405 return EINVAL; 406 } 407 408 switch (play->precision) { 409 case 8: 410 switch (play->encoding) { 411 case AUDIO_ENCODING_ULAW: 412 switch (play->channels) { 413 case 1: 414 sc->sc_decodefunc = vraiu_mulaw_1; 415 break; 416 case 2: 417 sc->sc_decodefunc = vraiu_mulaw_2; 418 break; 419 default: 420 DPRINTFN(0, ("vraiu_set_params: channel error" 421 " (%d)\n", play->channels)); 422 return EINVAL; 423 } 424 break; 425 case AUDIO_ENCODING_SLINEAR: 426 case AUDIO_ENCODING_SLINEAR_BE: 427 case AUDIO_ENCODING_SLINEAR_LE: 428 switch (play->channels) { 429 case 1: 430 sc->sc_decodefunc = vraiu_slinear8_1; 431 break; 432 case 2: 433 sc->sc_decodefunc = vraiu_slinear8_2; 434 break; 435 default: 436 DPRINTFN(0, ("vraiu_set_params: channel error" 437 " (%d)\n", play->channels)); 438 return EINVAL; 439 } 440 break; 441 case AUDIO_ENCODING_ULINEAR: 442 case AUDIO_ENCODING_ULINEAR_BE: 443 case AUDIO_ENCODING_ULINEAR_LE: 444 switch (play->channels) { 445 case 1: 446 sc->sc_decodefunc = vraiu_ulinear8_1; 447 break; 448 case 2: 449 sc->sc_decodefunc = vraiu_ulinear8_2; 450 break; 451 default: 452 DPRINTFN(0, ("vraiu_set_params: channel error" 453 " (%d)\n", play->channels)); 454 return EINVAL; 455 } 456 break; 457 default: 458 DPRINTFN(0, ("vraiu_set_params: encoding error" 459 " (%d)\n", play->encoding)); 460 return EINVAL; 461 } 462 break; 463 case 16: 464 switch (play->encoding) { 465 #if BYTE_ORDER == BIG_ENDIAN 466 case AUDIO_ENCODING_SLINEAR: 467 #endif 468 case AUDIO_ENCODING_SLINEAR_BE: 469 switch (play->channels) { 470 case 1: 471 #if BYTE_ORDER == BIG_ENDIAN 472 sc->sc_decodefunc = vraiu_slinear16_1; 473 #else 474 sc->sc_decodefunc = vraiu_slinear16sw_1; 475 #endif 476 break; 477 case 2: 478 #if BYTE_ORDER == BIG_ENDIAN 479 sc->sc_decodefunc = vraiu_slinear16_2; 480 #else 481 sc->sc_decodefunc = vraiu_slinear16sw_2; 482 #endif 483 break; 484 default: 485 DPRINTFN(0, ("vraiu_set_params: channel error" 486 " (%d)\n", play->channels)); 487 return EINVAL; 488 } 489 break; 490 #if BYTE_ORDER == LITTLE_ENDIAN 491 case AUDIO_ENCODING_SLINEAR: 492 #endif 493 case AUDIO_ENCODING_SLINEAR_LE: 494 switch (play->channels) { 495 case 1: 496 #if BYTE_ORDER == LITTLE_ENDIAN 497 sc->sc_decodefunc = vraiu_slinear16_1; 498 #else 499 sc->sc_decodefunc = vraiu_slinear16sw_1; 500 #endif 501 break; 502 case 2: 503 #if BYTE_ORDER == LITTLE_ENDIAN 504 sc->sc_decodefunc = vraiu_slinear16_2; 505 #else 506 sc->sc_decodefunc = vraiu_slinear16sw_2; 507 #endif 508 break; 509 default: 510 DPRINTFN(0, ("vraiu_set_params: channel error" 511 " (%d)\n", play->channels)); 512 return EINVAL; 513 } 514 break; 515 default: 516 DPRINTFN(0, ("vraiu_set_params: encoding error" 517 " (%d)\n", play->encoding)); 518 return EINVAL; 519 } 520 break; 521 default: 522 DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n", 523 play->precision)); 524 return EINVAL; 525 } 526 527 sc->sc_encoding = play->encoding; 528 sc->sc_precision = play->precision; 529 sc->sc_channels = play->channels; 530 return 0; 531 } 532 533 int 534 vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param) 535 { 536 struct vraiu_softc *sc; 537 int n; 538 539 sc = self; 540 n = AUDIO_BUF_SIZE; 541 if (sc->sc_precision == 8) 542 n /= 2; 543 n *= sc->sc_channels; 544 545 DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n", 546 bs, n)); 547 548 return n; 549 } 550 551 int 552 vraiu_commit_settings(void *self) 553 { 554 struct vraiu_softc *sc; 555 int err; 556 557 DPRINTFN(1, ("vraiu_commit_settings\n")); 558 sc = self; 559 if (sc->sc_status != EBUSY) 560 return sc->sc_status; 561 562 DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n", 563 sc->sc_rate)) 564 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate); 565 DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n")) 566 if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) { 567 DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n")); 568 return err; 569 } 570 DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n")) 571 if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) { 572 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0); 573 DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n")); 574 return err; 575 } 576 DPRINTFN(1, ("vraiu_commit_settings: Vref on\n")) 577 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU); 578 return 0; 579 } 580 581 int 582 vraiu_init_output(void *self, void *buffer, int size) 583 { 584 struct vraiu_softc *sc; 585 586 DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size)); 587 sc = self; 588 sc->sc_intr = NULL; 589 DPRINTFN(1, ("vraiu_init_output: speaker power on\n")) 590 config_hook_call(CONFIG_HOOK_POWERCONTROL, 591 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1); 592 DPRINTFN(1, ("vraiu_init_output: start output\n")) 593 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN); 594 return 0; 595 } 596 597 int 598 vraiu_start_output(void *self, void *block, int bsize, 599 void (*intr)(void *), void *intrarg) 600 { 601 struct vraiu_softc *sc; 602 603 DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n", 604 block, bsize)); 605 sc = self; 606 sc->sc_decodefunc(sc, sc->sc_buf, block, bsize); 607 vraiu_volume(sc, sc->sc_buf, block, bsize); 608 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE, 609 BUS_DMASYNC_PREWRITE); 610 sc->sc_intr = intr; 611 sc->sc_intrdata = intrarg; 612 /* clear interrupt status */ 613 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, 614 SENDINTR | SINTR | SIDLEINTR); 615 /* enable interrupt */ 616 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1); 617 return 0; 618 } 619 620 int 621 vraiu_start_input(void *self, void *block, int bsize, 622 void (*intr)(void *), void *intrarg) 623 { 624 625 DPRINTFN(3, ("vraiu_start_input\n")); 626 /* no input */ 627 return ENXIO; 628 } 629 630 int 631 vraiu_intr(void* self) 632 { 633 struct vraiu_softc *sc; 634 uint32_t reg; 635 636 DPRINTFN(2, ("vraiu_intr")); 637 sc = self; 638 639 mutex_spin_enter(&sc->sc_intr_lock); 640 641 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0); 642 vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, ®); 643 if (reg & AIUINT_INTSEND) { 644 DPRINTFN(2, (": AIUINT_INTSEND")); 645 if (sc->sc_intr) { 646 void (*intr)(void *); 647 intr = sc->sc_intr; 648 sc->sc_intr = NULL; 649 (*(intr))(sc->sc_intrdata); 650 } 651 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR); 652 } 653 DPRINTFN(2, ("\n")); 654 655 mutex_spin_exit(&sc->sc_intr_lock); 656 657 return 0; 658 } 659 660 int 661 vraiu_halt_output(void *self) 662 { 663 struct vraiu_softc *sc; 664 665 DPRINTFN(1, ("vraiu_halt_output\n")); 666 sc =self; 667 DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n")) 668 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0); 669 DPRINTFN(1, ("vraiu_halt_output: stop output\n")) 670 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0); 671 DPRINTFN(1, ("vraiu_halt_output: speaker power off\n")) 672 config_hook_call(CONFIG_HOOK_POWERCONTROL, 673 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0); 674 DPRINTFN(1, ("vraiu_halt_output: Vref off\n")) 675 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0); 676 DPRINTFN(1, ("vraiu_halt_output: disable DMA\n")) 677 sc->sc_dc->dc_disable(sc->sc_dc); 678 DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n")) 679 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0); 680 sc->sc_intr = NULL; 681 return 0; 682 } 683 684 int 685 vraiu_halt_input(void *self) 686 { 687 688 DPRINTFN(3, ("vraiu_halt_input\n")); 689 /* no input */ 690 return ENXIO; 691 } 692 693 694 int 695 vraiu_getdev(void *self, struct audio_device *ret) 696 { 697 698 DPRINTFN(3, ("vraiu_getdev\n")); 699 *ret = aiu_device; 700 return 0; 701 } 702 703 int 704 vraiu_set_port(void *self, mixer_ctrl_t *mc) 705 { 706 struct vraiu_softc *sc; 707 708 DPRINTFN(3, ("vraiu_set_port\n")); 709 sc = self; 710 /* software mixer, 1ch */ 711 if (mc->dev == 0) { 712 if (mc->type != AUDIO_MIXER_VALUE) 713 return EINVAL; 714 if (mc->un.value.num_channels != 1) 715 return EINVAL; 716 sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 717 return 0; 718 } 719 720 return EINVAL; 721 } 722 723 int 724 vraiu_get_port(void *self, mixer_ctrl_t *mc) 725 { 726 struct vraiu_softc *sc; 727 728 DPRINTFN(3, ("vraiu_get_port\n")); 729 sc = self; 730 /* software mixer, 1ch */ 731 if (mc->dev == 0) { 732 if (mc->un.value.num_channels != 1) 733 return EINVAL; 734 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume; 735 return 0; 736 } 737 738 return EINVAL; 739 } 740 741 int 742 vraiu_query_devinfo(void *self, mixer_devinfo_t *di) 743 { 744 745 DPRINTFN(3, ("vraiu_query_devinfo\n")); 746 /* software mixer, 1ch */ 747 switch (di->index) { 748 case 0: /* inputs.dac mixer value */ 749 di->mixer_class = 1; 750 di->next = di->prev = AUDIO_MIXER_LAST; 751 strcpy(di->label.name, AudioNdac); 752 di->type = AUDIO_MIXER_VALUE; 753 di->un.v.num_channels = 1; 754 strcpy(di->un.v.units.name, AudioNvolume); 755 return 0; 756 case 1: /* outputs class */ 757 di->mixer_class = 1; 758 di->next = di->prev = AUDIO_MIXER_LAST; 759 strcpy(di->label.name, AudioCinputs); 760 di->type = AUDIO_MIXER_CLASS; 761 return 0; 762 } 763 764 return ENXIO; 765 } 766 767 int 768 vraiu_get_props(void *self) 769 { 770 DPRINTFN(3, ("vraiu_get_props\n")); 771 772 return 0; 773 } 774 775 void 776 vraiu_get_locks(void *self, kmutex_t **intr, kmutex_t **thread) 777 { 778 struct vraiu_softc *sc; 779 780 DPRINTFN(3, ("vraiu_get_locks\n")); 781 sc = self; 782 783 *intr = &sc->sc_intr_lock; 784 *thread = &sc->sc_lock; 785 } 786 787 unsigned char mulaw_to_lin[] = { 788 0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 789 0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e, 790 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f, 791 0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 792 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 793 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 794 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 795 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 796 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 797 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 798 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 799 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 800 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 801 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 802 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 803 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 804 0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1, 805 0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1, 806 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, 807 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0, 808 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 809 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 810 0x8f, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8b, 811 0x8b, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x87, 812 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 813 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 814 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 815 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 816 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 817 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 818 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 819 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 820 }; 821 822 static void 823 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 824 { 825 char *q; 826 827 DPRINTFN(3, ("vraiu_slinear8_1\n")); 828 q = p; 829 #ifdef DIAGNOSTIC 830 if (n > AUDIO_BUF_SIZE/2) { 831 printf("%s: output data too large (%d > %d)\n", 832 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE/2); 833 n = AUDIO_BUF_SIZE/2; 834 } 835 #endif 836 while (n--) { 837 short i = *q++; 838 *dmap++ = (i << 2) + 0x200; 839 } 840 } 841 842 static void 843 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 844 { 845 char *q; 846 847 DPRINTFN(3, ("vraiu_slinear8_2\n")); 848 q = p; 849 #ifdef DIAGNOSTIC 850 if (n > AUDIO_BUF_SIZE) { 851 printf("%s: output data too large (%d > %d)\n", 852 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE); 853 n = AUDIO_BUF_SIZE; 854 } 855 #endif 856 n /= 2; 857 while (n--) { 858 short i = *q++; 859 short j = *q++; 860 *dmap++ = ((i + j) << 1) + 0x200; 861 } 862 } 863 864 static void 865 vraiu_ulinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 866 { 867 u_char *q; 868 869 DPRINTFN(3, ("vraiu_ulinear8_1\n")); 870 q = p; 871 #ifdef DIAGNOSTIC 872 if (n > AUDIO_BUF_SIZE/2) { 873 printf("%s: output data too large (%d > %d)\n", 874 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE/2); 875 n = AUDIO_BUF_SIZE/2; 876 } 877 #endif 878 while (n--) { 879 short i = *q++; 880 *dmap++ = i << 2; 881 } 882 } 883 884 static void 885 vraiu_ulinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 886 { 887 u_char *q; 888 889 DPRINTFN(3, ("vraiu_ulinear8_2\n")); 890 q = p; 891 #ifdef DIAGNOSTIC 892 if (n > AUDIO_BUF_SIZE) { 893 printf("%s: output data too large (%d > %d)\n", 894 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE); 895 n = AUDIO_BUF_SIZE; 896 } 897 #endif 898 n /= 2; 899 while (n--) { 900 short i = *q++; 901 short j = *q++; 902 *dmap++ = (i + j) << 1; 903 } 904 } 905 906 static void 907 vraiu_mulaw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 908 { 909 u_char *q; 910 911 DPRINTFN(3, ("vraiu_mulaw_1\n")); 912 q = p; 913 #ifdef DIAGNOSTIC 914 if (n > AUDIO_BUF_SIZE/2) { 915 printf("%s: output data too large (%d > %d)\n", 916 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE/2); 917 n = AUDIO_BUF_SIZE/2; 918 } 919 #endif 920 while (n--) { 921 short i = mulaw_to_lin[*q++]; 922 *dmap++ = i << 2; 923 } 924 } 925 926 static void 927 vraiu_mulaw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 928 { 929 u_char *q; 930 931 DPRINTFN(3, ("vraiu_mulaw_2\n")); 932 q = p; 933 #ifdef DIAGNOSTIC 934 if (n > AUDIO_BUF_SIZE) { 935 printf("%s: output data too large (%d > %d)\n", 936 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE); 937 n = AUDIO_BUF_SIZE; 938 } 939 #endif 940 n /= 2; 941 while (n--) { 942 short i = mulaw_to_lin[*q++]; 943 short j = mulaw_to_lin[*q++]; 944 *dmap++ = (i + j) << 1; 945 } 946 } 947 948 static void 949 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 950 { 951 short *q; 952 953 DPRINTFN(3, ("vraiu_slinear16_1\n")); 954 q = p; 955 #ifdef DIAGNOSTIC 956 if (n > AUDIO_BUF_SIZE) { 957 printf("%s: output data too large (%d > %d)\n", 958 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE); 959 n = AUDIO_BUF_SIZE; 960 } 961 #endif 962 n /= 2; 963 while (n--) { 964 short i = *q++; 965 *dmap++ = (i >> 6) + 0x200; 966 } 967 } 968 969 static void 970 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 971 { 972 short *q; 973 974 DPRINTFN(3, ("vraiu_slinear16_2\n")); 975 q = p; 976 #ifdef DIAGNOSTIC 977 if (n > AUDIO_BUF_SIZE*2) { 978 printf("%s: output data too large (%d > %d)\n", 979 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE*2); 980 n = AUDIO_BUF_SIZE*2; 981 } 982 #endif 983 n /= 4; 984 while (n--) { 985 short i = *q++; 986 short j = *q++; 987 *dmap++ = (i >> 7) + (j >> 7) + 0x200; 988 } 989 } 990 991 static void 992 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 993 { 994 short *q; 995 996 DPRINTFN(3, ("vraiu_slinear16sw_1\n")); 997 q = p; 998 #ifdef DIAGNOSTIC 999 if (n > AUDIO_BUF_SIZE) { 1000 printf("%s: output data too large (%d > %d)\n", 1001 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE); 1002 n = AUDIO_BUF_SIZE; 1003 } 1004 #endif 1005 n /= 2; 1006 while (n--) { 1007 short i = bswap16(*q++); 1008 *dmap++ = (i >> 6) + 0x200; 1009 } 1010 } 1011 1012 static void 1013 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 1014 { 1015 short *q; 1016 1017 DPRINTFN(3, ("vraiu_slinear16sw_2\n")); 1018 q = p; 1019 #ifdef DIAGNOSTIC 1020 if (n > AUDIO_BUF_SIZE*2) { 1021 printf("%s: output data too large (%d > %d)\n", 1022 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE*2); 1023 n = AUDIO_BUF_SIZE*2; 1024 } 1025 #endif 1026 n /= 4; 1027 while (n--) { 1028 short i = bswap16(*q++); 1029 short j = bswap16(*q++); 1030 *dmap++ = (i >> 7) + (j >> 7) + 0x200; 1031 } 1032 } 1033 1034 static void 1035 vraiu_volume(struct vraiu_softc *sc, u_short *dmap, void *p, int n) 1036 { 1037 int16_t *x; 1038 int i; 1039 short j; 1040 int vol; 1041 1042 x = (int16_t *)dmap; 1043 vol = sc->sc_volume; 1044 for (i = 0; i < n / 2; i++) { 1045 j = x[i] - 512; 1046 x[i] = ((j * vol) / 255) + 512; 1047 } 1048 1049 return; 1050 } 1051