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