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