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