1 /* $OpenBSD: auacer.c,v 1.16 2014/07/12 18:48:51 tedu 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 49 #include <dev/pci/pcidevs.h> 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/auacerreg.h> 52 53 #include <sys/audioio.h> 54 #include <dev/audio_if.h> 55 #include <dev/mulaw.h> 56 #include <dev/auconv.h> 57 58 #include <machine/bus.h> 59 60 #include <dev/ic/ac97.h> 61 62 struct auacer_dma { 63 bus_dmamap_t map; 64 caddr_t addr; 65 bus_dma_segment_t segs[1]; 66 int nsegs; 67 size_t size; 68 struct auacer_dma *next; 69 }; 70 71 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 72 #define KERNADDR(p) ((void *)((p)->addr)) 73 74 const struct pci_matchid auacer_pci_devices[] = { 75 { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5455 } 76 }; 77 78 struct auacer_cdata { 79 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX]; 80 }; 81 82 struct auacer_chan { 83 uint32_t ptr; 84 uint32_t start, p, end; 85 uint32_t blksize, fifoe; 86 uint32_t ack; 87 uint32_t port; 88 struct auacer_dmalist *dmalist; 89 void (*intr)(void *); 90 void *arg; 91 }; 92 93 struct auacer_softc { 94 struct device sc_dev; 95 void *sc_ih; 96 97 audio_device_t sc_audev; 98 99 bus_space_tag_t iot; 100 bus_space_handle_t mix_ioh; 101 bus_space_handle_t aud_ioh; 102 bus_dma_tag_t dmat; 103 104 struct ac97_codec_if *codec_if; 105 struct ac97_host_if host_if; 106 107 /* DMA scatter-gather lists. */ 108 bus_dmamap_t sc_cddmamap; 109 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr 110 111 struct auacer_cdata *sc_cdata; 112 113 struct auacer_chan sc_pcmo; 114 115 struct auacer_dma *sc_dmas; 116 117 pci_chipset_tag_t sc_pc; 118 pcitag_t sc_pt; 119 120 int sc_dmamap_flags; 121 }; 122 123 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a) 124 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a) 125 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a) 126 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v) 127 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v) 128 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v) 129 130 /* Debug */ 131 #ifdef AUACER_DEBUG 132 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0) 133 int auacer_debug = 0; 134 #define ALI_DEBUG_CODECIO 0x0001 135 #define ALI_DEBUG_DMA 0x0002 136 #define ALI_DEBUG_INTR 0x0004 137 #define ALI_DEBUG_API 0x0008 138 #define ALI_DEBUG_MIXERAPI 0x0010 139 #else 140 #define DPRINTF(x,y) /* nothing */ 141 #endif 142 143 struct cfdriver auacer_cd = { 144 NULL, "auacer", DV_DULL 145 }; 146 147 int auacer_match(struct device *, void *, void *); 148 void auacer_attach(struct device *, struct device *, void *); 149 int auacer_activate(struct device *, int); 150 int auacer_intr(void *); 151 152 struct cfattach auacer_ca = { 153 sizeof(struct auacer_softc), auacer_match, auacer_attach, NULL, 154 auacer_activate 155 }; 156 157 int auacer_open(void *, int); 158 void auacer_close(void *); 159 int auacer_query_encoding(void *, struct audio_encoding *); 160 int auacer_set_params(void *, int, int, struct audio_params *, 161 struct audio_params *); 162 int auacer_round_blocksize(void *, int); 163 int auacer_halt_output(void *); 164 int auacer_halt_input(void *); 165 int auacer_getdev(void *, struct audio_device *); 166 int auacer_set_port(void *, mixer_ctrl_t *); 167 int auacer_get_port(void *, mixer_ctrl_t *); 168 int auacer_query_devinfo(void *, mixer_devinfo_t *); 169 void *auacer_allocm(void *, int, size_t, int, int); 170 void auacer_freem(void *, void *, int); 171 size_t auacer_round_buffersize(void *, int, size_t); 172 paddr_t auacer_mappage(void *, void *, off_t, int); 173 int auacer_get_props(void *); 174 int auacer_trigger_output(void *, void *, void *, int, void (*)(void *), 175 void *, struct audio_params *); 176 int auacer_trigger_input(void *, void *, void *, int, void (*)(void *), 177 void *, struct audio_params *); 178 void auacer_get_default_params(void *, int, struct audio_params *); 179 180 int auacer_alloc_cdata(struct auacer_softc *); 181 182 int auacer_allocmem(struct auacer_softc *, size_t, size_t, 183 struct auacer_dma *); 184 int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 185 186 int auacer_set_rate(struct auacer_softc *, int, u_long); 187 void auacer_finish_attach(struct device *); 188 189 static void auacer_reset(struct auacer_softc *sc); 190 191 struct audio_hw_if auacer_hw_if = { 192 auacer_open, 193 auacer_close, 194 NULL, /* drain */ 195 auacer_query_encoding, 196 auacer_set_params, 197 auacer_round_blocksize, 198 NULL, /* commit_setting */ 199 NULL, /* init_output */ 200 NULL, /* init_input */ 201 NULL, /* start_output */ 202 NULL, /* start_input */ 203 auacer_halt_output, 204 auacer_halt_input, 205 NULL, /* speaker_ctl */ 206 auacer_getdev, 207 NULL, /* getfd */ 208 auacer_set_port, 209 auacer_get_port, 210 auacer_query_devinfo, 211 auacer_allocm, 212 auacer_freem, 213 auacer_round_buffersize, 214 auacer_mappage, 215 auacer_get_props, 216 auacer_trigger_output, 217 auacer_trigger_input, 218 auacer_get_default_params 219 }; 220 221 int auacer_attach_codec(void *, struct ac97_codec_if *); 222 int auacer_read_codec(void *, u_int8_t, u_int16_t *); 223 int auacer_write_codec(void *, u_int8_t, u_int16_t); 224 void auacer_reset_codec(void *); 225 226 int 227 auacer_match(struct device *parent, void *match, void *aux) 228 { 229 return (pci_matchbyid((struct pci_attach_args *)aux, auacer_pci_devices, 230 nitems(auacer_pci_devices))); 231 } 232 233 void 234 auacer_attach(struct device *parent, struct device *self, void *aux) 235 { 236 struct auacer_softc *sc = (struct auacer_softc *)self; 237 struct pci_attach_args *pa = aux; 238 pci_intr_handle_t ih; 239 bus_size_t aud_size; 240 const char *intrstr; 241 242 if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, 243 &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) { 244 printf(": can't map i/o space\n"); 245 return; 246 } 247 248 sc->sc_pc = pa->pa_pc; 249 sc->sc_pt = pa->pa_tag; 250 sc->dmat = pa->pa_dmat; 251 252 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 253 254 /* Map and establish the interrupt. */ 255 if (pci_intr_map(pa, &ih)) { 256 printf("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 257 return; 258 } 259 intrstr = pci_intr_string(pa->pa_pc, ih); 260 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO | IPL_MPSAFE, 261 auacer_intr, sc, sc->sc_dev.dv_xname); 262 if (sc->sc_ih == NULL) { 263 printf("%s: can't establish interrupt", 264 sc->sc_dev.dv_xname); 265 if (intrstr != NULL) 266 printf(" at %s", intrstr); 267 printf("\n"); 268 return; 269 } 270 271 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); 272 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, 273 "0x%02x", PCI_REVISION(pa->pa_class)); 274 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, MAX_AUDIO_DEV_LEN); 275 276 printf(": %s\n", intrstr); 277 278 /* Set up DMA lists. */ 279 auacer_alloc_cdata(sc); 280 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 281 sc->sc_pcmo.ptr = 0; 282 sc->sc_pcmo.port = ALI_BASE_PO; 283 284 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 285 sc->sc_pcmo.dmalist)); 286 287 sc->host_if.arg = sc; 288 sc->host_if.attach = auacer_attach_codec; 289 sc->host_if.read = auacer_read_codec; 290 sc->host_if.write = auacer_write_codec; 291 sc->host_if.reset = auacer_reset_codec; 292 293 if (ac97_attach(&sc->host_if) != 0) 294 return; 295 296 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); 297 298 auacer_reset(sc); 299 } 300 301 static int 302 auacer_ready_codec(struct auacer_softc *sc, int mask) 303 { 304 int count = 0; 305 306 for (count = 0; count < 0x7f; count++) { 307 int val = READ1(sc, ALI_CSPSR); 308 if (val & mask) 309 return 0; 310 } 311 312 printf("auacer_ready_codec: AC97 codec ready timeout.\n"); 313 return EBUSY; 314 } 315 316 static int 317 auacer_sema_codec(struct auacer_softc *sc) 318 { 319 int ttime = 100; 320 321 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 322 delay(1); 323 if (!ttime) 324 printf("auacer_sema_codec: timeout\n"); 325 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 326 } 327 328 int 329 auacer_read_codec(void *v, u_int8_t reg, u_int16_t *val) 330 { 331 struct auacer_softc *sc = v; 332 333 if (auacer_sema_codec(sc)) 334 return EIO; 335 336 reg |= ALI_CPR_ADDR_READ; 337 #if 0 338 if (ac97->num) 339 reg |= ALI_CPR_ADDR_SECONDARY; 340 #endif 341 WRITE2(sc, ALI_CPR_ADDR, reg); 342 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 343 return EIO; 344 *val = READ2(sc, ALI_SPR); 345 346 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 347 reg, *val)); 348 349 return 0; 350 } 351 352 int 353 auacer_write_codec(void *v, u_int8_t reg, u_int16_t val) 354 { 355 struct auacer_softc *sc = v; 356 357 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 358 reg, val)); 359 360 if (auacer_sema_codec(sc)) 361 return EIO; 362 WRITE2(sc, ALI_CPR, val); 363 #if 0 364 if (ac97->num) 365 reg |= ALI_CPR_ADDR_SECONDARY; 366 #endif 367 WRITE2(sc, ALI_CPR_ADDR, reg); 368 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 369 return 0; 370 } 371 372 int 373 auacer_attach_codec(void *v, struct ac97_codec_if *cif) 374 { 375 struct auacer_softc *sc = v; 376 377 sc->codec_if = cif; 378 return 0; 379 } 380 381 void 382 auacer_reset_codec(void *v) 383 { 384 struct auacer_softc *sc = v; 385 u_int32_t reg; 386 int i = 0; 387 388 reg = READ4(sc, ALI_SCR); 389 if ((reg & 2) == 0) /* Cold required */ 390 reg |= 2; 391 else 392 reg |= 1; /* Warm */ 393 reg &= ~0x80000000; /* ACLink on */ 394 WRITE4(sc, ALI_SCR, reg); 395 396 while (i < 10) { 397 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 398 break; 399 delay(50000); /* XXX */ 400 i++; 401 } 402 if (i == 10) { 403 return; 404 } 405 406 for (i = 0; i < 10; i++) { 407 reg = READ4(sc, ALI_RTSR); 408 if (reg & 0x80) /* primary codec */ 409 break; 410 WRITE4(sc, ALI_RTSR, reg | 0x80); 411 delay(50000); /* XXX */ 412 } 413 } 414 415 static void 416 auacer_reset(struct auacer_softc *sc) 417 { 418 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 419 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 420 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 421 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 422 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 423 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 424 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 425 } 426 427 int 428 auacer_open(void *v, int flags) 429 { 430 DPRINTF(ALI_DEBUG_API, ("auacer_open: flags=%d\n", flags)); 431 return 0; 432 } 433 434 void 435 auacer_close(void *v) 436 { 437 DPRINTF(ALI_DEBUG_API, ("auacer_close\n")); 438 } 439 440 void 441 auacer_get_default_params(void *addr, int mode, struct audio_params *params) 442 { 443 ac97_get_default_params(params); 444 } 445 446 int 447 auacer_query_encoding(void *v, struct audio_encoding *aep) 448 { 449 DPRINTF(ALI_DEBUG_API, ("auacer_query_encoding\n")); 450 451 switch (aep->index) { 452 case 0: 453 strlcpy(aep->name, AudioEulinear, sizeof aep->name); 454 aep->encoding = AUDIO_ENCODING_ULINEAR; 455 aep->precision = 8; 456 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 457 break; 458 case 1: 459 strlcpy(aep->name, AudioEmulaw, sizeof aep->name); 460 aep->encoding = AUDIO_ENCODING_ULAW; 461 aep->precision = 8; 462 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 463 break; 464 case 2: 465 strlcpy(aep->name, AudioEalaw, sizeof aep->name); 466 aep->encoding = AUDIO_ENCODING_ALAW; 467 aep->precision = 8; 468 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 469 break; 470 case 3: 471 strlcpy(aep->name, AudioEslinear, sizeof aep->name); 472 aep->encoding = AUDIO_ENCODING_SLINEAR; 473 aep->precision = 8; 474 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 475 break; 476 case 4: 477 strlcpy(aep->name, AudioEslinear_le, sizeof aep->name); 478 aep->encoding = AUDIO_ENCODING_SLINEAR_LE; 479 aep->precision = 16; 480 aep->flags = 0; 481 break; 482 case 5: 483 strlcpy(aep->name, AudioEulinear_le, sizeof aep->name); 484 aep->encoding = AUDIO_ENCODING_ULINEAR_LE; 485 aep->precision = 16; 486 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 487 break; 488 case 6: 489 strlcpy(aep->name, AudioEslinear_be, sizeof aep->name); 490 aep->encoding = AUDIO_ENCODING_SLINEAR_BE; 491 aep->precision = 16; 492 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 493 break; 494 case 7: 495 strlcpy(aep->name, AudioEulinear_be, sizeof aep->name); 496 aep->encoding = AUDIO_ENCODING_ULINEAR_BE; 497 aep->precision = 16; 498 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 499 break; 500 default: 501 return (EINVAL); 502 } 503 aep->bps = AUDIO_BPS(aep->precision); 504 aep->msb = 1; 505 506 return (0); 507 } 508 509 int 510 auacer_set_rate(struct auacer_softc *sc, int mode, u_long srate) 511 { 512 int ret; 513 u_long ratetmp; 514 515 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%lu\n", srate)); 516 517 ratetmp = srate; 518 if (mode == AUMODE_RECORD) 519 return sc->codec_if->vtbl->set_rate(sc->codec_if, 520 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 521 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 522 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 523 if (ret) 524 return ret; 525 ratetmp = srate; 526 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 527 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 528 if (ret) 529 return ret; 530 ratetmp = srate; 531 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 532 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 533 return ret; 534 } 535 536 static int 537 auacer_fixup_rate(int rate) 538 { 539 int i; 540 int rates[] = { 541 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000 542 }; 543 544 for (i = 0; i < nitems(rates) - 1; i++) 545 if (rate <= (rates[i] + rates[i+1]) / 2) 546 return (rates[i]); 547 return (rates[i]); 548 } 549 550 int 551 auacer_set_params(void *v, int setmode, int usemode, struct audio_params *play, 552 struct audio_params *rec) 553 { 554 struct auacer_softc *sc = v; 555 struct audio_params *p; 556 uint32_t control; 557 int mode; 558 559 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n")); 560 561 for (mode = AUMODE_RECORD; mode != -1; 562 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 563 if ((setmode & mode) == 0) 564 continue; 565 566 p = mode == AUMODE_PLAY ? play : rec; 567 if (p == NULL) 568 continue; 569 570 p->sample_rate = auacer_fixup_rate(p->sample_rate); 571 p->factor = 1; 572 if (p->precision == 8) 573 p->factor *= 2; 574 p->sw_code = NULL; 575 576 if (mode == AUMODE_RECORD) { 577 if (p->channels > 2) 578 p->channels = 2; 579 } 580 581 switch (p->encoding) { 582 case AUDIO_ENCODING_SLINEAR_BE: 583 if (p->precision == 16) { 584 p->sw_code = swap_bytes; 585 } else { 586 if (mode == AUMODE_PLAY) 587 p->sw_code = linear8_to_linear16_le; 588 else 589 p->sw_code = linear16_to_linear8_le; 590 } 591 break; 592 593 case AUDIO_ENCODING_SLINEAR_LE: 594 if (p->precision != 16) { 595 if (mode == AUMODE_PLAY) 596 p->sw_code = linear8_to_linear16_le; 597 else 598 p->sw_code = linear16_to_linear8_le; 599 } 600 break; 601 602 case AUDIO_ENCODING_ULINEAR_BE: 603 if (p->precision == 16) { 604 if (mode == AUMODE_PLAY) 605 p->sw_code = 606 swap_bytes_change_sign16_le; 607 else 608 p->sw_code = 609 change_sign16_swap_bytes_le; 610 } else { 611 if (mode == AUMODE_PLAY) 612 p->sw_code = ulinear8_to_linear16_le; 613 else 614 p->sw_code = linear16_to_ulinear8_le; 615 } 616 break; 617 618 case AUDIO_ENCODING_ULINEAR_LE: 619 if (p->precision == 16) { 620 p->sw_code = change_sign16_le; 621 } else { 622 if (mode == AUMODE_PLAY) 623 p->sw_code = ulinear8_to_linear16_le; 624 else 625 p->sw_code = linear16_to_ulinear8_le; 626 } 627 break; 628 629 case AUDIO_ENCODING_ULAW: 630 if (mode == AUMODE_PLAY) 631 p->sw_code = mulaw_to_slinear16_le; 632 else 633 p->sw_code = slinear16_to_mulaw_le; 634 break; 635 636 case AUDIO_ENCODING_ALAW: 637 if (mode == AUMODE_PLAY) 638 p->sw_code = alaw_to_slinear16_le; 639 else 640 p->sw_code = slinear16_to_alaw_le; 641 break; 642 643 default: 644 return (EINVAL); 645 } 646 p->bps = AUDIO_BPS(p->precision); 647 p->msb = 1; 648 649 if (AC97_IS_FIXED_RATE(sc->codec_if)) 650 p->sample_rate = AC97_SINGLE_RATE; 651 else if (auacer_set_rate(sc, mode, p->sample_rate)) 652 return EINVAL; 653 654 if (mode == AUMODE_PLAY) { 655 control = READ4(sc, ALI_SCR); 656 control &= ~ALI_SCR_PCM_246_MASK; 657 if (p->channels == 4) 658 control |= ALI_SCR_PCM_4; 659 else if (p->channels == 6) 660 control |= ALI_SCR_PCM_6; 661 WRITE4(sc, ALI_SCR, control); 662 } 663 } 664 665 return (0); 666 } 667 668 int 669 auacer_round_blocksize(void *v, int blk) 670 { 671 return ((blk + 0x3f) & ~0x3f); /* keep good alignment */ 672 } 673 674 static void 675 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 676 { 677 uint32_t val; 678 uint8_t port = chan->port; 679 uint32_t slot; 680 681 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 682 683 chan->intr = 0; 684 685 slot = ALI_PORT2SLOT(port); 686 687 val = READ4(sc, ALI_DMACR); 688 val |= 1 << (slot+16); /* pause */ 689 val &= ~(1 << slot); /* no start */ 690 WRITE4(sc, ALI_DMACR, val); 691 WRITE1(sc, port + ALI_OFF_CR, 0); 692 while (READ1(sc, port + ALI_OFF_CR)) 693 ; 694 /* reset whole DMA things */ 695 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 696 /* clear interrupts */ 697 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 698 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 699 } 700 701 int 702 auacer_halt_output(void *v) 703 { 704 struct auacer_softc *sc = v; 705 706 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 707 mtx_enter(&audio_lock); 708 auacer_halt(sc, &sc->sc_pcmo); 709 mtx_leave(&audio_lock); 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, 0); 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, 0); 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 mtx_enter(&audio_lock); 901 intrs = READ4(sc, ALI_INTERRUPTSR); 902 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs)); 903 904 ret = 0; 905 if (intrs & ALI_INT_PCMOUT) { 906 auacer_upd_chan(sc, &sc->sc_pcmo); 907 ret++; 908 } 909 mtx_leave(&audio_lock); 910 return ret != 0; 911 } 912 913 static void 914 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 915 uint32_t start, uint32_t size, uint32_t blksize, void (*intr)(void *), 916 void *arg) 917 { 918 uint32_t port, slot; 919 uint32_t offs, val; 920 921 chan->start = start; 922 chan->ptr = 0; 923 chan->p = chan->start; 924 chan->end = chan->start + size; 925 chan->blksize = blksize; 926 chan->ack = 0; 927 chan->intr = intr; 928 chan->arg = arg; 929 930 auacer_add_entry(chan); 931 auacer_add_entry(chan); 932 933 port = chan->port; 934 slot = ALI_PORT2SLOT(port); 935 936 WRITE1(sc, port + ALI_OFF_CIV, 0); 937 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 938 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 939 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 940 WRITE1(sc, port + ALI_OFF_CR, 941 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 942 val = READ4(sc, ALI_DMACR); 943 val &= ~(1 << (slot+16)); /* no pause */ 944 val |= 1 << slot; /* start */ 945 WRITE4(sc, ALI_DMACR, val); 946 } 947 948 int 949 auacer_trigger_output(void *v, void *start, void *end, int blksize, 950 void (*intr)(void *), void *arg, struct audio_params *param) 951 { 952 struct auacer_softc *sc = v; 953 struct auacer_dma *p; 954 uint32_t size; 955 956 DPRINTF(ALI_DEBUG_DMA, 957 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 958 start, end, blksize, intr, arg, param)); 959 960 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 961 ; 962 if (!p) { 963 printf("auacer_trigger_output: bad addr %p\n", start); 964 return (EINVAL); 965 } 966 967 size = (char *)end - (char *)start; 968 mtx_enter(&audio_lock); 969 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 970 intr, arg); 971 mtx_leave(&audio_lock); 972 return 0; 973 } 974 975 int 976 auacer_trigger_input(void *v, void *start, void *end, int blksize, 977 void (*intr)(void *), void *arg, struct audio_params *param) 978 { 979 return (EINVAL); 980 } 981 982 int 983 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 984 struct auacer_dma *p) 985 { 986 int error; 987 988 p->size = size; 989 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, p->segs, 990 nitems(p->segs), &p->nsegs, BUS_DMA_NOWAIT); 991 if (error) 992 return (error); 993 994 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, &p->addr, 995 BUS_DMA_NOWAIT | sc->sc_dmamap_flags); 996 if (error) 997 goto free; 998 999 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 0, 1000 BUS_DMA_NOWAIT, &p->map); 1001 if (error) 1002 goto unmap; 1003 1004 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1005 BUS_DMA_NOWAIT); 1006 if (error) 1007 goto destroy; 1008 return (0); 1009 1010 destroy: 1011 bus_dmamap_destroy(sc->dmat, p->map); 1012 unmap: 1013 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1014 free: 1015 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1016 return (error); 1017 } 1018 1019 int 1020 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 1021 { 1022 1023 bus_dmamap_unload(sc->dmat, p->map); 1024 bus_dmamap_destroy(sc->dmat, p->map); 1025 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1026 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1027 return (0); 1028 } 1029 1030 int 1031 auacer_alloc_cdata(struct auacer_softc *sc) 1032 { 1033 bus_dma_segment_t seg; 1034 int error, rseg; 1035 1036 /* 1037 * Allocate the control data structure, and create and load the 1038 * DMA map for it. 1039 */ 1040 if ((error = bus_dmamem_alloc(sc->dmat, sizeof(struct auacer_cdata), 1041 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 1042 printf("%s: unable to allocate control data, error = %d\n", 1043 sc->sc_dev.dv_xname, error); 1044 goto fail_0; 1045 } 1046 1047 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 1048 sizeof(struct auacer_cdata), (caddr_t *) &sc->sc_cdata, 1049 sc->sc_dmamap_flags)) != 0) { 1050 printf("%s: unable to map control data, error = %d\n", 1051 sc->sc_dev.dv_xname, error); 1052 goto fail_1; 1053 } 1054 1055 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 1056 sizeof(struct auacer_cdata), 0, 0, &sc->sc_cddmamap)) != 0) { 1057 printf("%s: unable to create control data DMA map, " 1058 "error = %d\n", sc->sc_dev.dv_xname, error); 1059 goto fail_2; 1060 } 1061 1062 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, sc->sc_cdata, 1063 sizeof(struct auacer_cdata), NULL, 0)) != 0) { 1064 printf("%s: unable to load control data DMA map, error = %d\n", 1065 sc->sc_dev.dv_xname, error); 1066 goto fail_3; 1067 } 1068 1069 return (0); 1070 1071 fail_3: 1072 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 1073 fail_2: 1074 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata, 1075 sizeof(struct auacer_cdata)); 1076 fail_1: 1077 bus_dmamem_free(sc->dmat, &seg, rseg); 1078 fail_0: 1079 return (error); 1080 } 1081 1082 int 1083 auacer_activate(struct device *self, int act) 1084 { 1085 struct auacer_softc *sc = (struct auacer_softc *)self; 1086 int rv = 0; 1087 1088 switch (act) { 1089 case DVACT_RESUME: 1090 ac97_resume(&sc->host_if, sc->codec_if); 1091 rv = config_activate_children(self, act); 1092 break; 1093 default: 1094 rv = config_activate_children(self, act); 1095 break; 1096 } 1097 return (rv); 1098 } 1099