1 /* $OpenBSD: envy.c,v 1.15 2009/03/29 21:53:52 sthen 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 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/ioctl.h> 22 #include <sys/audioio.h> 23 #include <sys/malloc.h> 24 #include <dev/pci/pcivar.h> 25 #include <dev/pci/pcidevs.h> 26 #include <dev/pci/envyvar.h> 27 #include <dev/pci/envyreg.h> 28 #include <dev/audio_if.h> 29 #include <machine/bus.h> 30 31 #ifdef ENVY_DEBUG 32 #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0) 33 #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0) 34 int envydebug = 1; 35 #else 36 #define DPRINTF(...) do {} while(0) 37 #define DPRINTFN(n, ...) do {} while(0) 38 #endif 39 #define DEVNAME(sc) ((sc)->dev.dv_xname) 40 41 int envymatch(struct device *, void *, void *); 42 void envyattach(struct device *, struct device *, void *); 43 int envydetach(struct device *, int); 44 45 int envy_ccs_read(struct envy_softc *, int); 46 void envy_ccs_write(struct envy_softc *, int, int); 47 int envy_cci_read(struct envy_softc *, int); 48 void envy_cci_write(struct envy_softc *, int, int); 49 void envy_i2c_wait(struct envy_softc *); 50 int envy_i2c_read(struct envy_softc *, int, int); 51 void envy_i2c_write(struct envy_softc *, int, int, int); 52 int envy_gpio_read(struct envy_softc *); 53 void envy_gpio_write(struct envy_softc *, int); 54 void envy_eeprom_read(struct envy_softc *, unsigned char *); 55 void envy_reset(struct envy_softc *); 56 int envy_ak_read(struct envy_softc *, int, int); 57 void envy_ak_write(struct envy_softc *, int, int, int); 58 int envy_intr(void *); 59 60 int envy_lineout_getsrc(struct envy_softc *, int); 61 void envy_lineout_setsrc(struct envy_softc *, int, int); 62 int envy_spdout_getsrc(struct envy_softc *, int); 63 void envy_spdout_setsrc(struct envy_softc *, int, int); 64 void envy_mon_getvol(struct envy_softc *, int, int, int *); 65 void envy_mon_setvol(struct envy_softc *, int, int, int); 66 67 int envy_open(void *, int); 68 void envy_close(void *); 69 void *envy_allocm(void *, int, size_t, int, int); 70 void envy_freem(void *, void *, int); 71 int envy_query_encoding(void *, struct audio_encoding *); 72 int envy_set_params(void *, int, int, struct audio_params *, 73 struct audio_params *); 74 int envy_round_blocksize(void *, int); 75 size_t envy_round_buffersize(void *, int, size_t); 76 int envy_trigger_output(void *, void *, void *, int, 77 void (*)(void *), void *, struct audio_params *); 78 int envy_trigger_input(void *, void *, void *, int, 79 void (*)(void *), void *, struct audio_params *); 80 int envy_halt_output(void *); 81 int envy_halt_input(void *); 82 int envy_getdev(void *, struct audio_device *); 83 int envy_query_devinfo(void *, struct mixer_devinfo *); 84 int envy_get_port(void *, struct mixer_ctrl *); 85 int envy_set_port(void *, struct mixer_ctrl *); 86 int envy_get_props(void *); 87 88 struct cfattach envy_ca = { 89 sizeof(struct envy_softc), envymatch, envyattach, envydetach 90 }; 91 92 struct cfdriver envy_cd = { 93 NULL, "envy", DV_DULL 94 }; 95 96 struct audio_hw_if envy_hw_if = { 97 envy_open, /* open */ 98 envy_close, /* close */ 99 NULL, /* drain */ 100 envy_query_encoding, /* query_encoding */ 101 envy_set_params, /* set_params */ 102 envy_round_blocksize, /* round_blocksize */ 103 NULL, /* commit_settings */ 104 NULL, /* init_output */ 105 NULL, /* init_input */ 106 NULL, /* start_output */ 107 NULL, /* start_input */ 108 envy_halt_output, /* halt_output */ 109 envy_halt_input, /* halt_input */ 110 NULL, /* speaker_ctl */ 111 envy_getdev, /* getdev */ 112 NULL, /* setfd */ 113 envy_set_port, /* set_port */ 114 envy_get_port, /* get_port */ 115 envy_query_devinfo, /* query_devinfo */ 116 envy_allocm, /* malloc */ 117 envy_freem, /* free */ 118 envy_round_buffersize, /* round_buffersize */ 119 NULL, /* mappage */ 120 envy_get_props, /* get_props */ 121 envy_trigger_output, /* trigger_output */ 122 envy_trigger_input, /* trigger_input */ 123 NULL 124 }; 125 126 /* 127 * correspondence between rates (in frames per second) 128 * and values of rate register 129 */ 130 struct { 131 int rate, reg; 132 } envy_rates[] = { 133 { 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5}, 134 {22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0}, 135 {64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1} 136 }; 137 138 int 139 envy_ccs_read(struct envy_softc *sc, int reg) 140 { 141 return bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg); 142 } 143 144 void 145 envy_ccs_write(struct envy_softc *sc, int reg, int val) 146 { 147 bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val); 148 } 149 150 int 151 envy_cci_read(struct envy_softc *sc, int index) 152 { 153 int val; 154 envy_ccs_write(sc, ENVY_CCI_INDEX, index); 155 val = envy_ccs_read(sc, ENVY_CCI_DATA); 156 return val; 157 } 158 159 void 160 envy_cci_write(struct envy_softc *sc, int index, int data) 161 { 162 envy_ccs_write(sc, ENVY_CCI_INDEX, index); 163 envy_ccs_write(sc, ENVY_CCI_DATA, data); 164 } 165 166 void 167 envy_i2c_wait(struct envy_softc *sc) 168 { 169 int timeout = 50, st; 170 171 for (;;) { 172 st = envy_ccs_read(sc, ENVY_I2C_CTL); 173 if (!(st & ENVY_I2C_CTL_BUSY)) 174 break; 175 if (timeout == 0) { 176 printf("%s: i2c busy timeout\n", DEVNAME(sc)); 177 break; 178 } 179 delay(50); 180 timeout--; 181 } 182 } 183 184 int 185 envy_i2c_read(struct envy_softc *sc, int dev, int addr) 186 { 187 envy_i2c_wait(sc); 188 envy_ccs_write(sc, ENVY_I2C_ADDR, addr); 189 envy_i2c_wait(sc); 190 envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1); 191 envy_i2c_wait(sc); 192 return envy_ccs_read(sc, ENVY_I2C_DATA); 193 } 194 195 void 196 envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data) 197 { 198 if (dev == 0x50) { 199 printf("%s: writing on eeprom is evil...\n", DEVNAME(sc)); 200 return; 201 } 202 envy_i2c_wait(sc); 203 envy_ccs_write(sc, ENVY_I2C_ADDR, addr); 204 envy_i2c_wait(sc); 205 envy_ccs_write(sc, ENVY_I2C_DATA, data); 206 envy_i2c_wait(sc); 207 envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1); 208 } 209 210 void 211 envy_eeprom_read(struct envy_softc *sc, unsigned char *eeprom) 212 { 213 int i; 214 215 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) { 216 eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i); 217 } 218 #ifdef ENVY_DEBUG 219 printf("%s: eeprom: ", DEVNAME(sc)); 220 for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) { 221 printf(" %02x", (unsigned)eeprom[i]); 222 } 223 printf("\n"); 224 #endif 225 } 226 227 int 228 envy_ak_read(struct envy_softc *sc, int dev, int addr) { 229 return sc->ak[dev].reg[addr]; 230 } 231 232 void 233 envy_ak_write(struct envy_softc *sc, int dev, int addr, int data) 234 { 235 int bits, i, reg; 236 237 DPRINTFN(2, "envy_ak_write: %d, %d, 0x%x\n", dev, addr, data); 238 sc->ak[dev].reg[addr] = data; 239 240 reg = envy_cci_read(sc, ENVY_GPIO_DATA); 241 reg &= ~ENVY_GPIO_CSMASK; 242 reg |= ENVY_GPIO_CS(dev); 243 envy_cci_write(sc, ENVY_GPIO_DATA, reg); 244 delay(1); 245 246 bits = 0xa000 | (addr << 8) | data; 247 for (i = 0; i < 16; i++) { 248 reg &= ~(ENVY_GPIO_CLK | ENVY_GPIO_DOUT); 249 reg |= (bits & 0x8000) ? ENVY_GPIO_DOUT : 0; 250 envy_cci_write(sc, ENVY_GPIO_DATA, reg); 251 delay(1); 252 253 reg |= ENVY_GPIO_CLK; 254 envy_cci_write(sc, ENVY_GPIO_DATA, reg); 255 delay(1); 256 bits <<= 1; 257 } 258 259 reg |= ENVY_GPIO_CSMASK; 260 envy_cci_write(sc, ENVY_GPIO_DATA, reg); 261 delay(1); 262 } 263 264 void 265 envy_reset(struct envy_softc *sc) 266 { 267 char eeprom[ENVY_EEPROM_MAXSZ]; 268 int dev; 269 270 /* 271 * full reset 272 */ 273 envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE); 274 delay(200); 275 envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE); 276 delay(200); 277 278 /* 279 * read config from eprom and write it to registers 280 */ 281 envy_eeprom_read(sc, eeprom); 282 pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF, 283 eeprom[ENVY_EEPROM_CONF] | 284 (eeprom[ENVY_EEPROM_ACLINK] << 8) | 285 (eeprom[ENVY_EEPROM_I2S] << 16) | 286 (eeprom[ENVY_EEPROM_SPDIF] << 24)); 287 envy_cci_write(sc, ENVY_GPIO_MASK, eeprom[ENVY_EEPROM_GPIOMASK]); 288 envy_cci_write(sc, ENVY_GPIO_DIR, eeprom[ENVY_EEPROM_GPIODIR]); 289 envy_cci_write(sc, ENVY_GPIO_DATA, eeprom[ENVY_EEPROM_GPIOST]); 290 291 DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc), 292 envy_cci_read(sc, ENVY_GPIO_MASK)); 293 DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc), 294 envy_cci_read(sc, ENVY_GPIO_DIR)); 295 DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc), 296 envy_cci_read(sc, ENVY_GPIO_DATA)); 297 298 /* 299 * reset ak4524 codecs 300 */ 301 for (dev = 0; dev < 4; dev++) { 302 envy_ak_write(sc, dev, AK_RST, 0x0); 303 delay(300); 304 envy_ak_write(sc, dev, AK_RST, AK_RST_AD | AK_RST_DA); 305 envy_ak_write(sc, dev, AK_FMT, AK_FMT_IIS24); 306 sc->ak[dev].reg[AK_DEEMVOL] = AK_DEEM_OFF; 307 sc->ak[dev].reg[AK_ADC_GAIN0] = 0x7f; 308 sc->ak[dev].reg[AK_ADC_GAIN1] = 0x7f; 309 sc->ak[dev].reg[AK_DAC_GAIN0] = 0x7f; 310 sc->ak[dev].reg[AK_DAC_GAIN1] = 0x7f; 311 } 312 313 /* 314 * clear all interrupts and unmask used ones 315 */ 316 envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff); 317 envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT); 318 } 319 320 int 321 envy_intr(void *self) 322 { 323 struct envy_softc *sc = (struct envy_softc *)self; 324 int st; 325 326 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR); 327 if (!(st & (ENVY_MT_INTR_PACK | ENVY_MT_INTR_RACK))) { 328 return 0; 329 } 330 if (st & ENVY_MT_INTR_PACK) { 331 st = ENVY_MT_INTR_PACK; 332 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 333 sc->ointr(sc->oarg); 334 } 335 if (st & ENVY_MT_INTR_RACK) { 336 st = ENVY_MT_INTR_RACK; 337 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 338 sc->iintr(sc->iarg); 339 } 340 return 1; 341 } 342 343 int 344 envy_lineout_getsrc(struct envy_softc *sc, int out) { 345 int reg, shift, src; 346 347 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC); 348 DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg); 349 shift = (out & 1) ? (out & ~1) + 8 : out; 350 src = (reg >> shift) & 3; 351 if (src == ENVY_MT_OUTSRC_DMA) { 352 return ENVY_MIX_OUTSRC_DMA; 353 } else if (src == ENVY_MT_OUTSRC_MON) { 354 return ENVY_MIX_OUTSRC_MON; 355 } 356 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL); 357 DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg); 358 reg = (reg >> (out * 4)) & 0xf; 359 if (src == ENVY_MT_OUTSRC_LINE) 360 return ENVY_MIX_OUTSRC_LINEIN + (reg & 7); 361 else 362 return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3); 363 } 364 365 void 366 envy_lineout_setsrc(struct envy_softc *sc, int out, int src) { 367 int reg, shift, mask, sel; 368 369 if (src < ENVY_MIX_OUTSRC_DMA) { 370 /* 371 * linein and spdin are used as output source so we 372 * must select the input source channel number 373 */ 374 if (src < ENVY_MIX_OUTSRC_SPDIN) 375 sel = src - ENVY_MIX_OUTSRC_LINEIN; 376 else 377 sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3; 378 379 shift = out * ENVY_MT_INSEL_BITS; 380 mask = ENVY_MT_INSEL_MASK << shift; 381 reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL); 382 reg = (reg & ~mask) | (sel << shift); 383 bus_space_write_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL, reg); 384 DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg); 385 } 386 387 /* 388 * set the lineout route register 389 */ 390 if (src < ENVY_MIX_OUTSRC_SPDIN) { 391 sel = ENVY_MT_OUTSRC_LINE; 392 } else if (src < ENVY_MIX_OUTSRC_DMA) { 393 sel = ENVY_MT_OUTSRC_SPD; 394 } else if (src == ENVY_MIX_OUTSRC_DMA) { 395 sel = ENVY_MT_OUTSRC_DMA; 396 } else { 397 sel = ENVY_MT_OUTSRC_MON; 398 } 399 shift = (out & 1) ? (out & ~1) + 8 : out; 400 mask = ENVY_MT_OUTSRC_MASK << shift; 401 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC); 402 reg = (reg & ~mask) | (sel << shift); 403 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC, reg); 404 DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg); 405 } 406 407 408 int 409 envy_spdout_getsrc(struct envy_softc *sc, int out) { 410 int reg, src, sel; 411 412 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE); 413 DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg); 414 src = (out == 0) ? reg : reg >> 2; 415 src &= ENVY_MT_SPDSRC_MASK; 416 if (src == ENVY_MT_SPDSRC_DMA) { 417 return ENVY_MIX_OUTSRC_DMA; 418 } else if (src == ENVY_MT_SPDSRC_MON) { 419 return ENVY_MIX_OUTSRC_MON; 420 } 421 422 sel = (out == 0) ? reg >> 8 : reg >> 12; 423 sel &= ENVY_MT_SPDSEL_MASK; 424 if (src == ENVY_MT_SPDSRC_LINE) 425 return ENVY_MIX_OUTSRC_LINEIN + (sel & 7); 426 else 427 return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3); 428 } 429 430 void 431 envy_spdout_setsrc(struct envy_softc *sc, int out, int src) { 432 int reg, shift, mask, sel; 433 434 reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE); 435 if (src < ENVY_MIX_OUTSRC_DMA) { 436 /* 437 * linein and spdin are used as output source so we 438 * must select the input source channel number 439 */ 440 if (src < ENVY_MIX_OUTSRC_SPDIN) 441 sel = src - ENVY_MIX_OUTSRC_LINEIN; 442 else 443 sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3; 444 445 shift = 8 + out * ENVY_MT_SPDSEL_BITS; 446 mask = ENVY_MT_SPDSEL_MASK << shift; 447 reg = (reg & ~mask) | (sel << shift); 448 } 449 450 /* 451 * set the lineout route register 452 */ 453 if (src < ENVY_MIX_OUTSRC_SPDIN) { 454 sel = ENVY_MT_OUTSRC_LINE; 455 } else if (src < ENVY_MIX_OUTSRC_DMA) { 456 sel = ENVY_MT_OUTSRC_SPD; 457 } else if (src == ENVY_MIX_OUTSRC_DMA) { 458 sel = ENVY_MT_OUTSRC_DMA; 459 } else { 460 sel = ENVY_MT_OUTSRC_MON; 461 } 462 shift = out * 2; 463 mask = ENVY_MT_SPDSRC_MASK << shift; 464 reg = (reg & ~mask) | (sel << shift); 465 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE, reg); 466 DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg); 467 } 468 469 void 470 envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val) { 471 int reg; 472 473 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx); 474 reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch); 475 *val = 0x7f - (reg & 0x7f); 476 } 477 478 void 479 envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val) { 480 int reg; 481 482 bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx); 483 reg = 0x7f - val; 484 DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val); 485 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch, reg); 486 } 487 488 int 489 envymatch(struct device *parent, void *match, void *aux) { 490 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 491 492 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ICENSEMBLE && 493 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_ICE1712) { 494 return 1; 495 } 496 return 0; 497 } 498 499 void 500 envyattach(struct device *parent, struct device *self, void *aux) 501 { 502 struct envy_softc *sc = (struct envy_softc *)self; 503 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 504 pci_intr_handle_t ih; 505 const char *intrstr; 506 507 sc->pci_tag = pa->pa_tag; 508 sc->pci_pc = pa->pa_pc; 509 sc->pci_dmat = pa->pa_dmat; 510 sc->pci_ih = NULL; 511 sc->ibuf.addr = sc->obuf.addr = NULL; 512 sc->ccs_iosz = 0; 513 sc->mt_iosz = 0; 514 515 if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0, 516 &sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) { 517 printf(": can't map ctl i/o space\n"); 518 sc->ccs_iosz = 0; 519 return; 520 } 521 if (pci_mapreg_map(pa, ENVY_MT_BAR, PCI_MAPREG_TYPE_IO, 0, 522 &sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) { 523 printf(": can't map mt i/o space\n"); 524 sc->mt_iosz = 0; 525 return; 526 } 527 if (pci_intr_map(pa, &ih)) { 528 printf(": can't map interrupt\n"); 529 } 530 intrstr = pci_intr_string(sc->pci_pc, ih); 531 sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO, 532 envy_intr, sc, sc->dev.dv_xname); 533 if (sc->pci_ih == NULL) { 534 printf(": can't establish interrupt"); 535 if (intrstr) 536 printf(" at %s", intrstr); 537 printf("\n"); 538 return; 539 } 540 printf(": %s\n", intrstr); 541 envy_reset(sc); 542 sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev); 543 } 544 545 int 546 envydetach(struct device *self, int flags) 547 { 548 struct envy_softc *sc = (struct envy_softc *)self; 549 550 if (sc->pci_ih != NULL) { 551 pci_intr_disestablish(sc->pci_pc, sc->pci_ih); 552 sc->pci_ih = NULL; 553 } 554 if (sc->ccs_iosz) { 555 bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz); 556 } 557 if (sc->mt_iosz) { 558 bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz); 559 } 560 return 0; 561 } 562 563 int 564 envy_open(void *self, int flags) 565 { 566 return 0; 567 } 568 569 void 570 envy_close(void *self) 571 { 572 } 573 574 void * 575 envy_allocm(void *self, int dir, size_t size, int type, int flags) 576 { 577 struct envy_softc *sc = (struct envy_softc *)self; 578 int err, rsegs, basereg, wait; 579 struct envy_buf *buf; 580 581 if (dir == AUMODE_RECORD) { 582 buf = &sc->ibuf; 583 basereg = ENVY_MT_RADDR; 584 } else { 585 buf = &sc->obuf; 586 basereg = ENVY_MT_PADDR; 587 } 588 if (buf->addr != NULL) { 589 DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir); 590 return NULL; 591 } 592 buf->size = size; 593 wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 594 595 #define ENVY_ALIGN 4 596 #define ENVY_BOUNDARY 0 597 598 err = bus_dmamem_alloc(sc->pci_dmat, buf->size, ENVY_ALIGN, 599 ENVY_BOUNDARY, &buf->seg, 1, &rsegs, wait); 600 if (err) { 601 DPRINTF("%s: dmamem_alloc: failed %d\n", DEVNAME(sc), err); 602 goto err_ret; 603 } 604 605 err = bus_dmamem_map(sc->pci_dmat, &buf->seg, rsegs, buf->size, 606 &buf->addr, wait | BUS_DMA_COHERENT); 607 if (err) { 608 DPRINTF("%s: dmamem_map: failed %d\n", DEVNAME(sc), err); 609 goto err_free; 610 } 611 612 err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0, 613 wait, &buf->map); 614 if (err) { 615 DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err); 616 goto err_unmap; 617 } 618 619 err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr, 620 buf->size, NULL, wait); 621 if (err) { 622 DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err); 623 goto err_destroy; 624 } 625 bus_space_write_4(sc->mt_iot, sc->mt_ioh, basereg, buf->seg.ds_addr); 626 DPRINTF("%s: allocated %d bytes dir=%d, ka=%p, da=%p\n", 627 DEVNAME(sc), buf->size, dir, buf->addr, buf->seg.ds_addr); 628 return buf->addr; 629 630 err_destroy: 631 bus_dmamap_destroy(sc->pci_dmat, buf->map); 632 err_unmap: 633 bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size); 634 err_free: 635 bus_dmamem_free(sc->pci_dmat, &buf->seg, 1); 636 err_ret: 637 return NULL; 638 } 639 640 void 641 envy_freem(void *self, void *addr, int type) 642 { 643 struct envy_buf *buf; 644 struct envy_softc *sc = (struct envy_softc *)self; 645 int dir; 646 647 if (sc->ibuf.addr == addr) { 648 buf = &sc->ibuf; 649 dir = AUMODE_RECORD; 650 } else if (sc->obuf.addr == addr) { 651 buf = &sc->obuf; 652 dir = AUMODE_PLAY; 653 } else { 654 DPRINTF("%s: no buf to free\n", DEVNAME(sc)); 655 return; 656 } 657 bus_dmamap_destroy(sc->pci_dmat, buf->map); 658 bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size); 659 bus_dmamem_free(sc->pci_dmat, &buf->seg, 1); 660 buf->addr = NULL; 661 DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir); 662 } 663 664 int 665 envy_query_encoding(void *self, struct audio_encoding *enc) 666 { 667 if (enc->index == 0) { 668 strlcpy(enc->name, AudioEslinear_le, sizeof(enc->name)); 669 enc->encoding = AUDIO_ENCODING_SLINEAR_LE; 670 enc->precision = 24; 671 enc->flags = 0; 672 return 0; 673 } 674 return EINVAL; 675 } 676 677 int 678 envy_set_params(void *self, int setmode, int usemode, 679 struct audio_params *p, struct audio_params *r) 680 { 681 struct envy_softc *sc = (struct envy_softc *)self; 682 int i, rate, reg; 683 684 if (setmode == 0) { 685 DPRINTF("%s: no params to set\n", DEVNAME(sc)); 686 return 0; 687 } 688 if (setmode == (AUMODE_PLAY | AUMODE_RECORD) && 689 p->sample_rate != r->sample_rate) { 690 DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc)); 691 r->sample_rate = p->sample_rate; 692 } 693 rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate; 694 for (i = 0; envy_rates[i].rate < rate; i++) { 695 if (envy_rates[i].rate == -1) { 696 i--; 697 DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i); 698 break; 699 } 700 } 701 reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE); 702 reg &= ~ENVY_MT_RATEMASK; 703 reg |= envy_rates[i].reg; 704 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE, reg); 705 if (setmode & AUMODE_PLAY) { 706 p->encoding = AUDIO_ENCODING_SLINEAR; 707 p->precision = 24; 708 p->channels = ENVY_PCHANS; 709 } 710 if (setmode & AUMODE_RECORD) { 711 r->encoding = AUDIO_ENCODING_SLINEAR; 712 r->precision = 24; 713 r->channels = ENVY_RCHANS; 714 } 715 return 0; 716 } 717 718 int 719 envy_round_blocksize(void *self, int blksz) 720 { 721 /* 722 * XXX: sizes depend on the mode but we don't have 723 * access to the mode here; So we use the greatest 724 * common divisor of input and output blocksizes, until 725 * upper layer is fixed 726 */ 727 #define ENVY_GCD (6 * 5 * 4) 728 return (blksz / ENVY_GCD) * ENVY_GCD; 729 } 730 731 size_t 732 envy_round_buffersize(void *self, int dir, size_t bufsz) 733 { 734 /* 735 * XXX: same remark as above 736 */ 737 return (bufsz / ENVY_GCD) * ENVY_GCD; 738 } 739 740 int 741 envy_trigger_output(void *self, void *start, void *end, int blksz, 742 void (*intr)(void *), void *arg, struct audio_params *param) 743 { 744 struct envy_softc *sc = (struct envy_softc *)self; 745 size_t bufsz; 746 int st; 747 748 bufsz = end - start; 749 if (bufsz % (ENVY_PCHANS * 4) != 0) { 750 DPRINTF("%s: %d: bad output bufsz\n", DEVNAME(sc), bufsz); 751 return EINVAL; 752 } 753 if (blksz % (ENVY_PCHANS * 4) != 0) { 754 DPRINTF("%s: %d: bad output blksz\n", DEVNAME(sc), blksz); 755 return EINVAL; 756 } 757 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 758 ENVY_MT_PBUFSZ, bufsz / 4 - 1); 759 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 760 ENVY_MT_PBLKSZ, blksz / 4 - 1); 761 762 sc->ointr = intr; 763 sc->oarg = arg; 764 765 st = ENVY_MT_INTR_PACK; 766 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 767 768 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 769 st |= ENVY_MT_CTL_PSTART; 770 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 771 return 0; 772 } 773 774 int 775 envy_trigger_input(void *self, void *start, void *end, int blksz, 776 void (*intr)(void *), void *arg, struct audio_params *param) 777 { 778 struct envy_softc *sc = (struct envy_softc *)self; 779 size_t bufsz; 780 int st; 781 782 bufsz = end - start; 783 if (bufsz % (ENVY_RCHANS * 4) != 0) { 784 DPRINTF("%s: %d: bad input bufsz\n", DEVNAME(sc), bufsz); 785 return EINVAL; 786 } 787 if (blksz % (ENVY_RCHANS * 4) != 0) { 788 DPRINTF("%s: %d: bad input blksz\n", DEVNAME(sc), blksz); 789 return EINVAL; 790 } 791 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 792 ENVY_MT_RBUFSZ, bufsz / 4 - 1); 793 bus_space_write_2(sc->mt_iot, sc->mt_ioh, 794 ENVY_MT_RBLKSZ, blksz / 4 - 1); 795 796 sc->iintr = intr; 797 sc->iarg = arg; 798 799 st = ENVY_MT_INTR_RACK; 800 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st); 801 802 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 803 st |= ENVY_MT_CTL_RSTART; 804 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 805 return 0; 806 } 807 808 int 809 envy_halt_output(void *self) 810 { 811 struct envy_softc *sc = (struct envy_softc *)self; 812 int st; 813 814 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 815 st &= ~ENVY_MT_CTL_PSTART; 816 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 817 return 0; 818 } 819 820 int 821 envy_halt_input(void *self) 822 { 823 struct envy_softc *sc = (struct envy_softc *)self; 824 int st; 825 826 st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL); 827 st &= ~ENVY_MT_CTL_RSTART; 828 bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st); 829 return 0; 830 } 831 832 int 833 envy_getdev(void *self, struct audio_device *dev) 834 { 835 strlcpy(dev->name, "Envy24", MAX_AUDIO_DEV_LEN); 836 strlcpy(dev->version, "-", MAX_AUDIO_DEV_LEN); /* XXX eeprom version */ 837 strlcpy(dev->config, "envy", MAX_AUDIO_DEV_LEN); 838 return 0; 839 } 840 841 int 842 envy_query_devinfo(void *self, struct mixer_devinfo *dev) 843 { 844 int i, n, out; 845 char *classes[] = { 846 AudioCinputs, AudioCoutputs, AudioCmonitor 847 }; 848 849 if (dev->index < 0) 850 return ENXIO; 851 852 dev->prev = dev->next = AUDIO_MIXER_LAST; 853 if (dev->index < ENVY_MIX_OUTSRC) { 854 dev->type = AUDIO_MIXER_CLASS; 855 dev->mixer_class = dev->index - ENVY_MIX_CLASSIN; 856 strlcpy(dev->label.name, 857 classes[dev->index - ENVY_MIX_CLASSIN], MAX_AUDIO_DEV_LEN); 858 return 0; 859 } 860 if (dev->index < ENVY_MIX_MONITOR) { 861 n = 0; 862 out = dev->index - ENVY_MIX_OUTSRC; 863 dev->type = AUDIO_MIXER_ENUM; 864 dev->mixer_class = ENVY_MIX_CLASSOUT; 865 dev->prev = ENVY_MIX_OLVL(4) + out; 866 for (i = 0; i < 10; i++) { 867 dev->un.e.member[n].ord = n; 868 snprintf(dev->un.e.member[n++].label.name, 869 MAX_AUDIO_DEV_LEN, AudioNline "%d", i); 870 } 871 dev->un.e.member[n].ord = n; 872 snprintf(dev->un.e.member[n++].label.name, 873 MAX_AUDIO_DEV_LEN, "play%d", out); 874 if (out < 2) { 875 dev->un.e.member[n].ord = n; 876 snprintf(dev->un.e.member[n++].label.name, 877 MAX_AUDIO_DEV_LEN, "mon%d", out); 878 } 879 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 880 AudioNsource, out); 881 dev->un.s.num_mem = n; 882 return 0; 883 } 884 if (dev->index < ENVY_MIX_ILVL(4)) { 885 out = dev->index - ENVY_MIX_MONITOR; 886 dev->type = AUDIO_MIXER_VALUE; 887 dev->mixer_class = ENVY_MIX_CLASSMON; 888 dev->un.v.delta = 2; 889 dev->un.v.num_channels = 1; 890 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 891 "%s%d", out < 10 ? "play" : "rec", out % 10); 892 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN); 893 return 0; 894 } 895 if (dev->index < ENVY_MIX_OLVL(4)) { /* inputs.line */ 896 out = dev->index - ENVY_MIX_ILVL(4); 897 dev->type = AUDIO_MIXER_VALUE; 898 dev->mixer_class = ENVY_MIX_CLASSIN; 899 dev->un.v.delta = 2; 900 dev->un.v.num_channels = 1; 901 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 902 AudioNline "%d", out); 903 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN); 904 return 0; 905 } 906 if (dev->index < ENVY_MIX_OMUTE(4)) { /* outputs.line */ 907 out = dev->index - ENVY_MIX_OLVL(4); 908 dev->type = AUDIO_MIXER_VALUE; 909 dev->mixer_class = ENVY_MIX_CLASSOUT; 910 dev->next = ENVY_MIX_OUTSRC + out; 911 dev->un.v.delta = 2; 912 dev->un.v.num_channels = 1; 913 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 914 AudioNline "%d", out); 915 strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN); 916 return 0; 917 } 918 if (dev->index < ENVY_MIX_INVAL(4)) { /* outputs.mute */ 919 out = dev->index - ENVY_MIX_OMUTE(4); 920 dev->type = AUDIO_MIXER_ENUM; 921 dev->mixer_class = ENVY_MIX_CLASSOUT; 922 dev->un.e.member[0].ord = 0; 923 strlcpy(dev->un.e.member[0].label.name, AudioNoff, 924 MAX_AUDIO_DEV_LEN); 925 dev->un.e.member[1].ord = 1; 926 strlcpy(dev->un.e.member[1].label.name, AudioNon, 927 MAX_AUDIO_DEV_LEN); 928 dev->un.s.num_mem = 2; 929 snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, 930 AudioNmute "%d-%d", 2 * out, 2 * out + 1); 931 return 0; 932 } 933 return ENXIO; 934 } 935 936 int 937 envy_get_port(void *self, struct mixer_ctrl *ctl) 938 { 939 struct envy_softc *sc = (struct envy_softc *)self; 940 int out, val; 941 942 if (ctl->dev < ENVY_MIX_OUTSRC) { 943 return EINVAL; 944 } 945 if (ctl->dev < ENVY_MIX_OUTSRC + 8) { 946 out = ctl->dev - ENVY_MIX_OUTSRC; 947 ctl->un.ord = envy_lineout_getsrc(sc, out); 948 return 0; 949 } 950 if (ctl->dev < ENVY_MIX_MONITOR) { 951 out = ctl->dev - (ENVY_MIX_OUTSRC + 8); 952 ctl->un.ord = envy_spdout_getsrc(sc, out); 953 return 0; 954 } 955 if (ctl->dev < ENVY_MIX_ILVL(4)) { 956 out = ctl->dev - ENVY_MIX_MONITOR; 957 envy_mon_getvol(sc, out / 2, out % 2, &val); 958 ctl->un.value.num_channels = 1; 959 ctl->un.value.level[0] = 2 * val; 960 return 0; 961 } 962 if (ctl->dev < ENVY_MIX_OLVL(4)) { 963 out = ctl->dev - ENVY_MIX_ILVL(4); 964 val = envy_ak_read(sc, out / 2, (out % 2) + AK_ADC_GAIN0); 965 ctl->un.value.num_channels = 1; 966 ctl->un.value.level[0] = 2 * val; 967 return 0; 968 } 969 if (ctl->dev < ENVY_MIX_OMUTE(4)) { 970 out = ctl->dev - ENVY_MIX_OLVL(4); 971 val = envy_ak_read(sc, out / 2, (out % 2) + AK_DAC_GAIN0); 972 ctl->un.value.num_channels = 1; 973 ctl->un.value.level[0] = 2 * val; 974 return 0; 975 } 976 if (ctl->dev < ENVY_MIX_INVAL(4)) { 977 out = ctl->dev - ENVY_MIX_OMUTE(4); 978 val = envy_ak_read(sc, out, AK_DEEMVOL); 979 ctl->un.ord = (val & AK_MUTE) ? 1 : 0; 980 return 0; 981 } 982 return ENXIO; 983 } 984 985 int 986 envy_set_port(void *self, struct mixer_ctrl *ctl) 987 { 988 struct envy_softc *sc = (struct envy_softc *)self; 989 int out, maxsrc, val; 990 991 if (ctl->dev < ENVY_MIX_OUTSRC) { 992 return EINVAL; 993 } 994 if (ctl->dev < ENVY_MIX_OUTSRC + 8) { 995 out = ctl->dev - ENVY_MIX_OUTSRC; 996 maxsrc = (out < 2 || out >= 8) ? 12 : 11; 997 if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc) 998 return EINVAL; 999 envy_lineout_setsrc(sc, out, ctl->un.ord); 1000 return 0; 1001 } 1002 if (ctl->dev < ENVY_MIX_MONITOR) { 1003 out = ctl->dev - (ENVY_MIX_OUTSRC + 8); 1004 if (ctl->un.ord < 0 || ctl->un.ord >= 12) 1005 return EINVAL; 1006 envy_spdout_setsrc(sc, out, ctl->un.ord); 1007 return 0; 1008 } 1009 if (ctl->dev < ENVY_MIX_ILVL(4)) { 1010 out = ctl->dev - ENVY_MIX_MONITOR; 1011 if (ctl->un.value.num_channels != 1) { 1012 return EINVAL; 1013 } 1014 val = ctl->un.value.level[0] / 2; 1015 envy_mon_setvol(sc, out / 2, out % 2, val); 1016 return 0; 1017 } 1018 if (ctl->dev < ENVY_MIX_OLVL(4)) { 1019 if (ctl->un.value.num_channels != 1) 1020 return EINVAL; 1021 out = ctl->dev - ENVY_MIX_ILVL(4); 1022 val = ctl->un.value.level[0] / 2; 1023 envy_ak_write(sc, out / 2, (out % 2) + AK_ADC_GAIN0, val); 1024 return 0; 1025 } 1026 if (ctl->dev < ENVY_MIX_OMUTE(4)) { 1027 if (ctl->un.value.num_channels != 1) 1028 return EINVAL; 1029 out = ctl->dev - ENVY_MIX_OLVL(4); 1030 val = ctl->un.value.level[0] / 2; 1031 envy_ak_write(sc, out / 2, (out % 2) + AK_DAC_GAIN0, val); 1032 return 0; 1033 } 1034 if (ctl->dev < ENVY_MIX_INVAL(4)) { 1035 if (ctl->un.ord >= 2) 1036 return EINVAL; 1037 out = ctl->dev - ENVY_MIX_OMUTE(4); 1038 val = AK_DEEM_OFF | (ctl->un.ord ? AK_MUTE : 0); 1039 envy_ak_write(sc, out, AK_DEEMVOL, val); 1040 return 0; 1041 } 1042 return ENXIO; 1043 } 1044 1045 int 1046 envy_get_props(void *self) 1047 { 1048 return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT; 1049 } 1050