auacer.c revision 1.3
1/* $NetBSD: auacer.c,v 1.3 2004/11/10 04:20:26 kent 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. 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.3 2004/11/10 04:20:26 kent 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 <machine/bus.h> 76 77#include <dev/ic/ac97reg.h> 78#include <dev/ic/ac97var.h> 79 80struct auacer_dma { 81 bus_dmamap_t map; 82 caddr_t 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 92struct auacer_cdata { 93 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX]; 94}; 95 96struct 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 107struct 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 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) 151int 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 161int auacer_match(struct device *, struct cfdata *, void *); 162void auacer_attach(struct device *, struct device *, void *); 163int auacer_intr(void *); 164 165CFATTACH_DECL(auacer, sizeof(struct auacer_softc), 166 auacer_match, auacer_attach, NULL, NULL); 167 168int auacer_open(void *, int); 169void auacer_close(void *); 170int auacer_query_encoding(void *, struct audio_encoding *); 171int auacer_set_params(void *, int, int, struct audio_params *, 172 struct audio_params *); 173int auacer_round_blocksize(void *, int); 174int auacer_halt_output(void *); 175int auacer_halt_input(void *); 176int auacer_getdev(void *, struct audio_device *); 177int auacer_set_port(void *, mixer_ctrl_t *); 178int auacer_get_port(void *, mixer_ctrl_t *); 179int auacer_query_devinfo(void *, mixer_devinfo_t *); 180void *auacer_allocm(void *, int, size_t, struct malloc_type *, int); 181void auacer_freem(void *, void *, struct malloc_type *); 182size_t auacer_round_buffersize(void *, int, size_t); 183paddr_t auacer_mappage(void *, void *, off_t, int); 184int auacer_get_props(void *); 185int auacer_trigger_output(void *, void *, void *, int, void (*)(void *), 186 void *, struct audio_params *); 187int auacer_trigger_input(void *, void *, void *, int, void (*)(void *), 188 void *, struct audio_params *); 189 190int auacer_alloc_cdata(struct auacer_softc *); 191 192int auacer_allocmem(struct auacer_softc *, size_t, size_t, 193 struct auacer_dma *); 194int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 195 196void auacer_powerhook(int, void *); 197int auacer_set_rate(struct auacer_softc *, int, u_long); 198void auacer_finish_attach(struct device *); 199 200static void auacer_reset(struct auacer_softc *sc); 201 202struct audio_hw_if auacer_hw_if = { 203 auacer_open, 204 auacer_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}; 231 232int auacer_attach_codec(void *, struct ac97_codec_if *); 233int auacer_read_codec(void *, u_int8_t, u_int16_t *); 234int auacer_write_codec(void *, u_int8_t, u_int16_t); 235int auacer_reset_codec(void *); 236 237int 238auacer_match(struct device *parent, struct cfdata *match, void *aux) 239{ 240 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 241 242 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI && 243 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M5455) 244 return 1; 245 return 0; 246} 247 248void 249auacer_attach(struct device *parent, struct device *self, void *aux) 250{ 251 struct auacer_softc *sc = (struct auacer_softc *)self; 252 struct pci_attach_args *pa = aux; 253 pci_intr_handle_t ih; 254 bus_size_t aud_size; 255 pcireg_t v; 256 const char *intrstr; 257 258 aprint_normal(": Acer Labs M5455 Audio controller\n"); 259 260 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot, 261 &sc->aud_ioh, NULL, &aud_size)) { 262 aprint_error(": can't map i/o space\n"); 263 return; 264 } 265 266 sc->sc_pc = pa->pa_pc; 267 sc->sc_pt = pa->pa_tag; 268 sc->dmat = pa->pa_dmat; 269 270 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 271 272 /* enable bus mastering */ 273 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 274 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 275 v | PCI_COMMAND_MASTER_ENABLE); 276 277 /* Map and establish the interrupt. */ 278 if (pci_intr_map(pa, &ih)) { 279 aprint_error("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 280 return; 281 } 282 intrstr = pci_intr_string(pa->pa_pc, ih); 283 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, 284 auacer_intr, sc); 285 if (sc->sc_ih == NULL) { 286 aprint_error("%s: can't establish interrupt", 287 sc->sc_dev.dv_xname); 288 if (intrstr != NULL) 289 aprint_normal(" at %s", intrstr); 290 aprint_normal("\n"); 291 return; 292 } 293 aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 294 295 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); 296 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, 297 "0x%02x", PCI_REVISION(pa->pa_class)); 298 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, MAX_AUDIO_DEV_LEN); 299 300 /* Set up DMA lists. */ 301 auacer_alloc_cdata(sc); 302 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 303 sc->sc_pcmo.ptr = 0; 304 sc->sc_pcmo.port = ALI_BASE_PO; 305 306 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 307 sc->sc_pcmo.dmalist)); 308 309 sc->host_if.arg = sc; 310 sc->host_if.attach = auacer_attach_codec; 311 sc->host_if.read = auacer_read_codec; 312 sc->host_if.write = auacer_write_codec; 313 sc->host_if.reset = auacer_reset_codec; 314 315 if (ac97_attach(&sc->host_if) != 0) 316 return; 317 318 /* Watch for power change */ 319 sc->sc_suspend = PWR_RESUME; 320 sc->sc_powerhook = powerhook_establish(auacer_powerhook, sc); 321 322 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev); 323 324 auacer_reset(sc); 325} 326 327static int 328auacer_ready_codec(struct auacer_softc *sc, int mask) 329{ 330 int count = 0; 331 332 for (count = 0; count < 0x7f; count++) { 333 int val = READ1(sc, ALI_CSPSR); 334 if (val & mask) 335 return 0; 336 } 337 338 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n"); 339 return EBUSY; 340} 341 342static int 343auacer_sema_codec(struct auacer_softc *sc) 344{ 345 int time = 100; 346 347 while (time-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 348 delay(1); 349 if (!time) 350 aprint_normal("auacer_sema_codec: timeout\n"); 351 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 352} 353 354int 355auacer_read_codec(void *v, u_int8_t reg, u_int16_t *val) 356{ 357 struct auacer_softc *sc = v; 358 359 if (auacer_sema_codec(sc)) 360 return EIO; 361 362 reg |= ALI_CPR_ADDR_READ; 363#if 0 364 if (ac97->num) 365 reg |= ALI_CPR_ADDR_SECONDARY; 366#endif 367 WRITE2(sc, ALI_CPR_ADDR, reg); 368 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 369 return EIO; 370 *val = READ2(sc, ALI_SPR); 371 372 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 373 reg, *val)); 374 375 return 0; 376} 377 378int 379auacer_write_codec(void *v, u_int8_t reg, u_int16_t val) 380{ 381 struct auacer_softc *sc = v; 382 383 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 384 reg, val)); 385 386 if (auacer_sema_codec(sc)) 387 return EIO; 388 WRITE2(sc, ALI_CPR, val); 389#if 0 390 if (ac97->num) 391 reg |= ALI_CPR_ADDR_SECONDARY; 392#endif 393 WRITE2(sc, ALI_CPR_ADDR, reg); 394 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 395 return 0; 396} 397 398int 399auacer_attach_codec(void *v, struct ac97_codec_if *cif) 400{ 401 struct auacer_softc *sc = v; 402 403 sc->codec_if = cif; 404 return 0; 405} 406 407int 408auacer_reset_codec(void *v) 409{ 410 struct auacer_softc *sc = v; 411 u_int32_t reg; 412 int i = 0; 413 414 reg = READ4(sc, ALI_SCR); 415 if ((reg & 2) == 0) /* Cold required */ 416 reg |= 2; 417 else 418 reg |= 1; /* Warm */ 419 reg &= ~0x80000000; /* ACLink on */ 420 WRITE4(sc, ALI_SCR, reg); 421 422 while (i < 10) { 423 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 424 break; 425 delay(50000); /* XXX */ 426 i++; 427 } 428 if (i == 10) { 429 return EIO; 430 } 431 432 for (i = 0; i < 10; i++) { 433 reg = READ4(sc, ALI_RTSR); 434 if (reg & 0x80) /* primary codec */ 435 break; 436 WRITE4(sc, ALI_RTSR, reg | 0x80); 437 delay(50000); /* XXX */ 438 } 439 440 return 0; 441} 442 443static void 444auacer_reset(struct auacer_softc *sc) 445{ 446 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 447 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 448 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 449 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 450 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 451 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 452 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 453} 454 455int 456auacer_open(void *v, int flags) 457{ 458 DPRINTF(ALI_DEBUG_API, ("auacer_open: flags=%d\n", flags)); 459 return 0; 460} 461 462void 463auacer_close(void *v) 464{ 465 DPRINTF(ALI_DEBUG_API, ("auacer_close\n")); 466} 467 468int 469auacer_query_encoding(void *v, struct audio_encoding *aep) 470{ 471 DPRINTF(ALI_DEBUG_API, ("auacer_query_encoding\n")); 472 473 switch (aep->index) { 474 case 0: 475 strcpy(aep->name, AudioEulinear); 476 aep->encoding = AUDIO_ENCODING_ULINEAR; 477 aep->precision = 8; 478 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 479 return (0); 480 case 1: 481 strcpy(aep->name, AudioEmulaw); 482 aep->encoding = AUDIO_ENCODING_ULAW; 483 aep->precision = 8; 484 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 485 return (0); 486 case 2: 487 strcpy(aep->name, AudioEalaw); 488 aep->encoding = AUDIO_ENCODING_ALAW; 489 aep->precision = 8; 490 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 491 return (0); 492 case 3: 493 strcpy(aep->name, AudioEslinear); 494 aep->encoding = AUDIO_ENCODING_SLINEAR; 495 aep->precision = 8; 496 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 497 return (0); 498 case 4: 499 strcpy(aep->name, AudioEslinear_le); 500 aep->encoding = AUDIO_ENCODING_SLINEAR_LE; 501 aep->precision = 16; 502 aep->flags = 0; 503 return (0); 504 case 5: 505 strcpy(aep->name, AudioEulinear_le); 506 aep->encoding = AUDIO_ENCODING_ULINEAR_LE; 507 aep->precision = 16; 508 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 509 return (0); 510 case 6: 511 strcpy(aep->name, AudioEslinear_be); 512 aep->encoding = AUDIO_ENCODING_SLINEAR_BE; 513 aep->precision = 16; 514 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 515 return (0); 516 case 7: 517 strcpy(aep->name, AudioEulinear_be); 518 aep->encoding = AUDIO_ENCODING_ULINEAR_BE; 519 aep->precision = 16; 520 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 521 return (0); 522 default: 523 return (EINVAL); 524 } 525} 526 527int 528auacer_set_rate(struct auacer_softc *sc, int mode, u_long srate) 529{ 530 int ret; 531 u_long ratetmp; 532 533 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%lu\n", srate)); 534 535 ratetmp = srate; 536 if (mode == AUMODE_RECORD) 537 return sc->codec_if->vtbl->set_rate(sc->codec_if, 538 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 539 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 540 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 541 if (ret) 542 return ret; 543 ratetmp = srate; 544 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 545 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 546 if (ret) 547 return ret; 548 ratetmp = srate; 549 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 550 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 551 return ret; 552} 553 554int 555auacer_set_params(void *v, int setmode, int usemode, struct audio_params *play, 556 struct audio_params *rec) 557{ 558 struct auacer_softc *sc = v; 559 struct audio_params *p; 560 uint32_t control; 561 int mode; 562 563 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n")); 564 565 for (mode = AUMODE_RECORD; mode != -1; 566 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 567 if ((setmode & mode) == 0) 568 continue; 569 570 p = mode == AUMODE_PLAY ? play : rec; 571 if (p == NULL) 572 continue; 573 574 if ((p->sample_rate != 8000) && 575 (p->sample_rate != 11025) && 576 (p->sample_rate != 12000) && 577 (p->sample_rate != 16000) && 578 (p->sample_rate != 22050) && 579 (p->sample_rate != 24000) && 580 (p->sample_rate != 32000) && 581 (p->sample_rate != 44100) && 582 (p->sample_rate != 48000)) 583 return (EINVAL); 584 585 p->factor = 1; 586 if (p->precision == 8) 587 p->factor *= 2; 588 589 p->sw_code = NULL; 590 /* setup hardware formats */ 591 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE; 592 p->hw_precision = 16; 593 594 if (mode == AUMODE_RECORD) { 595 if (p->channels < 1 || p->channels > 2) 596 return EINVAL; 597 } else { 598 switch (p->channels) { 599 case 1: 600 break; 601 case 2: 602 break; 603 case 4: 604 if (!AC97_IS_4CH(sc->codec_if)) 605 return EINVAL; 606 break; 607 case 6: 608 if (!AC97_IS_6CH(sc->codec_if)) 609 return EINVAL; 610 break; 611 default: 612 return EINVAL; 613 } 614 } 615 /* If monaural is requested, aurateconv expands a monaural 616 * stream to stereo. */ 617 if (p->channels == 1) 618 p->hw_channels = 2; 619 620 switch (p->encoding) { 621 case AUDIO_ENCODING_SLINEAR_BE: 622 if (p->precision == 16) { 623 p->sw_code = swap_bytes; 624 } else { 625 if (mode == AUMODE_PLAY) 626 p->sw_code = linear8_to_linear16_le; 627 else 628 p->sw_code = linear16_to_linear8_le; 629 } 630 break; 631 632 case AUDIO_ENCODING_SLINEAR_LE: 633 if (p->precision != 16) { 634 if (mode == AUMODE_PLAY) 635 p->sw_code = linear8_to_linear16_le; 636 else 637 p->sw_code = linear16_to_linear8_le; 638 } 639 break; 640 641 case AUDIO_ENCODING_ULINEAR_BE: 642 if (p->precision == 16) { 643 if (mode == AUMODE_PLAY) 644 p->sw_code = 645 swap_bytes_change_sign16_le; 646 else 647 p->sw_code = 648 change_sign16_swap_bytes_le; 649 } else { 650 if (mode == AUMODE_PLAY) 651 p->sw_code = 652 ulinear8_to_slinear16_le; 653 else 654 p->sw_code = 655 slinear16_to_ulinear8_le; 656 } 657 break; 658 659 case AUDIO_ENCODING_ULINEAR_LE: 660 if (p->precision == 16) { 661 p->sw_code = change_sign16_le; 662 } else { 663 if (mode == AUMODE_PLAY) 664 p->sw_code = 665 ulinear8_to_slinear16_le; 666 else 667 p->sw_code = 668 slinear16_to_ulinear8_le; 669 } 670 break; 671 672 case AUDIO_ENCODING_ULAW: 673 if (mode == AUMODE_PLAY) { 674 p->sw_code = mulaw_to_slinear16_le; 675 } else { 676 p->sw_code = slinear16_to_mulaw_le; 677 } 678 break; 679 680 case AUDIO_ENCODING_ALAW: 681 if (mode == AUMODE_PLAY) { 682 p->sw_code = alaw_to_slinear16_le; 683 } else { 684 p->sw_code = slinear16_to_alaw_le; 685 } 686 break; 687 688 default: 689 return (EINVAL); 690 } 691 692 if (AC97_IS_FIXED_RATE(sc->codec_if)) { 693 p->hw_sample_rate = AC97_SINGLE_RATE; 694 /* If hw_sample_rate is changed, aurateconv works. */ 695 } else { 696 if (auacer_set_rate(sc, mode, p->sample_rate)) 697 return EINVAL; 698 } 699 700 if (mode == AUMODE_PLAY) { 701 control = READ4(sc, ALI_SCR); 702 control &= ~ALI_SCR_PCM_246_MASK; 703 if (p->channels == 4) 704 control |= ALI_SCR_PCM_4; 705 else if (p->channels == 6) 706 control |= ALI_SCR_PCM_6; 707 WRITE4(sc, ALI_SCR, control); 708 } 709 } 710 711 return (0); 712} 713 714int 715auacer_round_blocksize(void *v, int blk) 716{ 717 718 return (blk & ~0x3f); /* keep good alignment */ 719} 720 721static void 722auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 723{ 724 uint32_t val; 725 uint8_t port = chan->port; 726 uint32_t slot; 727 728 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 729 730 chan->intr = 0; 731 732 slot = ALI_PORT2SLOT(port); 733 734 val = READ4(sc, ALI_DMACR); 735 val |= 1 << (slot+16); /* pause */ 736 val &= ~(1 << slot); /* no start */ 737 WRITE4(sc, ALI_DMACR, val); 738 WRITE1(sc, port + ALI_OFF_CR, 0); 739 while (READ1(sc, port + ALI_OFF_CR)) 740 ; 741 /* reset whole DMA things */ 742 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 743 /* clear interrupts */ 744 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 745 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 746} 747 748int 749auacer_halt_output(void *v) 750{ 751 struct auacer_softc *sc = v; 752 753 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 754 755 auacer_halt(sc, &sc->sc_pcmo); 756 757 return (0); 758} 759 760int 761auacer_halt_input(void *v) 762{ 763 /*struct auacer_softc *sc = v;*/ 764 765 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n")); 766 767 return (0); 768} 769 770int 771auacer_getdev(void *v, struct audio_device *adp) 772{ 773 struct auacer_softc *sc = v; 774 775 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n")); 776 777 *adp = sc->sc_audev; 778 return (0); 779} 780 781int 782auacer_set_port(void *v, mixer_ctrl_t *cp) 783{ 784 struct auacer_softc *sc = v; 785 786 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n")); 787 788 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 789} 790 791int 792auacer_get_port(void *v, mixer_ctrl_t *cp) 793{ 794 struct auacer_softc *sc = v; 795 796 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n")); 797 798 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 799} 800 801int 802auacer_query_devinfo(void *v, mixer_devinfo_t *dp) 803{ 804 struct auacer_softc *sc = v; 805 806 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n")); 807 808 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp)); 809} 810 811void * 812auacer_allocm(void *v, int direction, size_t size, struct malloc_type *pool, 813 int flags) 814{ 815 struct auacer_softc *sc = v; 816 struct auacer_dma *p; 817 int error; 818 819 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 820 return (NULL); 821 822 p = malloc(sizeof(*p), pool, flags | M_ZERO); 823 if (p == NULL) 824 return (NULL); 825 826 error = auacer_allocmem(sc, size, 0, p); 827 if (error) { 828 free(p, pool); 829 return (NULL); 830 } 831 832 p->next = sc->sc_dmas; 833 sc->sc_dmas = p; 834 835 return (KERNADDR(p)); 836} 837 838void 839auacer_freem(void *v, void *ptr, struct malloc_type *pool) 840{ 841 struct auacer_softc *sc = v; 842 struct auacer_dma *p, **pp; 843 844 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 845 if (KERNADDR(p) == ptr) { 846 auacer_freemem(sc, p); 847 *pp = p->next; 848 free(p, pool); 849 return; 850 } 851 } 852} 853 854size_t 855auacer_round_buffersize(void *v, int direction, size_t size) 856{ 857 858 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 859 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX; 860 861 return size; 862} 863 864paddr_t 865auacer_mappage(void *v, void *mem, off_t off, int prot) 866{ 867 struct auacer_softc *sc = v; 868 struct auacer_dma *p; 869 870 if (off < 0) 871 return (-1); 872 873 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) 874 ; 875 if (!p) 876 return (-1); 877 return (bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, 878 off, prot, BUS_DMA_WAITOK)); 879} 880 881int 882auacer_get_props(void *v) 883{ 884 struct auacer_softc *sc = v; 885 int props; 886 887 props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 888 /* 889 * Even if the codec is fixed-rate, set_param() succeeds for any sample 890 * rate because of aurateconv. Applications can't know what rate the 891 * device can process in the case of mmap(). 892 */ 893 if (!AC97_IS_FIXED_RATE(sc->codec_if)) 894 props |= AUDIO_PROP_MMAP; 895 return props; 896} 897 898static void 899auacer_add_entry(struct auacer_chan *chan) 900{ 901 struct auacer_dmalist *q; 902 903 q = &chan->dmalist[chan->ptr]; 904 905 DPRINTF(ALI_DEBUG_INTR, 906 ("auacer_add_entry: %p = %x @ 0x%x\n", 907 q, chan->blksize / 2, chan->p)); 908 909 q->base = htole32(chan->p); 910 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC); 911 chan->p += chan->blksize; 912 if (chan->p >= chan->end) 913 chan->p = chan->start; 914 915 if (++chan->ptr >= ALI_DMALIST_MAX) 916 chan->ptr = 0; 917} 918 919static void 920auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan) 921{ 922 uint32_t sts; 923 uint32_t civ; 924 925 sts = READ2(sc, chan->port + ALI_OFF_SR); 926 /* intr ack */ 927 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC); 928 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port)); 929 930 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts)); 931 932 if (sts & ALI_SR_DMA_INT_FIFO) { 933 printf("%s: fifo underrun # %u\n", 934 sc->sc_dev.dv_xname, ++chan->fifoe); 935 } 936 937 civ = READ1(sc, chan->port + ALI_OFF_CIV); 938 939 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr)); 940 941 /* XXX */ 942 while (chan->ptr != civ) { 943 auacer_add_entry(chan); 944 } 945 946 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 947 948 while (chan->ack != civ) { 949 if (chan->intr) { 950 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n")); 951 chan->intr(chan->arg); 952 } 953 chan->ack++; 954 if (chan->ack >= ALI_DMALIST_MAX) 955 chan->ack = 0; 956 } 957} 958 959int 960auacer_intr(void *v) 961{ 962 struct auacer_softc *sc = v; 963 int ret, intrs; 964 965 intrs = READ4(sc, ALI_INTERRUPTSR); 966 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs)); 967 968 ret = 0; 969 if (intrs & ALI_INT_PCMOUT) { 970 auacer_upd_chan(sc, &sc->sc_pcmo); 971 ret++; 972 } 973 974 return ret != 0; 975} 976 977static void 978auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 979 uint32_t start, uint32_t size, uint32_t blksize, 980 void (*intr)(void *), void *arg) 981{ 982 uint32_t port, slot; 983 uint32_t offs, val; 984 985 chan->start = start; 986 chan->ptr = 0; 987 chan->p = chan->start; 988 chan->end = chan->start + size; 989 chan->blksize = blksize; 990 chan->ack = 0; 991 chan->intr = intr; 992 chan->arg = arg; 993 994 auacer_add_entry(chan); 995 auacer_add_entry(chan); 996 997 port = chan->port; 998 slot = ALI_PORT2SLOT(port); 999 1000 WRITE1(sc, port + ALI_OFF_CIV, 0); 1001 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 1002 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 1003 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 1004 WRITE1(sc, port + ALI_OFF_CR, 1005 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 1006 val = READ4(sc, ALI_DMACR); 1007 val &= ~(1 << (slot+16)); /* no pause */ 1008 val |= 1 << slot; /* start */ 1009 WRITE4(sc, ALI_DMACR, val); 1010} 1011 1012int 1013auacer_trigger_output(void *v, void *start, void *end, int blksize, 1014 void (*intr)(void *), void *arg, struct audio_params *param) 1015{ 1016 struct auacer_softc *sc = v; 1017 struct auacer_dma *p; 1018 uint32_t size; 1019 1020 DPRINTF(ALI_DEBUG_DMA, 1021 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 1022 start, end, blksize, intr, arg, param)); 1023 1024 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 1025 ; 1026 if (!p) { 1027 printf("auacer_trigger_output: bad addr %p\n", start); 1028 return (EINVAL); 1029 } 1030 1031 size = (char *)end - (char *)start; 1032 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 1033 intr, arg); 1034 1035 return 0; 1036} 1037 1038int 1039auacer_trigger_input(void *v, void *start, void *end, int blksize, 1040 void (*intr)(void *), void *arg, 1041 struct audio_params *param) 1042{ 1043 return (EINVAL); 1044} 1045 1046int 1047auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 1048 struct auacer_dma *p) 1049{ 1050 int error; 1051 1052 p->size = size; 1053 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 1054 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 1055 &p->nsegs, BUS_DMA_NOWAIT); 1056 if (error) 1057 return (error); 1058 1059 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 1060 &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags); 1061 if (error) 1062 goto free; 1063 1064 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 1065 0, BUS_DMA_NOWAIT, &p->map); 1066 if (error) 1067 goto unmap; 1068 1069 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1070 BUS_DMA_NOWAIT); 1071 if (error) 1072 goto destroy; 1073 return (0); 1074 1075 destroy: 1076 bus_dmamap_destroy(sc->dmat, p->map); 1077 unmap: 1078 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1079 free: 1080 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1081 return (error); 1082} 1083 1084int 1085auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 1086{ 1087 1088 bus_dmamap_unload(sc->dmat, p->map); 1089 bus_dmamap_destroy(sc->dmat, p->map); 1090 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1091 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1092 return (0); 1093} 1094 1095int 1096auacer_alloc_cdata(struct auacer_softc *sc) 1097{ 1098 bus_dma_segment_t seg; 1099 int error, rseg; 1100 1101 /* 1102 * Allocate the control data structure, and create and load the 1103 * DMA map for it. 1104 */ 1105 if ((error = bus_dmamem_alloc(sc->dmat, 1106 sizeof(struct auacer_cdata), 1107 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 1108 printf("%s: unable to allocate control data, error = %d\n", 1109 sc->sc_dev.dv_xname, error); 1110 goto fail_0; 1111 } 1112 1113 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 1114 sizeof(struct auacer_cdata), 1115 (caddr_t *) &sc->sc_cdata, 1116 sc->sc_dmamap_flags)) != 0) { 1117 printf("%s: unable to map control data, error = %d\n", 1118 sc->sc_dev.dv_xname, error); 1119 goto fail_1; 1120 } 1121 1122 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 1123 sizeof(struct auacer_cdata), 0, 0, 1124 &sc->sc_cddmamap)) != 0) { 1125 printf("%s: unable to create control data DMA map, " 1126 "error = %d\n", sc->sc_dev.dv_xname, error); 1127 goto fail_2; 1128 } 1129 1130 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, 1131 sc->sc_cdata, sizeof(struct auacer_cdata), 1132 NULL, 0)) != 0) { 1133 printf("%s: unable tp load control data DMA map, " 1134 "error = %d\n", sc->sc_dev.dv_xname, error); 1135 goto fail_3; 1136 } 1137 1138 return (0); 1139 1140 fail_3: 1141 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 1142 fail_2: 1143 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata, 1144 sizeof(struct auacer_cdata)); 1145 fail_1: 1146 bus_dmamem_free(sc->dmat, &seg, rseg); 1147 fail_0: 1148 return (error); 1149} 1150 1151void 1152auacer_powerhook(int why, void *addr) 1153{ 1154 struct auacer_softc *sc = (struct auacer_softc *)addr; 1155 1156 switch (why) { 1157 case PWR_SUSPEND: 1158 case PWR_STANDBY: 1159 /* Power down */ 1160 DPRINTF(1, ("%s: power down\n", sc->sc_dev.dv_xname)); 1161 sc->sc_suspend = why; 1162 break; 1163 1164 case PWR_RESUME: 1165 /* Wake up */ 1166 DPRINTF(1, ("%s: power resume\n", sc->sc_dev.dv_xname)); 1167 if (sc->sc_suspend == PWR_RESUME) { 1168 printf("%s: resume without suspend.\n", 1169 sc->sc_dev.dv_xname); 1170 sc->sc_suspend = why; 1171 return; 1172 } 1173 sc->sc_suspend = why; 1174 auacer_reset_codec(sc); 1175 delay(1000); 1176 sc->codec_if->vtbl->restore_ports(sc->codec_if); 1177 break; 1178 1179 case PWR_SOFTSUSPEND: 1180 case PWR_SOFTSTANDBY: 1181 case PWR_SOFTRESUME: 1182 break; 1183 } 1184} 1185