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