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