1 /* $OpenBSD: envy.c,v 1.29 2009/10/11 12:59:29 ratchov Exp $ */ 2 /* 3 * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * TODO: 20 * 21 * - add nspdin, nspdout, to struct envy_card 22 * 23 * - use eeprom version rather isht flag 24 * 25 * - implement HT mixer, midi uart, spdif, init ADC/DACs for >48kHz modes 26 * 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/ioctl.h> 33 #include <sys/audioio.h> 34 #include <sys/malloc.h> 35 #include <dev/pci/pcivar.h> 36 #include <dev/pci/pcidevs.h> 37 #include <dev/pci/envyvar.h> 38 #include <dev/pci/envyreg.h> 39 #include <dev/audio_if.h> 40 #include <machine/bus.h> 41 42 #ifdef ENVY_DEBUG 43 #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0) 44 #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0) 45 int envydebug = 1; 46 #else 47 #define DPRINTF(...) do {} while(0) 48 #define DPRINTFN(n, ...) do {} while(0) 49 #endif 50 #define DEVNAME(sc) ((sc)->dev.dv_xname) 51 52 int envymatch(struct device *, void *, void *); 53 void envyattach(struct device *, struct device *, void *); 54 int envydetach(struct device *, int); 55 56 int envy_ccs_read(struct envy_softc *, int); 57 void envy_ccs_write(struct envy_softc *, int, int); 58 int envy_cci_read(struct envy_softc *, int); 59 void envy_cci_write(struct envy_softc *, int, int); 60 void envy_i2c_wait(struct envy_softc *); 61 int envy_i2c_read(struct envy_softc *, int, int); 62 void envy_i2c_write(struct envy_softc *, int, int, int); 63 int envy_gpio_getstate(struct envy_softc *); 64 void envy_gpio_setstate(struct envy_softc *, int); 65 int envy_gpio_getmask(struct envy_softc *); 66 void envy_gpio_setmask(struct envy_softc *, int); 67 int envy_gpio_getdir(struct envy_softc *); 68 void envy_gpio_setdir(struct envy_softc *, int); 69 int envy_eeprom_gpioxxx(struct envy_softc *, int); 70 void envy_reset(struct envy_softc *); 71 int envy_codec_read(struct envy_softc *, int, int); 72 void envy_codec_write(struct envy_softc *, int, int, int); 73 int envy_intr(void *); 74 75 int envy_lineout_getsrc(struct envy_softc *, int); 76 void envy_lineout_setsrc(struct envy_softc *, int, int); 77 int envy_spdout_getsrc(struct envy_softc *, int); 78 void envy_spdout_setsrc(struct envy_softc *, int, int); 79 void envy_mon_getvol(struct envy_softc *, int, int, int *); 80 void envy_mon_setvol(struct envy_softc *, int, int, int); 81 82 int envy_open(void *, int); 83 void envy_close(void *); 84 void *envy_allocm(void *, int, size_t, int, int); 85 void envy_freem(void *, void *, int); 86 int envy_query_encoding(void *, struct audio_encoding *); 87 int envy_set_params(void *, int, int, struct audio_params *, 88 struct audio_params *); 89 int envy_round_blocksize(void *, int); 90 size_t envy_round_buffersize(void *, int, size_t); 91 int envy_trigger_output(void *, void *, void *, int, 92 void (*)(void *), void *, struct audio_params *); 93 int envy_trigger_input(void *, void *, void *, int, 94 void (*)(void *), void *, struct audio_params *); 95 int envy_halt_output(void *); 96 int envy_halt_input(void *); 97 int envy_getdev(void *, struct audio_device *); 98 int envy_query_devinfo(void *, struct mixer_devinfo *); 99 int envy_get_port(void *, struct mixer_ctrl *); 100 int envy_set_port(void *, struct mixer_ctrl *); 101 int envy_get_props(void *); 102 103 void delta_init(struct envy_softc *); 104 void delta_codec_write(struct envy_softc *, int, int, int); 105 106 void julia_init(struct envy_softc *); 107 void julia_codec_write(struct envy_softc *, int, int, int); 108 109 void unkenvy_init(struct envy_softc *); 110 void unkenvy_codec_write(struct envy_softc *, int, int, int); 111 int unkenvy_codec_ndev(struct envy_softc *); 112 113 int ak4524_dac_ndev(struct envy_softc *); 114 void ak4524_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int); 115 void ak4524_dac_get(struct envy_softc *, struct mixer_ctrl *, int); 116 int ak4524_dac_set(struct envy_softc *, struct mixer_ctrl *, int); 117 int ak4524_adc_ndev(struct envy_softc *); 118 void ak4524_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int); 119 void ak4524_adc_get(struct envy_softc *, struct mixer_ctrl *, int); 120 int ak4524_adc_set(struct envy_softc *, struct mixer_ctrl *, int); 121 122 int ak4358_dac_ndev(struct envy_softc *); 123 void ak4358_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int); 124 void ak4358_dac_get(struct envy_softc *, struct mixer_ctrl *, int); 125 int ak4358_dac_set(struct envy_softc *, struct mixer_ctrl *, int); 126 127 struct cfattach envy_ca = { 128 sizeof(struct envy_softc), envymatch, envyattach, envydetach 129 }; 130 131 struct cfdriver envy_cd = { 132 NULL, "envy", DV_DULL 133 }; 134 135 struct audio_hw_if envy_hw_if = { 136 envy_open, /* open */ 137 envy_close, /* close */ 138 NULL, /* drain */ 139 envy_query_encoding, /* query_encoding */ 140 envy_set_params, /* set_params */ 141 envy_round_blocksize, /* round_blocksize */ 142 NULL, /* commit_settings */ 143 NULL, /* init_output */ 144 NULL, /* init_input */ 145 NULL, /* start_output */ 146 NULL, /* start_input */ 147 envy_halt_output, /* halt_output */ 148 envy_halt_input, /* halt_input */ 149 NULL, /* speaker_ctl */ 150 envy_getdev, /* getdev */ 151 NULL, /* setfd */ 152 envy_set_port, /* set_port */ 153 envy_get_port, /* get_port */ 154 envy_query_devinfo, /* query_devinfo */ 155 envy_allocm, /* malloc */ 156 envy_freem, /* free */ 157 envy_round_buffersize, /* round_buffersize */ 158 NULL, /* mappage */ 159 envy_get_props, /* get_props */ 160 envy_trigger_output, /* trigger_output */ 161 envy_trigger_input, /* trigger_input */ 162 NULL 163 }; 164 165 struct pci_matchid envy_matchids[] = { 166 { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_ICE1712 }, 167 { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_VT172x } 168 }; 169 170 /* 171 * correspondence between rates (in frames per second) 172 * and values of rate register 173 */ 174 struct { 175 int rate, reg; 176 } envy_rates[] = { 177 { 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5}, 178 {22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0}, 179 {64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1} 180 }; 181 182 /* 183 * ESI julia cards don't have EEPROM, use this copy 184 */ 185 static unsigned char julia_eeprom[ENVY_EEPROM_MAXSZ] = { 186 /* gpio mask/dir/state is from linux */ 187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 188 0x20, 0x80, 0xf8, 0xc3, 189 0x9f, 0xff, 0x7f, 190 0x9f, 0xff, 0x7f, 191 0x60, 0x00, 0x00 192 }; 193 194 struct envy_codec ak4524_dac = { 195 "ak4524 dac", ak4524_dac_ndev, ak4524_dac_devinfo, ak4524_dac_get, ak4524_dac_set 196 }, ak4524_adc = { 197 "ak4524 adc", ak4524_adc_ndev, ak4524_adc_devinfo, ak4524_adc_get, ak4524_adc_set 198 }, ak4358_dac = { 199 "ak4358 dac", ak4358_dac_ndev, ak4358_dac_devinfo, ak4358_dac_get, ak4358_dac_set 200 }, unkenvy_codec = { 201 "unknown codec", unkenvy_codec_ndev, NULL, NULL, NULL 202 }; 203 204 /* 205 * array with vendor/product sub-IDs to card info 206 */ 207 struct envy_card envy_cards[] = { 208 { 209 PCI_ID_CODE(0x1412, 0xd630), 210 "M-Audio Delta 1010", 211 8, &ak4524_adc, 8, &ak4524_dac, 212 delta_init, 213 delta_codec_write, 214 NULL 215 }, { 216 PCI_ID_CODE(0x1412, 0xd632), 217 "M-Audio Delta 66", 218 4, &ak4524_adc, 4, &ak4524_dac, 219 delta_init, 220 delta_codec_write, 221 NULL 222 }, { 223 PCI_ID_CODE(0x1412, 0xd633), 224 "M-Audio Delta 44", 225 4, &ak4524_adc, 4, &ak4524_dac, 226 delta_init, 227 delta_codec_write, 228 NULL 229 }, { 230 PCI_ID_CODE(0x1412, 0xd63b), 231 "M-Audio Delta 1010LT", 232 8, &ak4524_adc, 8, &ak4524_dac, 233 delta_init, 234 delta_codec_write, 235 NULL 236 }, { 237 0, 238 "unknown 1712-based card", 239 8, &unkenvy_codec, 8, &unkenvy_codec, 240 unkenvy_init, 241 unkenvy_codec_write 242 } 243 }, envy_cards_ht[] = { 244 { 245 PCI_ID_CODE(0x3031, 0x4553), 246 "ESI Julia", 247 2, &unkenvy_codec, 2, &ak4358_dac, 248 julia_init, 249 julia_codec_write, 250 julia_eeprom 251 }, { 252 0, 253 "unknown 1724-based card", 254 2, &unkenvy_codec, 8, &unkenvy_codec, 255 unkenvy_init, 256 unkenvy_codec_write 257 } 258 }; 259 260 261 /* 262 * m-audio delta specific code 263 */ 264 265 void 266 delta_init(struct envy_softc *sc) 267 { 268 int dev; 269 270 for (dev = 0; dev < sc->card->noch / 2; dev++) { 271 envy_codec_write(sc, dev, AK4524_RST, 0x0); 272 delay(300); 273 envy_codec_write(sc, dev, AK4524_RST, 274 AK4524_RST_AD | AK4524_RST_DA); 275 envy_codec_write(sc, dev, AK4524_FMT, 276 AK4524_FMT_IIS24); 277 sc->shadow[dev][AK4524_DEEMVOL] = AK4524_DEEM_OFF; 278 sc->shadow[dev][AK4524_ADC_GAIN0] = 0x7f; 279 sc->shadow[dev][AK4524_ADC_GAIN1] = 0x7f; 280 sc->shadow[dev][AK4524_DAC_GAIN0] = 0x7f; 281 sc->shadow[dev][AK4524_DAC_GAIN1] = 0x7f; 282 } 283 } 284 285 void 286 delta_codec_write(struct envy_softc *sc, int dev, int addr, int data) 287 { 288 int bits, i, reg; 289 290 reg = envy_gpio_getstate(sc); 291 reg &= ~ENVY_GPIO_CSMASK; 292 reg |= ENVY_GPIO_CS(dev); 293 envy_gpio_setstate(sc, reg); 294 delay(1); 295 296 bits = 0xa000 | (addr << 8) | data; 297 for (i = 0; i < 16; i++) { 298 reg &= ~(ENVY_GPIO_CLK | ENVY_GPIO_DOUT); 299 reg |= (bits & 0x8000) ? ENVY_GPIO_DOUT : 0; 300 envy_gpio_setstate(sc, reg); 301 delay(1); 302 303 reg |= ENVY_GPIO_CLK; 304 envy_gpio_setstate(sc, reg); 305 delay(1); 306 bits <<= 1; 307 } 308 309 reg |= ENVY_GPIO_CSMASK; 310 envy_gpio_setstate(sc, reg); 311 delay(1); 312 } 313 314 315 /* 316 * esi julia specific code 317 */ 318 319 void 320 julia_init(struct envy_softc *sc) 321 { 322 int i; 323 324 envy_codec_write(sc, 0, 0, 0); /* reset */ 325 delay(300); 326 envy_codec_write(sc, 0, 0, 0x87); /* i2s mode */ 327 for (i = 0; i < sc->card->noch; i++) { 328 sc->shadow[0][AK4358_ATT(i)] = 0xff; 329 } 330 } 331 332 void 333 julia_codec_write(struct envy_softc *sc, int dev, int addr, int data) 334 { 335 #define JULIA_AK4358_ADDR 0x11 336 envy_i2c_write(sc, JULIA_AK4358_ADDR, addr, data); 337 } 338 339 /* 340 * unknown card, ignore codecs setup and hope it works with the power on 341 * settings 342 */ 343 344 void 345 unkenvy_init(struct envy_softc *sc) 346 { 347 } 348 349 void 350 unkenvy_codec_write(struct envy_softc *sc, int dev, int addr, int data) 351 { 352 } 353 354 int 355 unkenvy_codec_ndev(struct envy_softc *sc) 356 { 357 return 0; 358 } 359 360 /* 361 * AK 4358 DAC specific code 362 */ 363 int 364 ak4358_dac_ndev(struct envy_softc *sc) 365 { 366 /* 1 volume knob per channel */ 367 return sc->card->noch; 368 } 369 370 371 void 372 ak4358_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx) 373 { 374 dev->type = AUDIO_MIXER_VALUE; 375 dev->mixer_class = ENVY_MIX_CLASSOUT; 376 dev->un.v.delta = 2; 377 dev->un.v.num_channels = 1; 378 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 379 AudioNline "%d", idx); 380 strlcpy(dev->un.v.units.name, AudioNvolume, 381 MAX_AUDIO_DEV_LEN); 382 } 383 384 void 385 ak4358_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 386 { 387 int val; 388 389 val = envy_codec_read(sc, 0, AK4358_ATT(idx)) & ~AK4358_ATT_EN; 390 ctl->un.value.num_channels = 1; 391 ctl->un.value.level[0] = 2 * val; 392 } 393 394 int 395 ak4358_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 396 { 397 int val; 398 399 if (ctl->un.value.num_channels != 1) 400 return EINVAL; 401 val = ctl->un.value.level[0] / 2; 402 envy_codec_write(sc, 0, AK4358_ATT(idx), val | AK4358_ATT_EN); 403 return 0; 404 } 405 406 /* 407 * AK 4524 DAC specific code 408 */ 409 int 410 ak4524_dac_ndev(struct envy_softc *sc) 411 { 412 /* 1 mute + 2 volume knobs per channel pair */ 413 return 3 * (sc->card->noch / 2); 414 } 415 416 void 417 ak4524_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx) 418 { 419 int ndev; 420 421 ndev = sc->card->noch; 422 if (idx < ndev) { 423 dev->type = AUDIO_MIXER_VALUE; 424 dev->mixer_class = ENVY_MIX_CLASSOUT; 425 dev->un.v.delta = 2; 426 dev->un.v.num_channels = 1; 427 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 428 AudioNline "%d", idx); 429 strlcpy(dev->un.v.units.name, AudioNvolume, 430 MAX_AUDIO_DEV_LEN); 431 } else { 432 idx -= ndev; 433 dev->type = AUDIO_MIXER_ENUM; 434 dev->mixer_class = ENVY_MIX_CLASSOUT; 435 dev->un.e.member[0].ord = 0; 436 strlcpy(dev->un.e.member[0].label.name, AudioNoff, 437 MAX_AUDIO_DEV_LEN); 438 dev->un.e.member[1].ord = 1; 439 strlcpy(dev->un.e.member[1].label.name, AudioNon, 440 MAX_AUDIO_DEV_LEN); 441 dev->un.e.num_mem = 2; 442 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 443 AudioNmute "%d-%d", 2 * idx, 2 * idx + 1); 444 } 445 } 446 447 void 448 ak4524_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 449 { 450 int val, ndev; 451 452 ndev = sc->card->noch; 453 if (idx < ndev) { 454 val = envy_codec_read(sc, idx / 2, 455 (idx % 2) + AK4524_DAC_GAIN0); 456 ctl->un.value.num_channels = 1; 457 ctl->un.value.level[0] = 2 * val; 458 } else { 459 idx -= ndev; 460 val = envy_codec_read(sc, idx, AK4524_DEEMVOL); 461 ctl->un.ord = (val & AK4524_MUTE) ? 1 : 0; 462 } 463 } 464 465 int 466 ak4524_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 467 { 468 int val, ndev; 469 470 ndev = sc->card->noch; 471 if (idx < ndev) { 472 if (ctl->un.value.num_channels != 1) 473 return EINVAL; 474 val = ctl->un.value.level[0] / 2; 475 envy_codec_write(sc, idx / 2, 476 (idx % 2) + AK4524_DAC_GAIN0, val); 477 } else { 478 idx -= ndev; 479 if (ctl->un.ord >= 2) 480 return EINVAL; 481 val = AK4524_DEEM_OFF | (ctl->un.ord ? AK4524_MUTE : 0); 482 envy_codec_write(sc, idx, AK4524_DEEMVOL, val); 483 } 484 return 0; 485 } 486 487 /* 488 * AK 4524 ADC specific code 489 */ 490 int 491 ak4524_adc_ndev(struct envy_softc *sc) 492 { 493 /* one volume per channel */ 494 return sc->card->nich; 495 } 496 497 void 498 ak4524_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx) 499 { 500 dev->type = AUDIO_MIXER_VALUE; 501 dev->mixer_class = ENVY_MIX_CLASSIN; 502 dev->un.v.delta = 2; 503 dev->un.v.num_channels = 1; 504 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, AudioNline "%d", idx); 505 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN); 506 } 507 508 void 509 ak4524_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 510 { 511 int val; 512 513 val = envy_codec_read(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0); 514 ctl->un.value.num_channels = 1; 515 ctl->un.value.level[0] = 2 * val; 516 } 517 518 int 519 ak4524_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx) 520 { 521 int val; 522 523 if (ctl->un.value.num_channels != 1) 524 return EINVAL; 525 val = ctl->un.value.level[0] / 2; 526 envy_codec_write(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0, val); 527 return 0; 528 } 529 530 /* 531 * generic Envy24 and Envy24HT code, common to all cards 532 */ 533 534 int 535 envy_ccs_read(struct envy_softc *sc, int reg) 536 { 537 return bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg); 538 } 539 540 void 541 envy_ccs_write(struct envy_softc *sc, int reg, int val) 542 { 543 bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val); 544 } 545 546 int 547 envy_cci_read(struct envy_softc *sc, int index) 548 { 549 int val; 550 envy_ccs_write(sc, ENVY_CCI_INDEX, index); 551 val = envy_ccs_read(sc, ENVY_CCI_DATA); 552 return val; 553 } 554 555 void 556 envy_cci_write(struct envy_softc *sc, int index, int data) 557 { 558 envy_ccs_write(sc, ENVY_CCI_INDEX, index); 559 envy_ccs_write(sc, ENVY_CCI_DATA, data); 560 } 561 562 int 563 envy_gpio_getstate(struct envy_softc *sc) 564 { 565 if (sc->isht) { 566 return envy_ccs_read(sc, ENVY_CCS_GPIODATA0) | 567 (envy_ccs_read(sc, ENVY_CCS_GPIODATA1) << 8) | 568 (envy_ccs_read(sc, ENVY_CCS_GPIODATA2) << 16); 569 } else 570 return envy_cci_read(sc, ENVY_CCI_GPIODATA); 571 } 572 573 void 574 envy_gpio_setstate(struct envy_softc *sc, int reg) 575 { 576 if (sc->isht) { 577 envy_ccs_write(sc, ENVY_CCS_GPIODATA0, reg & 0xff); 578 envy_ccs_write(sc, ENVY_CCS_GPIODATA1, (reg >> 8) & 0xff); 579 envy_ccs_write(sc, ENVY_CCS_GPIODATA2, (reg >> 16) & 0xff); 580 } else 581 envy_cci_write(sc, ENVY_CCI_GPIODATA, reg); 582 } 583 584 int 585 envy_gpio_getmask(struct envy_softc *sc) 586 { 587 if (sc->isht) { 588 return envy_ccs_read(sc, ENVY_CCS_GPIOMASK0) | 589 (envy_ccs_read(sc, ENVY_CCS_GPIOMASK1) << 8) | 590 (envy_ccs_read(sc, ENVY_CCS_GPIOMASK2) << 16); 591 } else 592 return envy_cci_read(sc, ENVY_CCI_GPIOMASK); 593 } 594 595 void 596 envy_gpio_setmask(struct envy_softc *sc, int mask) 597 { 598 if (sc->isht) { 599 envy_ccs_write(sc, ENVY_CCS_GPIOMASK0, mask & 0xff); 600 envy_ccs_write(sc, ENVY_CCS_GPIOMASK1, (mask >> 8) & 0xff); 601 envy_ccs_write(sc, ENVY_CCS_GPIOMASK2, (mask >> 16) & 0xff); 602 } else 603 envy_cci_write(sc, ENVY_CCI_GPIOMASK, mask); 604 } 605 606 int 607 envy_gpio_getdir(struct envy_softc *sc) 608 { 609 if (sc->isht) { 610 return envy_ccs_read(sc, ENVY_CCS_GPIODIR0) | 611 (envy_ccs_read(sc, ENVY_CCS_GPIODIR1) << 8) | 612 (envy_ccs_read(sc, ENVY_CCS_GPIODIR2) << 16); 613 } else 614 return envy_cci_read(sc, ENVY_CCI_GPIODIR); 615 } 616 617 void 618 envy_gpio_setdir(struct envy_softc *sc, int dir) 619 { 620 if (sc->isht) { 621 envy_ccs_write(sc, ENVY_CCS_GPIODIR0, dir & 0xff); 622 envy_ccs_write(sc, ENVY_CCS_GPIODIR1, (dir >> 8) & 0xff); 623 envy_ccs_write(sc, ENVY_CCS_GPIODIR2, (dir >> 16) & 0xff); 624 } else 625 envy_cci_write(sc, ENVY_CCI_GPIODIR, dir); 626 } 627 628 void 629 envy_i2c_wait(struct envy_softc *sc) 630 { 631 int timeout = 50, st; 632 633 for (;;) { 634 st = envy_ccs_read(sc, ENVY_I2C_CTL); 635 if (!(st & ENVY_I2C_CTL_BUSY)) 636 break; 637 if (timeout == 0) { 638 printf("%s: i2c busy timeout\n", DEVNAME(sc)); 639 break; 640 } 641 delay(50); 642 timeout--; 643 } 644 } 645 646 int 647 envy_i2c_read(struct envy_softc *sc, int dev, int addr) 648 { 649 envy_i2c_wait(sc); 650 envy_ccs_write(sc, ENVY_I2C_ADDR, addr); 651 envy_i2c_wait(sc); 652 envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1); 653 envy_i2c_wait(sc); 654 return envy_ccs_read(sc, ENVY_I2C_DATA); 655 } 656 657 void 658 envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data) 659 { 660 if (dev == 0x50) { 661 printf("%s: writing on eeprom is evil...\n", DEVNAME(sc)); 662 return; 663 } 664 envy_i2c_wait(sc); 665 envy_ccs_write(sc, ENVY_I2C_ADDR, addr); 666 envy_i2c_wait(sc); 667 envy_ccs_write(sc, ENVY_I2C_DATA, data); 668 envy_i2c_wait(sc); 669 envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1); 670 } 671 672 int 673 envy_codec_read(struct envy_softc *sc, int dev, int addr) { 674 return sc->shadow[dev][addr]; 675 } 676 677 void 678 envy_codec_write(struct envy_softc *sc, int dev, int addr, int data) 679 { 680 DPRINTFN(2, "envy_codec_write: %d, %d, 0x%x\n", dev, addr, data); 681 sc->shadow[dev][addr] = data; 682 sc->card->codec_write(sc, dev, addr, data); 683 } 684 685 int 686 envy_eeprom_gpioxxx(struct envy_softc *sc, int addr) 687 { 688 int val; 689 690 val = sc->eeprom[addr]; 691 if (sc->isht) { 692 val |= sc->eeprom[++addr] << 8; 693 val |= sc->eeprom[++addr] << 16; 694 } 695 return val; 696 } 697 698 void 699 envy_reset(struct envy_softc *sc) 700 { 701 int i; 702 703 /* 704 * full reset 705 */ 706 envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE); 707 delay(200); 708 envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE); 709 delay(200); 710 711 /* 712 * read eeprom using i2c device or from a static array 713 */ 714 if (sc->card->eeprom == NULL) { 715 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) { 716 sc->eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i); 717 } 718 #ifdef ENVY_DEBUG 719 printf("%s: eeprom: ", DEVNAME(sc)); 720 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) { 721 printf(" %02x", (unsigned)sc->eeprom[i]); 722 } 723 printf("\n"); 724 #endif 725 } else 726 memcpy(sc->eeprom, sc->card->eeprom, ENVY_EEPROM_MAXSZ); 727 728 /* 729 * write eeprom values to corresponding registers 730 */ 731 if (sc->isht) { 732 envy_ccs_write(sc, ENVY_CCS_CONF, 733 sc->eeprom[ENVY_EEPROM_CONF]); 734 envy_ccs_write(sc, ENVY_CCS_ACLINK, 735 sc->eeprom[ENVY_EEPROM_ACLINK]); 736 envy_ccs_write(sc, ENVY_CCS_I2S, 737 sc->eeprom[ENVY_EEPROM_I2S]); 738 envy_ccs_write(sc, ENVY_CCS_SPDIF, 739 sc->eeprom[ENVY_EEPROM_SPDIF]); 740 } else { 741 pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF, 742 sc->eeprom[ENVY_EEPROM_CONF] | 743 (sc->eeprom[ENVY_EEPROM_ACLINK] << 8) | 744 (sc->eeprom[ENVY_EEPROM_I2S] << 16) | 745 (sc->eeprom[ENVY_EEPROM_SPDIF] << 24)); 746 } 747 748 envy_gpio_setmask(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOMASK(sc))); 749 envy_gpio_setdir(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIODIR(sc))); 750 envy_gpio_setstate(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOST(sc))); 751 752 DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc), 753 envy_gpio_getmask(sc)); 754 DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc), 755 envy_gpio_getdir(sc)); 756 DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc), 757 envy_gpio_getstate(sc)); 758 759 /* 760 * clear all interrupts and unmask used ones 761 */ 762 envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff); 763 envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT); 764 if (sc->isht) { 765 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_NSTREAM, 766 4 - sc->card->noch / 2); 767 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_IMASK, 768 ~(ENVY_MT_IMASK_PDMA0 | ENVY_MT_IMASK_RDMA0)); 769 } 770 sc->card->init(sc); 771 } 772 773 int 774 envy_intr(void *self) 775 { 776 struct envy_softc *sc = (struct envy_softc *)self; 777 int st; 778 779 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR); 780 if (!(st & (ENVY_MT_INTR_PACK | ENVY_MT_INTR_RACK))) { 781 return 0; 782 } 783 if (st & ENVY_MT_INTR_PACK) { 784 st = ENVY_MT_INTR_PACK; 785 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 786 sc->ointr(sc->oarg); 787 } 788 if (st & ENVY_MT_INTR_RACK) { 789 st = ENVY_MT_INTR_RACK; 790 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 791 sc->iintr(sc->iarg); 792 } 793 return 1; 794 } 795 796 int 797 envy_lineout_getsrc(struct envy_softc *sc, int out) 798 { 799 int reg, shift, src; 800 801 if (sc->isht) { 802 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC); 803 DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg); 804 shift = 3 * (out / 2) + ((out & 1) ? 20 : 8); 805 src = (reg >> shift) & ENVY_MT_HTSRC_MASK; 806 if (src == ENVY_MT_HTSRC_DMA) { 807 return ENVY_MIX_OUTSRC_DMA; 808 } else { 809 src -= ENVY_MT_HTSRC_LINE; 810 return ENVY_MIX_OUTSRC_LINEIN + src; 811 } 812 } 813 814 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC); 815 DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg); 816 shift = (out & 1) ? (out & ~1) + 8 : out; 817 src = (reg >> shift) & 3; 818 if (src == ENVY_MT_OUTSRC_DMA) { 819 return ENVY_MIX_OUTSRC_DMA; 820 } else if (src == ENVY_MT_OUTSRC_MON) { 821 return ENVY_MIX_OUTSRC_MON; 822 } 823 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL); 824 DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg); 825 reg = (reg >> (out * 4)) & 0xf; 826 if (src == ENVY_MT_OUTSRC_LINE) 827 return ENVY_MIX_OUTSRC_LINEIN + (reg & 7); 828 else 829 return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3); 830 } 831 832 void 833 envy_lineout_setsrc(struct envy_softc *sc, int out, int src) 834 { 835 int reg, shift, mask, sel; 836 837 if (sc->isht) { 838 if (src < ENVY_MIX_OUTSRC_SPDIN) { 839 sel = ENVY_MT_HTSRC_LINE; 840 sel += src; 841 } else if (src < ENVY_MIX_OUTSRC_DMA) { 842 sel = ENVY_MT_HTSRC_SPD; 843 sel += src - ENVY_MIX_OUTSRC_SPDIN; 844 } else { 845 sel = ENVY_MT_HTSRC_DMA; 846 } 847 shift = 3 * (out / 2) + ((out & 1) ? 20 : 8); 848 mask = ENVY_MT_HTSRC_MASK << shift; 849 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC); 850 reg = (reg & ~mask) | (sel << shift); 851 bus_space_write_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC, reg); 852 DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg); 853 return; 854 } 855 856 if (src < ENVY_MIX_OUTSRC_DMA) { 857 /* 858 * linein and spdin are used as output source so we 859 * must select the input source channel number 860 */ 861 if (src < ENVY_MIX_OUTSRC_SPDIN) 862 sel = src - ENVY_MIX_OUTSRC_LINEIN; 863 else 864 sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3; 865 866 shift = out * ENVY_MT_INSEL_BITS; 867 mask = ENVY_MT_INSEL_MASK << shift; 868 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL); 869 reg = (reg & ~mask) | (sel << shift); 870 bus_space_write_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL, reg); 871 DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg); 872 } 873 874 /* 875 * set the lineout route register 876 */ 877 if (src < ENVY_MIX_OUTSRC_SPDIN) { 878 sel = ENVY_MT_OUTSRC_LINE; 879 } else if (src < ENVY_MIX_OUTSRC_DMA) { 880 sel = ENVY_MT_OUTSRC_SPD; 881 } else if (src == ENVY_MIX_OUTSRC_DMA) { 882 sel = ENVY_MT_OUTSRC_DMA; 883 } else { 884 sel = ENVY_MT_OUTSRC_MON; 885 } 886 shift = (out & 1) ? (out & ~1) + 8 : out; 887 mask = ENVY_MT_OUTSRC_MASK << shift; 888 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC); 889 reg = (reg & ~mask) | (sel << shift); 890 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC, reg); 891 DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg); 892 } 893 894 895 int 896 envy_spdout_getsrc(struct envy_softc *sc, int out) 897 { 898 int reg, src, sel; 899 900 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE); 901 DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg); 902 src = (out == 0) ? reg : reg >> 2; 903 src &= ENVY_MT_SPDSRC_MASK; 904 if (src == ENVY_MT_SPDSRC_DMA) { 905 return ENVY_MIX_OUTSRC_DMA; 906 } else if (src == ENVY_MT_SPDSRC_MON) { 907 return ENVY_MIX_OUTSRC_MON; 908 } 909 910 sel = (out == 0) ? reg >> 8 : reg >> 12; 911 sel &= ENVY_MT_SPDSEL_MASK; 912 if (src == ENVY_MT_SPDSRC_LINE) 913 return ENVY_MIX_OUTSRC_LINEIN + (sel & 7); 914 else 915 return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3); 916 } 917 918 void 919 envy_spdout_setsrc(struct envy_softc *sc, int out, int src) 920 { 921 int reg, shift, mask, sel; 922 923 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE); 924 if (src < ENVY_MIX_OUTSRC_DMA) { 925 /* 926 * linein and spdin are used as output source so we 927 * must select the input source channel number 928 */ 929 if (src < ENVY_MIX_OUTSRC_SPDIN) 930 sel = src - ENVY_MIX_OUTSRC_LINEIN; 931 else 932 sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3; 933 934 shift = 8 + out * ENVY_MT_SPDSEL_BITS; 935 mask = ENVY_MT_SPDSEL_MASK << shift; 936 reg = (reg & ~mask) | (sel << shift); 937 } 938 939 /* 940 * set the lineout route register 941 */ 942 if (src < ENVY_MIX_OUTSRC_SPDIN) { 943 sel = ENVY_MT_OUTSRC_LINE; 944 } else if (src < ENVY_MIX_OUTSRC_DMA) { 945 sel = ENVY_MT_OUTSRC_SPD; 946 } else if (src == ENVY_MIX_OUTSRC_DMA) { 947 sel = ENVY_MT_OUTSRC_DMA; 948 } else { 949 sel = ENVY_MT_OUTSRC_MON; 950 } 951 shift = out * 2; 952 mask = ENVY_MT_SPDSRC_MASK << shift; 953 reg = (reg & ~mask) | (sel << shift); 954 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE, reg); 955 DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg); 956 } 957 958 void 959 envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val) 960 { 961 int reg; 962 963 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx); 964 reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch); 965 *val = 0x7f - (reg & 0x7f); 966 } 967 968 void 969 envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val) 970 { 971 int reg; 972 973 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx); 974 reg = 0x7f - val; 975 DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val); 976 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch, reg); 977 } 978 979 int 980 envymatch(struct device *parent, void *match, void *aux) 981 { 982 return pci_matchbyid((struct pci_attach_args *)aux, envy_matchids, 983 sizeof(envy_matchids) / sizeof(envy_matchids[0])); 984 } 985 986 void 987 envyattach(struct device *parent, struct device *self, void *aux) 988 { 989 struct envy_softc *sc = (struct envy_softc *)self; 990 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 991 pci_intr_handle_t ih; 992 const char *intrstr; 993 int subid; 994 995 sc->pci_tag = pa->pa_tag; 996 sc->pci_pc = pa->pa_pc; 997 sc->pci_dmat = pa->pa_dmat; 998 sc->pci_ih = NULL; 999 sc->ibuf.addr = sc->obuf.addr = NULL; 1000 sc->ccs_iosz = 0; 1001 sc->mt_iosz = 0; 1002 sc->isht = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_VT172x); 1003 1004 if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0, 1005 &sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) { 1006 printf(": can't map ctl i/o space\n"); 1007 sc->ccs_iosz = 0; 1008 return; 1009 } 1010 if (pci_mapreg_map(pa, ENVY_MT_BAR(sc->isht), PCI_MAPREG_TYPE_IO, 0, 1011 &sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) { 1012 printf(": can't map mt i/o space\n"); 1013 sc->mt_iosz = 0; 1014 return; 1015 } 1016 if (pci_intr_map(pa, &ih)) { 1017 printf(": can't map interrupt\n"); 1018 } 1019 intrstr = pci_intr_string(sc->pci_pc, ih); 1020 sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO, 1021 envy_intr, sc, sc->dev.dv_xname); 1022 if (sc->pci_ih == NULL) { 1023 printf(": can't establish interrupt"); 1024 if (intrstr) 1025 printf(" at %s", intrstr); 1026 printf("\n"); 1027 return; 1028 } 1029 printf(": %s\n", intrstr); 1030 subid = pci_conf_read(sc->pci_pc, sc->pci_tag, PCI_SUBVEND_0); 1031 sc->card = sc->isht ? envy_cards_ht : envy_cards; 1032 while (sc->card->subid != subid) { 1033 if (sc->card->subid == 0) 1034 break; 1035 sc->card++; 1036 } 1037 printf("%s: %s, %u inputs, %u outputs\n", DEVNAME(sc), 1038 sc->card->name, sc->card->nich, sc->card->noch); 1039 envy_reset(sc); 1040 sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev); 1041 } 1042 1043 int 1044 envydetach(struct device *self, int flags) 1045 { 1046 struct envy_softc *sc = (struct envy_softc *)self; 1047 1048 if (sc->pci_ih != NULL) { 1049 pci_intr_disestablish(sc->pci_pc, sc->pci_ih); 1050 sc->pci_ih = NULL; 1051 } 1052 if (sc->ccs_iosz) { 1053 bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz); 1054 } 1055 if (sc->mt_iosz) { 1056 bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz); 1057 } 1058 return 0; 1059 } 1060 1061 int 1062 envy_open(void *self, int flags) 1063 { 1064 return 0; 1065 } 1066 1067 void 1068 envy_close(void *self) 1069 { 1070 } 1071 1072 void * 1073 envy_allocm(void *self, int dir, size_t size, int type, int flags) 1074 { 1075 struct envy_softc *sc = (struct envy_softc *)self; 1076 int err, rsegs, basereg, wait; 1077 struct envy_buf *buf; 1078 1079 if (dir == AUMODE_RECORD) { 1080 buf = &sc->ibuf; 1081 basereg = ENVY_MT_RADDR; 1082 } else { 1083 buf = &sc->obuf; 1084 basereg = ENVY_MT_PADDR; 1085 } 1086 if (buf->addr != NULL) { 1087 DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir); 1088 return NULL; 1089 } 1090 buf->size = size; 1091 wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 1092 1093 #define ENVY_ALIGN 4 1094 #define ENVY_BOUNDARY 0 1095 1096 err = bus_dmamem_alloc(sc->pci_dmat, buf->size, ENVY_ALIGN, 1097 ENVY_BOUNDARY, &buf->seg, 1, &rsegs, wait); 1098 if (err) { 1099 DPRINTF("%s: dmamem_alloc: failed %d\n", DEVNAME(sc), err); 1100 goto err_ret; 1101 } 1102 1103 err = bus_dmamem_map(sc->pci_dmat, &buf->seg, rsegs, buf->size, 1104 &buf->addr, wait | BUS_DMA_COHERENT); 1105 if (err) { 1106 DPRINTF("%s: dmamem_map: failed %d\n", DEVNAME(sc), err); 1107 goto err_free; 1108 } 1109 1110 err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0, 1111 wait, &buf->map); 1112 if (err) { 1113 DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err); 1114 goto err_unmap; 1115 } 1116 1117 err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr, 1118 buf->size, NULL, wait); 1119 if (err) { 1120 DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err); 1121 goto err_destroy; 1122 } 1123 bus_space_write_4(sc->mt_iot, sc->mt_ioh, basereg, buf->seg.ds_addr); 1124 DPRINTF("%s: allocated %ld bytes dir=%d, ka=%p, da=%p\n", 1125 DEVNAME(sc), buf->size, dir, buf->addr, (void *)buf->seg.ds_addr); 1126 return buf->addr; 1127 1128 err_destroy: 1129 bus_dmamap_destroy(sc->pci_dmat, buf->map); 1130 err_unmap: 1131 bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size); 1132 err_free: 1133 bus_dmamem_free(sc->pci_dmat, &buf->seg, 1); 1134 err_ret: 1135 return NULL; 1136 } 1137 1138 void 1139 envy_freem(void *self, void *addr, int type) 1140 { 1141 struct envy_buf *buf; 1142 struct envy_softc *sc = (struct envy_softc *)self; 1143 int dir; 1144 1145 if (sc->ibuf.addr == addr) { 1146 buf = &sc->ibuf; 1147 dir = AUMODE_RECORD; 1148 } else if (sc->obuf.addr == addr) { 1149 buf = &sc->obuf; 1150 dir = AUMODE_PLAY; 1151 } else { 1152 DPRINTF("%s: no buf to free\n", DEVNAME(sc)); 1153 return; 1154 } 1155 bus_dmamap_destroy(sc->pci_dmat, buf->map); 1156 bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size); 1157 bus_dmamem_free(sc->pci_dmat, &buf->seg, 1); 1158 buf->addr = NULL; 1159 DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir); 1160 } 1161 1162 int 1163 envy_query_encoding(void *self, struct audio_encoding *enc) 1164 { 1165 if (enc->index == 0) { 1166 strlcpy(enc->name, AudioEslinear_le, sizeof(enc->name)); 1167 enc->encoding = AUDIO_ENCODING_SLINEAR_LE; 1168 enc->precision = 24; 1169 enc->flags = 0; 1170 return 0; 1171 } 1172 return EINVAL; 1173 } 1174 1175 int 1176 envy_set_params(void *self, int setmode, int usemode, 1177 struct audio_params *p, struct audio_params *r) 1178 { 1179 struct envy_softc *sc = (struct envy_softc *)self; 1180 int i, rate, reg; 1181 1182 if (setmode == 0) { 1183 DPRINTF("%s: no params to set\n", DEVNAME(sc)); 1184 return 0; 1185 } 1186 if (setmode == (AUMODE_PLAY | AUMODE_RECORD) && 1187 p->sample_rate != r->sample_rate) { 1188 DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc)); 1189 r->sample_rate = p->sample_rate; 1190 } 1191 rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate; 1192 for (i = 0; envy_rates[i].rate < rate; i++) { 1193 if (envy_rates[i].rate == -1) { 1194 i--; 1195 DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i); 1196 break; 1197 } 1198 } 1199 reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE); 1200 reg &= ~ENVY_MT_RATEMASK; 1201 reg |= envy_rates[i].reg; 1202 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE, reg); 1203 if (setmode & AUMODE_PLAY) { 1204 p->encoding = AUDIO_ENCODING_SLINEAR; 1205 p->precision = 24; 1206 p->channels = sc->isht ? sc->card->noch : ENVY_PCHANS; 1207 } 1208 if (setmode & AUMODE_RECORD) { 1209 r->encoding = AUDIO_ENCODING_SLINEAR; 1210 r->precision = 24; 1211 r->channels = sc->isht ? sc->card->nich : ENVY_RCHANS; 1212 } 1213 return 0; 1214 } 1215 1216 int 1217 envy_round_blocksize(void *self, int blksz) 1218 { 1219 struct envy_softc *sc = (struct envy_softc *)self; 1220 int mul, pmult, rmult; 1221 1222 /* 1223 * XXX: audio(4) layer doesn't round to the sample size 1224 * until it's fixed, roll our own rounding 1225 */ 1226 1227 pmult = (sc->isht ? sc->card->noch : ENVY_PCHANS); 1228 if (pmult == 0) 1229 pmult = 1; 1230 rmult = (sc->isht ? sc->card->nich : ENVY_RCHANS); 1231 if (rmult == 0) 1232 rmult = 1; 1233 mul = pmult * rmult; 1234 while ((mul & 0x1f) != 0) 1235 mul <<= 1; 1236 blksz -= blksz % mul; 1237 if (blksz == 0) 1238 blksz = mul; 1239 return blksz; 1240 } 1241 1242 size_t 1243 envy_round_buffersize(void *self, int dir, size_t bufsz) 1244 { 1245 return bufsz; 1246 } 1247 1248 int 1249 envy_trigger_output(void *self, void *start, void *end, int blksz, 1250 void (*intr)(void *), void *arg, struct audio_params *param) 1251 { 1252 struct envy_softc *sc = (struct envy_softc *)self; 1253 size_t bufsz; 1254 int st; 1255 1256 bufsz = (char *)end - (char *)start; 1257 #ifdef ENVY_DEBUG 1258 if (blksz % (sc->isht ? sc->card->noch * 4 : ENVY_PFRAME_SIZE) != 0) { 1259 printf("%s: %d: bad output blksz\n", DEVNAME(sc), blksz); 1260 return EINVAL; 1261 } 1262 if (bufsz % blksz) { 1263 printf("%s: %ld: bad output bufsz\n", DEVNAME(sc), bufsz); 1264 return EINVAL; 1265 } 1266 #endif 1267 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 1268 ENVY_MT_PBUFSZ, bufsz / 4 - 1); 1269 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 1270 ENVY_MT_PBLKSZ(sc), blksz / 4 - 1); 1271 1272 sc->ointr = intr; 1273 sc->oarg = arg; 1274 1275 st = ENVY_MT_INTR_PACK; 1276 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 1277 1278 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 1279 st |= ENVY_MT_CTL_PSTART; 1280 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 1281 return 0; 1282 } 1283 1284 int 1285 envy_trigger_input(void *self, void *start, void *end, int blksz, 1286 void (*intr)(void *), void *arg, struct audio_params *param) 1287 { 1288 struct envy_softc *sc = (struct envy_softc *)self; 1289 size_t bufsz; 1290 int st; 1291 1292 bufsz = (char *)end - (char *)start; 1293 #ifdef ENVY_DEBUG 1294 if (blksz % (sc->isht ? sc->card->nich * 4 : ENVY_RFRAME_SIZE) != 0) { 1295 printf("%s: %d: bad input blksz\n", DEVNAME(sc), blksz); 1296 return EINVAL; 1297 } 1298 if (bufsz % blksz != 0) { 1299 printf("%s: %ld: bad input bufsz\n", DEVNAME(sc), bufsz); 1300 return EINVAL; 1301 } 1302 #endif 1303 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 1304 ENVY_MT_RBUFSZ, bufsz / 4 - 1); 1305 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 1306 ENVY_MT_RBLKSZ, blksz / 4 - 1); 1307 1308 sc->iintr = intr; 1309 sc->iarg = arg; 1310 1311 st = ENVY_MT_INTR_RACK; 1312 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 1313 1314 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 1315 st |= ENVY_MT_CTL_RSTART(sc); 1316 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 1317 return 0; 1318 } 1319 1320 int 1321 envy_halt_output(void *self) 1322 { 1323 struct envy_softc *sc = (struct envy_softc *)self; 1324 int st; 1325 1326 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 1327 st &= ~ENVY_MT_CTL_PSTART; 1328 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 1329 return 0; 1330 } 1331 1332 int 1333 envy_halt_input(void *self) 1334 { 1335 struct envy_softc *sc = (struct envy_softc *)self; 1336 int st; 1337 1338 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 1339 st &= ~ENVY_MT_CTL_RSTART(sc); 1340 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 1341 return 0; 1342 } 1343 1344 int 1345 envy_getdev(void *self, struct audio_device *dev) 1346 { 1347 struct envy_softc *sc = (struct envy_softc *)self; 1348 1349 strlcpy(dev->name, sc->isht ? "Envy24HT" : "Envy24", MAX_AUDIO_DEV_LEN); 1350 strlcpy(dev->version, "-", MAX_AUDIO_DEV_LEN); 1351 strlcpy(dev->config, sc->card->name, MAX_AUDIO_DEV_LEN); 1352 return 0; 1353 } 1354 1355 int 1356 envy_query_devinfo(void *self, struct mixer_devinfo *dev) 1357 { 1358 struct envy_softc *sc = (struct envy_softc *)self; 1359 int i, n, idx, ndev; 1360 char *classes[] = { 1361 AudioCinputs, AudioCoutputs, AudioCmonitor 1362 }; 1363 1364 if (dev->index < 0) 1365 return ENXIO; 1366 1367 idx = dev->index; 1368 ndev = ENVY_MIX_NCLASS; 1369 dev->prev = dev->next = AUDIO_MIXER_LAST; 1370 1371 /* 1372 * classes 1373 */ 1374 if (idx < ndev) { 1375 dev->type = AUDIO_MIXER_CLASS; 1376 dev->mixer_class = idx; 1377 strlcpy(dev->label.name, classes[idx], MAX_AUDIO_DEV_LEN); 1378 return 0; 1379 } 1380 idx -= ndev; 1381 1382 /* 1383 * output.lineX_source 1384 */ 1385 ndev = sc->card->noch; 1386 if (idx < ndev) { 1387 n = 0; 1388 dev->type = AUDIO_MIXER_ENUM; 1389 dev->mixer_class = ENVY_MIX_CLASSOUT; 1390 for (i = 0; i < sc->card->nich; i++) { 1391 dev->un.e.member[n].ord = n; 1392 snprintf(dev->un.e.member[n++].label.name, 1393 MAX_AUDIO_DEV_LEN, AudioNline "%d", i); 1394 } 1395 dev->un.e.member[n].ord = n; 1396 snprintf(dev->un.e.member[n++].label.name, 1397 MAX_AUDIO_DEV_LEN, "play%d", idx); 1398 if (!sc->isht && idx < 2) { 1399 dev->un.e.member[n].ord = n; 1400 snprintf(dev->un.e.member[n++].label.name, 1401 MAX_AUDIO_DEV_LEN, "mon%d", idx); 1402 } 1403 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 1404 "line%u_" AudioNsource, idx); 1405 dev->un.s.num_mem = n; 1406 return 0; 1407 } 1408 idx -= ndev; 1409 1410 /* 1411 * envy monitor level 1412 */ 1413 ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR; 1414 if (idx < ndev) { 1415 dev->type = AUDIO_MIXER_VALUE; 1416 dev->mixer_class = ENVY_MIX_CLASSMON; 1417 dev->un.v.delta = 2; 1418 dev->un.v.num_channels = 1; 1419 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 1420 "%s%d", idx < 10 ? "play" : "rec", idx % 10); 1421 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN); 1422 return 0; 1423 } 1424 idx -= ndev; 1425 1426 /* 1427 * inputs.xxx 1428 */ 1429 ndev = sc->card->adc->ndev(sc); 1430 if (idx < ndev) { 1431 sc->card->adc->devinfo(sc, dev, idx); 1432 return 0; 1433 } 1434 idx -= ndev; 1435 1436 /* 1437 * outputs.xxx 1438 */ 1439 ndev = sc->card->dac->ndev(sc); 1440 if (idx < ndev) { 1441 sc->card->dac->devinfo(sc, dev, idx); 1442 return 0; 1443 } 1444 return ENXIO; 1445 } 1446 1447 int 1448 envy_get_port(void *self, struct mixer_ctrl *ctl) 1449 { 1450 struct envy_softc *sc = (struct envy_softc *)self; 1451 int val, idx, ndev; 1452 1453 if (ctl->dev < ENVY_MIX_NCLASS) { 1454 return EINVAL; 1455 } 1456 1457 idx = ctl->dev - ENVY_MIX_NCLASS; 1458 ndev = sc->card->noch; 1459 if (idx < ndev) { 1460 ctl->un.ord = envy_lineout_getsrc(sc, idx); 1461 if (ctl->un.ord >= ENVY_MIX_NOUTSRC) 1462 ctl->un.ord -= ENVY_MIX_NOUTSRC - sc->card->nich; 1463 return 0; 1464 } 1465 idx -= ndev; 1466 ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR; 1467 if (idx < ndev) { 1468 envy_mon_getvol(sc, idx / 2, idx % 2, &val); 1469 ctl->un.value.num_channels = 1; 1470 ctl->un.value.level[0] = 2 * val; 1471 return 0; 1472 } 1473 idx -= ndev; 1474 ndev = sc->card->adc->ndev(sc); 1475 if (idx < ndev) { 1476 sc->card->adc->get(sc, ctl, idx); 1477 return 0; 1478 } 1479 idx -= ndev; 1480 ndev = sc->card->dac->ndev(sc); 1481 if (idx < ndev) { 1482 sc->card->dac->get(sc, ctl, idx); 1483 return 0; 1484 } 1485 return ENXIO; 1486 } 1487 1488 int 1489 envy_set_port(void *self, struct mixer_ctrl *ctl) 1490 { 1491 struct envy_softc *sc = (struct envy_softc *)self; 1492 int maxsrc, val, idx, ndev; 1493 1494 if (ctl->dev < ENVY_MIX_NCLASS) { 1495 return EINVAL; 1496 } 1497 1498 idx = ctl->dev - ENVY_MIX_NCLASS; 1499 ndev = sc->card->noch; 1500 if (idx < ndev) { 1501 maxsrc = sc->card->nich + 1; 1502 if (idx < 2) 1503 maxsrc++; 1504 if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc) 1505 return EINVAL; 1506 if (ctl->un.ord >= sc->card->nich) 1507 ctl->un.ord += ENVY_MIX_NOUTSRC - sc->card->nich; 1508 envy_lineout_setsrc(sc, idx, ctl->un.ord); 1509 return 0; 1510 } 1511 idx -= ndev; 1512 ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR; 1513 if (idx < ndev) { 1514 if (ctl->un.value.num_channels != 1) { 1515 return EINVAL; 1516 } 1517 val = ctl->un.value.level[0] / 2; 1518 envy_mon_setvol(sc, idx / 2, idx % 2, val); 1519 return 0; 1520 } 1521 idx -= ndev; 1522 ndev = sc->card->adc->ndev(sc); 1523 if (idx < ndev) 1524 return sc->card->adc->set(sc, ctl, idx); 1525 idx -= ndev; 1526 ndev = sc->card->dac->ndev(sc); 1527 if (idx < ndev) 1528 return sc->card->dac->set(sc, ctl, idx); 1529 return ENXIO; 1530 } 1531 1532 int 1533 envy_get_props(void *self) 1534 { 1535 return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT; 1536 } 1537