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