1 /* $NetBSD: auacer.c,v 1.18 2007/12/09 20:28:05 jmcneill 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.18 2007/12/09 20:28:05 jmcneill 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 #define AUACER_NFORMATS 3 137 struct audio_format sc_formats[AUACER_NFORMATS]; 138 struct audio_encoding_set *sc_encodings; 139 }; 140 141 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a) 142 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a) 143 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a) 144 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v) 145 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v) 146 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v) 147 148 /* Debug */ 149 #ifdef AUACER_DEBUG 150 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0) 151 int auacer_debug = 0; 152 #define ALI_DEBUG_CODECIO 0x0001 153 #define ALI_DEBUG_DMA 0x0002 154 #define ALI_DEBUG_INTR 0x0004 155 #define ALI_DEBUG_API 0x0008 156 #define ALI_DEBUG_MIXERAPI 0x0010 157 #else 158 #define DPRINTF(x,y) /* nothing */ 159 #endif 160 161 static int auacer_intr(void *); 162 163 static int auacer_query_encoding(void *, struct audio_encoding *); 164 static int auacer_set_params(void *, int, int, audio_params_t *, 165 audio_params_t *, stream_filter_list_t *, 166 stream_filter_list_t *); 167 static int auacer_round_blocksize(void *, int, int, 168 const audio_params_t *); 169 static int auacer_halt_output(void *); 170 static int auacer_halt_input(void *); 171 static int auacer_getdev(void *, struct audio_device *); 172 static int auacer_set_port(void *, mixer_ctrl_t *); 173 static int auacer_get_port(void *, mixer_ctrl_t *); 174 static int auacer_query_devinfo(void *, mixer_devinfo_t *); 175 static void *auacer_allocm(void *, int, size_t, struct malloc_type *, int); 176 static void auacer_freem(void *, void *, struct malloc_type *); 177 static size_t auacer_round_buffersize(void *, int, size_t); 178 static paddr_t auacer_mappage(void *, void *, off_t, int); 179 static int auacer_get_props(void *); 180 static int auacer_trigger_output(void *, void *, void *, int, 181 void (*)(void *), void *, 182 const audio_params_t *); 183 static int auacer_trigger_input(void *, void *, void *, int, 184 void (*)(void *), void *, 185 const audio_params_t *); 186 187 static int auacer_alloc_cdata(struct auacer_softc *); 188 189 static int auacer_allocmem(struct auacer_softc *, size_t, size_t, 190 struct auacer_dma *); 191 static int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 192 193 static bool auacer_resume(device_t); 194 static int auacer_set_rate(struct auacer_softc *, int, u_int); 195 196 static void auacer_reset(struct auacer_softc *sc); 197 198 static struct audio_hw_if auacer_hw_if = { 199 NULL, /* open */ 200 NULL, /* close */ 201 NULL, /* drain */ 202 auacer_query_encoding, 203 auacer_set_params, 204 auacer_round_blocksize, 205 NULL, /* commit_setting */ 206 NULL, /* init_output */ 207 NULL, /* init_input */ 208 NULL, /* start_output */ 209 NULL, /* start_input */ 210 auacer_halt_output, 211 auacer_halt_input, 212 NULL, /* speaker_ctl */ 213 auacer_getdev, 214 NULL, /* getfd */ 215 auacer_set_port, 216 auacer_get_port, 217 auacer_query_devinfo, 218 auacer_allocm, 219 auacer_freem, 220 auacer_round_buffersize, 221 auacer_mappage, 222 auacer_get_props, 223 auacer_trigger_output, 224 auacer_trigger_input, 225 NULL, /* dev_ioctl */ 226 NULL, /* powerstate */ 227 }; 228 229 #define AUACER_FORMATS_4CH 1 230 #define AUACER_FORMATS_6CH 2 231 static const struct audio_format auacer_formats[AUACER_NFORMATS] = { 232 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 233 2, AUFMT_STEREO, 0, {8000, 48000}}, 234 {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 235 4, AUFMT_SURROUND4, 0, {8000, 48000}}, 236 {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 237 6, AUFMT_DOLBY_5_1, 0, {8000, 48000}}, 238 }; 239 240 static int auacer_attach_codec(void *, struct ac97_codec_if *); 241 static int auacer_read_codec(void *, uint8_t, uint16_t *); 242 static int auacer_write_codec(void *, uint8_t, uint16_t); 243 static int auacer_reset_codec(void *); 244 245 static int 246 auacer_match(struct device *parent, struct cfdata *match, 247 void *aux) 248 { 249 struct pci_attach_args *pa; 250 251 pa = (struct pci_attach_args *)aux; 252 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI && 253 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M5455) 254 return 1; 255 return 0; 256 } 257 258 static void 259 auacer_attach(struct device *parent, struct device *self, void *aux) 260 { 261 struct auacer_softc *sc; 262 struct pci_attach_args *pa; 263 pci_intr_handle_t ih; 264 bus_size_t aud_size; 265 pcireg_t v; 266 const char *intrstr; 267 int i; 268 269 sc = (struct auacer_softc *)self; 270 pa = aux; 271 aprint_normal(": Acer Labs M5455 Audio controller\n"); 272 273 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot, 274 &sc->aud_ioh, NULL, &aud_size)) { 275 aprint_error(": can't map i/o space\n"); 276 return; 277 } 278 279 sc->sc_pc = pa->pa_pc; 280 sc->sc_pt = pa->pa_tag; 281 sc->dmat = pa->pa_dmat; 282 283 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 284 285 /* enable bus mastering */ 286 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 287 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 288 v | PCI_COMMAND_MASTER_ENABLE); 289 290 /* Map and establish the interrupt. */ 291 if (pci_intr_map(pa, &ih)) { 292 aprint_error("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 293 return; 294 } 295 intrstr = pci_intr_string(pa->pa_pc, ih); 296 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, 297 auacer_intr, sc); 298 if (sc->sc_ih == NULL) { 299 aprint_error("%s: can't establish interrupt", 300 sc->sc_dev.dv_xname); 301 if (intrstr != NULL) 302 aprint_normal(" at %s", intrstr); 303 aprint_normal("\n"); 304 return; 305 } 306 aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 307 308 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); 309 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, 310 "0x%02x", PCI_REVISION(pa->pa_class)); 311 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, MAX_AUDIO_DEV_LEN); 312 313 /* Set up DMA lists. */ 314 auacer_alloc_cdata(sc); 315 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 316 sc->sc_pcmo.ptr = 0; 317 sc->sc_pcmo.port = ALI_BASE_PO; 318 319 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 320 sc->sc_pcmo.dmalist)); 321 322 sc->host_if.arg = sc; 323 sc->host_if.attach = auacer_attach_codec; 324 sc->host_if.read = auacer_read_codec; 325 sc->host_if.write = auacer_write_codec; 326 sc->host_if.reset = auacer_reset_codec; 327 328 if (ac97_attach(&sc->host_if, self) != 0) 329 return; 330 331 /* setup audio_format */ 332 memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats)); 333 if (!AC97_IS_4CH(sc->codec_if)) 334 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]); 335 if (!AC97_IS_6CH(sc->codec_if)) 336 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_6CH]); 337 if (AC97_IS_FIXED_RATE(sc->codec_if)) { 338 for (i = 0; i < AUACER_NFORMATS; i++) { 339 sc->sc_formats[i].frequency_type = 1; 340 sc->sc_formats[i].frequency[0] = 48000; 341 } 342 } 343 344 if (0 != auconv_create_encodings(sc->sc_formats, AUACER_NFORMATS, 345 &sc->sc_encodings)) { 346 return; 347 } 348 349 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); 350 351 auacer_reset(sc); 352 353 if (!pmf_device_register(self, NULL, auacer_resume)) 354 aprint_error_dev(self, "couldn't establish power handler\n"); 355 } 356 357 CFATTACH_DECL(auacer, sizeof(struct auacer_softc), 358 auacer_match, auacer_attach, NULL, NULL); 359 360 static int 361 auacer_ready_codec(struct auacer_softc *sc, int mask) 362 { 363 int count; 364 365 for (count = 0; count < 0x7f; count++) { 366 int val = READ1(sc, ALI_CSPSR); 367 if (val & mask) 368 return 0; 369 } 370 371 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n"); 372 return EBUSY; 373 } 374 375 static int 376 auacer_sema_codec(struct auacer_softc *sc) 377 { 378 int ttime; 379 380 ttime = 100; 381 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 382 delay(1); 383 if (!ttime) 384 aprint_normal("auacer_sema_codec: timeout\n"); 385 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 386 } 387 388 static int 389 auacer_read_codec(void *v, uint8_t reg, uint16_t *val) 390 { 391 struct auacer_softc *sc; 392 393 sc = v; 394 if (auacer_sema_codec(sc)) 395 return EIO; 396 397 reg |= ALI_CPR_ADDR_READ; 398 #if 0 399 if (ac97->num) 400 reg |= ALI_CPR_ADDR_SECONDARY; 401 #endif 402 WRITE2(sc, ALI_CPR_ADDR, reg); 403 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 404 return EIO; 405 *val = READ2(sc, ALI_SPR); 406 407 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 408 reg, *val)); 409 410 return 0; 411 } 412 413 int 414 auacer_write_codec(void *v, uint8_t reg, uint16_t val) 415 { 416 struct auacer_softc *sc; 417 418 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 419 reg, val)); 420 sc = v; 421 if (auacer_sema_codec(sc)) 422 return EIO; 423 WRITE2(sc, ALI_CPR, val); 424 #if 0 425 if (ac97->num) 426 reg |= ALI_CPR_ADDR_SECONDARY; 427 #endif 428 WRITE2(sc, ALI_CPR_ADDR, reg); 429 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 430 return 0; 431 } 432 433 static int 434 auacer_attach_codec(void *v, struct ac97_codec_if *cif) 435 { 436 struct auacer_softc *sc; 437 438 sc = v; 439 sc->codec_if = cif; 440 return 0; 441 } 442 443 static int 444 auacer_reset_codec(void *v) 445 { 446 struct auacer_softc *sc; 447 uint32_t reg; 448 int i; 449 450 sc = v; 451 i = 0; 452 reg = READ4(sc, ALI_SCR); 453 if ((reg & 2) == 0) /* Cold required */ 454 reg |= 2; 455 else 456 reg |= 1; /* Warm */ 457 reg &= ~0x80000000; /* ACLink on */ 458 WRITE4(sc, ALI_SCR, reg); 459 460 while (i < 10) { 461 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 462 break; 463 delay(50000); /* XXX */ 464 i++; 465 } 466 if (i == 10) { 467 return EIO; 468 } 469 470 for (i = 0; i < 10; i++) { 471 reg = READ4(sc, ALI_RTSR); 472 if (reg & 0x80) /* primary codec */ 473 break; 474 WRITE4(sc, ALI_RTSR, reg | 0x80); 475 delay(50000); /* XXX */ 476 } 477 478 return 0; 479 } 480 481 static void 482 auacer_reset(struct auacer_softc *sc) 483 { 484 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 485 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 486 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 487 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 488 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 489 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 490 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 491 } 492 493 static int 494 auacer_query_encoding(void *v, struct audio_encoding *aep) 495 { 496 struct auacer_softc *sc; 497 498 DPRINTF(ALI_DEBUG_API, ("auacer_query_encoding\n")); 499 sc = v; 500 return auconv_query_encoding(sc->sc_encodings, aep); 501 } 502 503 static int 504 auacer_set_rate(struct auacer_softc *sc, int mode, u_int srate) 505 { 506 int ret; 507 u_int ratetmp; 508 509 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%u\n", srate)); 510 511 ratetmp = srate; 512 if (mode == AUMODE_RECORD) 513 return sc->codec_if->vtbl->set_rate(sc->codec_if, 514 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 515 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 516 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 517 if (ret) 518 return ret; 519 ratetmp = srate; 520 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 521 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 522 if (ret) 523 return ret; 524 ratetmp = srate; 525 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 526 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 527 return ret; 528 } 529 530 static int 531 auacer_set_params(void *v, int setmode, int usemode, 532 audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil, 533 stream_filter_list_t *rfil) 534 { 535 struct auacer_softc *sc; 536 struct audio_params *p; 537 stream_filter_list_t *fil; 538 uint32_t control; 539 int mode, index; 540 541 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n")); 542 sc = v; 543 for (mode = AUMODE_RECORD; mode != -1; 544 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 545 if ((setmode & mode) == 0) 546 continue; 547 548 p = mode == AUMODE_PLAY ? play : rec; 549 if (p == NULL) 550 continue; 551 552 if ((p->sample_rate != 8000) && 553 (p->sample_rate != 11025) && 554 (p->sample_rate != 12000) && 555 (p->sample_rate != 16000) && 556 (p->sample_rate != 22050) && 557 (p->sample_rate != 24000) && 558 (p->sample_rate != 32000) && 559 (p->sample_rate != 44100) && 560 (p->sample_rate != 48000)) 561 return (EINVAL); 562 563 fil = mode == AUMODE_PLAY ? pfil : rfil; 564 index = auconv_set_converter(sc->sc_formats, AUACER_NFORMATS, 565 mode, p, TRUE, fil); 566 if (index < 0) 567 return EINVAL; 568 if (fil->req_size > 0) 569 p = &fil->filters[0].param; 570 /* p points HW encoding */ 571 if (sc->sc_formats[index].frequency_type != 1 572 && auacer_set_rate(sc, mode, p->sample_rate)) 573 return EINVAL; 574 if (mode == AUMODE_PLAY) { 575 control = READ4(sc, ALI_SCR); 576 control &= ~ALI_SCR_PCM_246_MASK; 577 if (p->channels == 4) 578 control |= ALI_SCR_PCM_4; 579 else if (p->channels == 6) 580 control |= ALI_SCR_PCM_6; 581 WRITE4(sc, ALI_SCR, control); 582 } 583 } 584 585 return (0); 586 } 587 588 static int 589 auacer_round_blocksize(void *v, int blk, int mode, 590 const audio_params_t *param) 591 { 592 593 return blk & ~0x3f; /* keep good alignment */ 594 } 595 596 static void 597 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 598 { 599 uint32_t val; 600 uint8_t port; 601 uint32_t slot; 602 603 port = chan->port; 604 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 605 chan->intr = 0; 606 607 slot = ALI_PORT2SLOT(port); 608 609 val = READ4(sc, ALI_DMACR); 610 val |= 1 << (slot+16); /* pause */ 611 val &= ~(1 << slot); /* no start */ 612 WRITE4(sc, ALI_DMACR, val); 613 WRITE1(sc, port + ALI_OFF_CR, 0); 614 while (READ1(sc, port + ALI_OFF_CR)) 615 ; 616 /* reset whole DMA things */ 617 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 618 /* clear interrupts */ 619 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 620 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 621 } 622 623 static int 624 auacer_halt_output(void *v) 625 { 626 struct auacer_softc *sc; 627 628 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 629 sc = v; 630 auacer_halt(sc, &sc->sc_pcmo); 631 632 return 0; 633 } 634 635 static int 636 auacer_halt_input(void *v) 637 { 638 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n")); 639 640 return 0; 641 } 642 643 static int 644 auacer_getdev(void *v, struct audio_device *adp) 645 { 646 struct auacer_softc *sc; 647 648 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n")); 649 sc = v; 650 *adp = sc->sc_audev; 651 return 0; 652 } 653 654 static int 655 auacer_set_port(void *v, mixer_ctrl_t *cp) 656 { 657 struct auacer_softc *sc; 658 659 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n")); 660 sc = v; 661 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); 662 } 663 664 static int 665 auacer_get_port(void *v, mixer_ctrl_t *cp) 666 { 667 struct auacer_softc *sc; 668 669 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n")); 670 sc = v; 671 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); 672 } 673 674 static int 675 auacer_query_devinfo(void *v, mixer_devinfo_t *dp) 676 { 677 struct auacer_softc *sc; 678 679 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n")); 680 sc = v; 681 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); 682 } 683 684 static void * 685 auacer_allocm(void *v, int direction, size_t size, 686 struct malloc_type *pool, int flags) 687 { 688 struct auacer_softc *sc; 689 struct auacer_dma *p; 690 int error; 691 692 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 693 return NULL; 694 695 p = malloc(sizeof(*p), pool, flags | M_ZERO); 696 if (p == NULL) 697 return NULL; 698 sc = v; 699 error = auacer_allocmem(sc, size, 0, p); 700 if (error) { 701 free(p, pool); 702 return NULL; 703 } 704 705 p->next = sc->sc_dmas; 706 sc->sc_dmas = p; 707 708 return KERNADDR(p); 709 } 710 711 static void 712 auacer_freem(void *v, void *ptr, struct malloc_type *pool) 713 { 714 struct auacer_softc *sc; 715 struct auacer_dma *p, **pp; 716 717 sc = v; 718 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 719 if (KERNADDR(p) == ptr) { 720 auacer_freemem(sc, p); 721 *pp = p->next; 722 free(p, pool); 723 return; 724 } 725 } 726 } 727 728 static size_t 729 auacer_round_buffersize(void *v, int direction, size_t size) 730 { 731 732 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 733 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX; 734 735 return size; 736 } 737 738 static paddr_t 739 auacer_mappage(void *v, void *mem, off_t off, int prot) 740 { 741 struct auacer_softc *sc; 742 struct auacer_dma *p; 743 744 if (off < 0) 745 return -1; 746 sc = v; 747 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) 748 continue; 749 if (p == NULL) 750 return -1; 751 return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, 752 off, prot, BUS_DMA_WAITOK); 753 } 754 755 static int 756 auacer_get_props(void *v) 757 { 758 struct auacer_softc *sc; 759 int props; 760 761 sc = v; 762 props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 763 /* 764 * Even if the codec is fixed-rate, set_param() succeeds for any sample 765 * rate because of aurateconv. Applications can't know what rate the 766 * device can process in the case of mmap(). 767 */ 768 if (!AC97_IS_FIXED_RATE(sc->codec_if)) 769 props |= AUDIO_PROP_MMAP; 770 return props; 771 } 772 773 static void 774 auacer_add_entry(struct auacer_chan *chan) 775 { 776 struct auacer_dmalist *q; 777 778 q = &chan->dmalist[chan->ptr]; 779 780 DPRINTF(ALI_DEBUG_INTR, 781 ("auacer_add_entry: %p = %x @ 0x%x\n", 782 q, chan->blksize / 2, chan->p)); 783 784 q->base = htole32(chan->p); 785 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC); 786 chan->p += chan->blksize; 787 if (chan->p >= chan->end) 788 chan->p = chan->start; 789 790 if (++chan->ptr >= ALI_DMALIST_MAX) 791 chan->ptr = 0; 792 } 793 794 static void 795 auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan) 796 { 797 uint32_t sts; 798 uint32_t civ; 799 800 sts = READ2(sc, chan->port + ALI_OFF_SR); 801 /* intr ack */ 802 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC); 803 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port)); 804 805 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts)); 806 807 if (sts & ALI_SR_DMA_INT_FIFO) { 808 printf("%s: fifo underrun # %u\n", 809 sc->sc_dev.dv_xname, ++chan->fifoe); 810 } 811 812 civ = READ1(sc, chan->port + ALI_OFF_CIV); 813 814 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr)); 815 816 /* XXX */ 817 while (chan->ptr != civ) { 818 auacer_add_entry(chan); 819 } 820 821 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 822 823 while (chan->ack != civ) { 824 if (chan->intr) { 825 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n")); 826 chan->intr(chan->arg); 827 } 828 chan->ack++; 829 if (chan->ack >= ALI_DMALIST_MAX) 830 chan->ack = 0; 831 } 832 } 833 834 static int 835 auacer_intr(void *v) 836 { 837 struct auacer_softc *sc; 838 int ret, intrs; 839 840 sc = v; 841 intrs = READ4(sc, ALI_INTERRUPTSR); 842 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs)); 843 844 ret = 0; 845 if (intrs & ALI_INT_PCMOUT) { 846 auacer_upd_chan(sc, &sc->sc_pcmo); 847 ret++; 848 } 849 850 return ret != 0; 851 } 852 853 static void 854 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 855 uint32_t start, uint32_t size, uint32_t blksize, 856 void (*intr)(void *), void *arg) 857 { 858 uint32_t port, slot; 859 uint32_t offs, val; 860 861 chan->start = start; 862 chan->ptr = 0; 863 chan->p = chan->start; 864 chan->end = chan->start + size; 865 chan->blksize = blksize; 866 chan->ack = 0; 867 chan->intr = intr; 868 chan->arg = arg; 869 870 auacer_add_entry(chan); 871 auacer_add_entry(chan); 872 873 port = chan->port; 874 slot = ALI_PORT2SLOT(port); 875 876 WRITE1(sc, port + ALI_OFF_CIV, 0); 877 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 878 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 879 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 880 WRITE1(sc, port + ALI_OFF_CR, 881 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 882 val = READ4(sc, ALI_DMACR); 883 val &= ~(1 << (slot+16)); /* no pause */ 884 val |= 1 << slot; /* start */ 885 WRITE4(sc, ALI_DMACR, val); 886 } 887 888 static int 889 auacer_trigger_output(void *v, void *start, void *end, int blksize, 890 void (*intr)(void *), void *arg, const audio_params_t *param) 891 { 892 struct auacer_softc *sc; 893 struct auacer_dma *p; 894 uint32_t size; 895 896 DPRINTF(ALI_DEBUG_DMA, 897 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 898 start, end, blksize, intr, arg, param)); 899 sc = v; 900 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 901 continue; 902 if (!p) { 903 printf("auacer_trigger_output: bad addr %p\n", start); 904 return (EINVAL); 905 } 906 907 size = (char *)end - (char *)start; 908 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 909 intr, arg); 910 911 return 0; 912 } 913 914 static int 915 auacer_trigger_input(void *v, void *start, void *end, 916 int blksize, void (*intr)(void *), void *arg, 917 const audio_params_t *param) 918 { 919 return EINVAL; 920 } 921 922 static int 923 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 924 struct auacer_dma *p) 925 { 926 int error; 927 928 p->size = size; 929 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 930 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 931 &p->nsegs, BUS_DMA_NOWAIT); 932 if (error) 933 return error; 934 935 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 936 &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags); 937 if (error) 938 goto free; 939 940 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 941 0, BUS_DMA_NOWAIT, &p->map); 942 if (error) 943 goto unmap; 944 945 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 946 BUS_DMA_NOWAIT); 947 if (error) 948 goto destroy; 949 return (0); 950 951 destroy: 952 bus_dmamap_destroy(sc->dmat, p->map); 953 unmap: 954 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 955 free: 956 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 957 return error; 958 } 959 960 static int 961 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 962 { 963 964 bus_dmamap_unload(sc->dmat, p->map); 965 bus_dmamap_destroy(sc->dmat, p->map); 966 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 967 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 968 return 0; 969 } 970 971 static int 972 auacer_alloc_cdata(struct auacer_softc *sc) 973 { 974 bus_dma_segment_t seg; 975 int error, rseg; 976 977 /* 978 * Allocate the control data structure, and create and load the 979 * DMA map for it. 980 */ 981 if ((error = bus_dmamem_alloc(sc->dmat, 982 sizeof(struct auacer_cdata), 983 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 984 printf("%s: unable to allocate control data, error = %d\n", 985 sc->sc_dev.dv_xname, error); 986 goto fail_0; 987 } 988 989 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 990 sizeof(struct auacer_cdata), 991 (void **) &sc->sc_cdata, 992 sc->sc_dmamap_flags)) != 0) { 993 printf("%s: unable to map control data, error = %d\n", 994 sc->sc_dev.dv_xname, error); 995 goto fail_1; 996 } 997 998 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 999 sizeof(struct auacer_cdata), 0, 0, 1000 &sc->sc_cddmamap)) != 0) { 1001 printf("%s: unable to create control data DMA map, " 1002 "error = %d\n", sc->sc_dev.dv_xname, error); 1003 goto fail_2; 1004 } 1005 1006 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, 1007 sc->sc_cdata, sizeof(struct auacer_cdata), 1008 NULL, 0)) != 0) { 1009 printf("%s: unable to load control data DMA map, " 1010 "error = %d\n", sc->sc_dev.dv_xname, error); 1011 goto fail_3; 1012 } 1013 1014 return 0; 1015 1016 fail_3: 1017 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 1018 fail_2: 1019 bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata, 1020 sizeof(struct auacer_cdata)); 1021 fail_1: 1022 bus_dmamem_free(sc->dmat, &seg, rseg); 1023 fail_0: 1024 return error; 1025 } 1026 1027 static bool 1028 auacer_resume(device_t dv) 1029 { 1030 struct auacer_softc *sc = device_private(dv); 1031 1032 auacer_reset_codec(sc); 1033 delay(1000); 1034 sc->codec_if->vtbl->restore_ports(sc->codec_if); 1035 1036 return true; 1037 } 1038