1 /* 2 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com> 3 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <dev/sound/pcm/sound.h> 30 #include <dev/sound/pcm/ac97.h> 31 #include <dev/sound/pci/spicds.h> 32 #include <dev/sound/pci/envy24ht.h> 33 34 #include <dev/pci/pcireg.h> 35 #include <dev/pci/pcivar.h> 36 37 #include "mixer_if.h" 38 39 SND_DECLARE_FILE("$FreeBSD$"); 40 41 MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio"); 42 43 /* -------------------------------------------------------------------- */ 44 45 struct sc_info; 46 47 #define ENVY24HT_PLAY_CHNUM 8 48 #define ENVY24HT_REC_CHNUM 2 49 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */) 50 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */) 51 #define ENVY24HT_SAMPLE_NUM 4096 52 53 #define ENVY24HT_TIMEOUT 1000 54 55 #define ENVY24HT_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE) 56 57 #define ENVY24HT_NAMELEN 32 58 59 struct envy24ht_sample { 60 volatile u_int32_t buffer; 61 }; 62 63 typedef struct envy24ht_sample sample32_t; 64 65 /* channel registers */ 66 struct sc_chinfo { 67 struct snd_dbuf *buffer; 68 struct pcm_channel *channel; 69 struct sc_info *parent; 70 int dir; 71 unsigned num; /* hw channel number */ 72 73 /* channel information */ 74 u_int32_t format; 75 u_int32_t speed; 76 u_int32_t blk; /* hw block size(dword) */ 77 78 /* format conversion structure */ 79 u_int8_t *data; 80 unsigned int size; /* data buffer size(byte) */ 81 int unit; /* sample size(byte) */ 82 unsigned int offset; /* samples number offset */ 83 void (*emldma)(struct sc_chinfo *); 84 85 /* flags */ 86 int run; 87 }; 88 89 /* codec interface entrys */ 90 struct codec_entry { 91 void *(*create)(device_t dev, void *devinfo, int dir, int num); 92 void (*destroy)(void *codec); 93 void (*init)(void *codec); 94 void (*reinit)(void *codec); 95 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right); 96 void (*setrate)(void *codec, int which, int rate); 97 }; 98 99 /* system configuration information */ 100 struct cfg_info { 101 char *name; 102 u_int16_t subvendor, subdevice; 103 u_int8_t scfg, acl, i2s, spdif; 104 u_int32_t gpiomask, gpiostate, gpiodir; 105 u_int32_t cdti, cclk, cs; 106 u_int8_t cif, type, free; 107 struct codec_entry *codec; 108 }; 109 110 /* device private data */ 111 struct sc_info { 112 device_t dev; 113 struct mtx *lock; 114 115 /* Control/Status registor */ 116 struct resource *cs; 117 int csid; 118 bus_space_tag_t cst; 119 bus_space_handle_t csh; 120 /* MultiTrack registor */ 121 struct resource *mt; 122 int mtid; 123 bus_space_tag_t mtt; 124 bus_space_handle_t mth; 125 /* DMA tag */ 126 bus_dma_tag_t dmat; 127 /* IRQ resource */ 128 struct resource *irq; 129 int irqid; 130 void *ih; 131 132 /* system configuration data */ 133 struct cfg_info *cfg; 134 135 /* ADC/DAC number and info */ 136 int adcn, dacn; 137 void *adc[4], *dac[4]; 138 139 /* mixer control data */ 140 u_int32_t src; 141 u_int8_t left[ENVY24HT_CHAN_NUM]; 142 u_int8_t right[ENVY24HT_CHAN_NUM]; 143 144 /* Play/Record DMA fifo */ 145 sample32_t *pbuf; 146 sample32_t *rbuf; 147 u_int32_t psize, rsize; /* DMA buffer size(byte) */ 148 u_int16_t blk[2]; /* transfer check blocksize(dword) */ 149 bus_dmamap_t pmap, rmap; 150 151 /* current status */ 152 u_int32_t speed; 153 int run[2]; 154 u_int16_t intr[2]; 155 struct pcmchan_caps caps[2]; 156 157 /* channel info table */ 158 unsigned chnum; 159 struct sc_chinfo chan[11]; 160 }; 161 162 /* -------------------------------------------------------------------- */ 163 164 /* 165 * prototypes 166 */ 167 168 /* DMA emulator */ 169 static void envy24ht_p8u(struct sc_chinfo *); 170 static void envy24ht_p16sl(struct sc_chinfo *); 171 static void envy24ht_p32sl(struct sc_chinfo *); 172 static void envy24ht_r16sl(struct sc_chinfo *); 173 static void envy24ht_r32sl(struct sc_chinfo *); 174 175 /* channel interface */ 176 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 177 static int envy24htchan_setformat(kobj_t, void *, u_int32_t); 178 static int envy24htchan_setspeed(kobj_t, void *, u_int32_t); 179 static int envy24htchan_setblocksize(kobj_t, void *, u_int32_t); 180 static int envy24htchan_trigger(kobj_t, void *, int); 181 static int envy24htchan_getptr(kobj_t, void *); 182 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *); 183 184 /* mixer interface */ 185 static int envy24htmixer_init(struct snd_mixer *); 186 static int envy24htmixer_reinit(struct snd_mixer *); 187 static int envy24htmixer_uninit(struct snd_mixer *); 188 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned); 189 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t); 190 191 /* SPI codec access interface */ 192 static void *envy24ht_spi_create(device_t, void *, int, int); 193 static void envy24ht_spi_destroy(void *); 194 static void envy24ht_spi_init(void *); 195 static void envy24ht_spi_reinit(void *); 196 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int); 197 198 /* -------------------------------------------------------------------- */ 199 200 /* 201 system constant tables 202 */ 203 204 /* API -> hardware channel map */ 205 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = { 206 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */ 207 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */ 208 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */ 209 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */ 210 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */ 211 ENVY24HT_CHAN_REC_MIX, /* 5 */ 212 ENVY24HT_CHAN_REC_SPDIF, /* 6 */ 213 ENVY24HT_CHAN_REC_ADC1, /* 7 */ 214 ENVY24HT_CHAN_REC_ADC2, /* 8 */ 215 ENVY24HT_CHAN_REC_ADC3, /* 9 */ 216 ENVY24HT_CHAN_REC_ADC4, /* 10 */ 217 }; 218 219 /* mixer -> API channel map. see above */ 220 static int envy24ht_mixmap[] = { 221 -1, /* Master output level. It is depend on codec support */ 222 -1, /* Treble level of all output channels */ 223 -1, /* Bass level of all output channels */ 224 -1, /* Volume of synthesier input */ 225 0, /* Output level for the audio device */ 226 -1, /* Output level for the PC speaker */ 227 7, /* line in jack */ 228 -1, /* microphone jack */ 229 -1, /* CD audio input */ 230 -1, /* Recording monitor */ 231 1, /* alternative codec */ 232 -1, /* global recording level */ 233 -1, /* Input gain */ 234 -1, /* Output gain */ 235 8, /* Input source 1 */ 236 9, /* Input source 2 */ 237 10, /* Input source 3 */ 238 6, /* Digital (input) 1 */ 239 -1, /* Digital (input) 2 */ 240 -1, /* Digital (input) 3 */ 241 -1, /* Phone input */ 242 -1, /* Phone output */ 243 -1, /* Video/TV (audio) in */ 244 -1, /* Radio in */ 245 -1, /* Monitor volume */ 246 }; 247 248 /* variable rate audio */ 249 static u_int32_t envy24ht_speed[] = { 250 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 251 12000, 11025, 9600, 8000, 0 252 }; 253 254 /* known boards configuration */ 255 static struct codec_entry spi_codec = { 256 envy24ht_spi_create, 257 envy24ht_spi_destroy, 258 envy24ht_spi_init, 259 envy24ht_spi_reinit, 260 envy24ht_spi_setvolume, 261 NULL, /* setrate */ 262 }; 263 264 static struct cfg_info cfg_table[] = { 265 { 266 "Envy24HT audio (Terratec Aureon 7.1 Space)", 267 0x153b, 0x1145, 268 0x0b, 0x80, 0xfc, 0xc3, 269 0x21efff, 0x7fffff, 0x5e1000, 270 0x40000, 0x80000, 0x1000, 0x00, 0x02, 271 0, 272 &spi_codec, 273 }, 274 { 275 "Envy24HT audio (Terratec Aureon 5.1 Sky)", 276 0x153b, 0x1147, 277 0x0a, 0x80, 0xfc, 0xc3, 278 0x21efff, 0x7fffff, 0x5e1000, 279 0x40000, 0x80000, 0x1000, 0x00, 0x02, 280 0, 281 &spi_codec, 282 }, 283 { 284 "Envy24HT audio (Terratec Aureon 7.1 Universe)", 285 0x153b, 0x1153, 286 0x0b, 0x80, 0xfc, 0xc3, 287 0x21efff, 0x7fffff, 0x5e1000, 288 0x40000, 0x80000, 0x1000, 0x00, 0x02, 289 0, 290 &spi_codec, 291 }, 292 { 293 "Envy24HT audio (AudioTrak Prodigy 7.1)", 294 0x4933, 0x4553, 295 0x0b, 0x80, 0xfc, 0xc3, 296 0x21efff, 0x7fffff, 0x5e1000, 297 0x40000, 0x80000, 0x1000, 0x00, 0x02, 298 0, 299 &spi_codec, 300 }, 301 { 302 "Envy24HT audio (Terratec PHASE 28)", 303 0x153b, 0x1149, 304 0x0b, 0x80, 0xfc, 0xc3, 305 0x21efff, 0x7fffff, 0x5e1000, 306 0x40000, 0x80000, 0x1000, 0x00, 0x02, 307 0, 308 &spi_codec, 309 }, 310 { 311 "Envy24HT-S audio (Terratec PHASE 22)", 312 0x153b, 0x1150, 313 0x10, 0x80, 0xf0, 0xc3, 314 0x7ffbc7, 0x7fffff, 0x438, 315 0x20, 0x10, 0x400, 0x00, 0x00, 316 0, 317 &spi_codec, 318 }, 319 { 320 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)", 321 0x3132, 0x4154, 322 0x0b, 0x80, 0xfc, 0xc3, 323 0x7ff8ff, 0x7fffff, 0x700, 324 0x400, 0x200, 0x100, 0x00, 0x02, 325 0, 326 &spi_codec, 327 }, 328 { 329 "Envy24HT audio (M-Audio Revolution 7.1)", 330 0x1412, 0x3630, 331 0x43, 0x80, 0xf8, 0xc1, 332 0x3fff85, 0x72, 0x4000fa, 333 0x08, 0x02, 0x20, 0x00, 0x04, 334 0, 335 &spi_codec, 336 }, 337 { 338 "Envy24GT audio (M-Audio Revolution 5.1)", 339 0x1412, 0x3631, 340 0x42, 0x80, 0xf8, 0xc1, 341 0x3fff85, 0x72, 0x4000fa, 342 0x08, 0x02, 0x20, 0x00, 0x03, 343 0, 344 &spi_codec, 345 }, 346 { 347 "Envy24HT audio (M-Audio Audiophile 192)", 348 0x1412, 0x3632, 349 0x68, 0x80, 0xf8, 0xc3, 350 0x45, 0x4000b5, 0x7fffba, 351 0x08, 0x02, 0x10, 0x00, 0x03, 352 0, 353 &spi_codec, 354 }, 355 { 356 "Envy24HT audio (Generic)", 357 0, 0, 358 0x0b, 0x80, 0xfc, 0xc3, 359 0x21efff, 0x7fffff, 0x5e1000, 360 0x40000, 0x80000, 0x1000, 0x00, 0x02, 361 0, 362 &spi_codec, /* default codec routines */ 363 } 364 }; 365 366 static u_int32_t envy24ht_recfmt[] = { 367 AFMT_STEREO | AFMT_S16_LE, 368 AFMT_STEREO | AFMT_S32_LE, 369 0 370 }; 371 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0}; 372 373 static u_int32_t envy24ht_playfmt[] = { 374 AFMT_STEREO | AFMT_U8, 375 AFMT_STEREO | AFMT_S16_LE, 376 AFMT_STEREO | AFMT_S32_LE, 377 0 378 }; 379 380 static struct pcmchan_caps envy24ht_playcaps = {8000, 96000, envy24ht_playfmt, 0}; 381 382 struct envy24ht_emldma { 383 u_int32_t format; 384 void (*emldma)(struct sc_chinfo *); 385 int unit; 386 }; 387 388 static struct envy24ht_emldma envy24ht_pemltab[] = { 389 {AFMT_STEREO | AFMT_U8, envy24ht_p8u, 2}, 390 {AFMT_STEREO | AFMT_S16_LE, envy24ht_p16sl, 4}, 391 {AFMT_STEREO | AFMT_S32_LE, envy24ht_p32sl, 8}, 392 {0, NULL, 0} 393 }; 394 395 static struct envy24ht_emldma envy24ht_remltab[] = { 396 {AFMT_STEREO | AFMT_S16_LE, envy24ht_r16sl, 4}, 397 {AFMT_STEREO | AFMT_S32_LE, envy24ht_r32sl, 8}, 398 {0, NULL, 0} 399 }; 400 401 /* -------------------------------------------------------------------- */ 402 403 /* common routines */ 404 static u_int32_t 405 envy24ht_rdcs(struct sc_info *sc, int regno, int size) 406 { 407 switch (size) { 408 case 1: 409 return bus_space_read_1(sc->cst, sc->csh, regno); 410 case 2: 411 return bus_space_read_2(sc->cst, sc->csh, regno); 412 case 4: 413 return bus_space_read_4(sc->cst, sc->csh, regno); 414 default: 415 return 0xffffffff; 416 } 417 } 418 419 static void 420 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size) 421 { 422 switch (size) { 423 case 1: 424 bus_space_write_1(sc->cst, sc->csh, regno, data); 425 break; 426 case 2: 427 bus_space_write_2(sc->cst, sc->csh, regno, data); 428 break; 429 case 4: 430 bus_space_write_4(sc->cst, sc->csh, regno, data); 431 break; 432 } 433 } 434 435 static u_int32_t 436 envy24ht_rdmt(struct sc_info *sc, int regno, int size) 437 { 438 switch (size) { 439 case 1: 440 return bus_space_read_1(sc->mtt, sc->mth, regno); 441 case 2: 442 return bus_space_read_2(sc->mtt, sc->mth, regno); 443 case 4: 444 return bus_space_read_4(sc->mtt, sc->mth, regno); 445 default: 446 return 0xffffffff; 447 } 448 } 449 450 static void 451 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size) 452 { 453 switch (size) { 454 case 1: 455 bus_space_write_1(sc->mtt, sc->mth, regno, data); 456 break; 457 case 2: 458 bus_space_write_2(sc->mtt, sc->mth, regno, data); 459 break; 460 case 4: 461 bus_space_write_4(sc->mtt, sc->mth, regno, data); 462 break; 463 } 464 } 465 466 /* -------------------------------------------------------------------- */ 467 468 /* I2C port/E2PROM access routines */ 469 470 static int 471 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr) 472 { 473 u_int32_t data; 474 int i; 475 476 #if(0) 477 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 478 #endif 479 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 480 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1); 481 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0) 482 break; 483 DELAY(32); /* 31.25kHz */ 484 } 485 if (i == ENVY24HT_TIMEOUT) { 486 return -1; 487 } 488 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1); 489 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV, 490 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1); 491 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 492 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1); 493 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0) 494 break; 495 DELAY(32); /* 31.25kHz */ 496 } 497 if (i == ENVY24HT_TIMEOUT) { 498 return -1; 499 } 500 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1); 501 502 #if(0) 503 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data); 504 #endif 505 return (int)data; 506 } 507 508 #if 0 509 static int 510 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) 511 { 512 u_int32_t tmp; 513 int i; 514 515 #if(0) 516 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 517 #endif 518 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 519 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1); 520 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0) 521 break; 522 DELAY(32); /* 31.25kHz */ 523 } 524 if (i == ENVY24HT_TIMEOUT) { 525 return -1; 526 } 527 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1); 528 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1); 529 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV, 530 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1); 531 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 532 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1); 533 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0) 534 break; 535 DELAY(32); /* 31.25kHz */ 536 } 537 if (i == ENVY24HT_TIMEOUT) { 538 return -1; 539 } 540 541 return 0; 542 } 543 #endif 544 545 static int 546 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr) 547 { 548 u_int32_t data; 549 550 #if(0) 551 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr); 552 #endif 553 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1); 554 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) { 555 #if(0) 556 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n"); 557 #endif 558 return -1; 559 } 560 561 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr); 562 } 563 564 static struct cfg_info * 565 envy24ht_rom2cfg(struct sc_info *sc) 566 { 567 struct cfg_info *buff; 568 int size; 569 int i; 570 571 #if(0) 572 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n"); 573 #endif 574 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE); 575 if (size < ENVY24HT_E2PROM_GPIOSTATE + 3) { 576 #if(0) 577 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size); 578 #endif 579 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT); 580 if (buff == NULL) { 581 #if(0) 582 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n"); 583 #endif 584 return NULL; 585 } 586 buff->free = 1; 587 588 /* no valid e2prom, using default values */ 589 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8; 590 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1); 591 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8; 592 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1); 593 buff->scfg = 0x0b; 594 buff->acl = 0x80; 595 buff->i2s = 0xfc; 596 buff->spdif = 0xc3; 597 buff->gpiomask = 0x21efff; 598 buff->gpiostate = 0x7fffff; 599 buff->gpiodir = 0x5e1000; 600 buff->cdti = 0x40000; 601 buff->cclk = 0x80000; 602 buff->cs = 0x1000; 603 buff->cif = 0x00; 604 buff->type = 0x02; 605 606 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; 607 i++) 608 if (cfg_table[i].subvendor == buff->subvendor && 609 cfg_table[i].subdevice == buff->subdevice) 610 break; 611 buff->name = cfg_table[i].name; 612 buff->codec = cfg_table[i].codec; 613 614 return buff; 615 #if 0 616 return NULL; 617 #endif 618 } 619 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT); 620 if (buff == NULL) { 621 #if(0) 622 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n"); 623 #endif 624 return NULL; 625 } 626 buff->free = 1; 627 628 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8; 629 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1); 630 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8; 631 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1); 632 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG); 633 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL); 634 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S); 635 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF); 636 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \ 637 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \ 638 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16; 639 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \ 640 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \ 641 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16; 642 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \ 643 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \ 644 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16; 645 646 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) 647 if (cfg_table[i].subvendor == buff->subvendor && 648 cfg_table[i].subdevice == buff->subdevice) 649 break; 650 buff->name = cfg_table[i].name; 651 buff->codec = cfg_table[i].codec; 652 653 return buff; 654 } 655 656 static void 657 envy24ht_cfgfree(struct cfg_info *cfg) { 658 if (cfg == NULL) 659 return; 660 if (cfg->free) 661 free(cfg, M_ENVY24HT); 662 return; 663 } 664 665 /* -------------------------------------------------------------------- */ 666 667 /* AC'97 codec access routines */ 668 669 #if 0 670 static int 671 envy24ht_coldcd(struct sc_info *sc) 672 { 673 u_int32_t data; 674 int i; 675 676 #if(0) 677 device_printf(sc->dev, "envy24ht_coldcd()\n"); 678 #endif 679 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1); 680 DELAY(10); 681 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1); 682 DELAY(1000); 683 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 684 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 685 if (data & ENVY24HT_MT_AC97CMD_RDY) { 686 return 0; 687 } 688 } 689 690 return -1; 691 } 692 693 static int 694 envy24ht_slavecd(struct sc_info *sc) 695 { 696 u_int32_t data; 697 int i; 698 699 #if(0) 700 device_printf(sc->dev, "envy24ht_slavecd()\n"); 701 #endif 702 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 703 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1); 704 DELAY(10); 705 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1); 706 DELAY(1000); 707 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 708 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 709 if (data & ENVY24HT_MT_AC97CMD_RDY) { 710 return 0; 711 } 712 } 713 714 return -1; 715 } 716 717 static int 718 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno) 719 { 720 struct sc_info *sc = (struct sc_info *)devinfo; 721 u_int32_t data; 722 int i; 723 724 #if(0) 725 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno); 726 #endif 727 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1); 728 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1); 729 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 730 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 731 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0) 732 break; 733 } 734 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2); 735 736 #if(0) 737 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data); 738 #endif 739 return (int)data; 740 } 741 742 static int 743 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data) 744 { 745 struct sc_info *sc = (struct sc_info *)devinfo; 746 u_int32_t cmd; 747 int i; 748 749 #if(0) 750 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data); 751 #endif 752 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1); 753 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2); 754 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1); 755 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 756 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 757 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0) 758 break; 759 } 760 761 return 0; 762 } 763 764 static kobj_method_t envy24ht_ac97_methods[] = { 765 KOBJMETHOD(ac97_read, envy24ht_rdcd), 766 KOBJMETHOD(ac97_write, envy24ht_wrcd), 767 {0, 0} 768 }; 769 AC97_DECLARE(envy24ht_ac97); 770 #endif 771 772 /* -------------------------------------------------------------------- */ 773 774 /* GPIO access routines */ 775 776 static u_int32_t 777 envy24ht_gpiord(struct sc_info *sc) 778 { 779 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150) 780 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2); 781 else 782 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2)); 783 } 784 785 static void 786 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data) 787 { 788 #if(0) 789 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF); 790 return; 791 #endif 792 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2); 793 if (sc->cfg->subdevice != 0x1150) 794 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1); 795 return; 796 } 797 798 #if 0 799 static u_int32_t 800 envy24ht_gpiogetmask(struct sc_info *sc) 801 { 802 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2)); 803 } 804 #endif 805 806 static void 807 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask) 808 { 809 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2); 810 if (sc->cfg->subdevice != 0x1150) 811 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1); 812 return; 813 } 814 815 #if 0 816 static u_int32_t 817 envy24ht_gpiogetdir(struct sc_info *sc) 818 { 819 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4; 820 } 821 #endif 822 823 static void 824 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir) 825 { 826 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150) 827 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2); 828 else 829 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4); 830 return; 831 } 832 833 /* -------------------------------------------------------------------- */ 834 835 /* SPI codec access interface routine */ 836 837 struct envy24ht_spi_codec { 838 struct spicds_info *info; 839 struct sc_info *parent; 840 int dir; 841 int num; 842 int cs, cclk, cdti; 843 }; 844 845 static void 846 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) 847 { 848 u_int32_t data = 0; 849 struct envy24ht_spi_codec *ptr = codec; 850 851 #if(0) 852 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti); 853 #endif 854 data = envy24ht_gpiord(ptr->parent); 855 data &= ~(ptr->cs | ptr->cclk | ptr->cdti); 856 if (cs) data += ptr->cs; 857 if (cclk) data += ptr->cclk; 858 if (cdti) data += ptr->cdti; 859 envy24ht_gpiowr(ptr->parent, data); 860 return; 861 } 862 863 static void * 864 envy24ht_spi_create(device_t dev, void *info, int dir, int num) 865 { 866 struct sc_info *sc = info; 867 struct envy24ht_spi_codec *buff = NULL; 868 869 #if(0) 870 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num); 871 #endif 872 873 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT); 874 if (buff == NULL) 875 return NULL; 876 877 if (dir == PCMDIR_REC && sc->adc[num] != NULL) 878 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info; 879 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL) 880 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info; 881 else 882 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl); 883 if (buff->info == NULL) { 884 free(buff, M_ENVY24HT); 885 return NULL; 886 } 887 888 buff->parent = sc; 889 buff->dir = dir; 890 buff->num = num; 891 892 return (void *)buff; 893 } 894 895 static void 896 envy24ht_spi_destroy(void *codec) 897 { 898 struct envy24ht_spi_codec *ptr = codec; 899 if (ptr == NULL) 900 return; 901 #if(0) 902 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n"); 903 #endif 904 905 if (ptr->dir == PCMDIR_PLAY) { 906 if (ptr->parent->dac[ptr->num] != NULL) 907 spicds_destroy(ptr->info); 908 } 909 else { 910 if (ptr->parent->adc[ptr->num] != NULL) 911 spicds_destroy(ptr->info); 912 } 913 914 free(codec, M_ENVY24HT); 915 } 916 917 static void 918 envy24ht_spi_init(void *codec) 919 { 920 struct envy24ht_spi_codec *ptr = codec; 921 if (ptr == NULL) 922 return; 923 #if(0) 924 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n"); 925 #endif 926 ptr->cs = ptr->parent->cfg->cs; 927 ptr->cclk = ptr->parent->cfg->cclk; 928 ptr->cdti = ptr->parent->cfg->cdti; 929 spicds_settype(ptr->info, ptr->parent->cfg->type); 930 spicds_setcif(ptr->info, ptr->parent->cfg->cif); 931 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \ 932 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) { 933 spicds_setformat(ptr->info, 934 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 935 spicds_setdvc(ptr->info, 0); 936 } 937 938 /* for the time being, init only first codec */ 939 if (ptr->num == 0) 940 spicds_init(ptr->info); 941 } 942 943 static void 944 envy24ht_spi_reinit(void *codec) 945 { 946 struct envy24ht_spi_codec *ptr = codec; 947 if (ptr == NULL) 948 return; 949 #if(0) 950 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n"); 951 #endif 952 953 spicds_reinit(ptr->info); 954 } 955 956 static void 957 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 958 { 959 struct envy24ht_spi_codec *ptr = codec; 960 if (ptr == NULL) 961 return; 962 #if(0) 963 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n"); 964 #endif 965 966 spicds_set(ptr->info, dir, left, right); 967 } 968 969 /* -------------------------------------------------------------------- */ 970 971 /* hardware access routeines */ 972 973 static struct { 974 u_int32_t speed; 975 u_int32_t code; 976 } envy24ht_speedtab[] = { 977 {48000, ENVY24HT_MT_RATE_48000}, 978 {24000, ENVY24HT_MT_RATE_24000}, 979 {12000, ENVY24HT_MT_RATE_12000}, 980 {9600, ENVY24HT_MT_RATE_9600}, 981 {32000, ENVY24HT_MT_RATE_32000}, 982 {16000, ENVY24HT_MT_RATE_16000}, 983 {8000, ENVY24HT_MT_RATE_8000}, 984 {96000, ENVY24HT_MT_RATE_96000}, 985 {64000, ENVY24HT_MT_RATE_64000}, 986 {44100, ENVY24HT_MT_RATE_44100}, 987 {22050, ENVY24HT_MT_RATE_22050}, 988 {11025, ENVY24HT_MT_RATE_11025}, 989 {88200, ENVY24HT_MT_RATE_88200}, 990 {0, 0x10} 991 }; 992 993 static int 994 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) { 995 u_int32_t code; 996 int i = 0; 997 998 #if(0) 999 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed); 1000 if (speed == 0) { 1001 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */ 1002 envy24ht_slavecd(sc); 1003 } 1004 else { 1005 #endif 1006 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) { 1007 if (envy24ht_speedtab[i].speed == speed) 1008 break; 1009 } 1010 code = envy24ht_speedtab[i].code; 1011 #if 0 1012 } 1013 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code); 1014 #endif 1015 if (code < 0x10) { 1016 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1); 1017 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1); 1018 code &= ENVY24HT_MT_RATE_MASK; 1019 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) { 1020 if (envy24ht_speedtab[i].code == code) 1021 break; 1022 } 1023 speed = envy24ht_speedtab[i].speed; 1024 } 1025 else 1026 speed = 0; 1027 1028 #if(0) 1029 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed); 1030 #endif 1031 return speed; 1032 } 1033 1034 static void 1035 envy24ht_setvolume(struct sc_info *sc, unsigned ch) 1036 { 1037 #if(0) 1038 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch); 1039 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1); 1040 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 1041 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1); 1042 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 1043 #endif 1044 } 1045 1046 static void 1047 envy24ht_mutevolume(struct sc_info *sc, unsigned ch) 1048 { 1049 #if 0 1050 u_int32_t vol; 1051 1052 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch); 1053 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE; 1054 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1); 1055 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2); 1056 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1); 1057 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2); 1058 #endif 1059 } 1060 1061 static u_int32_t 1062 envy24ht_gethwptr(struct sc_info *sc, int dir) 1063 { 1064 int unit, regno; 1065 u_int32_t ptr, rtn; 1066 1067 #if(0) 1068 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir); 1069 #endif 1070 if (dir == PCMDIR_PLAY) { 1071 rtn = sc->psize / 4; 1072 unit = ENVY24HT_PLAY_BUFUNIT / 4; 1073 regno = ENVY24HT_MT_PCNT; 1074 } 1075 else { 1076 rtn = sc->rsize / 4; 1077 unit = ENVY24HT_REC_BUFUNIT / 4; 1078 regno = ENVY24HT_MT_RCNT; 1079 } 1080 1081 ptr = envy24ht_rdmt(sc, regno, 2); 1082 rtn -= (ptr + 1); 1083 rtn /= unit; 1084 1085 #if(0) 1086 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn); 1087 #endif 1088 return rtn; 1089 } 1090 1091 static void 1092 envy24ht_updintr(struct sc_info *sc, int dir) 1093 { 1094 int regptr, regintr; 1095 u_int32_t mask, intr; 1096 u_int32_t ptr, size, cnt; 1097 u_int16_t blk; 1098 1099 #if(0) 1100 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir); 1101 #endif 1102 if (dir == PCMDIR_PLAY) { 1103 blk = sc->blk[0]; 1104 size = sc->psize / 4; 1105 regptr = ENVY24HT_MT_PCNT; 1106 regintr = ENVY24HT_MT_PTERM; 1107 mask = ~ENVY24HT_MT_INT_PMASK; 1108 } 1109 else { 1110 blk = sc->blk[1]; 1111 size = sc->rsize / 4; 1112 regptr = ENVY24HT_MT_RCNT; 1113 regintr = ENVY24HT_MT_RTERM; 1114 mask = ~ENVY24HT_MT_INT_RMASK; 1115 } 1116 1117 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1; 1118 /* 1119 cnt = blk - ptr % blk - 1; 1120 if (cnt == 0) 1121 cnt = blk - 1; 1122 */ 1123 cnt = blk - 1; 1124 #if(0) 1125 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1126 #endif 1127 envy24ht_wrmt(sc, regintr, cnt, 2); 1128 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1129 #if(0) 1130 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1131 #endif 1132 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1); 1133 #if(0) 1134 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n", 1135 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1)); 1136 #endif 1137 1138 return; 1139 } 1140 1141 #if 0 1142 static void 1143 envy24ht_maskintr(struct sc_info *sc, int dir) 1144 { 1145 u_int32_t mask, intr; 1146 1147 #if(0) 1148 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir); 1149 #endif 1150 if (dir == PCMDIR_PLAY) 1151 mask = ENVY24HT_MT_INT_PMASK; 1152 else 1153 mask = ENVY24HT_MT_INT_RMASK; 1154 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1); 1155 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1); 1156 1157 return; 1158 } 1159 #endif 1160 1161 static int 1162 envy24ht_checkintr(struct sc_info *sc, int dir) 1163 { 1164 u_int32_t mask, stat, intr, rtn; 1165 1166 #if(0) 1167 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir); 1168 #endif 1169 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1); 1170 if (dir == PCMDIR_PLAY) { 1171 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) { 1172 mask = ~ENVY24HT_MT_INT_RSTAT; 1173 envy24ht_wrmt(sc, 0x1a, 0x01, 1); 1174 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1); 1175 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1176 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1); 1177 } 1178 } 1179 else { 1180 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) { 1181 mask = ~ENVY24HT_MT_INT_PSTAT; 1182 #if 0 1183 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK; 1184 #endif 1185 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1); 1186 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1187 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1); 1188 } 1189 } 1190 1191 return rtn; 1192 } 1193 1194 static void 1195 envy24ht_start(struct sc_info *sc, int dir) 1196 { 1197 u_int32_t stat, sw; 1198 1199 #if(0) 1200 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir); 1201 #endif 1202 if (dir == PCMDIR_PLAY) 1203 sw = ENVY24HT_MT_PCTL_PSTART; 1204 else 1205 sw = ENVY24HT_MT_PCTL_RSTART; 1206 1207 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1208 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1); 1209 #if(0) 1210 DELAY(100); 1211 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 1212 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 1213 #endif 1214 1215 return; 1216 } 1217 1218 static void 1219 envy24ht_stop(struct sc_info *sc, int dir) 1220 { 1221 u_int32_t stat, sw; 1222 1223 #if(0) 1224 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir); 1225 #endif 1226 if (dir == PCMDIR_PLAY) 1227 sw = ~ENVY24HT_MT_PCTL_PSTART; 1228 else 1229 sw = ~ENVY24HT_MT_PCTL_RSTART; 1230 1231 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1232 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1); 1233 1234 return; 1235 } 1236 1237 #if 0 1238 static int 1239 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1240 { 1241 return 0; 1242 } 1243 #endif 1244 1245 /* -------------------------------------------------------------------- */ 1246 1247 /* buffer copy routines */ 1248 static void 1249 envy24ht_p32sl(struct sc_chinfo *ch) 1250 { 1251 int length; 1252 sample32_t *dmabuf; 1253 u_int32_t *data; 1254 int src, dst, ssize, dsize, slot; 1255 int i; 1256 1257 length = sndbuf_getready(ch->buffer) / 8; 1258 dmabuf = ch->parent->pbuf; 1259 data = (u_int32_t *)ch->data; 1260 src = sndbuf_getreadyptr(ch->buffer) / 4; 1261 dst = src / 2 + ch->offset; 1262 ssize = ch->size / 4; 1263 dsize = ch->size / 8; 1264 slot = ch->num * 2; 1265 1266 for (i = 0; i < length; i++) { 1267 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src]; 1268 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1269 dst++; 1270 dst %= dsize; 1271 src += 2; 1272 src %= ssize; 1273 } 1274 1275 return; 1276 } 1277 1278 static void 1279 envy24ht_p16sl(struct sc_chinfo *ch) 1280 { 1281 int length; 1282 sample32_t *dmabuf; 1283 u_int16_t *data; 1284 int src, dst, ssize, dsize, slot; 1285 int i; 1286 1287 #if(0) 1288 device_printf(ch->parent->dev, "envy24ht_p16sl()\n"); 1289 #endif 1290 length = sndbuf_getready(ch->buffer) / 4; 1291 dmabuf = ch->parent->pbuf; 1292 data = (u_int16_t *)ch->data; 1293 src = sndbuf_getreadyptr(ch->buffer) / 2; 1294 dst = src / 2 + ch->offset; 1295 ssize = ch->size / 2; 1296 dsize = ch->size / 4; 1297 slot = ch->num * 2; 1298 #if(0) 1299 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1300 #endif 1301 1302 for (i = 0; i < length; i++) { 1303 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1304 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1305 #if(0) 1306 if (i < 16) { 1307 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]); 1308 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]); 1309 } 1310 #endif 1311 dst++; 1312 dst %= dsize; 1313 src += 2; 1314 src %= ssize; 1315 } 1316 #if(0) 1317 printf("\n"); 1318 #endif 1319 1320 return; 1321 } 1322 1323 static void 1324 envy24ht_p8u(struct sc_chinfo *ch) 1325 { 1326 int length; 1327 sample32_t *dmabuf; 1328 u_int8_t *data; 1329 int src, dst, ssize, dsize, slot; 1330 int i; 1331 1332 length = sndbuf_getready(ch->buffer) / 2; 1333 dmabuf = ch->parent->pbuf; 1334 data = (u_int8_t *)ch->data; 1335 src = sndbuf_getreadyptr(ch->buffer); 1336 dst = src / 2 + ch->offset; 1337 ssize = ch->size; 1338 dsize = ch->size / 4; 1339 slot = ch->num * 2; 1340 1341 for (i = 0; i < length; i++) { 1342 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1343 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1344 dst++; 1345 dst %= dsize; 1346 src += 2; 1347 src %= ssize; 1348 } 1349 1350 return; 1351 } 1352 1353 static void 1354 envy24ht_r32sl(struct sc_chinfo *ch) 1355 { 1356 int length; 1357 sample32_t *dmabuf; 1358 u_int32_t *data; 1359 int src, dst, ssize, dsize, slot; 1360 int i; 1361 1362 length = sndbuf_getfree(ch->buffer) / 8; 1363 dmabuf = ch->parent->rbuf; 1364 data = (u_int32_t *)ch->data; 1365 dst = sndbuf_getfreeptr(ch->buffer) / 4; 1366 src = dst / 2 + ch->offset; 1367 dsize = ch->size / 4; 1368 ssize = ch->size / 8; 1369 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1370 1371 for (i = 0; i < length; i++) { 1372 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1373 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1374 dst += 2; 1375 dst %= dsize; 1376 src++; 1377 src %= ssize; 1378 } 1379 1380 return; 1381 } 1382 1383 static void 1384 envy24ht_r16sl(struct sc_chinfo *ch) 1385 { 1386 int length; 1387 sample32_t *dmabuf; 1388 u_int16_t *data; 1389 int src, dst, ssize, dsize, slot; 1390 int i; 1391 1392 length = sndbuf_getfree(ch->buffer) / 4; 1393 dmabuf = ch->parent->rbuf; 1394 data = (u_int16_t *)ch->data; 1395 dst = sndbuf_getfreeptr(ch->buffer) / 2; 1396 src = dst / 2 + ch->offset; 1397 dsize = ch->size / 2; 1398 ssize = ch->size / 8; 1399 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1400 1401 for (i = 0; i < length; i++) { 1402 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1403 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1404 dst += 2; 1405 dst %= dsize; 1406 src++; 1407 src %= ssize; 1408 } 1409 1410 return; 1411 } 1412 1413 /* -------------------------------------------------------------------- */ 1414 1415 /* channel interface */ 1416 static void * 1417 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1418 { 1419 struct sc_info *sc = (struct sc_info *)devinfo; 1420 struct sc_chinfo *ch; 1421 unsigned num; 1422 1423 #if(0) 1424 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir); 1425 #endif 1426 snd_mtxlock(sc->lock); 1427 #if 0 1428 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1429 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1430 snd_mtxunlock(sc->lock); 1431 return NULL; 1432 } 1433 #endif 1434 num = sc->chnum; 1435 1436 ch = &sc->chan[num]; 1437 ch->size = 8 * ENVY24HT_SAMPLE_NUM; 1438 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT); 1439 if (ch->data == NULL) { 1440 ch->size = 0; 1441 ch = NULL; 1442 } 1443 else { 1444 ch->buffer = b; 1445 ch->channel = c; 1446 ch->parent = sc; 1447 ch->dir = dir; 1448 /* set channel map */ 1449 ch->num = envy24ht_chanmap[num]; 1450 snd_mtxunlock(sc->lock); 1451 sndbuf_setup(ch->buffer, ch->data, ch->size); 1452 snd_mtxlock(sc->lock); 1453 /* these 2 values are dummy */ 1454 ch->unit = 4; 1455 ch->blk = 10240; 1456 } 1457 snd_mtxunlock(sc->lock); 1458 1459 return ch; 1460 } 1461 1462 static int 1463 envy24htchan_free(kobj_t obj, void *data) 1464 { 1465 struct sc_chinfo *ch = data; 1466 struct sc_info *sc = ch->parent; 1467 1468 #if(0) 1469 device_printf(sc->dev, "envy24htchan_free()\n"); 1470 #endif 1471 snd_mtxlock(sc->lock); 1472 if (ch->data != NULL) { 1473 free(ch->data, M_ENVY24HT); 1474 ch->data = NULL; 1475 } 1476 snd_mtxunlock(sc->lock); 1477 1478 return 0; 1479 } 1480 1481 static int 1482 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format) 1483 { 1484 struct sc_chinfo *ch = data; 1485 struct sc_info *sc = ch->parent; 1486 struct envy24ht_emldma *emltab; 1487 /* unsigned int bcnt, bsize; */ 1488 int i; 1489 1490 #if(0) 1491 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format); 1492 #endif 1493 snd_mtxlock(sc->lock); 1494 /* check and get format related information */ 1495 if (ch->dir == PCMDIR_PLAY) 1496 emltab = envy24ht_pemltab; 1497 else 1498 emltab = envy24ht_remltab; 1499 if (emltab == NULL) { 1500 snd_mtxunlock(sc->lock); 1501 return -1; 1502 } 1503 for (i = 0; emltab[i].format != 0; i++) 1504 if (emltab[i].format == format) 1505 break; 1506 if (emltab[i].format == 0) { 1507 snd_mtxunlock(sc->lock); 1508 return -1; 1509 } 1510 1511 /* set format information */ 1512 ch->format = format; 1513 ch->emldma = emltab[i].emldma; 1514 if (ch->unit > emltab[i].unit) 1515 ch->blk *= ch->unit / emltab[i].unit; 1516 else 1517 ch->blk /= emltab[i].unit / ch->unit; 1518 ch->unit = emltab[i].unit; 1519 1520 /* set channel buffer information */ 1521 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; 1522 #if 0 1523 if (ch->dir == PCMDIR_PLAY) 1524 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1525 else 1526 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1527 bsize *= ch->unit; 1528 bcnt = ch->size / bsize; 1529 sndbuf_resize(ch->buffer, bcnt, bsize); 1530 #endif 1531 snd_mtxunlock(sc->lock); 1532 1533 #if(0) 1534 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0); 1535 #endif 1536 return 0; 1537 } 1538 1539 /* 1540 IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1541 of speed information value. And real hardware speed setting is done 1542 at start triggered(see envy24htchan_trigger()). So, at this function 1543 is called, any value that ENVY24 can use is able to set. But, at 1544 start triggerd, some other channel is running, and that channel's 1545 speed isn't same with, then trigger function will fail. 1546 */ 1547 static int 1548 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1549 { 1550 struct sc_chinfo *ch = data; 1551 u_int32_t val, prev; 1552 int i; 1553 1554 #if(0) 1555 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed); 1556 #endif 1557 prev = 0x7fffffff; 1558 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) { 1559 if (abs(val - speed) < abs(prev - speed)) 1560 prev = val; 1561 else 1562 break; 1563 } 1564 ch->speed = prev; 1565 1566 #if(0) 1567 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed); 1568 #endif 1569 return ch->speed; 1570 } 1571 1572 static int 1573 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1574 { 1575 struct sc_chinfo *ch = data; 1576 /* struct sc_info *sc = ch->parent; */ 1577 u_int32_t size, prev; 1578 unsigned int bcnt, bsize; 1579 1580 #if(0) 1581 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize); 1582 #endif 1583 prev = 0x7fffffff; 1584 /* snd_mtxlock(sc->lock); */ 1585 for (size = ch->size / 2; size > 0; size /= 2) { 1586 if (abs(size - blocksize) < abs(prev - blocksize)) 1587 prev = size; 1588 else 1589 break; 1590 } 1591 1592 ch->blk = prev / ch->unit; 1593 if (ch->dir == PCMDIR_PLAY) 1594 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4; 1595 else 1596 ch->blk *= ENVY24HT_REC_BUFUNIT / 4; 1597 /* set channel buffer information */ 1598 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */ 1599 if (ch->dir == PCMDIR_PLAY) 1600 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1601 else 1602 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1603 bsize *= ch->unit; 1604 bcnt = ch->size / bsize; 1605 sndbuf_resize(ch->buffer, bcnt, bsize); 1606 /* snd_mtxunlock(sc->lock); */ 1607 1608 #if(0) 1609 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev); 1610 #endif 1611 return prev; 1612 } 1613 1614 /* semantic note: must start at beginning of buffer */ 1615 static int 1616 envy24htchan_trigger(kobj_t obj, void *data, int go) 1617 { 1618 struct sc_chinfo *ch = data; 1619 struct sc_info *sc = ch->parent; 1620 u_int32_t ptr; 1621 int slot; 1622 #if 0 1623 int i; 1624 1625 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go); 1626 #endif 1627 snd_mtxlock(sc->lock); 1628 if (ch->dir == PCMDIR_PLAY) 1629 slot = 0; 1630 else 1631 slot = 1; 1632 switch (go) { 1633 case PCMTRIG_START: 1634 #if(0) 1635 device_printf(sc->dev, "envy24htchan_trigger(): start\n"); 1636 #endif 1637 /* check or set channel speed */ 1638 if (sc->run[0] == 0 && sc->run[1] == 0) { 1639 sc->speed = envy24ht_setspeed(sc, ch->speed); 1640 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1641 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1642 } 1643 else if (ch->speed != 0 && ch->speed != sc->speed) 1644 return -1; 1645 if (ch->speed == 0) 1646 ch->channel->speed = sc->speed; 1647 /* start or enable channel */ 1648 sc->run[slot]++; 1649 if (sc->run[slot] == 1) { 1650 /* first channel */ 1651 ch->offset = 0; 1652 sc->blk[slot] = ch->blk; 1653 } 1654 else { 1655 ptr = envy24ht_gethwptr(sc, ch->dir); 1656 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1657 (ch->size / 4)) * 4 / ch->unit; 1658 if (ch->blk < sc->blk[slot]) 1659 sc->blk[slot] = ch->blk; 1660 } 1661 if (ch->dir == PCMDIR_PLAY) { 1662 ch->emldma(ch); 1663 envy24ht_setvolume(sc, ch->num); 1664 } 1665 envy24ht_updintr(sc, ch->dir); 1666 if (sc->run[slot] == 1) 1667 envy24ht_start(sc, ch->dir); 1668 ch->run = 1; 1669 break; 1670 case PCMTRIG_EMLDMAWR: 1671 #if(0) 1672 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n"); 1673 #endif 1674 if (ch->run != 1) 1675 return -1; 1676 ch->emldma(ch); 1677 break; 1678 case PCMTRIG_EMLDMARD: 1679 #if(0) 1680 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n"); 1681 #endif 1682 if (ch->run != 1) 1683 return -1; 1684 ch->emldma(ch); 1685 break; 1686 case PCMTRIG_ABORT: 1687 #if(0) 1688 device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); 1689 #endif 1690 ch->run = 0; 1691 sc->run[slot]--; 1692 if (ch->dir == PCMDIR_PLAY) 1693 envy24ht_mutevolume(sc, ch->num); 1694 if (sc->run[slot] == 0) { 1695 envy24ht_stop(sc, ch->dir); 1696 sc->intr[slot] = 0; 1697 } 1698 /* else if (ch->blk == sc->blk[slot]) { 1699 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2; 1700 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) { 1701 if (sc->chan[i].dir == ch->dir && 1702 sc->chan[i].run == 1 && 1703 sc->chan[i].blk < sc->blk[slot]) 1704 sc->blk[slot] = sc->chan[i].blk; 1705 } 1706 if (ch->blk != sc->blk[slot]) 1707 envy24ht_updintr(sc, ch->dir); 1708 }*/ 1709 break; 1710 } 1711 snd_mtxunlock(sc->lock); 1712 1713 return 0; 1714 } 1715 1716 static int 1717 envy24htchan_getptr(kobj_t obj, void *data) 1718 { 1719 struct sc_chinfo *ch = data; 1720 struct sc_info *sc = ch->parent; 1721 u_int32_t ptr; 1722 int rtn; 1723 1724 #if(0) 1725 device_printf(sc->dev, "envy24htchan_getptr()\n"); 1726 #endif 1727 snd_mtxlock(sc->lock); 1728 ptr = envy24ht_gethwptr(sc, ch->dir); 1729 rtn = ptr * ch->unit; 1730 snd_mtxunlock(sc->lock); 1731 1732 #if(0) 1733 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n", 1734 rtn); 1735 #endif 1736 return rtn; 1737 } 1738 1739 static struct pcmchan_caps * 1740 envy24htchan_getcaps(kobj_t obj, void *data) 1741 { 1742 struct sc_chinfo *ch = data; 1743 struct sc_info *sc = ch->parent; 1744 struct pcmchan_caps *rtn; 1745 1746 #if(0) 1747 device_printf(sc->dev, "envy24htchan_getcaps()\n"); 1748 #endif 1749 snd_mtxlock(sc->lock); 1750 if (ch->dir == PCMDIR_PLAY) { 1751 if (sc->run[0] == 0) 1752 rtn = &envy24ht_playcaps; 1753 else 1754 rtn = &sc->caps[0]; 1755 } 1756 else { 1757 if (sc->run[1] == 0) 1758 rtn = &envy24ht_reccaps; 1759 else 1760 rtn = &sc->caps[1]; 1761 } 1762 snd_mtxunlock(sc->lock); 1763 1764 return rtn; 1765 } 1766 1767 static kobj_method_t envy24htchan_methods[] = { 1768 KOBJMETHOD(channel_init, envy24htchan_init), 1769 KOBJMETHOD(channel_free, envy24htchan_free), 1770 KOBJMETHOD(channel_setformat, envy24htchan_setformat), 1771 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed), 1772 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize), 1773 KOBJMETHOD(channel_trigger, envy24htchan_trigger), 1774 KOBJMETHOD(channel_getptr, envy24htchan_getptr), 1775 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps), 1776 { 0, 0 } 1777 }; 1778 CHANNEL_DECLARE(envy24htchan); 1779 1780 /* -------------------------------------------------------------------- */ 1781 1782 /* mixer interface */ 1783 1784 static int 1785 envy24htmixer_init(struct snd_mixer *m) 1786 { 1787 struct sc_info *sc = mix_getdevinfo(m); 1788 1789 #if(0) 1790 device_printf(sc->dev, "envy24htmixer_init()\n"); 1791 #endif 1792 if (sc == NULL) 1793 return -1; 1794 1795 /* set volume control rate */ 1796 snd_mtxlock(sc->lock); 1797 #if 0 1798 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1799 #endif 1800 1801 mix_setdevs(m, ENVY24HT_MIX_MASK); 1802 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); 1803 snd_mtxunlock(sc->lock); 1804 1805 return 0; 1806 } 1807 1808 static int 1809 envy24htmixer_reinit(struct snd_mixer *m) 1810 { 1811 struct sc_info *sc = mix_getdevinfo(m); 1812 1813 if (sc == NULL) 1814 return -1; 1815 #if(0) 1816 device_printf(sc->dev, "envy24htmixer_reinit()\n"); 1817 #endif 1818 1819 return 0; 1820 } 1821 1822 static int 1823 envy24htmixer_uninit(struct snd_mixer *m) 1824 { 1825 struct sc_info *sc = mix_getdevinfo(m); 1826 1827 if (sc == NULL) 1828 return -1; 1829 #if(0) 1830 device_printf(sc->dev, "envy24htmixer_uninit()\n"); 1831 #endif 1832 1833 return 0; 1834 } 1835 1836 static int 1837 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1838 { 1839 struct sc_info *sc = mix_getdevinfo(m); 1840 int ch = envy24ht_mixmap[dev]; 1841 int hwch; 1842 int i; 1843 1844 if (sc == NULL) 1845 return -1; 1846 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1847 return -1; 1848 if (dev != 0 && ch == -1) 1849 return -1; 1850 hwch = envy24ht_chanmap[ch]; 1851 #if(0) 1852 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n", 1853 dev, left, right); 1854 #endif 1855 1856 snd_mtxlock(sc->lock); 1857 if (dev == 0) { 1858 for (i = 0; i < sc->dacn; i++) { 1859 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1860 } 1861 } 1862 else { 1863 /* set volume value for hardware */ 1864 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN) 1865 sc->left[hwch] = ENVY24HT_VOL_MUTE; 1866 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN) 1867 sc->right[hwch] = ENVY24HT_VOL_MUTE; 1868 1869 /* set volume for record channel and running play channel */ 1870 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1871 envy24ht_setvolume(sc, hwch); 1872 } 1873 snd_mtxunlock(sc->lock); 1874 1875 return right << 8 | left; 1876 } 1877 1878 static u_int32_t 1879 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1880 { 1881 struct sc_info *sc = mix_getdevinfo(m); 1882 int ch = envy24ht_mixmap[src]; 1883 #if(0) 1884 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src); 1885 #endif 1886 1887 if (ch > ENVY24HT_CHAN_PLAY_SPDIF) 1888 sc->src = ch; 1889 return src; 1890 } 1891 1892 static kobj_method_t envy24htmixer_methods[] = { 1893 KOBJMETHOD(mixer_init, envy24htmixer_init), 1894 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit), 1895 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit), 1896 KOBJMETHOD(mixer_set, envy24htmixer_set), 1897 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc), 1898 { 0, 0 } 1899 }; 1900 MIXER_DECLARE(envy24htmixer); 1901 1902 /* -------------------------------------------------------------------- */ 1903 1904 /* The interrupt handler */ 1905 static void 1906 envy24ht_intr(void *p) 1907 { 1908 struct sc_info *sc = (struct sc_info *)p; 1909 struct sc_chinfo *ch; 1910 u_int32_t ptr, dsize, feed; 1911 int i; 1912 1913 #if(0) 1914 device_printf(sc->dev, "envy24ht_intr()\n"); 1915 #endif 1916 snd_mtxlock(sc->lock); 1917 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) { 1918 #if(0) 1919 device_printf(sc->dev, "envy24ht_intr(): play\n"); 1920 #endif 1921 dsize = sc->psize / 4; 1922 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1; 1923 #if(0) 1924 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr); 1925 #endif 1926 ptr -= ptr % sc->blk[0]; 1927 feed = (ptr + dsize - sc->intr[0]) % dsize; 1928 #if(0) 1929 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1930 #endif 1931 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) { 1932 ch = &sc->chan[i]; 1933 #if(0) 1934 if (ch->run) 1935 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk); 1936 #endif 1937 if (ch->run && ch->blk <= feed) { 1938 snd_mtxunlock(sc->lock); 1939 chn_intr(ch->channel); 1940 snd_mtxlock(sc->lock); 1941 } 1942 } 1943 sc->intr[0] = ptr; 1944 envy24ht_updintr(sc, PCMDIR_PLAY); 1945 } 1946 if (envy24ht_checkintr(sc, PCMDIR_REC)) { 1947 #if(0) 1948 device_printf(sc->dev, "envy24ht_intr(): rec\n"); 1949 #endif 1950 dsize = sc->rsize / 4; 1951 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1; 1952 ptr -= ptr % sc->blk[1]; 1953 feed = (ptr + dsize - sc->intr[1]) % dsize; 1954 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) { 1955 ch = &sc->chan[i]; 1956 if (ch->run && ch->blk <= feed) { 1957 snd_mtxunlock(sc->lock); 1958 chn_intr(ch->channel); 1959 snd_mtxlock(sc->lock); 1960 } 1961 } 1962 sc->intr[1] = ptr; 1963 envy24ht_updintr(sc, PCMDIR_REC); 1964 } 1965 snd_mtxunlock(sc->lock); 1966 1967 return; 1968 } 1969 1970 /* 1971 * Probe and attach the card 1972 */ 1973 1974 static int 1975 envy24ht_pci_probe(device_t dev) 1976 { 1977 u_int16_t sv, sd; 1978 int i; 1979 1980 #if(0) 1981 printf("envy24ht_pci_probe()\n"); 1982 #endif 1983 if (pci_get_device(dev) == PCID_ENVY24HT && 1984 pci_get_vendor(dev) == PCIV_ENVY24) { 1985 sv = pci_get_subvendor(dev); 1986 sd = pci_get_subdevice(dev); 1987 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 1988 if (cfg_table[i].subvendor == sv && 1989 cfg_table[i].subdevice == sd) { 1990 break; 1991 } 1992 } 1993 device_set_desc(dev, cfg_table[i].name); 1994 #if(0) 1995 printf("envy24ht_pci_probe(): return 0\n"); 1996 #endif 1997 return 0; 1998 } 1999 else { 2000 #if(0) 2001 printf("envy24ht_pci_probe(): return ENXIO\n"); 2002 #endif 2003 return ENXIO; 2004 } 2005 } 2006 2007 static void 2008 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2009 { 2010 /* struct sc_info *sc = (struct sc_info *)arg; */ 2011 2012 #if(0) 2013 device_printf(sc->dev, "envy24ht_dmapsetmap()\n"); 2014 if (bootverbose) { 2015 printf("envy24ht(play): setmap %lx, %lx; ", 2016 (unsigned long)segs->ds_addr, 2017 (unsigned long)segs->ds_len); 2018 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 2019 } 2020 #endif 2021 } 2022 2023 static void 2024 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2025 { 2026 /* struct sc_info *sc = (struct sc_info *)arg; */ 2027 2028 #if(0) 2029 device_printf(sc->dev, "envy24ht_dmarsetmap()\n"); 2030 if (bootverbose) { 2031 printf("envy24ht(record): setmap %lx, %lx; ", 2032 (unsigned long)segs->ds_addr, 2033 (unsigned long)segs->ds_len); 2034 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2035 } 2036 #endif 2037 } 2038 2039 static void 2040 envy24ht_dmafree(struct sc_info *sc) 2041 { 2042 #if(0) 2043 device_printf(sc->dev, "envy24ht_dmafree():"); 2044 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2045 else printf(" sc->rmap(null)"); 2046 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2047 else printf(" sc->pmap(null)"); 2048 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2049 else printf(" sc->rbuf(null)"); 2050 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2051 else printf(" sc->pbuf(null)\n"); 2052 #endif 2053 #if(0) 2054 if (sc->rmap) 2055 bus_dmamap_unload(sc->dmat, sc->rmap); 2056 if (sc->pmap) 2057 bus_dmamap_unload(sc->dmat, sc->pmap); 2058 if (sc->rbuf) 2059 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2060 if (sc->pbuf) 2061 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2062 #else 2063 bus_dmamap_unload(sc->dmat, sc->rmap); 2064 bus_dmamap_unload(sc->dmat, sc->pmap); 2065 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2066 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2067 #endif 2068 2069 sc->rmap = sc->pmap = NULL; 2070 sc->pbuf = NULL; 2071 sc->rbuf = NULL; 2072 2073 return; 2074 } 2075 2076 static int 2077 envy24ht_dmainit(struct sc_info *sc) 2078 { 2079 u_int32_t addr; 2080 2081 #if(0) 2082 device_printf(sc->dev, "envy24ht_dmainit()\n"); 2083 #endif 2084 /* init values */ 2085 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2086 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2087 sc->pbuf = NULL; 2088 sc->rbuf = NULL; 2089 sc->pmap = sc->rmap = NULL; 2090 sc->blk[0] = sc->blk[1] = 0; 2091 2092 /* allocate DMA buffer */ 2093 #if(0) 2094 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2095 #endif 2096 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2097 goto bad; 2098 #if(0) 2099 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2100 #endif 2101 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2102 goto bad; 2103 #if(0) 2104 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2105 #endif 2106 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0)) 2107 goto bad; 2108 #if(0) 2109 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2110 #endif 2111 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0)) 2112 goto bad; 2113 bzero(sc->pbuf, sc->psize); 2114 bzero(sc->rbuf, sc->rsize); 2115 2116 /* set values to register */ 2117 addr = vtophys(sc->pbuf); 2118 #if(0) 2119 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2120 #endif 2121 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4); 2122 #if(0) 2123 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 2124 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2125 #endif 2126 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2); 2127 #if(0) 2128 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 2129 #endif 2130 addr = vtophys(sc->rbuf); 2131 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4); 2132 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2); 2133 2134 return 0; 2135 bad: 2136 envy24ht_dmafree(sc); 2137 return ENOSPC; 2138 } 2139 2140 static void 2141 envy24ht_putcfg(struct sc_info *sc) 2142 { 2143 device_printf(sc->dev, "system configuration\n"); 2144 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2145 sc->cfg->subvendor, sc->cfg->subdevice); 2146 printf(" XIN2 Clock Source: "); 2147 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) { 2148 case 0x00: 2149 printf("24.576MHz(96kHz*256)\n"); 2150 break; 2151 case 0x40: 2152 printf("49.152MHz(192kHz*256)\n"); 2153 break; 2154 case 0x80: 2155 printf("reserved\n"); 2156 break; 2157 default: 2158 printf("illeagal system setting\n"); 2159 } 2160 printf(" MPU-401 UART(s) #: "); 2161 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU) 2162 printf("1\n"); 2163 else 2164 printf("not implemented\n"); 2165 switch (sc->adcn) { 2166 case 0x01 || 0x02: 2167 printf(" ADC #: "); 2168 printf("%d\n", sc->adcn); 2169 break; 2170 case 0x03: 2171 printf(" ADC #: "); 2172 printf("%d", 1); 2173 printf(" and SPDIF receiver connected\n"); 2174 break; 2175 default: 2176 printf(" no physical inputs\n"); 2177 } 2178 printf(" DAC #: "); 2179 printf("%d\n", sc->dacn); 2180 printf(" Multi-track converter type: "); 2181 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) { 2182 printf("AC'97(SDATA_OUT:"); 2183 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE) 2184 printf("packed"); 2185 else 2186 printf("split"); 2187 printf(")\n"); 2188 } 2189 else { 2190 printf("I2S("); 2191 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL) 2192 printf("with volume, "); 2193 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ) 2194 printf("192KHz support, "); 2195 else 2196 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ) 2197 printf("192KHz support, "); 2198 else 2199 printf("48KHz support, "); 2200 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) { 2201 case ENVY24HT_CCSM_I2S_16BIT: 2202 printf("16bit resolution, "); 2203 break; 2204 case ENVY24HT_CCSM_I2S_18BIT: 2205 printf("18bit resolution, "); 2206 break; 2207 case ENVY24HT_CCSM_I2S_20BIT: 2208 printf("20bit resolution, "); 2209 break; 2210 case ENVY24HT_CCSM_I2S_24BIT: 2211 printf("24bit resolution, "); 2212 break; 2213 } 2214 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID); 2215 } 2216 printf(" S/PDIF(IN/OUT): "); 2217 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN) 2218 printf("1/"); 2219 else 2220 printf("0/"); 2221 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT) 2222 printf("1 "); 2223 else 2224 printf("0 "); 2225 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT)) 2226 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2); 2227 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2228 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2229 } 2230 2231 static int 2232 envy24ht_init(struct sc_info *sc) 2233 { 2234 u_int32_t data; 2235 #if(0) 2236 int rtn; 2237 #endif 2238 int i; 2239 u_int32_t sv, sd; 2240 2241 2242 #if(0) 2243 device_printf(sc->dev, "envy24ht_init()\n"); 2244 #endif 2245 2246 /* reset chip */ 2247 #if 0 2248 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1); 2249 DELAY(200); 2250 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1); 2251 DELAY(200); 2252 2253 /* legacy hardware disable */ 2254 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2255 data |= PCIM_LAC_DISABLE; 2256 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2257 #endif 2258 2259 /* check system configuration */ 2260 sc->cfg = NULL; 2261 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2262 /* 1st: search configuration from table */ 2263 sv = pci_get_subvendor(sc->dev); 2264 sd = pci_get_subdevice(sc->dev); 2265 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2266 #if(0) 2267 device_printf(sc->dev, "Set configuration from table\n"); 2268 #endif 2269 sc->cfg = &cfg_table[i]; 2270 break; 2271 } 2272 } 2273 if (sc->cfg == NULL) { 2274 /* 2nd: read configuration from table */ 2275 sc->cfg = envy24ht_rom2cfg(sc); 2276 } 2277 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */ 2278 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1; 2279 2280 if (1 /* bootverbose */) { 2281 envy24ht_putcfg(sc); 2282 } 2283 2284 /* set system configuration */ 2285 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1); 2286 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1); 2287 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1); 2288 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1); 2289 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); 2290 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); 2291 envy24ht_gpiowr(sc, sc->cfg->gpiostate); 2292 2293 for (i = 0; i < sc->adcn; i++) { 2294 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2295 sc->cfg->codec->init(sc->adc[i]); 2296 } 2297 for (i = 0; i < sc->dacn; i++) { 2298 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2299 sc->cfg->codec->init(sc->dac[i]); 2300 } 2301 2302 /* initialize DMA buffer */ 2303 #if(0) 2304 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n"); 2305 #endif 2306 if (envy24ht_dmainit(sc)) 2307 return ENOSPC; 2308 2309 /* initialize status */ 2310 sc->run[0] = sc->run[1] = 0; 2311 sc->intr[0] = sc->intr[1] = 0; 2312 sc->speed = 0; 2313 sc->caps[0].fmtlist = envy24ht_playfmt; 2314 sc->caps[1].fmtlist = envy24ht_recfmt; 2315 2316 /* set channel router */ 2317 #if 0 2318 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2319 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0); 2320 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2321 #endif 2322 2323 /* set macro interrupt mask */ 2324 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2325 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1); 2326 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2327 #if(0) 2328 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data); 2329 #endif 2330 2331 return 0; 2332 } 2333 2334 static int 2335 envy24ht_alloc_resource(struct sc_info *sc) 2336 { 2337 /* allocate I/O port resource */ 2338 sc->csid = PCIR_CCS; 2339 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2340 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2341 sc->mtid = ENVY24HT_PCIR_MT; 2342 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2343 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2344 if (!sc->cs || !sc->mt) { 2345 device_printf(sc->dev, "unable to map IO port space\n"); 2346 return ENXIO; 2347 } 2348 sc->cst = rman_get_bustag(sc->cs); 2349 sc->csh = rman_get_bushandle(sc->cs); 2350 sc->mtt = rman_get_bustag(sc->mt); 2351 sc->mth = rman_get_bushandle(sc->mt); 2352 #if(0) 2353 device_printf(sc->dev, 2354 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n", 2355 pci_read_config(sc->dev, PCIR_CCS, 4), 2356 pci_read_config(sc->dev, PCIR_MT, 4)); 2357 #endif 2358 2359 /* allocate interupt resource */ 2360 sc->irqid = 0; 2361 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2362 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2363 if (!sc->irq || 2364 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) { 2365 device_printf(sc->dev, "unable to map interrupt\n"); 2366 return ENXIO; 2367 } 2368 2369 /* allocate DMA resource */ 2370 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2371 /*alignment*/4, 2372 /*boundary*/0, 2373 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2374 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2375 /*filter*/NULL, /*filterarg*/NULL, 2376 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2377 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2378 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2379 /*lockarg*/&Giant, &sc->dmat) != 0) { 2380 device_printf(sc->dev, "unable to create dma tag\n"); 2381 return ENXIO; 2382 } 2383 2384 return 0; 2385 } 2386 2387 static int 2388 envy24ht_pci_attach(device_t dev) 2389 { 2390 u_int32_t data; 2391 struct sc_info *sc; 2392 char status[SND_STATUSLEN]; 2393 int err = 0; 2394 int i; 2395 2396 #if(0) 2397 device_printf(dev, "envy24ht_pci_attach()\n"); 2398 #endif 2399 /* get sc_info data area */ 2400 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) { 2401 device_printf(dev, "cannot allocate softc\n"); 2402 return ENXIO; 2403 } 2404 2405 bzero(sc, sizeof(*sc)); 2406 sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2407 "snd_envy24ht softc"); 2408 sc->dev = dev; 2409 2410 /* initialize PCI interface */ 2411 data = pci_read_config(dev, PCIR_COMMAND, 2); 2412 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2413 pci_write_config(dev, PCIR_COMMAND, data, 2); 2414 data = pci_read_config(dev, PCIR_COMMAND, 2); 2415 2416 /* allocate resources */ 2417 err = envy24ht_alloc_resource(sc); 2418 if (err) { 2419 device_printf(dev, "unable to allocate system resources\n"); 2420 goto bad; 2421 } 2422 2423 /* initialize card */ 2424 err = envy24ht_init(sc); 2425 if (err) { 2426 device_printf(dev, "unable to initialize the card\n"); 2427 goto bad; 2428 } 2429 2430 /* set multi track mixer */ 2431 mixer_init(dev, &envy24htmixer_class, sc); 2432 2433 /* set channel information */ 2434 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */ 2435 err = pcm_register(dev, sc, 1, 2 + sc->adcn); 2436 if (err) 2437 goto bad; 2438 sc->chnum = 0; 2439 /* for (i = 0; i < 5; i++) { */ 2440 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc); 2441 sc->chnum++; 2442 /* } */ 2443 for (i = 0; i < 2 + sc->adcn; i++) { 2444 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc); 2445 sc->chnum++; 2446 } 2447 2448 /* set status iformation */ 2449 snprintf(status, SND_STATUSLEN, 2450 "at io 0x%lx:%ld,0x%lx:%ld irq %ld", 2451 rman_get_start(sc->cs), 2452 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2453 rman_get_start(sc->mt), 2454 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2455 rman_get_start(sc->irq)); 2456 pcm_setstatus(dev, status); 2457 2458 return 0; 2459 2460 bad: 2461 if (sc->ih) 2462 bus_teardown_intr(dev, sc->irq, sc->ih); 2463 if (sc->irq) 2464 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2465 envy24ht_dmafree(sc); 2466 if (sc->dmat) 2467 bus_dma_tag_destroy(sc->dmat); 2468 if (sc->cfg->codec->destroy != NULL) { 2469 for (i = 0; i < sc->adcn; i++) 2470 sc->cfg->codec->destroy(sc->adc[i]); 2471 for (i = 0; i < sc->dacn; i++) 2472 sc->cfg->codec->destroy(sc->dac[i]); 2473 } 2474 envy24ht_cfgfree(sc->cfg); 2475 if (sc->cs) 2476 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2477 if (sc->mt) 2478 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2479 if (sc->lock) 2480 snd_mtxfree(sc->lock); 2481 free(sc, M_ENVY24HT); 2482 return err; 2483 } 2484 2485 static int 2486 envy24ht_pci_detach(device_t dev) 2487 { 2488 struct sc_info *sc; 2489 int r; 2490 int i; 2491 2492 #if(0) 2493 device_printf(dev, "envy24ht_pci_detach()\n"); 2494 #endif 2495 sc = pcm_getdevinfo(dev); 2496 if (sc == NULL) 2497 return 0; 2498 r = pcm_unregister(dev); 2499 if (r) 2500 return r; 2501 2502 envy24ht_dmafree(sc); 2503 if (sc->cfg->codec->destroy != NULL) { 2504 for (i = 0; i < sc->adcn; i++) 2505 sc->cfg->codec->destroy(sc->adc[i]); 2506 for (i = 0; i < sc->dacn; i++) 2507 sc->cfg->codec->destroy(sc->dac[i]); 2508 } 2509 envy24ht_cfgfree(sc->cfg); 2510 bus_dma_tag_destroy(sc->dmat); 2511 bus_teardown_intr(dev, sc->irq, sc->ih); 2512 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2513 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2514 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2515 snd_mtxfree(sc->lock); 2516 free(sc, M_ENVY24HT); 2517 return 0; 2518 } 2519 2520 static device_method_t envy24ht_methods[] = { 2521 /* Device interface */ 2522 DEVMETHOD(device_probe, envy24ht_pci_probe), 2523 DEVMETHOD(device_attach, envy24ht_pci_attach), 2524 DEVMETHOD(device_detach, envy24ht_pci_detach), 2525 { 0, 0 } 2526 }; 2527 2528 static driver_t envy24ht_driver = { 2529 "pcm", 2530 envy24ht_methods, 2531 #if __FreeBSD_version > 500000 2532 PCM_SOFTC_SIZE, 2533 #else 2534 sizeof(struct snddev_info), 2535 #endif 2536 }; 2537 2538 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0); 2539 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2540 MODULE_DEPEND(snd_envy24ht, snd_spicds, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2541 MODULE_VERSION(snd_envy24ht, 1); 2542