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