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