1 /* $OpenBSD: auacer.c,v 1.22 2019/12/14 12:35:19 fcambus 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 48 #include <dev/pci/pcidevs.h> 49 #include <dev/pci/pcivar.h> 50 #include <dev/pci/auacerreg.h> 51 52 #include <sys/audioio.h> 53 #include <dev/audio_if.h> 54 55 #include <machine/bus.h> 56 57 #include <dev/ic/ac97.h> 58 59 struct auacer_dma { 60 bus_dmamap_t map; 61 caddr_t addr; 62 bus_dma_segment_t segs[1]; 63 int nsegs; 64 size_t size; 65 struct auacer_dma *next; 66 }; 67 68 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 69 #define KERNADDR(p) ((void *)((p)->addr)) 70 71 const struct pci_matchid auacer_pci_devices[] = { 72 { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5455 } 73 }; 74 75 struct auacer_cdata { 76 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX]; 77 }; 78 79 struct auacer_chan { 80 uint32_t ptr; 81 uint32_t start, p, end; 82 uint32_t blksize, fifoe; 83 uint32_t ack; 84 uint32_t port; 85 struct auacer_dmalist *dmalist; 86 void (*intr)(void *); 87 void *arg; 88 }; 89 90 struct auacer_softc { 91 struct device sc_dev; 92 void *sc_ih; 93 94 bus_space_tag_t iot; 95 bus_space_handle_t mix_ioh; 96 bus_space_handle_t aud_ioh; 97 bus_dma_tag_t dmat; 98 99 struct ac97_codec_if *codec_if; 100 struct ac97_host_if host_if; 101 102 /* DMA scatter-gather lists. */ 103 bus_dmamap_t sc_cddmamap; 104 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr 105 106 struct auacer_cdata *sc_cdata; 107 108 struct auacer_chan sc_pcmo; 109 110 struct auacer_dma *sc_dmas; 111 112 pci_chipset_tag_t sc_pc; 113 pcitag_t sc_pt; 114 115 int sc_dmamap_flags; 116 }; 117 118 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a) 119 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a) 120 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a) 121 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v) 122 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v) 123 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v) 124 125 /* Debug */ 126 #ifdef AUACER_DEBUG 127 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0) 128 int auacer_debug = 0; 129 #define ALI_DEBUG_CODECIO 0x0001 130 #define ALI_DEBUG_DMA 0x0002 131 #define ALI_DEBUG_INTR 0x0004 132 #define ALI_DEBUG_API 0x0008 133 #define ALI_DEBUG_MIXERAPI 0x0010 134 #else 135 #define DPRINTF(x,y) /* nothing */ 136 #endif 137 138 struct cfdriver auacer_cd = { 139 NULL, "auacer", DV_DULL 140 }; 141 142 int auacer_match(struct device *, void *, void *); 143 void auacer_attach(struct device *, struct device *, void *); 144 int auacer_activate(struct device *, int); 145 int auacer_intr(void *); 146 147 struct cfattach auacer_ca = { 148 sizeof(struct auacer_softc), auacer_match, auacer_attach, NULL, 149 auacer_activate 150 }; 151 152 int auacer_open(void *, int); 153 void auacer_close(void *); 154 int auacer_set_params(void *, int, int, struct audio_params *, 155 struct audio_params *); 156 int auacer_round_blocksize(void *, int); 157 int auacer_halt_output(void *); 158 int auacer_halt_input(void *); 159 int auacer_set_port(void *, mixer_ctrl_t *); 160 int auacer_get_port(void *, mixer_ctrl_t *); 161 int auacer_query_devinfo(void *, mixer_devinfo_t *); 162 void *auacer_allocm(void *, int, size_t, int, int); 163 void auacer_freem(void *, void *, int); 164 size_t auacer_round_buffersize(void *, int, size_t); 165 int auacer_get_props(void *); 166 int auacer_trigger_output(void *, void *, void *, int, void (*)(void *), 167 void *, struct audio_params *); 168 int auacer_trigger_input(void *, void *, void *, int, void (*)(void *), 169 void *, struct audio_params *); 170 171 int auacer_alloc_cdata(struct auacer_softc *); 172 173 int auacer_allocmem(struct auacer_softc *, size_t, size_t, 174 struct auacer_dma *); 175 int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 176 177 int auacer_set_rate(struct auacer_softc *, int, u_long); 178 void auacer_finish_attach(struct device *); 179 180 static void auacer_reset(struct auacer_softc *sc); 181 182 struct audio_hw_if auacer_hw_if = { 183 auacer_open, 184 auacer_close, 185 auacer_set_params, 186 auacer_round_blocksize, 187 NULL, /* commit_setting */ 188 NULL, /* init_output */ 189 NULL, /* init_input */ 190 NULL, /* start_output */ 191 NULL, /* start_input */ 192 auacer_halt_output, 193 auacer_halt_input, 194 NULL, /* speaker_ctl */ 195 NULL, /* getfd */ 196 auacer_set_port, 197 auacer_get_port, 198 auacer_query_devinfo, 199 auacer_allocm, 200 auacer_freem, 201 auacer_round_buffersize, 202 auacer_get_props, 203 auacer_trigger_output, 204 auacer_trigger_input 205 }; 206 207 int auacer_attach_codec(void *, struct ac97_codec_if *); 208 int auacer_read_codec(void *, u_int8_t, u_int16_t *); 209 int auacer_write_codec(void *, u_int8_t, u_int16_t); 210 void auacer_reset_codec(void *); 211 212 int 213 auacer_match(struct device *parent, void *match, void *aux) 214 { 215 return (pci_matchbyid((struct pci_attach_args *)aux, auacer_pci_devices, 216 nitems(auacer_pci_devices))); 217 } 218 219 void 220 auacer_attach(struct device *parent, struct device *self, void *aux) 221 { 222 struct auacer_softc *sc = (struct auacer_softc *)self; 223 struct pci_attach_args *pa = aux; 224 pci_intr_handle_t ih; 225 bus_size_t aud_size; 226 const char *intrstr; 227 228 if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, 229 &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) { 230 printf(": can't map i/o space\n"); 231 return; 232 } 233 234 sc->sc_pc = pa->pa_pc; 235 sc->sc_pt = pa->pa_tag; 236 sc->dmat = pa->pa_dmat; 237 238 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 239 240 /* Map and establish the interrupt. */ 241 if (pci_intr_map(pa, &ih)) { 242 printf("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 243 return; 244 } 245 intrstr = pci_intr_string(pa->pa_pc, ih); 246 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO | IPL_MPSAFE, 247 auacer_intr, sc, sc->sc_dev.dv_xname); 248 if (sc->sc_ih == NULL) { 249 printf("%s: can't establish interrupt", 250 sc->sc_dev.dv_xname); 251 if (intrstr != NULL) 252 printf(" at %s", intrstr); 253 printf("\n"); 254 return; 255 } 256 257 printf(": %s\n", intrstr); 258 259 /* Set up DMA lists. */ 260 auacer_alloc_cdata(sc); 261 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 262 sc->sc_pcmo.ptr = 0; 263 sc->sc_pcmo.port = ALI_BASE_PO; 264 265 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 266 sc->sc_pcmo.dmalist)); 267 268 sc->host_if.arg = sc; 269 sc->host_if.attach = auacer_attach_codec; 270 sc->host_if.read = auacer_read_codec; 271 sc->host_if.write = auacer_write_codec; 272 sc->host_if.reset = auacer_reset_codec; 273 274 if (ac97_attach(&sc->host_if) != 0) 275 return; 276 277 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); 278 279 auacer_reset(sc); 280 } 281 282 static int 283 auacer_ready_codec(struct auacer_softc *sc, int mask) 284 { 285 int count = 0; 286 287 for (count = 0; count < 0x7f; count++) { 288 int val = READ1(sc, ALI_CSPSR); 289 if (val & mask) 290 return 0; 291 } 292 293 printf("auacer_ready_codec: AC97 codec ready timeout.\n"); 294 return EBUSY; 295 } 296 297 static int 298 auacer_sema_codec(struct auacer_softc *sc) 299 { 300 int ttime = 100; 301 302 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 303 delay(1); 304 if (!ttime) 305 printf("auacer_sema_codec: timeout\n"); 306 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 307 } 308 309 int 310 auacer_read_codec(void *v, u_int8_t reg, u_int16_t *val) 311 { 312 struct auacer_softc *sc = v; 313 314 if (auacer_sema_codec(sc)) 315 return EIO; 316 317 reg |= ALI_CPR_ADDR_READ; 318 #if 0 319 if (ac97->num) 320 reg |= ALI_CPR_ADDR_SECONDARY; 321 #endif 322 WRITE2(sc, ALI_CPR_ADDR, reg); 323 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 324 return EIO; 325 *val = READ2(sc, ALI_SPR); 326 327 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 328 reg, *val)); 329 330 return 0; 331 } 332 333 int 334 auacer_write_codec(void *v, u_int8_t reg, u_int16_t val) 335 { 336 struct auacer_softc *sc = v; 337 338 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 339 reg, val)); 340 341 if (auacer_sema_codec(sc)) 342 return EIO; 343 WRITE2(sc, ALI_CPR, val); 344 #if 0 345 if (ac97->num) 346 reg |= ALI_CPR_ADDR_SECONDARY; 347 #endif 348 WRITE2(sc, ALI_CPR_ADDR, reg); 349 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 350 return 0; 351 } 352 353 int 354 auacer_attach_codec(void *v, struct ac97_codec_if *cif) 355 { 356 struct auacer_softc *sc = v; 357 358 sc->codec_if = cif; 359 return 0; 360 } 361 362 void 363 auacer_reset_codec(void *v) 364 { 365 struct auacer_softc *sc = v; 366 u_int32_t reg; 367 int i = 0; 368 369 reg = READ4(sc, ALI_SCR); 370 if ((reg & 2) == 0) /* Cold required */ 371 reg |= 2; 372 else 373 reg |= 1; /* Warm */ 374 reg &= ~0x80000000; /* ACLink on */ 375 WRITE4(sc, ALI_SCR, reg); 376 377 while (i < 10) { 378 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 379 break; 380 delay(50000); /* XXX */ 381 i++; 382 } 383 if (i == 10) { 384 return; 385 } 386 387 for (i = 0; i < 10; i++) { 388 reg = READ4(sc, ALI_RTSR); 389 if (reg & 0x80) /* primary codec */ 390 break; 391 WRITE4(sc, ALI_RTSR, reg | 0x80); 392 delay(50000); /* XXX */ 393 } 394 } 395 396 static void 397 auacer_reset(struct auacer_softc *sc) 398 { 399 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 400 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 401 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 402 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 403 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 404 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 405 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 406 } 407 408 int 409 auacer_open(void *v, int flags) 410 { 411 DPRINTF(ALI_DEBUG_API, ("auacer_open: flags=%d\n", flags)); 412 return 0; 413 } 414 415 void 416 auacer_close(void *v) 417 { 418 DPRINTF(ALI_DEBUG_API, ("auacer_close\n")); 419 } 420 421 int 422 auacer_set_rate(struct auacer_softc *sc, int mode, u_long srate) 423 { 424 int ret; 425 u_long ratetmp; 426 427 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%lu\n", srate)); 428 429 ratetmp = srate; 430 if (mode == AUMODE_RECORD) 431 return sc->codec_if->vtbl->set_rate(sc->codec_if, 432 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 433 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 434 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 435 if (ret) 436 return ret; 437 ratetmp = srate; 438 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 439 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 440 if (ret) 441 return ret; 442 ratetmp = srate; 443 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 444 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 445 return ret; 446 } 447 448 static int 449 auacer_fixup_rate(int rate) 450 { 451 int i; 452 int rates[] = { 453 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000 454 }; 455 456 for (i = 0; i < nitems(rates) - 1; i++) 457 if (rate <= (rates[i] + rates[i+1]) / 2) 458 return (rates[i]); 459 return (rates[i]); 460 } 461 462 int 463 auacer_set_params(void *v, int setmode, int usemode, struct audio_params *play, 464 struct audio_params *rec) 465 { 466 struct auacer_softc *sc = v; 467 struct audio_params *p; 468 uint32_t control; 469 int mode; 470 471 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n")); 472 473 for (mode = AUMODE_RECORD; mode != -1; 474 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 475 if ((setmode & mode) == 0) 476 continue; 477 478 p = mode == AUMODE_PLAY ? play : rec; 479 if (p == NULL) 480 continue; 481 482 p->sample_rate = auacer_fixup_rate(p->sample_rate); 483 p->precision = 16; 484 p->encoding = AUDIO_ENCODING_SLINEAR_LE; 485 if (mode == AUMODE_RECORD) { 486 if (p->channels > 2) 487 p->channels = 2; 488 } 489 p->bps = AUDIO_BPS(p->precision); 490 p->msb = 1; 491 492 if (AC97_IS_FIXED_RATE(sc->codec_if)) 493 p->sample_rate = AC97_SINGLE_RATE; 494 else if (auacer_set_rate(sc, mode, p->sample_rate)) 495 return EINVAL; 496 497 if (mode == AUMODE_PLAY) { 498 control = READ4(sc, ALI_SCR); 499 control &= ~ALI_SCR_PCM_246_MASK; 500 if (p->channels == 4) 501 control |= ALI_SCR_PCM_4; 502 else if (p->channels == 6) 503 control |= ALI_SCR_PCM_6; 504 WRITE4(sc, ALI_SCR, control); 505 } 506 } 507 508 return (0); 509 } 510 511 int 512 auacer_round_blocksize(void *v, int blk) 513 { 514 return ((blk + 0x3f) & ~0x3f); /* keep good alignment */ 515 } 516 517 static void 518 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 519 { 520 uint32_t val; 521 uint8_t port = chan->port; 522 uint32_t slot; 523 524 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 525 526 chan->intr = 0; 527 528 slot = ALI_PORT2SLOT(port); 529 530 val = READ4(sc, ALI_DMACR); 531 val |= 1 << (slot+16); /* pause */ 532 val &= ~(1 << slot); /* no start */ 533 WRITE4(sc, ALI_DMACR, val); 534 WRITE1(sc, port + ALI_OFF_CR, 0); 535 while (READ1(sc, port + ALI_OFF_CR)) 536 ; 537 /* reset whole DMA things */ 538 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 539 /* clear interrupts */ 540 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 541 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 542 } 543 544 int 545 auacer_halt_output(void *v) 546 { 547 struct auacer_softc *sc = v; 548 549 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 550 mtx_enter(&audio_lock); 551 auacer_halt(sc, &sc->sc_pcmo); 552 mtx_leave(&audio_lock); 553 return (0); 554 } 555 556 int 557 auacer_halt_input(void *v) 558 { 559 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n")); 560 return (0); 561 } 562 563 int 564 auacer_set_port(void *v, mixer_ctrl_t *cp) 565 { 566 struct auacer_softc *sc = v; 567 568 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n")); 569 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 570 } 571 572 int 573 auacer_get_port(void *v, mixer_ctrl_t *cp) 574 { 575 struct auacer_softc *sc = v; 576 577 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n")); 578 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 579 } 580 581 int 582 auacer_query_devinfo(void *v, mixer_devinfo_t *dp) 583 { 584 struct auacer_softc *sc = v; 585 586 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n")); 587 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp)); 588 } 589 590 void * 591 auacer_allocm(void *v, int direction, size_t size, int pool, int flags) 592 { 593 struct auacer_softc *sc = v; 594 struct auacer_dma *p; 595 int error; 596 597 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 598 return (NULL); 599 600 p = malloc(sizeof(*p), pool, flags | M_ZERO); 601 if (p == NULL) 602 return (NULL); 603 604 error = auacer_allocmem(sc, size, PAGE_SIZE, p); 605 if (error) { 606 free(p, pool, sizeof(*p)); 607 return (NULL); 608 } 609 610 p->next = sc->sc_dmas; 611 sc->sc_dmas = p; 612 613 return (KERNADDR(p)); 614 } 615 616 void 617 auacer_freem(void *v, void *ptr, int pool) 618 { 619 struct auacer_softc *sc = v; 620 struct auacer_dma *p, **pp; 621 622 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 623 if (KERNADDR(p) == ptr) { 624 auacer_freemem(sc, p); 625 *pp = p->next; 626 free(p, pool, sizeof(*p)); 627 return; 628 } 629 } 630 } 631 632 size_t 633 auacer_round_buffersize(void *v, int direction, size_t size) 634 { 635 636 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 637 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX; 638 639 return size; 640 } 641 642 int 643 auacer_get_props(void *v) 644 { 645 return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX | 646 AUDIO_PROP_MMAP); 647 } 648 649 static void 650 auacer_add_entry(struct auacer_chan *chan) 651 { 652 struct auacer_dmalist *q; 653 654 q = &chan->dmalist[chan->ptr]; 655 656 DPRINTF(ALI_DEBUG_INTR, 657 ("auacer_add_entry: %p = %x @ 0x%x\n", 658 q, chan->blksize / 2, chan->p)); 659 660 q->base = htole32(chan->p); 661 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC); 662 chan->p += chan->blksize; 663 if (chan->p >= chan->end) 664 chan->p = chan->start; 665 666 if (++chan->ptr >= ALI_DMALIST_MAX) 667 chan->ptr = 0; 668 } 669 670 static void 671 auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan) 672 { 673 uint32_t sts; 674 uint32_t civ; 675 676 sts = READ2(sc, chan->port + ALI_OFF_SR); 677 /* intr ack */ 678 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC); 679 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port)); 680 681 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts)); 682 683 if (sts & ALI_SR_DMA_INT_FIFO) { 684 printf("%s: fifo underrun # %u\n", 685 sc->sc_dev.dv_xname, ++chan->fifoe); 686 } 687 688 civ = READ1(sc, chan->port + ALI_OFF_CIV); 689 690 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr)); 691 692 /* XXX */ 693 while (chan->ptr != civ) { 694 auacer_add_entry(chan); 695 } 696 697 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 698 699 while (chan->ack != civ) { 700 if (chan->intr) { 701 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n")); 702 chan->intr(chan->arg); 703 } 704 chan->ack++; 705 if (chan->ack >= ALI_DMALIST_MAX) 706 chan->ack = 0; 707 } 708 } 709 710 int 711 auacer_intr(void *v) 712 { 713 struct auacer_softc *sc = v; 714 int ret, intrs; 715 716 mtx_enter(&audio_lock); 717 intrs = READ4(sc, ALI_INTERRUPTSR); 718 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs)); 719 720 ret = 0; 721 if (intrs & ALI_INT_PCMOUT) { 722 auacer_upd_chan(sc, &sc->sc_pcmo); 723 ret++; 724 } 725 mtx_leave(&audio_lock); 726 return ret != 0; 727 } 728 729 static void 730 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 731 uint32_t start, uint32_t size, uint32_t blksize, void (*intr)(void *), 732 void *arg) 733 { 734 uint32_t port, slot; 735 uint32_t offs, val; 736 737 chan->start = start; 738 chan->ptr = 0; 739 chan->p = chan->start; 740 chan->end = chan->start + size; 741 chan->blksize = blksize; 742 chan->ack = 0; 743 chan->intr = intr; 744 chan->arg = arg; 745 746 auacer_add_entry(chan); 747 auacer_add_entry(chan); 748 749 port = chan->port; 750 slot = ALI_PORT2SLOT(port); 751 752 WRITE1(sc, port + ALI_OFF_CIV, 0); 753 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 754 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 755 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 756 WRITE1(sc, port + ALI_OFF_CR, 757 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 758 val = READ4(sc, ALI_DMACR); 759 val &= ~(1 << (slot+16)); /* no pause */ 760 val |= 1 << slot; /* start */ 761 WRITE4(sc, ALI_DMACR, val); 762 } 763 764 int 765 auacer_trigger_output(void *v, void *start, void *end, int blksize, 766 void (*intr)(void *), void *arg, struct audio_params *param) 767 { 768 struct auacer_softc *sc = v; 769 struct auacer_dma *p; 770 uint32_t size; 771 772 DPRINTF(ALI_DEBUG_DMA, 773 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 774 start, end, blksize, intr, arg, param)); 775 776 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 777 ; 778 if (!p) { 779 printf("auacer_trigger_output: bad addr %p\n", start); 780 return (EINVAL); 781 } 782 783 size = (char *)end - (char *)start; 784 mtx_enter(&audio_lock); 785 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 786 intr, arg); 787 mtx_leave(&audio_lock); 788 return 0; 789 } 790 791 int 792 auacer_trigger_input(void *v, void *start, void *end, int blksize, 793 void (*intr)(void *), void *arg, struct audio_params *param) 794 { 795 return (EINVAL); 796 } 797 798 int 799 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 800 struct auacer_dma *p) 801 { 802 int error; 803 804 p->size = size; 805 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, p->segs, 806 nitems(p->segs), &p->nsegs, BUS_DMA_NOWAIT); 807 if (error) 808 return (error); 809 810 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, &p->addr, 811 BUS_DMA_NOWAIT | sc->sc_dmamap_flags); 812 if (error) 813 goto free; 814 815 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 0, 816 BUS_DMA_NOWAIT, &p->map); 817 if (error) 818 goto unmap; 819 820 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 821 BUS_DMA_NOWAIT); 822 if (error) 823 goto destroy; 824 return (0); 825 826 destroy: 827 bus_dmamap_destroy(sc->dmat, p->map); 828 unmap: 829 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 830 free: 831 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 832 return (error); 833 } 834 835 int 836 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 837 { 838 839 bus_dmamap_unload(sc->dmat, p->map); 840 bus_dmamap_destroy(sc->dmat, p->map); 841 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 842 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 843 return (0); 844 } 845 846 int 847 auacer_alloc_cdata(struct auacer_softc *sc) 848 { 849 bus_dma_segment_t seg; 850 int error, rseg; 851 852 /* 853 * Allocate the control data structure, and create and load the 854 * DMA map for it. 855 */ 856 if ((error = bus_dmamem_alloc(sc->dmat, sizeof(struct auacer_cdata), 857 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 858 printf("%s: unable to allocate control data, error = %d\n", 859 sc->sc_dev.dv_xname, error); 860 goto fail_0; 861 } 862 863 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 864 sizeof(struct auacer_cdata), (caddr_t *) &sc->sc_cdata, 865 sc->sc_dmamap_flags)) != 0) { 866 printf("%s: unable to map control data, error = %d\n", 867 sc->sc_dev.dv_xname, error); 868 goto fail_1; 869 } 870 871 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 872 sizeof(struct auacer_cdata), 0, 0, &sc->sc_cddmamap)) != 0) { 873 printf("%s: unable to create control data DMA map, " 874 "error = %d\n", sc->sc_dev.dv_xname, error); 875 goto fail_2; 876 } 877 878 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, sc->sc_cdata, 879 sizeof(struct auacer_cdata), NULL, 0)) != 0) { 880 printf("%s: unable to load control data DMA map, error = %d\n", 881 sc->sc_dev.dv_xname, error); 882 goto fail_3; 883 } 884 885 return (0); 886 887 fail_3: 888 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 889 fail_2: 890 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata, 891 sizeof(struct auacer_cdata)); 892 fail_1: 893 bus_dmamem_free(sc->dmat, &seg, rseg); 894 fail_0: 895 return (error); 896 } 897 898 int 899 auacer_activate(struct device *self, int act) 900 { 901 struct auacer_softc *sc = (struct auacer_softc *)self; 902 903 if (act == DVACT_RESUME) 904 ac97_resume(&sc->host_if, sc->codec_if); 905 return (config_activate_children(self, act)); 906 } 907