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 = 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 } 2092 #endif 2093 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4); 2094 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2); 2095 } 2096 2097 static void 2098 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2099 { 2100 struct sc_info *sc = arg; 2101 2102 #if(0) 2103 device_printf(sc->dev, "envy24ht_dmarsetmap()\n"); 2104 if (bootverbose) { 2105 printf("envy24ht(record): setmap %lx, %lx; ", 2106 (unsigned long)segs->ds_addr, 2107 (unsigned long)segs->ds_len); 2108 } 2109 #endif 2110 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4); 2111 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2); 2112 } 2113 2114 static void 2115 envy24ht_dmafree(struct sc_info *sc) 2116 { 2117 #if(0) 2118 device_printf(sc->dev, "envy24ht_dmafree():"); 2119 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2120 else printf(" sc->rmap(null)"); 2121 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2122 else printf(" sc->pmap(null)"); 2123 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2124 else printf(" sc->rbuf(null)"); 2125 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2126 else printf(" sc->pbuf(null)\n"); 2127 #endif 2128 #if(0) 2129 if (sc->rmap) 2130 bus_dmamap_unload(sc->dmat, sc->rmap); 2131 if (sc->pmap) 2132 bus_dmamap_unload(sc->dmat, sc->pmap); 2133 if (sc->rbuf) 2134 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2135 if (sc->pbuf) 2136 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2137 #else 2138 bus_dmamap_unload(sc->dmat, sc->rmap); 2139 bus_dmamap_unload(sc->dmat, sc->pmap); 2140 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2141 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2142 #endif 2143 2144 sc->rmap = sc->pmap = NULL; 2145 sc->pbuf = NULL; 2146 sc->rbuf = NULL; 2147 2148 return; 2149 } 2150 2151 static int 2152 envy24ht_dmainit(struct sc_info *sc) 2153 { 2154 2155 #if(0) 2156 device_printf(sc->dev, "envy24ht_dmainit()\n"); 2157 #endif 2158 /* init values */ 2159 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2160 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2161 sc->pbuf = NULL; 2162 sc->rbuf = NULL; 2163 sc->pmap = sc->rmap = NULL; 2164 sc->blk[0] = sc->blk[1] = 0; 2165 2166 /* allocate DMA buffer */ 2167 #if(0) 2168 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2169 #endif 2170 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2171 goto bad; 2172 #if(0) 2173 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2174 #endif 2175 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2176 goto bad; 2177 #if(0) 2178 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2179 #endif 2180 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT)) 2181 goto bad; 2182 #if(0) 2183 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2184 #endif 2185 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT)) 2186 goto bad; 2187 bzero(sc->pbuf, sc->psize); 2188 bzero(sc->rbuf, sc->rsize); 2189 2190 return 0; 2191 bad: 2192 envy24ht_dmafree(sc); 2193 return ENOSPC; 2194 } 2195 2196 static void 2197 envy24ht_putcfg(struct sc_info *sc) 2198 { 2199 device_printf(sc->dev, "system configuration\n"); 2200 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2201 sc->cfg->subvendor, sc->cfg->subdevice); 2202 printf(" XIN2 Clock Source: "); 2203 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) { 2204 case 0x00: 2205 printf("24.576MHz(96kHz*256)\n"); 2206 break; 2207 case 0x40: 2208 printf("49.152MHz(192kHz*256)\n"); 2209 break; 2210 case 0x80: 2211 printf("reserved\n"); 2212 break; 2213 default: 2214 printf("illeagal system setting\n"); 2215 } 2216 printf(" MPU-401 UART(s) #: "); 2217 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU) 2218 printf("1\n"); 2219 else 2220 printf("not implemented\n"); 2221 switch (sc->adcn) { 2222 case 0x01: 2223 case 0x02: 2224 printf(" ADC #: "); 2225 printf("%d\n", sc->adcn); 2226 break; 2227 case 0x03: 2228 printf(" ADC #: "); 2229 printf("%d", 1); 2230 printf(" and SPDIF receiver connected\n"); 2231 break; 2232 default: 2233 printf(" no physical inputs\n"); 2234 } 2235 printf(" DAC #: "); 2236 printf("%d\n", sc->dacn); 2237 printf(" Multi-track converter type: "); 2238 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) { 2239 printf("AC'97(SDATA_OUT:"); 2240 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE) 2241 printf("packed"); 2242 else 2243 printf("split"); 2244 printf(")\n"); 2245 } 2246 else { 2247 printf("I2S("); 2248 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL) 2249 printf("with volume, "); 2250 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ) 2251 printf("192KHz support, "); 2252 else 2253 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ) 2254 printf("192KHz support, "); 2255 else 2256 printf("48KHz support, "); 2257 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) { 2258 case ENVY24HT_CCSM_I2S_16BIT: 2259 printf("16bit resolution, "); 2260 break; 2261 case ENVY24HT_CCSM_I2S_18BIT: 2262 printf("18bit resolution, "); 2263 break; 2264 case ENVY24HT_CCSM_I2S_20BIT: 2265 printf("20bit resolution, "); 2266 break; 2267 case ENVY24HT_CCSM_I2S_24BIT: 2268 printf("24bit resolution, "); 2269 break; 2270 } 2271 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID); 2272 } 2273 printf(" S/PDIF(IN/OUT): "); 2274 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN) 2275 printf("1/"); 2276 else 2277 printf("0/"); 2278 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT) 2279 printf("1 "); 2280 else 2281 printf("0 "); 2282 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT)) 2283 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2); 2284 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2285 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2286 } 2287 2288 static int 2289 envy24ht_init(struct sc_info *sc) 2290 { 2291 u_int32_t data; 2292 #if(0) 2293 int rtn; 2294 #endif 2295 int i; 2296 u_int32_t sv, sd; 2297 2298 2299 #if(0) 2300 device_printf(sc->dev, "envy24ht_init()\n"); 2301 #endif 2302 2303 /* reset chip */ 2304 #if 0 2305 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1); 2306 DELAY(200); 2307 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1); 2308 DELAY(200); 2309 2310 /* legacy hardware disable */ 2311 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2312 data |= PCIM_LAC_DISABLE; 2313 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2314 #endif 2315 2316 /* check system configuration */ 2317 sc->cfg = NULL; 2318 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2319 /* 1st: search configuration from table */ 2320 sv = pci_get_subvendor(sc->dev); 2321 sd = pci_get_subdevice(sc->dev); 2322 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2323 #if(0) 2324 device_printf(sc->dev, "Set configuration from table\n"); 2325 #endif 2326 sc->cfg = &cfg_table[i]; 2327 break; 2328 } 2329 } 2330 if (sc->cfg == NULL) { 2331 /* 2nd: read configuration from table */ 2332 sc->cfg = envy24ht_rom2cfg(sc); 2333 } 2334 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */ 2335 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1; 2336 2337 if (1 /* bootverbose */) { 2338 envy24ht_putcfg(sc); 2339 } 2340 2341 /* set system configuration */ 2342 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1); 2343 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1); 2344 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1); 2345 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1); 2346 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); 2347 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); 2348 envy24ht_gpiowr(sc, sc->cfg->gpiostate); 2349 2350 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { 2351 envy24ht_wri2c(sc, 0x22, 0x00, 0x07); 2352 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); 2353 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); 2354 } 2355 2356 for (i = 0; i < sc->adcn; i++) { 2357 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2358 sc->cfg->codec->init(sc->adc[i]); 2359 } 2360 for (i = 0; i < sc->dacn; i++) { 2361 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2362 sc->cfg->codec->init(sc->dac[i]); 2363 } 2364 2365 /* initialize DMA buffer */ 2366 #if(0) 2367 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n"); 2368 #endif 2369 if (envy24ht_dmainit(sc)) 2370 return ENOSPC; 2371 2372 /* initialize status */ 2373 sc->run[0] = sc->run[1] = 0; 2374 sc->intr[0] = sc->intr[1] = 0; 2375 sc->speed = 0; 2376 sc->caps[0].fmtlist = envy24ht_playfmt; 2377 sc->caps[1].fmtlist = envy24ht_recfmt; 2378 2379 /* set channel router */ 2380 #if 0 2381 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0); 2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2384 #endif 2385 2386 /* set macro interrupt mask */ 2387 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2388 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1); 2389 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2390 #if(0) 2391 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data); 2392 #endif 2393 2394 return 0; 2395 } 2396 2397 static int 2398 envy24ht_alloc_resource(struct sc_info *sc) 2399 { 2400 /* allocate I/O port resource */ 2401 sc->csid = PCIR_CCS; 2402 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2403 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2404 sc->mtid = ENVY24HT_PCIR_MT; 2405 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2406 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2407 if (!sc->cs || !sc->mt) { 2408 device_printf(sc->dev, "unable to map IO port space\n"); 2409 return ENXIO; 2410 } 2411 sc->cst = rman_get_bustag(sc->cs); 2412 sc->csh = rman_get_bushandle(sc->cs); 2413 sc->mtt = rman_get_bustag(sc->mt); 2414 sc->mth = rman_get_bushandle(sc->mt); 2415 #if(0) 2416 device_printf(sc->dev, 2417 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n", 2418 pci_read_config(sc->dev, PCIR_CCS, 4), 2419 pci_read_config(sc->dev, PCIR_MT, 4)); 2420 #endif 2421 2422 /* allocate interrupt resource */ 2423 sc->irqid = 0; 2424 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2425 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2426 if (!sc->irq || 2427 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) { 2428 device_printf(sc->dev, "unable to map interrupt\n"); 2429 return ENXIO; 2430 } 2431 2432 /* allocate DMA resource */ 2433 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2434 /*alignment*/4, 2435 /*boundary*/0, 2436 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 2437 /*highaddr*/BUS_SPACE_MAXADDR, 2438 /*filter*/NULL, /*filterarg*/NULL, 2439 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2440 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2441 /*flags*/0, /*lockfunc*/NULL, 2442 /*lockarg*/NULL, &sc->dmat) != 0) { 2443 device_printf(sc->dev, "unable to create dma tag\n"); 2444 return ENXIO; 2445 } 2446 2447 return 0; 2448 } 2449 2450 static int 2451 envy24ht_pci_attach(device_t dev) 2452 { 2453 struct sc_info *sc; 2454 char status[SND_STATUSLEN]; 2455 int err = 0; 2456 int i; 2457 2458 #if(0) 2459 device_printf(dev, "envy24ht_pci_attach()\n"); 2460 #endif 2461 /* get sc_info data area */ 2462 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) { 2463 device_printf(dev, "cannot allocate softc\n"); 2464 return ENXIO; 2465 } 2466 2467 bzero(sc, sizeof(*sc)); 2468 sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2469 "snd_envy24ht softc"); 2470 sc->dev = dev; 2471 2472 /* initialize PCI interface */ 2473 pci_enable_busmaster(dev); 2474 2475 /* allocate resources */ 2476 err = envy24ht_alloc_resource(sc); 2477 if (err) { 2478 device_printf(dev, "unable to allocate system resources\n"); 2479 goto bad; 2480 } 2481 2482 /* initialize card */ 2483 err = envy24ht_init(sc); 2484 if (err) { 2485 device_printf(dev, "unable to initialize the card\n"); 2486 goto bad; 2487 } 2488 2489 /* set multi track mixer */ 2490 mixer_init(dev, &envy24htmixer_class, sc); 2491 2492 /* set channel information */ 2493 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */ 2494 err = pcm_register(dev, sc, 1, 2 + sc->adcn); 2495 if (err) 2496 goto bad; 2497 sc->chnum = 0; 2498 /* for (i = 0; i < 5; i++) { */ 2499 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc); 2500 sc->chnum++; 2501 /* } */ 2502 for (i = 0; i < 2 + sc->adcn; i++) { 2503 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc); 2504 sc->chnum++; 2505 } 2506 2507 /* set status iformation */ 2508 snprintf(status, SND_STATUSLEN, 2509 "at io 0x%lx:%ld,0x%lx:%ld irq %ld", 2510 rman_get_start(sc->cs), 2511 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2512 rman_get_start(sc->mt), 2513 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2514 rman_get_start(sc->irq)); 2515 pcm_setstatus(dev, status); 2516 2517 return 0; 2518 2519 bad: 2520 if (sc->ih) 2521 bus_teardown_intr(dev, sc->irq, sc->ih); 2522 if (sc->irq) 2523 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2524 envy24ht_dmafree(sc); 2525 if (sc->dmat) 2526 bus_dma_tag_destroy(sc->dmat); 2527 if (sc->cfg->codec->destroy != NULL) { 2528 for (i = 0; i < sc->adcn; i++) 2529 sc->cfg->codec->destroy(sc->adc[i]); 2530 for (i = 0; i < sc->dacn; i++) 2531 sc->cfg->codec->destroy(sc->dac[i]); 2532 } 2533 envy24ht_cfgfree(sc->cfg); 2534 if (sc->cs) 2535 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2536 if (sc->mt) 2537 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2538 if (sc->lock) 2539 snd_mtxfree(sc->lock); 2540 free(sc, M_ENVY24HT); 2541 return err; 2542 } 2543 2544 static int 2545 envy24ht_pci_detach(device_t dev) 2546 { 2547 struct sc_info *sc; 2548 int r; 2549 int i; 2550 2551 #if(0) 2552 device_printf(dev, "envy24ht_pci_detach()\n"); 2553 #endif 2554 sc = pcm_getdevinfo(dev); 2555 if (sc == NULL) 2556 return 0; 2557 r = pcm_unregister(dev); 2558 if (r) 2559 return r; 2560 2561 envy24ht_dmafree(sc); 2562 if (sc->cfg->codec->destroy != NULL) { 2563 for (i = 0; i < sc->adcn; i++) 2564 sc->cfg->codec->destroy(sc->adc[i]); 2565 for (i = 0; i < sc->dacn; i++) 2566 sc->cfg->codec->destroy(sc->dac[i]); 2567 } 2568 envy24ht_cfgfree(sc->cfg); 2569 bus_dma_tag_destroy(sc->dmat); 2570 bus_teardown_intr(dev, sc->irq, sc->ih); 2571 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2572 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2573 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2574 snd_mtxfree(sc->lock); 2575 free(sc, M_ENVY24HT); 2576 return 0; 2577 } 2578 2579 static device_method_t envy24ht_methods[] = { 2580 /* Device interface */ 2581 DEVMETHOD(device_probe, envy24ht_pci_probe), 2582 DEVMETHOD(device_attach, envy24ht_pci_attach), 2583 DEVMETHOD(device_detach, envy24ht_pci_detach), 2584 { 0, 0 } 2585 }; 2586 2587 static driver_t envy24ht_driver = { 2588 "pcm", 2589 envy24ht_methods, 2590 #if __FreeBSD_version > 500000 2591 PCM_SOFTC_SIZE, 2592 #else 2593 sizeof(struct snddev_info), 2594 #endif 2595 }; 2596 2597 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0); 2598 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2599 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1); 2600 MODULE_VERSION(snd_envy24ht, 1); 2601