1 /* $NetBSD: auich.c,v 1.17 2002/04/11 10:54:23 augustss Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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 * Copyright (c) 2000 Michael Shalayeff 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. The name of the author may not be used to endorse or promote products 52 * derived from this software without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 58 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 59 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 63 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 64 * THE POSSIBILITY OF SUCH DAMAGE. 65 * 66 * from OpenBSD: ich.c,v 1.3 2000/08/11 06:17:18 mickey Exp 67 */ 68 69 /* #define ICH_DEBUG */ 70 /* 71 * AC'97 audio found on Intel 810/820/440MX chipsets. 72 * http://developer.intel.com/design/chipsets/datashts/290655.htm 73 * http://developer.intel.com/design/chipsets/manuals/298028.htm 74 * 75 * TODO: 76 * 77 * - Probe codecs for supported sample rates. 78 * 79 * - Add support for the microphone input. 80 */ 81 82 #include <sys/cdefs.h> 83 __KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.17 2002/04/11 10:54:23 augustss Exp $"); 84 85 #include <sys/param.h> 86 #include <sys/systm.h> 87 #include <sys/kernel.h> 88 #include <sys/malloc.h> 89 #include <sys/device.h> 90 #include <sys/fcntl.h> 91 #include <sys/proc.h> 92 93 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ 94 95 #include <dev/pci/pcidevs.h> 96 #include <dev/pci/pcivar.h> 97 #include <dev/pci/auichreg.h> 98 99 #include <sys/audioio.h> 100 #include <dev/audio_if.h> 101 #include <dev/mulaw.h> 102 #include <dev/auconv.h> 103 104 #include <machine/bus.h> 105 106 #include <dev/ic/ac97reg.h> 107 #include <dev/ic/ac97var.h> 108 109 struct auich_dma { 110 bus_dmamap_t map; 111 caddr_t addr; 112 bus_dma_segment_t segs[1]; 113 int nsegs; 114 size_t size; 115 struct auich_dma *next; 116 }; 117 118 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 119 #define KERNADDR(p) ((void *)((p)->addr)) 120 121 struct auich_cdata { 122 struct auich_dmalist ic_dmalist_pcmo[ICH_DMALIST_MAX]; 123 struct auich_dmalist ic_dmalist_pcmi[ICH_DMALIST_MAX]; 124 struct auich_dmalist ic_dmalist_mici[ICH_DMALIST_MAX]; 125 }; 126 127 #define ICH_CDOFF(x) offsetof(struct auich_cdata, x) 128 #define ICH_PCMO_OFF(x) ICH_CDOFF(ic_dmalist_pcmo[(x)]) 129 #define ICH_PCMI_OFF(x) ICH_CDOFF(ic_dmalist_pcmi[(x)]) 130 #define ICH_MICI_OFF(x) ICH_CDOFF(ic_dmalist_mici[(x)]) 131 132 struct auich_softc { 133 struct device sc_dev; 134 void *sc_ih; 135 136 audio_device_t sc_audev; 137 138 bus_space_tag_t iot; 139 bus_space_handle_t mix_ioh; 140 bus_space_handle_t aud_ioh; 141 bus_dma_tag_t dmat; 142 143 struct ac97_codec_if *codec_if; 144 struct ac97_host_if host_if; 145 146 /* DMA scatter-gather lists. */ 147 bus_dmamap_t sc_cddmamap; 148 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr 149 150 struct auich_cdata *sc_cdata; 151 #define dmalist_pcmo sc_cdata->ic_dmalist_pcmo 152 #define dmalist_pcmi sc_cdata->ic_dmalist_pcmi 153 #define dmalist_mici sc_cdata->ic_dmalist_mici 154 155 int ptr_pcmo, 156 ptr_pcmi, 157 ptr_mici; 158 159 /* i/o buffer pointers */ 160 u_int32_t pcmo_start, pcmo_p, pcmo_end; 161 int pcmo_blksize, pcmo_fifoe; 162 163 u_int32_t pcmi_start, pcmi_p, pcmi_end; 164 int pcmi_blksize, pcmi_fifoe; 165 166 u_int32_t mici_start, mici_p, mici_end; 167 int mici_blksize, mici_fifoe; 168 169 struct auich_dma *sc_dmas; 170 171 int sc_fixed_rate; 172 173 void (*sc_pintr)(void *); 174 void *sc_parg; 175 176 void (*sc_rintr)(void *); 177 void *sc_rarg; 178 179 /* Power Management */ 180 void *sc_powerhook; 181 int sc_suspend; 182 u_int16_t ext_status; 183 }; 184 185 #define FIXED_RATE 48000 186 187 /* Debug */ 188 #ifdef AUDIO_DEBUG 189 #define DPRINTF(l,x) do { if (auich_debug & (l)) printf x; } while(0) 190 int auich_debug = 0xfffe; 191 #define ICH_DEBUG_CODECIO 0x0001 192 #define ICH_DEBUG_DMA 0x0002 193 #define ICH_DEBUG_PARAM 0x0004 194 #else 195 #define DPRINTF(x,y) /* nothing */ 196 #endif 197 198 int auich_match(struct device *, struct cfdata *, void *); 199 void auich_attach(struct device *, struct device *, void *); 200 int auich_intr(void *); 201 202 struct cfattach auich_ca = { 203 sizeof(struct auich_softc), auich_match, auich_attach 204 }; 205 206 int auich_open(void *, int); 207 void auich_close(void *); 208 int auich_query_encoding(void *, struct audio_encoding *); 209 int auich_set_params(void *, int, int, struct audio_params *, 210 struct audio_params *); 211 int auich_round_blocksize(void *, int); 212 int auich_halt_output(void *); 213 int auich_halt_input(void *); 214 int auich_getdev(void *, struct audio_device *); 215 int auich_set_port(void *, mixer_ctrl_t *); 216 int auich_get_port(void *, mixer_ctrl_t *); 217 int auich_query_devinfo(void *, mixer_devinfo_t *); 218 void *auich_allocm(void *, int, size_t, int, int); 219 void auich_freem(void *, void *, int); 220 size_t auich_round_buffersize(void *, int, size_t); 221 paddr_t auich_mappage(void *, void *, off_t, int); 222 int auich_get_props(void *); 223 int auich_trigger_output(void *, void *, void *, int, void (*)(void *), 224 void *, struct audio_params *); 225 int auich_trigger_input(void *, void *, void *, int, void (*)(void *), 226 void *, struct audio_params *); 227 228 int auich_alloc_cdata(struct auich_softc *); 229 230 int auich_allocmem(struct auich_softc *, size_t, size_t, 231 struct auich_dma *); 232 int auich_freemem(struct auich_softc *, struct auich_dma *); 233 234 void auich_powerhook(int, void *); 235 int auich_set_rate(struct auich_softc *sc, int mode, uint srate); 236 237 238 struct audio_hw_if auich_hw_if = { 239 auich_open, 240 auich_close, 241 NULL, /* drain */ 242 auich_query_encoding, 243 auich_set_params, 244 auich_round_blocksize, 245 NULL, /* commit_setting */ 246 NULL, /* init_output */ 247 NULL, /* init_input */ 248 NULL, /* start_output */ 249 NULL, /* start_input */ 250 auich_halt_output, 251 auich_halt_input, 252 NULL, /* speaker_ctl */ 253 auich_getdev, 254 NULL, /* getfd */ 255 auich_set_port, 256 auich_get_port, 257 auich_query_devinfo, 258 auich_allocm, 259 auich_freem, 260 auich_round_buffersize, 261 auich_mappage, 262 auich_get_props, 263 auich_trigger_output, 264 auich_trigger_input, 265 NULL, /* dev_ioctl */ 266 }; 267 268 int auich_attach_codec(void *, struct ac97_codec_if *); 269 int auich_read_codec(void *, u_int8_t, u_int16_t *); 270 int auich_write_codec(void *, u_int8_t, u_int16_t); 271 void auich_reset_codec(void *); 272 273 static const struct auich_devtype { 274 int product; 275 const char *name; 276 const char *shortname; 277 } auich_devices[] = { 278 { PCI_PRODUCT_INTEL_82801AA_ACA, 279 "i82801AA (ICH) AC-97 Audio", "ICH" }, 280 { PCI_PRODUCT_INTEL_82801AB_ACA, 281 "i82801AB (ICH0) AC-97 Audio", "ICH0" }, 282 { PCI_PRODUCT_INTEL_82801BA_ACA, 283 "i82801BA (ICH2) AC-97 Audio", "ICH2" }, 284 { PCI_PRODUCT_INTEL_82440MX_ACA, 285 "i82440MX AC-97 Audio", "440MX" }, 286 { PCI_PRODUCT_INTEL_82801CA_AC, 287 "i82801CA AC-97 Audio", "i830M" }, 288 289 { 0, 290 NULL, NULL }, 291 }; 292 293 static const struct auich_devtype * 294 auich_lookup(struct pci_attach_args *pa) 295 { 296 const struct auich_devtype *d; 297 298 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) 299 return (NULL); 300 301 for (d = auich_devices; d->name != NULL; d++) { 302 if (PCI_PRODUCT(pa->pa_id) == d->product) 303 return (d); 304 } 305 306 return (NULL); 307 } 308 309 int 310 auich_match(struct device *parent, struct cfdata *match, void *aux) 311 { 312 struct pci_attach_args *pa = aux; 313 314 if (auich_lookup(pa) != NULL) 315 return (1); 316 317 return (0); 318 } 319 320 void 321 auich_attach(struct device *parent, struct device *self, void *aux) 322 { 323 struct auich_softc *sc = (struct auich_softc *)self; 324 struct pci_attach_args *pa = aux; 325 pci_intr_handle_t ih; 326 bus_size_t mix_size, aud_size; 327 pcireg_t csr; 328 const char *intrstr; 329 const struct auich_devtype *d; 330 u_int16_t ext_id, ext_status; 331 332 d = auich_lookup(pa); 333 if (d == NULL) 334 panic("auich_attach: impossible"); 335 336 printf(": %s\n", d->name); 337 338 if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0, 339 &sc->iot, &sc->mix_ioh, NULL, &mix_size)) { 340 printf("%s: can't map codec i/o space\n", 341 sc->sc_dev.dv_xname); 342 return; 343 } 344 if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0, 345 &sc->iot, &sc->aud_ioh, NULL, &aud_size)) { 346 printf("%s: can't map device i/o space\n", 347 sc->sc_dev.dv_xname); 348 return; 349 } 350 sc->dmat = pa->pa_dmat; 351 352 /* enable bus mastering */ 353 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 354 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 355 csr | PCI_COMMAND_MASTER_ENABLE); 356 357 /* Map and establish the interrupt. */ 358 if (pci_intr_map(pa, &ih)) { 359 printf("%s: can't map interrupt\n", sc->sc_dev.dv_xname); 360 return; 361 } 362 intrstr = pci_intr_string(pa->pa_pc, ih); 363 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, 364 auich_intr, sc); 365 if (sc->sc_ih == NULL) { 366 printf("%s: can't establish interrupt", sc->sc_dev.dv_xname); 367 if (intrstr != NULL) 368 printf(" at %s", intrstr); 369 printf("\n"); 370 return; 371 } 372 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 373 374 sprintf(sc->sc_audev.name, "%s AC97", d->shortname); 375 sprintf(sc->sc_audev.version, "0x%02x", PCI_REVISION(pa->pa_class)); 376 strcpy(sc->sc_audev.config, sc->sc_dev.dv_xname); 377 378 /* Set up DMA lists. */ 379 sc->ptr_pcmo = sc->ptr_pcmi = sc->ptr_mici = 0; 380 auich_alloc_cdata(sc); 381 382 DPRINTF(ICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n", 383 sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici)); 384 385 /* Reset codec and AC'97 */ 386 auich_reset_codec(sc); 387 388 sc->host_if.arg = sc; 389 sc->host_if.attach = auich_attach_codec; 390 sc->host_if.read = auich_read_codec; 391 sc->host_if.write = auich_write_codec; 392 sc->host_if.reset = auich_reset_codec; 393 394 if (ac97_attach(&sc->host_if) != 0) 395 return; 396 397 auich_read_codec(sc, AC97_REG_EXTENDED_ID, &ext_id); 398 if ((ext_id & (AC97_CODEC_DOES_VRA | AC97_CODEC_DOES_MICVRA)) != 0) { 399 auich_read_codec(sc, AC97_REG_EXTENDED_STATUS, &ext_status); 400 if ((ext_id & AC97_CODEC_DOES_VRA) !=0) 401 ext_status |= AC97_ENAB_VRA; 402 if ((ext_id & AC97_CODEC_DOES_MICVRA) !=0) 403 ext_status |= AC97_ENAB_MICVRA; 404 auich_write_codec(sc, AC97_REG_EXTENDED_STATUS, ext_status); 405 406 /* so it claims to do variable rate, let's make sure */ 407 if (auich_set_rate(sc, AUMODE_PLAY, 44100) == 44100) 408 sc->sc_fixed_rate = 0; 409 else 410 sc->sc_fixed_rate = FIXED_RATE; 411 } else { 412 sc->sc_fixed_rate = FIXED_RATE; 413 } 414 if (sc->sc_fixed_rate) 415 printf("%s: warning, fixed rate codec\n", sc->sc_dev.dv_xname); 416 417 audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev); 418 419 /* Watch for power change */ 420 sc->sc_suspend = PWR_RESUME; 421 sc->sc_powerhook = powerhook_establish(auich_powerhook, sc); 422 } 423 424 #define ICH_CODECIO_INTERVAL 10 425 int 426 auich_read_codec(void *v, u_int8_t reg, u_int16_t *val) 427 { 428 struct auich_softc *sc = v; 429 int i; 430 uint32_t status; 431 432 if (!(bus_space_read_4(sc->iot, sc->aud_ioh, ICH_GSTS) & ICH_PCR)) { 433 printf("auich_read_codec: codec is not ready."); 434 *val = 0xffff; 435 return -1; 436 } 437 /* wait for an access semaphore */ 438 for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && 439 bus_space_read_1(sc->iot, sc->aud_ioh, ICH_CAS) & 1; 440 DELAY(ICH_CODECIO_INTERVAL)); 441 442 if (i > 0) { 443 *val = bus_space_read_2(sc->iot, sc->mix_ioh, reg); 444 DPRINTF(ICH_DEBUG_CODECIO, 445 ("auich_read_codec(%x, %x)\n", reg, *val)); 446 status = bus_space_read_4(sc->iot, sc->aud_ioh, ICH_GSTS); 447 if (status & ICH_RCS) { 448 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GSTS, 449 status & ~(ICH_SRI|ICH_PRI|ICH_GSCI)); 450 *val = 0xffff; 451 } 452 return 0; 453 } else { 454 DPRINTF(ICH_DEBUG_CODECIO, 455 ("%s: read_codec timeout\n", sc->sc_dev.dv_xname)); 456 return -1; 457 } 458 } 459 460 int 461 auich_write_codec(void *v, u_int8_t reg, u_int16_t val) 462 { 463 struct auich_softc *sc = v; 464 int i; 465 466 DPRINTF(ICH_DEBUG_CODECIO, ("auich_write_codec(%x, %x)\n", reg, val)); 467 if (!(bus_space_read_4(sc->iot, sc->aud_ioh, ICH_GSTS) & ICH_PCR)) { 468 printf("auich_write_codec: codec is not ready."); 469 return -1; 470 } 471 /* wait for an access semaphore */ 472 for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && 473 bus_space_read_1(sc->iot, sc->aud_ioh, ICH_CAS) & 1; 474 DELAY(ICH_CODECIO_INTERVAL)); 475 476 if (i > 0) { 477 bus_space_write_2(sc->iot, sc->mix_ioh, reg, val); 478 return 0; 479 } else { 480 DPRINTF(ICH_DEBUG_CODECIO, 481 ("%s: write_codec timeout\n", sc->sc_dev.dv_xname)); 482 return -1; 483 } 484 } 485 486 int 487 auich_attach_codec(void *v, struct ac97_codec_if *cif) 488 { 489 struct auich_softc *sc = v; 490 491 sc->codec_if = cif; 492 return 0; 493 } 494 495 void 496 auich_reset_codec(void *v) 497 { 498 struct auich_softc *sc = v; 499 int i; 500 501 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GCTRL, 0); 502 DELAY(10); 503 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GCTRL, ICH_CRESET); 504 505 for (i = 500000; i-- && 506 !(bus_space_read_4(sc->iot, sc->aud_ioh, ICH_GSTS) & ICH_PCR); 507 DELAY(1)); /* or ICH_SCR? */ 508 } 509 510 int 511 auich_open(void *v, int flags) 512 { 513 514 return 0; 515 } 516 517 void 518 auich_close(void *v) 519 { 520 struct auich_softc *sc = v; 521 522 auich_halt_output(sc); 523 auich_halt_input(sc); 524 525 sc->sc_pintr = NULL; 526 sc->sc_rintr = NULL; 527 } 528 529 int 530 auich_query_encoding(void *v, struct audio_encoding *aep) 531 { 532 533 switch (aep->index) { 534 case 0: 535 strcpy(aep->name, AudioEulinear); 536 aep->encoding = AUDIO_ENCODING_ULINEAR; 537 aep->precision = 8; 538 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 539 return (0); 540 case 1: 541 strcpy(aep->name, AudioEmulaw); 542 aep->encoding = AUDIO_ENCODING_ULAW; 543 aep->precision = 8; 544 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 545 return (0); 546 case 2: 547 strcpy(aep->name, AudioEalaw); 548 aep->encoding = AUDIO_ENCODING_ALAW; 549 aep->precision = 8; 550 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 551 return (0); 552 case 3: 553 strcpy(aep->name, AudioEslinear); 554 aep->encoding = AUDIO_ENCODING_SLINEAR; 555 aep->precision = 8; 556 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 557 return (0); 558 case 4: 559 strcpy(aep->name, AudioEslinear_le); 560 aep->encoding = AUDIO_ENCODING_SLINEAR_LE; 561 aep->precision = 16; 562 aep->flags = 0; 563 return (0); 564 case 5: 565 strcpy(aep->name, AudioEulinear_le); 566 aep->encoding = AUDIO_ENCODING_ULINEAR_LE; 567 aep->precision = 16; 568 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 569 return (0); 570 case 6: 571 strcpy(aep->name, AudioEslinear_be); 572 aep->encoding = AUDIO_ENCODING_SLINEAR_BE; 573 aep->precision = 16; 574 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 575 return (0); 576 case 7: 577 strcpy(aep->name, AudioEulinear_be); 578 aep->encoding = AUDIO_ENCODING_ULINEAR_BE; 579 aep->precision = 16; 580 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 581 return (0); 582 default: 583 return (EINVAL); 584 } 585 } 586 587 int 588 auich_set_rate(struct auich_softc *sc, int mode, uint srate) 589 { 590 u_int16_t val, rate, inout; 591 592 inout = mode == AUMODE_PLAY ? ICH_PM_PCMO : ICH_PM_PCMI; 593 594 auich_read_codec(sc, AC97_REG_POWER, &val); 595 auich_write_codec(sc, AC97_REG_POWER, val | inout); 596 597 if (mode == AUMODE_PLAY) { 598 auich_write_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE, srate); 599 auich_read_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE, &rate); 600 } else { 601 auich_write_codec(sc, AC97_REG_PCM_LR_ADC_RATE, srate); 602 auich_read_codec(sc, AC97_REG_PCM_LR_ADC_RATE, &rate); 603 } 604 605 auich_write_codec(sc, AC97_REG_POWER, val); 606 607 return rate; 608 } 609 610 int 611 auich_set_params(void *v, int setmode, int usemode, struct audio_params *play, 612 struct audio_params *rec) 613 { 614 struct auich_softc *sc = v; 615 struct audio_params *p; 616 int mode; 617 618 for (mode = AUMODE_RECORD; mode != -1; 619 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 620 if ((setmode & mode) == 0) 621 continue; 622 623 p = mode == AUMODE_PLAY ? play : rec; 624 if (p == NULL) 625 continue; 626 627 if ((p->sample_rate != 8000) && 628 (p->sample_rate != 11025) && 629 (p->sample_rate != 16000) && 630 (p->sample_rate != 22050) && 631 (p->sample_rate != 32000) && 632 (p->sample_rate != 44100) && 633 (p->sample_rate != 48000)) 634 return (EINVAL); 635 636 p->factor = 1; 637 if (p->precision == 8) 638 p->factor *= 2; 639 640 p->sw_code = NULL; 641 /* setup hardware formats */ 642 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE; 643 p->hw_precision = 16; 644 if (p->channels < 2) 645 p->hw_channels = 2; 646 switch (p->encoding) { 647 case AUDIO_ENCODING_SLINEAR_BE: 648 if (p->precision == 16) { 649 p->sw_code = swap_bytes; 650 } else { 651 if (mode == AUMODE_PLAY) 652 p->sw_code = linear8_to_linear16_le; 653 else 654 p->sw_code = linear16_to_linear8_le; 655 } 656 break; 657 658 case AUDIO_ENCODING_SLINEAR_LE: 659 if (p->precision != 16) { 660 if (mode == AUMODE_PLAY) 661 p->sw_code = linear8_to_linear16_le; 662 else 663 p->sw_code = linear16_to_linear8_le; 664 } 665 break; 666 667 case AUDIO_ENCODING_ULINEAR_BE: 668 if (p->precision == 16) { 669 if (mode == AUMODE_PLAY) 670 p->sw_code = 671 swap_bytes_change_sign16_le; 672 else 673 p->sw_code = 674 change_sign16_swap_bytes_le; 675 } else { 676 if (mode == AUMODE_PLAY) 677 p->sw_code = 678 ulinear8_to_slinear16_le; 679 else 680 p->sw_code = 681 slinear16_to_ulinear8_le; 682 } 683 break; 684 685 case AUDIO_ENCODING_ULINEAR_LE: 686 if (p->precision == 16) { 687 p->sw_code = change_sign16_le; 688 } else { 689 if (mode == AUMODE_PLAY) 690 p->sw_code = 691 ulinear8_to_slinear16_le; 692 else 693 p->sw_code = 694 slinear16_to_ulinear8_le; 695 } 696 break; 697 698 case AUDIO_ENCODING_ULAW: 699 if (mode == AUMODE_PLAY) { 700 p->sw_code = mulaw_to_slinear16_le; 701 } else { 702 p->sw_code = slinear16_to_mulaw_le; 703 } 704 break; 705 706 case AUDIO_ENCODING_ALAW: 707 if (mode == AUMODE_PLAY) { 708 p->sw_code = alaw_to_slinear16_le; 709 } else { 710 p->sw_code = slinear16_to_alaw_le; 711 } 712 break; 713 714 default: 715 return (EINVAL); 716 } 717 718 if (sc->sc_fixed_rate) 719 p->hw_sample_rate = sc->sc_fixed_rate; 720 else 721 p->hw_sample_rate = auich_set_rate(sc, mode, 722 p->sample_rate); 723 } 724 725 return (0); 726 } 727 728 int 729 auich_round_blocksize(void *v, int blk) 730 { 731 732 return (blk & ~0x3f); /* keep good alignment */ 733 } 734 735 int 736 auich_halt_output(void *v) 737 { 738 struct auich_softc *sc = v; 739 740 DPRINTF(ICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname)); 741 742 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CTRL, ICH_RR); 743 744 return (0); 745 } 746 747 int 748 auich_halt_input(void *v) 749 { 750 struct auich_softc *sc = v; 751 752 DPRINTF(ICH_DEBUG_DMA, 753 ("%s: halt_input\n", sc->sc_dev.dv_xname)); 754 755 /* XXX halt both unless known otherwise */ 756 757 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RR); 758 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_MICI + ICH_CTRL, ICH_RR); 759 760 return (0); 761 } 762 763 int 764 auich_getdev(void *v, struct audio_device *adp) 765 { 766 struct auich_softc *sc = v; 767 768 *adp = sc->sc_audev; 769 return (0); 770 } 771 772 int 773 auich_set_port(void *v, mixer_ctrl_t *cp) 774 { 775 struct auich_softc *sc = v; 776 777 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp)); 778 } 779 780 int 781 auich_get_port(void *v, mixer_ctrl_t *cp) 782 { 783 struct auich_softc *sc = v; 784 785 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp)); 786 } 787 788 int 789 auich_query_devinfo(void *v, mixer_devinfo_t *dp) 790 { 791 struct auich_softc *sc = v; 792 793 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp)); 794 } 795 796 void * 797 auich_allocm(void *v, int direction, size_t size, int pool, int flags) 798 { 799 struct auich_softc *sc = v; 800 struct auich_dma *p; 801 int error; 802 803 if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) 804 return (NULL); 805 806 p = malloc(sizeof(*p), pool, flags|M_ZERO); 807 if (p == NULL) 808 return (NULL); 809 810 error = auich_allocmem(sc, size, 0, p); 811 if (error) { 812 free(p, pool); 813 return (NULL); 814 } 815 816 p->next = sc->sc_dmas; 817 sc->sc_dmas = p; 818 819 return (KERNADDR(p)); 820 } 821 822 void 823 auich_freem(void *v, void *ptr, int pool) 824 { 825 struct auich_softc *sc = v; 826 struct auich_dma *p, **pp; 827 828 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 829 if (KERNADDR(p) == ptr) { 830 auich_freemem(sc, p); 831 *pp = p->next; 832 free(p, pool); 833 return; 834 } 835 } 836 } 837 838 size_t 839 auich_round_buffersize(void *v, int direction, size_t size) 840 { 841 842 if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) 843 size = ICH_DMALIST_MAX * ICH_DMASEG_MAX; 844 845 return size; 846 } 847 848 paddr_t 849 auich_mappage(void *v, void *mem, off_t off, int prot) 850 { 851 struct auich_softc *sc = v; 852 struct auich_dma *p; 853 854 if (off < 0) 855 return (-1); 856 857 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) 858 ; 859 if (!p) 860 return (-1); 861 return (bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, 862 off, prot, BUS_DMA_WAITOK)); 863 } 864 865 int 866 auich_get_props(void *v) 867 { 868 869 return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | 870 AUDIO_PROP_FULLDUPLEX); 871 } 872 873 int 874 auich_intr(void *v) 875 { 876 struct auich_softc *sc = v; 877 int ret = 0, sts, gsts, i, qptr; 878 879 gsts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_GSTS); 880 DPRINTF(ICH_DEBUG_DMA, ("auich_intr: gsts=0x%x\n", gsts)); 881 882 if (gsts & ICH_POINT) { 883 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_PCMO+ICH_STS); 884 DPRINTF(ICH_DEBUG_DMA, 885 ("auich_intr: osts=0x%x\n", sts)); 886 887 if (sts & ICH_FIFOE) { 888 printf("%s: fifo underrun # %u\n", 889 sc->sc_dev.dv_xname, ++sc->pcmo_fifoe); 890 } 891 892 i = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CIV); 893 if (sts & (ICH_LVBCI | ICH_CELV)) { 894 struct auich_dmalist *q; 895 896 qptr = sc->ptr_pcmo; 897 898 while (qptr != i) { 899 q = &sc->dmalist_pcmo[qptr]; 900 901 q->base = sc->pcmo_p; 902 q->len = (sc->pcmo_blksize / 2) | ICH_DMAF_IOC; 903 DPRINTF(ICH_DEBUG_DMA, 904 ("auich_intr: %p, %p = %x @ 0x%x\n", 905 &sc->dmalist_pcmo[i], q, 906 sc->pcmo_blksize / 2, sc->pcmo_p)); 907 908 sc->pcmo_p += sc->pcmo_blksize; 909 if (sc->pcmo_p >= sc->pcmo_end) 910 sc->pcmo_p = sc->pcmo_start; 911 912 if (++qptr == ICH_DMALIST_MAX) 913 qptr = 0; 914 } 915 916 sc->ptr_pcmo = qptr; 917 bus_space_write_1(sc->iot, sc->aud_ioh, 918 ICH_PCMO + ICH_LVI, 919 (sc->ptr_pcmo - 1) & ICH_LVI_MASK); 920 } 921 922 if (sts & ICH_BCIS && sc->sc_pintr) 923 sc->sc_pintr(sc->sc_parg); 924 925 /* int ack */ 926 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_STS, 927 sts & (ICH_LVBCI | ICH_CELV | ICH_BCIS | ICH_FIFOE)); 928 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_POINT); 929 ret++; 930 } 931 932 if (gsts & ICH_PIINT) { 933 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_PCMI+ICH_STS); 934 DPRINTF(ICH_DEBUG_DMA, 935 ("auich_intr: ists=0x%x\n", sts)); 936 937 if (sts & ICH_FIFOE) { 938 printf("%s: fifo overrun # %u\n", 939 sc->sc_dev.dv_xname, ++sc->pcmi_fifoe); 940 } 941 942 i = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CIV); 943 if (sts & (ICH_LVBCI | ICH_CELV)) { 944 struct auich_dmalist *q; 945 946 qptr = sc->ptr_pcmi; 947 948 while (qptr != i) { 949 q = &sc->dmalist_pcmi[qptr]; 950 951 q->base = sc->pcmi_p; 952 q->len = (sc->pcmi_blksize / 2) | ICH_DMAF_IOC; 953 DPRINTF(ICH_DEBUG_DMA, 954 ("auich_intr: %p, %p = %x @ 0x%x\n", 955 &sc->dmalist_pcmi[i], q, 956 sc->pcmi_blksize / 2, sc->pcmi_p)); 957 958 sc->pcmi_p += sc->pcmi_blksize; 959 if (sc->pcmi_p >= sc->pcmi_end) 960 sc->pcmi_p = sc->pcmi_start; 961 962 if (++qptr == ICH_DMALIST_MAX) 963 qptr = 0; 964 } 965 966 sc->ptr_pcmi = qptr; 967 bus_space_write_1(sc->iot, sc->aud_ioh, 968 ICH_PCMI + ICH_LVI, 969 (sc->ptr_pcmi - 1) & ICH_LVI_MASK); 970 } 971 972 if (sts & ICH_BCIS && sc->sc_rintr) 973 sc->sc_rintr(sc->sc_rarg); 974 975 /* int ack */ 976 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_STS, 977 sts & (ICH_LVBCI | ICH_CELV | ICH_BCIS | ICH_FIFOE)); 978 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_POINT); 979 ret++; 980 } 981 982 if (gsts & ICH_MIINT) { 983 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_MICI+ICH_STS); 984 DPRINTF(ICH_DEBUG_DMA, 985 ("auich_intr: ists=0x%x\n", sts)); 986 if (sts & ICH_FIFOE) 987 printf("%s: fifo overrun\n", sc->sc_dev.dv_xname); 988 989 /* TODO mic input dma */ 990 991 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_MIINT); 992 } 993 994 return ret; 995 } 996 997 int 998 auich_trigger_output(void *v, void *start, void *end, int blksize, 999 void (*intr)(void *), void *arg, struct audio_params *param) 1000 { 1001 struct auich_softc *sc = v; 1002 struct auich_dmalist *q; 1003 struct auich_dma *p; 1004 size_t size; 1005 1006 DPRINTF(ICH_DEBUG_DMA, 1007 ("auich_trigger_output(%p, %p, %d, %p, %p, %p)\n", 1008 start, end, blksize, intr, arg, param)); 1009 1010 sc->sc_pintr = intr; 1011 sc->sc_parg = arg; 1012 1013 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 1014 ; 1015 if (!p) { 1016 printf("auich_trigger_output: bad addr %p\n", start); 1017 return (EINVAL); 1018 } 1019 1020 size = (size_t)((caddr_t)end - (caddr_t)start); 1021 1022 /* 1023 * The logic behind this is: 1024 * setup one buffer to play, then LVI dump out the rest 1025 * to the scatter-gather chain. 1026 */ 1027 sc->pcmo_start = DMAADDR(p); 1028 sc->pcmo_p = sc->pcmo_start + blksize; 1029 sc->pcmo_end = sc->pcmo_start + size; 1030 sc->pcmo_blksize = blksize; 1031 1032 sc->ptr_pcmo = 0; 1033 q = &sc->dmalist_pcmo[sc->ptr_pcmo]; 1034 q->base = sc->pcmo_start; 1035 q->len = (blksize / 2) | ICH_DMAF_IOC; 1036 if (++sc->ptr_pcmo == ICH_DMALIST_MAX) 1037 sc->ptr_pcmo = 0; 1038 1039 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_BDBAR, 1040 sc->sc_cddma + ICH_PCMO_OFF(0)); 1041 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CTRL, 1042 ICH_IOCE | ICH_FEIE | ICH_LVBIE | ICH_RPBM); 1043 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_LVI, 1044 (sc->ptr_pcmo - 1) & ICH_LVI_MASK); 1045 1046 return (0); 1047 } 1048 1049 int 1050 auich_trigger_input(v, start, end, blksize, intr, arg, param) 1051 void *v; 1052 void *start, *end; 1053 int blksize; 1054 void (*intr)(void *); 1055 void *arg; 1056 struct audio_params *param; 1057 { 1058 struct auich_softc *sc = v; 1059 struct auich_dmalist *q; 1060 struct auich_dma *p; 1061 size_t size; 1062 1063 DPRINTF(ICH_DEBUG_DMA, 1064 ("auich_trigger_input(%p, %p, %d, %p, %p, %p)\n", 1065 start, end, blksize, intr, arg, param)); 1066 1067 sc->sc_rintr = intr; 1068 sc->sc_rarg = arg; 1069 1070 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 1071 ; 1072 if (!p) { 1073 printf("auich_trigger_input: bad addr %p\n", start); 1074 return (EINVAL); 1075 } 1076 1077 size = (size_t)((caddr_t)end - (caddr_t)start); 1078 1079 /* 1080 * The logic behind this is: 1081 * setup one buffer to play, then LVI dump out the rest 1082 * to the scatter-gather chain. 1083 */ 1084 sc->pcmi_start = DMAADDR(p); 1085 sc->pcmi_p = sc->pcmi_start + blksize; 1086 sc->pcmi_end = sc->pcmi_start + size; 1087 sc->pcmi_blksize = blksize; 1088 1089 sc->ptr_pcmi = 0; 1090 q = &sc->dmalist_pcmi[sc->ptr_pcmi]; 1091 q->base = sc->pcmi_start; 1092 q->len = (blksize / 2) | ICH_DMAF_IOC; 1093 if (++sc->ptr_pcmi == ICH_DMALIST_MAX) 1094 sc->ptr_pcmi = 0; 1095 1096 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR, 1097 sc->sc_cddma + ICH_PCMI_OFF(0)); 1098 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, 1099 ICH_IOCE | ICH_FEIE | ICH_LVBIE | ICH_RPBM); 1100 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_LVI, 1101 (sc->ptr_pcmi - 1) & ICH_LVI_MASK); 1102 1103 return (0); 1104 } 1105 1106 int 1107 auich_allocmem(struct auich_softc *sc, size_t size, size_t align, 1108 struct auich_dma *p) 1109 { 1110 int error; 1111 1112 p->size = size; 1113 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 1114 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 1115 &p->nsegs, BUS_DMA_NOWAIT); 1116 if (error) 1117 return (error); 1118 1119 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 1120 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 1121 if (error) 1122 goto free; 1123 1124 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 1125 0, BUS_DMA_NOWAIT, &p->map); 1126 if (error) 1127 goto unmap; 1128 1129 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1130 BUS_DMA_NOWAIT); 1131 if (error) 1132 goto destroy; 1133 return (0); 1134 1135 destroy: 1136 bus_dmamap_destroy(sc->dmat, p->map); 1137 unmap: 1138 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1139 free: 1140 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1141 return (error); 1142 } 1143 1144 int 1145 auich_freemem(struct auich_softc *sc, struct auich_dma *p) 1146 { 1147 1148 bus_dmamap_unload(sc->dmat, p->map); 1149 bus_dmamap_destroy(sc->dmat, p->map); 1150 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1151 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1152 return (0); 1153 } 1154 1155 int 1156 auich_alloc_cdata(struct auich_softc *sc) 1157 { 1158 bus_dma_segment_t seg; 1159 int error, rseg; 1160 1161 /* 1162 * Allocate the control data structure, and create and load the 1163 * DMA map for it. 1164 */ 1165 if ((error = bus_dmamem_alloc(sc->dmat, 1166 sizeof(struct auich_cdata), 1167 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 1168 printf("%s: unable to allocate control data, error = %d\n", 1169 sc->sc_dev.dv_xname, error); 1170 goto fail_0; 1171 } 1172 1173 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 1174 sizeof(struct auich_cdata), 1175 (caddr_t *) &sc->sc_cdata, 1176 BUS_DMA_COHERENT)) != 0) { 1177 printf("%s: unable to map control data, error = %d\n", 1178 sc->sc_dev.dv_xname, error); 1179 goto fail_1; 1180 } 1181 1182 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auich_cdata), 1, 1183 sizeof(struct auich_cdata), 0, 0, 1184 &sc->sc_cddmamap)) != 0) { 1185 printf("%s: unable to create control data DMA map, " 1186 "error = %d\n", sc->sc_dev.dv_xname, error); 1187 goto fail_2; 1188 } 1189 1190 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, 1191 sc->sc_cdata, sizeof(struct auich_cdata), 1192 NULL, 0)) != 0) { 1193 printf("%s: unable tp load control data DMA map, " 1194 "error = %d\n", sc->sc_dev.dv_xname, error); 1195 goto fail_3; 1196 } 1197 1198 return (0); 1199 1200 fail_3: 1201 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 1202 fail_2: 1203 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata, 1204 sizeof(struct auich_cdata)); 1205 fail_1: 1206 bus_dmamem_free(sc->dmat, &seg, rseg); 1207 fail_0: 1208 return (error); 1209 } 1210 1211 void 1212 auich_powerhook(int why, void *addr) 1213 { 1214 struct auich_softc *sc = (struct auich_softc *)addr; 1215 1216 switch (why) { 1217 case PWR_SUSPEND: 1218 case PWR_STANDBY: 1219 /* Power down */ 1220 DPRINTF(1, ("%s: power down\n", sc->sc_dev.dv_xname)); 1221 sc->sc_suspend = why; 1222 auich_read_codec(sc, AC97_REG_EXTENDED_STATUS, &sc->ext_status); 1223 break; 1224 1225 case PWR_RESUME: 1226 /* Wake up */ 1227 DPRINTF(1, ("%s: power resume\n", sc->sc_dev.dv_xname)); 1228 if (sc->sc_suspend == PWR_RESUME) { 1229 printf("%s: resume without suspend.\n", 1230 sc->sc_dev.dv_xname); 1231 sc->sc_suspend = why; 1232 return; 1233 } 1234 sc->sc_suspend = why; 1235 auich_reset_codec(sc); 1236 DELAY(1000); 1237 (sc->codec_if->vtbl->restore_ports)(sc->codec_if); 1238 auich_write_codec(sc, AC97_REG_EXTENDED_STATUS, sc->ext_status); 1239 break; 1240 1241 case PWR_SOFTSUSPEND: 1242 case PWR_SOFTSTANDBY: 1243 case PWR_SOFTRESUME: 1244 break; 1245 } 1246 } 1247