1 /* $OpenBSD: auacer.c,v 1.4 2008/10/25 22:30:43 jakemsr Exp $ */ 2 /* $NetBSD: auacer.c,v 1.3 2004/11/10 04:20:26 kent Exp $ */ 3 4 /*- 5 * Copyright (c) 2004 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Acer Labs M5455 audio driver 35 * 36 * Acer provides data sheets after signing an NDA. 37 * The chip behaves somewhat like the Intel i8x0, so this driver 38 * is loosely based on the auich driver. Additional information taken from 39 * the ALSA intel8x0.c driver (which handles M5455 as well). 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/device.h> 47 #include <sys/fcntl.h> 48 #include <sys/proc.h> 49 50 #include <dev/pci/pcidevs.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/auacerreg.h> 53 54 #include <sys/audioio.h> 55 #include <dev/audio_if.h> 56 #include <dev/mulaw.h> 57 #include <dev/auconv.h> 58 59 #include <machine/bus.h> 60 61 #include <dev/ic/ac97.h> 62 63 struct auacer_dma { 64 bus_dmamap_t map; 65 caddr_t addr; 66 bus_dma_segment_t segs[1]; 67 int nsegs; 68 size_t size; 69 struct auacer_dma *next; 70 }; 71 72 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 73 #define KERNADDR(p) ((void *)((p)->addr)) 74 75 const struct pci_matchid auacer_pci_devices[] = { 76 { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5455 } 77 }; 78 79 struct auacer_cdata { 80 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX]; 81 }; 82 83 struct auacer_chan { 84 uint32_t ptr; 85 uint32_t start, p, end; 86 uint32_t blksize, fifoe; 87 uint32_t ack; 88 uint32_t port; 89 struct auacer_dmalist *dmalist; 90 void (*intr)(void *); 91 void *arg; 92 }; 93 94 struct auacer_softc { 95 struct device sc_dev; 96 void *sc_ih; 97 98 audio_device_t sc_audev; 99 100 bus_space_tag_t iot; 101 bus_space_handle_t mix_ioh; 102 bus_space_handle_t aud_ioh; 103 bus_dma_tag_t dmat; 104 105 struct ac97_codec_if *codec_if; 106 struct ac97_host_if host_if; 107 108 /* DMA scatter-gather lists. */ 109 bus_dmamap_t sc_cddmamap; 110 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr 111 112 struct auacer_cdata *sc_cdata; 113 114 struct auacer_chan sc_pcmo; 115 116 struct auacer_dma *sc_dmas; 117 118 pci_chipset_tag_t sc_pc; 119 pcitag_t sc_pt; 120 121 int sc_dmamap_flags; 122 123 /* Power Management */ 124 void *sc_powerhook; 125 int sc_suspend; 126 }; 127 128 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a) 129 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a) 130 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a) 131 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v) 132 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v) 133 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v) 134 135 /* Debug */ 136 #ifdef AUACER_DEBUG 137 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0) 138 int auacer_debug = 0; 139 #define ALI_DEBUG_CODECIO 0x0001 140 #define ALI_DEBUG_DMA 0x0002 141 #define ALI_DEBUG_INTR 0x0004 142 #define ALI_DEBUG_API 0x0008 143 #define ALI_DEBUG_MIXERAPI 0x0010 144 #else 145 #define DPRINTF(x,y) /* nothing */ 146 #endif 147 148 struct cfdriver auacer_cd = { 149 NULL, "auacer", DV_DULL 150 }; 151 152 int auacer_match(struct device *, void *, void *); 153 void auacer_attach(struct device *, struct device *, void *); 154 int auacer_intr(void *); 155 156 struct cfattach auacer_ca = { 157 sizeof(struct auacer_softc), auacer_match, auacer_attach 158 }; 159 160 int auacer_open(void *, int); 161 void auacer_close(void *); 162 int auacer_query_encoding(void *, struct audio_encoding *); 163 int auacer_set_params(void *, int, int, struct audio_params *, 164 struct audio_params *); 165 int auacer_round_blocksize(void *, int); 166 int auacer_halt_output(void *); 167 int auacer_halt_input(void *); 168 int auacer_getdev(void *, struct audio_device *); 169 int auacer_set_port(void *, mixer_ctrl_t *); 170 int auacer_get_port(void *, mixer_ctrl_t *); 171 int auacer_query_devinfo(void *, mixer_devinfo_t *); 172 void *auacer_allocm(void *, int, size_t, int, int); 173 void auacer_freem(void *, void *, int); 174 size_t auacer_round_buffersize(void *, int, size_t); 175 paddr_t auacer_mappage(void *, void *, off_t, int); 176 int auacer_get_props(void *); 177 int auacer_trigger_output(void *, void *, void *, int, void (*)(void *), 178 void *, struct audio_params *); 179 int auacer_trigger_input(void *, void *, void *, int, void (*)(void *), 180 void *, struct audio_params *); 181 void auacer_get_default_params(void *, int, struct audio_params *); 182 183 int auacer_alloc_cdata(struct auacer_softc *); 184 185 int auacer_allocmem(struct auacer_softc *, size_t, size_t, 186 struct auacer_dma *); 187 int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 188 189 void auacer_powerhook(int, void *); 190 int auacer_set_rate(struct auacer_softc *, int, u_long); 191 void auacer_finish_attach(struct device *); 192 193 static void auacer_reset(struct auacer_softc *sc); 194 195 struct audio_hw_if auacer_hw_if = { 196 auacer_open, 197 auacer_close, 198 NULL, /* drain */ 199 auacer_query_encoding, 200 auacer_set_params, 201 auacer_round_blocksize, 202 NULL, /* commit_setting */ 203 NULL, /* init_output */ 204 NULL, /* init_input */ 205 NULL, /* start_output */ 206 NULL, /* start_input */ 207 auacer_halt_output, 208 auacer_halt_input, 209 NULL, /* speaker_ctl */ 210 auacer_getdev, 211 NULL, /* getfd */ 212 auacer_set_port, 213 auacer_get_port, 214 auacer_query_devinfo, 215 auacer_allocm, 216 auacer_freem, 217 auacer_round_buffersize, 218 auacer_mappage, 219 auacer_get_props, 220 auacer_trigger_output, 221 auacer_trigger_input, 222 auacer_get_default_params 223 }; 224 225 int auacer_attach_codec(void *, struct ac97_codec_if *); 226 int auacer_read_codec(void *, u_int8_t, u_int16_t *); 227 int auacer_write_codec(void *, u_int8_t, u_int16_t); 228 void auacer_reset_codec(void *); 229 230 int 231 auacer_match(struct device *parent, void *match, void *aux) 232 { 233 return (pci_matchbyid((struct pci_attach_args *)aux, auacer_pci_devices, 234 sizeof(auacer_pci_devices)/sizeof(auacer_pci_devices[0]))); 235 } 236 237 void 238 auacer_attach(struct device *parent, struct device *self, void *aux) 239 { 240 struct auacer_softc *sc = (struct auacer_softc *)self; 241 struct pci_attach_args *pa = aux; 242 pci_intr_handle_t ih; 243 bus_size_t aud_size; 244 const char *intrstr; 245 246 if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, 247 &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) { 248 printf(": can't map i/o space\n"); 249 return; 250 } 251 252 sc->sc_pc = pa->pa_pc; 253 sc->sc_pt = pa->pa_tag; 254 sc->dmat = pa->pa_dmat; 255 256 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 257 258 /* Map and establish the interrupt. */ 259 if (pci_intr_map(pa, &ih)) { 260 printf("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 261 return; 262 } 263 intrstr = pci_intr_string(pa->pa_pc, ih); 264 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, 265 auacer_intr, sc, sc->sc_dev.dv_xname); 266 if (sc->sc_ih == NULL) { 267 printf("%s: can't establish interrupt", 268 sc->sc_dev.dv_xname); 269 if (intrstr != NULL) 270 printf(" at %s", intrstr); 271 printf("\n"); 272 return; 273 } 274 275 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); 276 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, 277 "0x%02x", PCI_REVISION(pa->pa_class)); 278 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, MAX_AUDIO_DEV_LEN); 279 280 printf(": %s\n", intrstr); 281 282 /* Set up DMA lists. */ 283 auacer_alloc_cdata(sc); 284 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 285 sc->sc_pcmo.ptr = 0; 286 sc->sc_pcmo.port = ALI_BASE_PO; 287 288 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 289 sc->sc_pcmo.dmalist)); 290 291 sc->host_if.arg = sc; 292 sc->host_if.attach = auacer_attach_codec; 293 sc->host_if.read = auacer_read_codec; 294 sc->host_if.write = auacer_write_codec; 295 sc->host_if.reset = auacer_reset_codec; 296 297 if (ac97_attach(&sc->host_if) != 0) 298 return; 299 300 /* Watch for power change */ 301 sc->sc_suspend = PWR_RESUME; 302 sc->sc_powerhook = powerhook_establish(auacer_powerhook, sc); 303 304 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); 305 306 auacer_reset(sc); 307 } 308 309 static int 310 auacer_ready_codec(struct auacer_softc *sc, int mask) 311 { 312 int count = 0; 313 314 for (count = 0; count < 0x7f; count++) { 315 int val = READ1(sc, ALI_CSPSR); 316 if (val & mask) 317 return 0; 318 } 319 320 printf("auacer_ready_codec: AC97 codec ready timeout.\n"); 321 return EBUSY; 322 } 323 324 static int 325 auacer_sema_codec(struct auacer_softc *sc) 326 { 327 int ttime = 100; 328 329 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 330 delay(1); 331 if (!ttime) 332 printf("auacer_sema_codec: timeout\n"); 333 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 334 } 335 336 int 337 auacer_read_codec(void *v, u_int8_t reg, u_int16_t *val) 338 { 339 struct auacer_softc *sc = v; 340 341 if (auacer_sema_codec(sc)) 342 return EIO; 343 344 reg |= ALI_CPR_ADDR_READ; 345 #if 0 346 if (ac97->num) 347 reg |= ALI_CPR_ADDR_SECONDARY; 348 #endif 349 WRITE2(sc, ALI_CPR_ADDR, reg); 350 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 351 return EIO; 352 *val = READ2(sc, ALI_SPR); 353 354 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 355 reg, *val)); 356 357 return 0; 358 } 359 360 int 361 auacer_write_codec(void *v, u_int8_t reg, u_int16_t val) 362 { 363 struct auacer_softc *sc = v; 364 365 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 366 reg, val)); 367 368 if (auacer_sema_codec(sc)) 369 return EIO; 370 WRITE2(sc, ALI_CPR, val); 371 #if 0 372 if (ac97->num) 373 reg |= ALI_CPR_ADDR_SECONDARY; 374 #endif 375 WRITE2(sc, ALI_CPR_ADDR, reg); 376 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 377 return 0; 378 } 379 380 int 381 auacer_attach_codec(void *v, struct ac97_codec_if *cif) 382 { 383 struct auacer_softc *sc = v; 384 385 sc->codec_if = cif; 386 return 0; 387 } 388 389 void 390 auacer_reset_codec(void *v) 391 { 392 struct auacer_softc *sc = v; 393 u_int32_t reg; 394 int i = 0; 395 396 reg = READ4(sc, ALI_SCR); 397 if ((reg & 2) == 0) /* Cold required */ 398 reg |= 2; 399 else 400 reg |= 1; /* Warm */ 401 reg &= ~0x80000000; /* ACLink on */ 402 WRITE4(sc, ALI_SCR, reg); 403 404 while (i < 10) { 405 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 406 break; 407 delay(50000); /* XXX */ 408 i++; 409 } 410 if (i == 10) { 411 return; 412 } 413 414 for (i = 0; i < 10; i++) { 415 reg = READ4(sc, ALI_RTSR); 416 if (reg & 0x80) /* primary codec */ 417 break; 418 WRITE4(sc, ALI_RTSR, reg | 0x80); 419 delay(50000); /* XXX */ 420 } 421 } 422 423 static void 424 auacer_reset(struct auacer_softc *sc) 425 { 426 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 427 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 428 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 429 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 430 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 431 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 432 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 433 } 434 435 int 436 auacer_open(void *v, int flags) 437 { 438 DPRINTF(ALI_DEBUG_API, ("auacer_open: flags=%d\n", flags)); 439 return 0; 440 } 441 442 void 443 auacer_close(void *v) 444 { 445 DPRINTF(ALI_DEBUG_API, ("auacer_close\n")); 446 } 447 448 void 449 auacer_get_default_params(void *addr, int mode, struct audio_params *params) 450 { 451 ac97_get_default_params(params); 452 } 453 454 int 455 auacer_query_encoding(void *v, struct audio_encoding *aep) 456 { 457 DPRINTF(ALI_DEBUG_API, ("auacer_query_encoding\n")); 458 459 switch (aep->index) { 460 case 0: 461 strlcpy(aep->name, AudioEulinear, sizeof aep->name); 462 aep->encoding = AUDIO_ENCODING_ULINEAR; 463 aep->precision = 8; 464 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 465 return (0); 466 case 1: 467 strlcpy(aep->name, AudioEmulaw, sizeof aep->name); 468 aep->encoding = AUDIO_ENCODING_ULAW; 469 aep->precision = 8; 470 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 471 return (0); 472 case 2: 473 strlcpy(aep->name, AudioEalaw, sizeof aep->name); 474 aep->encoding = AUDIO_ENCODING_ALAW; 475 aep->precision = 8; 476 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 477 return (0); 478 case 3: 479 strlcpy(aep->name, AudioEslinear, sizeof aep->name); 480 aep->encoding = AUDIO_ENCODING_SLINEAR; 481 aep->precision = 8; 482 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 483 return (0); 484 case 4: 485 strlcpy(aep->name, AudioEslinear_le, sizeof aep->name); 486 aep->encoding = AUDIO_ENCODING_SLINEAR_LE; 487 aep->precision = 16; 488 aep->flags = 0; 489 return (0); 490 case 5: 491 strlcpy(aep->name, AudioEulinear_le, sizeof aep->name); 492 aep->encoding = AUDIO_ENCODING_ULINEAR_LE; 493 aep->precision = 16; 494 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 495 return (0); 496 case 6: 497 strlcpy(aep->name, AudioEslinear_be, sizeof aep->name); 498 aep->encoding = AUDIO_ENCODING_SLINEAR_BE; 499 aep->precision = 16; 500 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 501 return (0); 502 case 7: 503 strlcpy(aep->name, AudioEulinear_be, sizeof aep->name); 504 aep->encoding = AUDIO_ENCODING_ULINEAR_BE; 505 aep->precision = 16; 506 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 507 return (0); 508 default: 509 return (EINVAL); 510 } 511 } 512 513 int 514 auacer_set_rate(struct auacer_softc *sc, int mode, u_long srate) 515 { 516 int ret; 517 u_long ratetmp; 518 519 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%lu\n", srate)); 520 521 ratetmp = srate; 522 if (mode == AUMODE_RECORD) 523 return sc->codec_if->vtbl->set_rate(sc->codec_if, 524 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 525 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 526 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 527 if (ret) 528 return ret; 529 ratetmp = srate; 530 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 531 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 532 if (ret) 533 return ret; 534 ratetmp = srate; 535 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 536 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 537 return ret; 538 } 539 540 static int 541 auacer_fixup_rate(int rate) 542 { 543 int i; 544 int rates[] = { 545 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000 546 }; 547 548 for (i = 0; i < sizeof(rates)/sizeof(rates[0]) - 1; i++) 549 if (rate <= (rates[i] + rates[i+1]) / 2) 550 return (rates[i]); 551 return (rates[i]); 552 } 553 554 int 555 auacer_set_params(void *v, int setmode, int usemode, struct audio_params *play, 556 struct audio_params *rec) 557 { 558 struct auacer_softc *sc = v; 559 struct audio_params *p; 560 uint32_t control; 561 int mode; 562 563 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n")); 564 565 for (mode = AUMODE_RECORD; mode != -1; 566 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 567 if ((setmode & mode) == 0) 568 continue; 569 570 p = mode == AUMODE_PLAY ? play : rec; 571 if (p == NULL) 572 continue; 573 574 p->sample_rate = auacer_fixup_rate(p->sample_rate); 575 p->factor = 1; 576 if (p->precision == 8) 577 p->factor *= 2; 578 p->sw_code = NULL; 579 580 if (mode == AUMODE_RECORD) { 581 if (p->channels > 2) 582 p->channels = 2; 583 } 584 585 switch (p->encoding) { 586 case AUDIO_ENCODING_SLINEAR_BE: 587 if (p->precision == 16) { 588 p->sw_code = swap_bytes; 589 } else { 590 if (mode == AUMODE_PLAY) 591 p->sw_code = linear8_to_linear16_le; 592 else 593 p->sw_code = linear16_to_linear8_le; 594 } 595 break; 596 597 case AUDIO_ENCODING_SLINEAR_LE: 598 if (p->precision != 16) { 599 if (mode == AUMODE_PLAY) 600 p->sw_code = linear8_to_linear16_le; 601 else 602 p->sw_code = linear16_to_linear8_le; 603 } 604 break; 605 606 case AUDIO_ENCODING_ULINEAR_BE: 607 if (p->precision == 16) { 608 if (mode == AUMODE_PLAY) 609 p->sw_code = 610 swap_bytes_change_sign16_le; 611 else 612 p->sw_code = 613 change_sign16_swap_bytes_le; 614 } else { 615 if (mode == AUMODE_PLAY) 616 p->sw_code = ulinear8_to_linear16_le; 617 else 618 p->sw_code = linear16_to_ulinear8_le; 619 } 620 break; 621 622 case AUDIO_ENCODING_ULINEAR_LE: 623 if (p->precision == 16) { 624 p->sw_code = change_sign16_le; 625 } else { 626 if (mode == AUMODE_PLAY) 627 p->sw_code = ulinear8_to_linear16_le; 628 else 629 p->sw_code = linear16_to_ulinear8_le; 630 } 631 break; 632 633 case AUDIO_ENCODING_ULAW: 634 if (mode == AUMODE_PLAY) 635 p->sw_code = mulaw_to_slinear16_le; 636 else 637 p->sw_code = slinear16_to_mulaw_le; 638 break; 639 640 case AUDIO_ENCODING_ALAW: 641 if (mode == AUMODE_PLAY) 642 p->sw_code = alaw_to_slinear16_le; 643 else 644 p->sw_code = slinear16_to_alaw_le; 645 break; 646 647 default: 648 return (EINVAL); 649 } 650 651 if (AC97_IS_FIXED_RATE(sc->codec_if)) 652 p->sample_rate = AC97_SINGLE_RATE; 653 else if (auacer_set_rate(sc, mode, p->sample_rate)) 654 return EINVAL; 655 656 if (mode == AUMODE_PLAY) { 657 control = READ4(sc, ALI_SCR); 658 control &= ~ALI_SCR_PCM_246_MASK; 659 if (p->channels == 4) 660 control |= ALI_SCR_PCM_4; 661 else if (p->channels == 6) 662 control |= ALI_SCR_PCM_6; 663 WRITE4(sc, ALI_SCR, control); 664 } 665 } 666 667 return (0); 668 } 669 670 int 671 auacer_round_blocksize(void *v, int blk) 672 { 673 return (blk & ~0x3f); /* keep good alignment */ 674 } 675 676 static void 677 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 678 { 679 uint32_t val; 680 uint8_t port = chan->port; 681 uint32_t slot; 682 683 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 684 685 chan->intr = 0; 686 687 slot = ALI_PORT2SLOT(port); 688 689 val = READ4(sc, ALI_DMACR); 690 val |= 1 << (slot+16); /* pause */ 691 val &= ~(1 << slot); /* no start */ 692 WRITE4(sc, ALI_DMACR, val); 693 WRITE1(sc, port + ALI_OFF_CR, 0); 694 while (READ1(sc, port + ALI_OFF_CR)) 695 ; 696 /* reset whole DMA things */ 697 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 698 /* clear interrupts */ 699 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 700 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 701 } 702 703 int 704 auacer_halt_output(void *v) 705 { 706 struct auacer_softc *sc = v; 707 708 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 709 auacer_halt(sc, &sc->sc_pcmo); 710 return (0); 711 } 712 713 int 714 auacer_halt_input(void *v) 715 { 716 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n")); 717 return (0); 718 } 719 720 int 721 auacer_getdev(void *v, struct audio_device *adp) 722 { 723 struct auacer_softc *sc = v; 724 725 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n")); 726 *adp = sc->sc_audev; 727 return (0); 728 } 729 730 int 731 auacer_set_port(void *v, mixer_ctrl_t *cp) 732 { 733 struct auacer_softc *sc = v; 734 735 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n")); 736 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 737 } 738 739 int 740 auacer_get_port(void *v, mixer_ctrl_t *cp) 741 { 742 struct auacer_softc *sc = v; 743 744 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n")); 745 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 746 } 747 748 int 749 auacer_query_devinfo(void *v, mixer_devinfo_t *dp) 750 { 751 struct auacer_softc *sc = v; 752 753 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n")); 754 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp)); 755 } 756 757 void * 758 auacer_allocm(void *v, int direction, size_t size, int pool, int flags) 759 { 760 struct auacer_softc *sc = v; 761 struct auacer_dma *p; 762 int error; 763 764 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 765 return (NULL); 766 767 p = malloc(sizeof(*p), pool, flags | M_ZERO); 768 if (p == NULL) 769 return (NULL); 770 771 error = auacer_allocmem(sc, size, PAGE_SIZE, p); 772 if (error) { 773 free(p, pool); 774 return (NULL); 775 } 776 777 p->next = sc->sc_dmas; 778 sc->sc_dmas = p; 779 780 return (KERNADDR(p)); 781 } 782 783 void 784 auacer_freem(void *v, void *ptr, int pool) 785 { 786 struct auacer_softc *sc = v; 787 struct auacer_dma *p, **pp; 788 789 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 790 if (KERNADDR(p) == ptr) { 791 auacer_freemem(sc, p); 792 *pp = p->next; 793 free(p, pool); 794 return; 795 } 796 } 797 } 798 799 size_t 800 auacer_round_buffersize(void *v, int direction, size_t size) 801 { 802 803 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 804 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX; 805 806 return size; 807 } 808 809 paddr_t 810 auacer_mappage(void *v, void *mem, off_t off, int prot) 811 { 812 struct auacer_softc *sc = v; 813 struct auacer_dma *p; 814 815 if (off < 0) 816 return (-1); 817 818 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) 819 ; 820 if (!p) 821 return (-1); 822 return (bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, 823 off, prot, BUS_DMA_WAITOK)); 824 } 825 826 int 827 auacer_get_props(void *v) 828 { 829 return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX | 830 AUDIO_PROP_MMAP); 831 } 832 833 static void 834 auacer_add_entry(struct auacer_chan *chan) 835 { 836 struct auacer_dmalist *q; 837 838 q = &chan->dmalist[chan->ptr]; 839 840 DPRINTF(ALI_DEBUG_INTR, 841 ("auacer_add_entry: %p = %x @ 0x%x\n", 842 q, chan->blksize / 2, chan->p)); 843 844 q->base = htole32(chan->p); 845 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC); 846 chan->p += chan->blksize; 847 if (chan->p >= chan->end) 848 chan->p = chan->start; 849 850 if (++chan->ptr >= ALI_DMALIST_MAX) 851 chan->ptr = 0; 852 } 853 854 static void 855 auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan) 856 { 857 uint32_t sts; 858 uint32_t civ; 859 860 sts = READ2(sc, chan->port + ALI_OFF_SR); 861 /* intr ack */ 862 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC); 863 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port)); 864 865 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts)); 866 867 if (sts & ALI_SR_DMA_INT_FIFO) { 868 printf("%s: fifo underrun # %u\n", 869 sc->sc_dev.dv_xname, ++chan->fifoe); 870 } 871 872 civ = READ1(sc, chan->port + ALI_OFF_CIV); 873 874 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr)); 875 876 /* XXX */ 877 while (chan->ptr != civ) { 878 auacer_add_entry(chan); 879 } 880 881 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 882 883 while (chan->ack != civ) { 884 if (chan->intr) { 885 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n")); 886 chan->intr(chan->arg); 887 } 888 chan->ack++; 889 if (chan->ack >= ALI_DMALIST_MAX) 890 chan->ack = 0; 891 } 892 } 893 894 int 895 auacer_intr(void *v) 896 { 897 struct auacer_softc *sc = v; 898 int ret, intrs; 899 900 intrs = READ4(sc, ALI_INTERRUPTSR); 901 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs)); 902 903 ret = 0; 904 if (intrs & ALI_INT_PCMOUT) { 905 auacer_upd_chan(sc, &sc->sc_pcmo); 906 ret++; 907 } 908 909 return ret != 0; 910 } 911 912 static void 913 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 914 uint32_t start, uint32_t size, uint32_t blksize, void (*intr)(void *), 915 void *arg) 916 { 917 uint32_t port, slot; 918 uint32_t offs, val; 919 920 chan->start = start; 921 chan->ptr = 0; 922 chan->p = chan->start; 923 chan->end = chan->start + size; 924 chan->blksize = blksize; 925 chan->ack = 0; 926 chan->intr = intr; 927 chan->arg = arg; 928 929 auacer_add_entry(chan); 930 auacer_add_entry(chan); 931 932 port = chan->port; 933 slot = ALI_PORT2SLOT(port); 934 935 WRITE1(sc, port + ALI_OFF_CIV, 0); 936 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 937 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 938 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 939 WRITE1(sc, port + ALI_OFF_CR, 940 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 941 val = READ4(sc, ALI_DMACR); 942 val &= ~(1 << (slot+16)); /* no pause */ 943 val |= 1 << slot; /* start */ 944 WRITE4(sc, ALI_DMACR, val); 945 } 946 947 int 948 auacer_trigger_output(void *v, void *start, void *end, int blksize, 949 void (*intr)(void *), void *arg, struct audio_params *param) 950 { 951 struct auacer_softc *sc = v; 952 struct auacer_dma *p; 953 uint32_t size; 954 955 DPRINTF(ALI_DEBUG_DMA, 956 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 957 start, end, blksize, intr, arg, param)); 958 959 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 960 ; 961 if (!p) { 962 printf("auacer_trigger_output: bad addr %p\n", start); 963 return (EINVAL); 964 } 965 966 size = (char *)end - (char *)start; 967 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 968 intr, arg); 969 970 return 0; 971 } 972 973 int 974 auacer_trigger_input(void *v, void *start, void *end, int blksize, 975 void (*intr)(void *), void *arg, struct audio_params *param) 976 { 977 return (EINVAL); 978 } 979 980 int 981 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 982 struct auacer_dma *p) 983 { 984 int error; 985 986 p->size = size; 987 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, p->segs, 988 sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs, BUS_DMA_NOWAIT); 989 if (error) 990 return (error); 991 992 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, &p->addr, 993 BUS_DMA_NOWAIT | sc->sc_dmamap_flags); 994 if (error) 995 goto free; 996 997 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 0, 998 BUS_DMA_NOWAIT, &p->map); 999 if (error) 1000 goto unmap; 1001 1002 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1003 BUS_DMA_NOWAIT); 1004 if (error) 1005 goto destroy; 1006 return (0); 1007 1008 destroy: 1009 bus_dmamap_destroy(sc->dmat, p->map); 1010 unmap: 1011 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1012 free: 1013 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1014 return (error); 1015 } 1016 1017 int 1018 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 1019 { 1020 1021 bus_dmamap_unload(sc->dmat, p->map); 1022 bus_dmamap_destroy(sc->dmat, p->map); 1023 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1024 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1025 return (0); 1026 } 1027 1028 int 1029 auacer_alloc_cdata(struct auacer_softc *sc) 1030 { 1031 bus_dma_segment_t seg; 1032 int error, rseg; 1033 1034 /* 1035 * Allocate the control data structure, and create and load the 1036 * DMA map for it. 1037 */ 1038 if ((error = bus_dmamem_alloc(sc->dmat, sizeof(struct auacer_cdata), 1039 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 1040 printf("%s: unable to allocate control data, error = %d\n", 1041 sc->sc_dev.dv_xname, error); 1042 goto fail_0; 1043 } 1044 1045 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 1046 sizeof(struct auacer_cdata), (caddr_t *) &sc->sc_cdata, 1047 sc->sc_dmamap_flags)) != 0) { 1048 printf("%s: unable to map control data, error = %d\n", 1049 sc->sc_dev.dv_xname, error); 1050 goto fail_1; 1051 } 1052 1053 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 1054 sizeof(struct auacer_cdata), 0, 0, &sc->sc_cddmamap)) != 0) { 1055 printf("%s: unable to create control data DMA map, " 1056 "error = %d\n", sc->sc_dev.dv_xname, error); 1057 goto fail_2; 1058 } 1059 1060 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, sc->sc_cdata, 1061 sizeof(struct auacer_cdata), NULL, 0)) != 0) { 1062 printf("%s: unable to load control data DMA map, error = %d\n", 1063 sc->sc_dev.dv_xname, error); 1064 goto fail_3; 1065 } 1066 1067 return (0); 1068 1069 fail_3: 1070 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 1071 fail_2: 1072 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata, 1073 sizeof(struct auacer_cdata)); 1074 fail_1: 1075 bus_dmamem_free(sc->dmat, &seg, rseg); 1076 fail_0: 1077 return (error); 1078 } 1079 1080 void 1081 auacer_powerhook(int why, void *addr) 1082 { 1083 struct auacer_softc *sc = (struct auacer_softc *)addr; 1084 1085 if (why != PWR_RESUME) { 1086 /* Power down */ 1087 DPRINTF(1, ("%s: power down\n", sc->sc_dev.dv_xname)); 1088 sc->sc_suspend = why; 1089 } else { 1090 /* Wake up */ 1091 DPRINTF(1, ("%s: power resume\n", sc->sc_dev.dv_xname)); 1092 if (sc->sc_suspend == PWR_RESUME) { 1093 printf("%s: resume without suspend.\n", 1094 sc->sc_dev.dv_xname); 1095 sc->sc_suspend = why; 1096 return; 1097 } 1098 sc->sc_suspend = why; 1099 auacer_reset_codec(sc); 1100 delay(1000); 1101 (sc->codec_if->vtbl->restore_ports)(sc->codec_if); 1102 } 1103 } 1104