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