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 int error = 0; 1681 #if 0 1682 int i; 1683 1684 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go); 1685 #endif 1686 snd_mtxlock(sc->lock); 1687 if (ch->dir == PCMDIR_PLAY) 1688 slot = 0; 1689 else 1690 slot = 1; 1691 switch (go) { 1692 case PCMTRIG_START: 1693 #if(0) 1694 device_printf(sc->dev, "envy24htchan_trigger(): start\n"); 1695 #endif 1696 /* check or set channel speed */ 1697 if (sc->run[0] == 0 && sc->run[1] == 0) { 1698 sc->speed = envy24ht_setspeed(sc, ch->speed); 1699 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1700 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1701 } 1702 else if (ch->speed != 0 && ch->speed != sc->speed) { 1703 error = -1; 1704 goto fail; 1705 } 1706 if (ch->speed == 0) 1707 ch->channel->speed = sc->speed; 1708 /* start or enable channel */ 1709 sc->run[slot]++; 1710 if (sc->run[slot] == 1) { 1711 /* first channel */ 1712 ch->offset = 0; 1713 sc->blk[slot] = ch->blk; 1714 } 1715 else { 1716 ptr = envy24ht_gethwptr(sc, ch->dir); 1717 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1718 (ch->size / 4)) * 4 / ch->unit; 1719 if (ch->blk < sc->blk[slot]) 1720 sc->blk[slot] = ch->blk; 1721 } 1722 if (ch->dir == PCMDIR_PLAY) { 1723 ch->emldma(ch); 1724 envy24ht_setvolume(sc, ch->num); 1725 } 1726 envy24ht_updintr(sc, ch->dir); 1727 if (sc->run[slot] == 1) 1728 envy24ht_start(sc, ch->dir); 1729 ch->run = 1; 1730 break; 1731 case PCMTRIG_EMLDMAWR: 1732 #if(0) 1733 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n"); 1734 #endif 1735 if (ch->run != 1) { 1736 error = -1; 1737 goto fail; 1738 } 1739 ch->emldma(ch); 1740 break; 1741 case PCMTRIG_EMLDMARD: 1742 #if(0) 1743 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n"); 1744 #endif 1745 if (ch->run != 1) { 1746 error = -1; 1747 goto fail; 1748 } 1749 ch->emldma(ch); 1750 break; 1751 case PCMTRIG_ABORT: 1752 if (ch->run) { 1753 #if(0) 1754 device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); 1755 #endif 1756 ch->run = 0; 1757 sc->run[slot]--; 1758 if (ch->dir == PCMDIR_PLAY) 1759 envy24ht_mutevolume(sc, ch->num); 1760 if (sc->run[slot] == 0) { 1761 envy24ht_stop(sc, ch->dir); 1762 sc->intr[slot] = 0; 1763 } 1764 /* else if (ch->blk == sc->blk[slot]) { 1765 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2; 1766 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) { 1767 if (sc->chan[i].dir == ch->dir && 1768 sc->chan[i].run == 1 && 1769 sc->chan[i].blk < sc->blk[slot]) 1770 sc->blk[slot] = sc->chan[i].blk; 1771 } 1772 if (ch->blk != sc->blk[slot]) 1773 envy24ht_updintr(sc, ch->dir); 1774 }*/ 1775 } 1776 break; 1777 } 1778 fail: 1779 snd_mtxunlock(sc->lock); 1780 return (error); 1781 } 1782 1783 static int 1784 envy24htchan_getptr(kobj_t obj, void *data) 1785 { 1786 struct sc_chinfo *ch = data; 1787 struct sc_info *sc = ch->parent; 1788 u_int32_t ptr; 1789 int rtn; 1790 1791 #if(0) 1792 device_printf(sc->dev, "envy24htchan_getptr()\n"); 1793 #endif 1794 snd_mtxlock(sc->lock); 1795 ptr = envy24ht_gethwptr(sc, ch->dir); 1796 rtn = ptr * ch->unit; 1797 snd_mtxunlock(sc->lock); 1798 1799 #if(0) 1800 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n", 1801 rtn); 1802 #endif 1803 return rtn; 1804 } 1805 1806 static struct pcmchan_caps * 1807 envy24htchan_getcaps(kobj_t obj, void *data) 1808 { 1809 struct sc_chinfo *ch = data; 1810 struct sc_info *sc = ch->parent; 1811 struct pcmchan_caps *rtn; 1812 1813 #if(0) 1814 device_printf(sc->dev, "envy24htchan_getcaps()\n"); 1815 #endif 1816 snd_mtxlock(sc->lock); 1817 if (ch->dir == PCMDIR_PLAY) { 1818 if (sc->run[0] == 0) 1819 rtn = &envy24ht_playcaps; 1820 else 1821 rtn = &sc->caps[0]; 1822 } 1823 else { 1824 if (sc->run[1] == 0) 1825 rtn = &envy24ht_reccaps; 1826 else 1827 rtn = &sc->caps[1]; 1828 } 1829 snd_mtxunlock(sc->lock); 1830 1831 return rtn; 1832 } 1833 1834 static kobj_method_t envy24htchan_methods[] = { 1835 KOBJMETHOD(channel_init, envy24htchan_init), 1836 KOBJMETHOD(channel_free, envy24htchan_free), 1837 KOBJMETHOD(channel_setformat, envy24htchan_setformat), 1838 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed), 1839 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize), 1840 KOBJMETHOD(channel_trigger, envy24htchan_trigger), 1841 KOBJMETHOD(channel_getptr, envy24htchan_getptr), 1842 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps), 1843 { 0, 0 } 1844 }; 1845 CHANNEL_DECLARE(envy24htchan); 1846 1847 /* -------------------------------------------------------------------- */ 1848 1849 /* mixer interface */ 1850 1851 static int 1852 envy24htmixer_init(struct snd_mixer *m) 1853 { 1854 struct sc_info *sc = mix_getdevinfo(m); 1855 1856 #if(0) 1857 device_printf(sc->dev, "envy24htmixer_init()\n"); 1858 #endif 1859 if (sc == NULL) 1860 return -1; 1861 1862 /* set volume control rate */ 1863 snd_mtxlock(sc->lock); 1864 #if 0 1865 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1866 #endif 1867 1868 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL); 1869 1870 mix_setdevs(m, ENVY24HT_MIX_MASK); 1871 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); 1872 1873 snd_mtxunlock(sc->lock); 1874 1875 return 0; 1876 } 1877 1878 static int 1879 envy24htmixer_reinit(struct snd_mixer *m) 1880 { 1881 struct sc_info *sc = mix_getdevinfo(m); 1882 1883 if (sc == NULL) 1884 return -1; 1885 #if(0) 1886 device_printf(sc->dev, "envy24htmixer_reinit()\n"); 1887 #endif 1888 1889 return 0; 1890 } 1891 1892 static int 1893 envy24htmixer_uninit(struct snd_mixer *m) 1894 { 1895 struct sc_info *sc = mix_getdevinfo(m); 1896 1897 if (sc == NULL) 1898 return -1; 1899 #if(0) 1900 device_printf(sc->dev, "envy24htmixer_uninit()\n"); 1901 #endif 1902 1903 return 0; 1904 } 1905 1906 static int 1907 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1908 { 1909 struct sc_info *sc = mix_getdevinfo(m); 1910 int ch = envy24ht_mixmap[dev]; 1911 int hwch; 1912 int i; 1913 1914 if (sc == NULL) 1915 return -1; 1916 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1917 return -1; 1918 if (dev != 0 && ch == -1) 1919 return -1; 1920 hwch = envy24ht_chanmap[ch]; 1921 #if(0) 1922 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n", 1923 dev, left, right); 1924 #endif 1925 1926 snd_mtxlock(sc->lock); 1927 if (dev == 0) { 1928 for (i = 0; i < sc->dacn; i++) { 1929 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1930 } 1931 } 1932 else { 1933 /* set volume value for hardware */ 1934 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN) 1935 sc->left[hwch] = ENVY24HT_VOL_MUTE; 1936 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN) 1937 sc->right[hwch] = ENVY24HT_VOL_MUTE; 1938 1939 /* set volume for record channel and running play channel */ 1940 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1941 envy24ht_setvolume(sc, hwch); 1942 } 1943 snd_mtxunlock(sc->lock); 1944 1945 return right << 8 | left; 1946 } 1947 1948 static u_int32_t 1949 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1950 { 1951 struct sc_info *sc = mix_getdevinfo(m); 1952 int ch = envy24ht_mixmap[src]; 1953 #if(0) 1954 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src); 1955 #endif 1956 1957 if (ch > ENVY24HT_CHAN_PLAY_SPDIF) 1958 sc->src = ch; 1959 return src; 1960 } 1961 1962 static kobj_method_t envy24htmixer_methods[] = { 1963 KOBJMETHOD(mixer_init, envy24htmixer_init), 1964 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit), 1965 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit), 1966 KOBJMETHOD(mixer_set, envy24htmixer_set), 1967 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc), 1968 { 0, 0 } 1969 }; 1970 MIXER_DECLARE(envy24htmixer); 1971 1972 /* -------------------------------------------------------------------- */ 1973 1974 /* The interrupt handler */ 1975 static void 1976 envy24ht_intr(void *p) 1977 { 1978 struct sc_info *sc = (struct sc_info *)p; 1979 struct sc_chinfo *ch; 1980 u_int32_t ptr, dsize, feed; 1981 int i; 1982 1983 #if(0) 1984 device_printf(sc->dev, "envy24ht_intr()\n"); 1985 #endif 1986 snd_mtxlock(sc->lock); 1987 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) { 1988 #if(0) 1989 device_printf(sc->dev, "envy24ht_intr(): play\n"); 1990 #endif 1991 dsize = sc->psize / 4; 1992 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1; 1993 #if(0) 1994 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr); 1995 #endif 1996 ptr -= ptr % sc->blk[0]; 1997 feed = (ptr + dsize - sc->intr[0]) % dsize; 1998 #if(0) 1999 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 2000 #endif 2001 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) { 2002 ch = &sc->chan[i]; 2003 #if(0) 2004 if (ch->run) 2005 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk); 2006 #endif 2007 if (ch->run && ch->blk <= feed) { 2008 snd_mtxunlock(sc->lock); 2009 chn_intr(ch->channel); 2010 snd_mtxlock(sc->lock); 2011 } 2012 } 2013 sc->intr[0] = ptr; 2014 envy24ht_updintr(sc, PCMDIR_PLAY); 2015 } 2016 if (envy24ht_checkintr(sc, PCMDIR_REC)) { 2017 #if(0) 2018 device_printf(sc->dev, "envy24ht_intr(): rec\n"); 2019 #endif 2020 dsize = sc->rsize / 4; 2021 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1; 2022 ptr -= ptr % sc->blk[1]; 2023 feed = (ptr + dsize - sc->intr[1]) % dsize; 2024 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) { 2025 ch = &sc->chan[i]; 2026 if (ch->run && ch->blk <= feed) { 2027 snd_mtxunlock(sc->lock); 2028 chn_intr(ch->channel); 2029 snd_mtxlock(sc->lock); 2030 } 2031 } 2032 sc->intr[1] = ptr; 2033 envy24ht_updintr(sc, PCMDIR_REC); 2034 } 2035 snd_mtxunlock(sc->lock); 2036 2037 return; 2038 } 2039 2040 /* 2041 * Probe and attach the card 2042 */ 2043 2044 static int 2045 envy24ht_pci_probe(device_t dev) 2046 { 2047 u_int16_t sv, sd; 2048 int i; 2049 2050 #if(0) 2051 printf("envy24ht_pci_probe()\n"); 2052 #endif 2053 if (pci_get_device(dev) == PCID_ENVY24HT && 2054 pci_get_vendor(dev) == PCIV_ENVY24) { 2055 sv = pci_get_subvendor(dev); 2056 sd = pci_get_subdevice(dev); 2057 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2058 if (cfg_table[i].subvendor == sv && 2059 cfg_table[i].subdevice == sd) { 2060 break; 2061 } 2062 } 2063 device_set_desc(dev, cfg_table[i].name); 2064 #if(0) 2065 printf("envy24ht_pci_probe(): return 0\n"); 2066 #endif 2067 return 0; 2068 } 2069 else { 2070 #if(0) 2071 printf("envy24ht_pci_probe(): return ENXIO\n"); 2072 #endif 2073 return ENXIO; 2074 } 2075 } 2076 2077 static void 2078 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2079 { 2080 /* struct sc_info *sc = (struct sc_info *)arg; */ 2081 2082 #if(0) 2083 device_printf(sc->dev, "envy24ht_dmapsetmap()\n"); 2084 if (bootverbose) { 2085 printf("envy24ht(play): setmap %lx, %lx; ", 2086 (unsigned long)segs->ds_addr, 2087 (unsigned long)segs->ds_len); 2088 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 2089 } 2090 #endif 2091 } 2092 2093 static void 2094 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2095 { 2096 /* struct sc_info *sc = (struct sc_info *)arg; */ 2097 2098 #if(0) 2099 device_printf(sc->dev, "envy24ht_dmarsetmap()\n"); 2100 if (bootverbose) { 2101 printf("envy24ht(record): setmap %lx, %lx; ", 2102 (unsigned long)segs->ds_addr, 2103 (unsigned long)segs->ds_len); 2104 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2105 } 2106 #endif 2107 } 2108 2109 static void 2110 envy24ht_dmafree(struct sc_info *sc) 2111 { 2112 #if(0) 2113 device_printf(sc->dev, "envy24ht_dmafree():"); 2114 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2115 else printf(" sc->rmap(null)"); 2116 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2117 else printf(" sc->pmap(null)"); 2118 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2119 else printf(" sc->rbuf(null)"); 2120 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2121 else printf(" sc->pbuf(null)\n"); 2122 #endif 2123 #if(0) 2124 if (sc->rmap) 2125 bus_dmamap_unload(sc->dmat, sc->rmap); 2126 if (sc->pmap) 2127 bus_dmamap_unload(sc->dmat, sc->pmap); 2128 if (sc->rbuf) 2129 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2130 if (sc->pbuf) 2131 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2132 #else 2133 bus_dmamap_unload(sc->dmat, sc->rmap); 2134 bus_dmamap_unload(sc->dmat, sc->pmap); 2135 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2136 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2137 #endif 2138 2139 sc->rmap = sc->pmap = NULL; 2140 sc->pbuf = NULL; 2141 sc->rbuf = NULL; 2142 2143 return; 2144 } 2145 2146 static int 2147 envy24ht_dmainit(struct sc_info *sc) 2148 { 2149 u_int32_t addr; 2150 2151 #if(0) 2152 device_printf(sc->dev, "envy24ht_dmainit()\n"); 2153 #endif 2154 /* init values */ 2155 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2156 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2157 sc->pbuf = NULL; 2158 sc->rbuf = NULL; 2159 sc->pmap = sc->rmap = NULL; 2160 sc->blk[0] = sc->blk[1] = 0; 2161 2162 /* allocate DMA buffer */ 2163 #if(0) 2164 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2165 #endif 2166 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2167 goto bad; 2168 #if(0) 2169 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2170 #endif 2171 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2172 goto bad; 2173 #if(0) 2174 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2175 #endif 2176 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0)) 2177 goto bad; 2178 #if(0) 2179 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2180 #endif 2181 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0)) 2182 goto bad; 2183 bzero(sc->pbuf, sc->psize); 2184 bzero(sc->rbuf, sc->rsize); 2185 2186 /* set values to register */ 2187 addr = vtophys(sc->pbuf); 2188 #if(0) 2189 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2190 #endif 2191 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4); 2192 #if(0) 2193 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 2194 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2195 #endif 2196 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2); 2197 #if(0) 2198 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 2199 #endif 2200 addr = vtophys(sc->rbuf); 2201 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4); 2202 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2); 2203 2204 return 0; 2205 bad: 2206 envy24ht_dmafree(sc); 2207 return ENOSPC; 2208 } 2209 2210 static void 2211 envy24ht_putcfg(struct sc_info *sc) 2212 { 2213 device_printf(sc->dev, "system configuration\n"); 2214 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2215 sc->cfg->subvendor, sc->cfg->subdevice); 2216 printf(" XIN2 Clock Source: "); 2217 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) { 2218 case 0x00: 2219 printf("24.576MHz(96kHz*256)\n"); 2220 break; 2221 case 0x40: 2222 printf("49.152MHz(192kHz*256)\n"); 2223 break; 2224 case 0x80: 2225 printf("reserved\n"); 2226 break; 2227 default: 2228 printf("illeagal system setting\n"); 2229 } 2230 printf(" MPU-401 UART(s) #: "); 2231 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU) 2232 printf("1\n"); 2233 else 2234 printf("not implemented\n"); 2235 switch (sc->adcn) { 2236 case 0x01 || 0x02: 2237 printf(" ADC #: "); 2238 printf("%d\n", sc->adcn); 2239 break; 2240 case 0x03: 2241 printf(" ADC #: "); 2242 printf("%d", 1); 2243 printf(" and SPDIF receiver connected\n"); 2244 break; 2245 default: 2246 printf(" no physical inputs\n"); 2247 } 2248 printf(" DAC #: "); 2249 printf("%d\n", sc->dacn); 2250 printf(" Multi-track converter type: "); 2251 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) { 2252 printf("AC'97(SDATA_OUT:"); 2253 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE) 2254 printf("packed"); 2255 else 2256 printf("split"); 2257 printf(")\n"); 2258 } 2259 else { 2260 printf("I2S("); 2261 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL) 2262 printf("with volume, "); 2263 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ) 2264 printf("192KHz support, "); 2265 else 2266 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ) 2267 printf("192KHz support, "); 2268 else 2269 printf("48KHz support, "); 2270 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) { 2271 case ENVY24HT_CCSM_I2S_16BIT: 2272 printf("16bit resolution, "); 2273 break; 2274 case ENVY24HT_CCSM_I2S_18BIT: 2275 printf("18bit resolution, "); 2276 break; 2277 case ENVY24HT_CCSM_I2S_20BIT: 2278 printf("20bit resolution, "); 2279 break; 2280 case ENVY24HT_CCSM_I2S_24BIT: 2281 printf("24bit resolution, "); 2282 break; 2283 } 2284 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID); 2285 } 2286 printf(" S/PDIF(IN/OUT): "); 2287 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN) 2288 printf("1/"); 2289 else 2290 printf("0/"); 2291 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT) 2292 printf("1 "); 2293 else 2294 printf("0 "); 2295 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT)) 2296 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2); 2297 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2298 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2299 } 2300 2301 static int 2302 envy24ht_init(struct sc_info *sc) 2303 { 2304 u_int32_t data; 2305 #if(0) 2306 int rtn; 2307 #endif 2308 int i; 2309 u_int32_t sv, sd; 2310 2311 2312 #if(0) 2313 device_printf(sc->dev, "envy24ht_init()\n"); 2314 #endif 2315 2316 /* reset chip */ 2317 #if 0 2318 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1); 2319 DELAY(200); 2320 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1); 2321 DELAY(200); 2322 2323 /* legacy hardware disable */ 2324 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2325 data |= PCIM_LAC_DISABLE; 2326 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2327 #endif 2328 2329 /* check system configuration */ 2330 sc->cfg = NULL; 2331 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2332 /* 1st: search configuration from table */ 2333 sv = pci_get_subvendor(sc->dev); 2334 sd = pci_get_subdevice(sc->dev); 2335 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2336 #if(0) 2337 device_printf(sc->dev, "Set configuration from table\n"); 2338 #endif 2339 sc->cfg = &cfg_table[i]; 2340 break; 2341 } 2342 } 2343 if (sc->cfg == NULL) { 2344 /* 2nd: read configuration from table */ 2345 sc->cfg = envy24ht_rom2cfg(sc); 2346 } 2347 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */ 2348 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1; 2349 2350 if (1 /* bootverbose */) { 2351 envy24ht_putcfg(sc); 2352 } 2353 2354 /* set system configuration */ 2355 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1); 2356 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1); 2357 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1); 2358 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1); 2359 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); 2360 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); 2361 envy24ht_gpiowr(sc, sc->cfg->gpiostate); 2362 2363 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { 2364 envy24ht_wri2c(sc, 0x22, 0x00, 0x07); 2365 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); 2366 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); 2367 } 2368 2369 for (i = 0; i < sc->adcn; i++) { 2370 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2371 sc->cfg->codec->init(sc->adc[i]); 2372 } 2373 for (i = 0; i < sc->dacn; i++) { 2374 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2375 sc->cfg->codec->init(sc->dac[i]); 2376 } 2377 2378 /* initialize DMA buffer */ 2379 #if(0) 2380 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n"); 2381 #endif 2382 if (envy24ht_dmainit(sc)) 2383 return ENOSPC; 2384 2385 /* initialize status */ 2386 sc->run[0] = sc->run[1] = 0; 2387 sc->intr[0] = sc->intr[1] = 0; 2388 sc->speed = 0; 2389 sc->caps[0].fmtlist = envy24ht_playfmt; 2390 sc->caps[1].fmtlist = envy24ht_recfmt; 2391 2392 /* set channel router */ 2393 #if 0 2394 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2395 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0); 2396 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2397 #endif 2398 2399 /* set macro interrupt mask */ 2400 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2401 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1); 2402 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2403 #if(0) 2404 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data); 2405 #endif 2406 2407 return 0; 2408 } 2409 2410 static int 2411 envy24ht_alloc_resource(struct sc_info *sc) 2412 { 2413 /* allocate I/O port resource */ 2414 sc->csid = PCIR_CCS; 2415 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2416 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2417 sc->mtid = ENVY24HT_PCIR_MT; 2418 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2419 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2420 if (!sc->cs || !sc->mt) { 2421 device_printf(sc->dev, "unable to map IO port space\n"); 2422 return ENXIO; 2423 } 2424 sc->cst = rman_get_bustag(sc->cs); 2425 sc->csh = rman_get_bushandle(sc->cs); 2426 sc->mtt = rman_get_bustag(sc->mt); 2427 sc->mth = rman_get_bushandle(sc->mt); 2428 #if(0) 2429 device_printf(sc->dev, 2430 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n", 2431 pci_read_config(sc->dev, PCIR_CCS, 4), 2432 pci_read_config(sc->dev, PCIR_MT, 4)); 2433 #endif 2434 2435 /* allocate interrupt resource */ 2436 sc->irqid = 0; 2437 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2438 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2439 if (!sc->irq || 2440 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) { 2441 device_printf(sc->dev, "unable to map interrupt\n"); 2442 return ENXIO; 2443 } 2444 2445 /* allocate DMA resource */ 2446 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2447 /*alignment*/4, 2448 /*boundary*/0, 2449 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2450 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2451 /*filter*/NULL, /*filterarg*/NULL, 2452 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2453 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2454 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2455 /*lockarg*/&Giant, &sc->dmat) != 0) { 2456 device_printf(sc->dev, "unable to create dma tag\n"); 2457 return ENXIO; 2458 } 2459 2460 return 0; 2461 } 2462 2463 static int 2464 envy24ht_pci_attach(device_t dev) 2465 { 2466 u_int32_t data; 2467 struct sc_info *sc; 2468 char status[SND_STATUSLEN]; 2469 int err = 0; 2470 int i; 2471 2472 #if(0) 2473 device_printf(dev, "envy24ht_pci_attach()\n"); 2474 #endif 2475 /* get sc_info data area */ 2476 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) { 2477 device_printf(dev, "cannot allocate softc\n"); 2478 return ENXIO; 2479 } 2480 2481 bzero(sc, sizeof(*sc)); 2482 sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2483 "snd_envy24ht softc"); 2484 sc->dev = dev; 2485 2486 /* initialize PCI interface */ 2487 data = pci_read_config(dev, PCIR_COMMAND, 2); 2488 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2489 pci_write_config(dev, PCIR_COMMAND, data, 2); 2490 data = pci_read_config(dev, PCIR_COMMAND, 2); 2491 2492 /* allocate resources */ 2493 err = envy24ht_alloc_resource(sc); 2494 if (err) { 2495 device_printf(dev, "unable to allocate system resources\n"); 2496 goto bad; 2497 } 2498 2499 /* initialize card */ 2500 err = envy24ht_init(sc); 2501 if (err) { 2502 device_printf(dev, "unable to initialize the card\n"); 2503 goto bad; 2504 } 2505 2506 /* set multi track mixer */ 2507 mixer_init(dev, &envy24htmixer_class, sc); 2508 2509 /* set channel information */ 2510 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */ 2511 err = pcm_register(dev, sc, 1, 2 + sc->adcn); 2512 if (err) 2513 goto bad; 2514 sc->chnum = 0; 2515 /* for (i = 0; i < 5; i++) { */ 2516 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc); 2517 sc->chnum++; 2518 /* } */ 2519 for (i = 0; i < 2 + sc->adcn; i++) { 2520 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc); 2521 sc->chnum++; 2522 } 2523 2524 /* set status iformation */ 2525 snprintf(status, SND_STATUSLEN, 2526 "at io 0x%lx:%ld,0x%lx:%ld irq %ld", 2527 rman_get_start(sc->cs), 2528 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2529 rman_get_start(sc->mt), 2530 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2531 rman_get_start(sc->irq)); 2532 pcm_setstatus(dev, status); 2533 2534 return 0; 2535 2536 bad: 2537 if (sc->ih) 2538 bus_teardown_intr(dev, sc->irq, sc->ih); 2539 if (sc->irq) 2540 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2541 envy24ht_dmafree(sc); 2542 if (sc->dmat) 2543 bus_dma_tag_destroy(sc->dmat); 2544 if (sc->cfg->codec->destroy != NULL) { 2545 for (i = 0; i < sc->adcn; i++) 2546 sc->cfg->codec->destroy(sc->adc[i]); 2547 for (i = 0; i < sc->dacn; i++) 2548 sc->cfg->codec->destroy(sc->dac[i]); 2549 } 2550 envy24ht_cfgfree(sc->cfg); 2551 if (sc->cs) 2552 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2553 if (sc->mt) 2554 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2555 if (sc->lock) 2556 snd_mtxfree(sc->lock); 2557 free(sc, M_ENVY24HT); 2558 return err; 2559 } 2560 2561 static int 2562 envy24ht_pci_detach(device_t dev) 2563 { 2564 struct sc_info *sc; 2565 int r; 2566 int i; 2567 2568 #if(0) 2569 device_printf(dev, "envy24ht_pci_detach()\n"); 2570 #endif 2571 sc = pcm_getdevinfo(dev); 2572 if (sc == NULL) 2573 return 0; 2574 r = pcm_unregister(dev); 2575 if (r) 2576 return r; 2577 2578 envy24ht_dmafree(sc); 2579 if (sc->cfg->codec->destroy != NULL) { 2580 for (i = 0; i < sc->adcn; i++) 2581 sc->cfg->codec->destroy(sc->adc[i]); 2582 for (i = 0; i < sc->dacn; i++) 2583 sc->cfg->codec->destroy(sc->dac[i]); 2584 } 2585 envy24ht_cfgfree(sc->cfg); 2586 bus_dma_tag_destroy(sc->dmat); 2587 bus_teardown_intr(dev, sc->irq, sc->ih); 2588 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2589 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2590 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2591 snd_mtxfree(sc->lock); 2592 free(sc, M_ENVY24HT); 2593 return 0; 2594 } 2595 2596 static device_method_t envy24ht_methods[] = { 2597 /* Device interface */ 2598 DEVMETHOD(device_probe, envy24ht_pci_probe), 2599 DEVMETHOD(device_attach, envy24ht_pci_attach), 2600 DEVMETHOD(device_detach, envy24ht_pci_detach), 2601 { 0, 0 } 2602 }; 2603 2604 static driver_t envy24ht_driver = { 2605 "pcm", 2606 envy24ht_methods, 2607 #if __FreeBSD_version > 500000 2608 PCM_SOFTC_SIZE, 2609 #else 2610 sizeof(struct snddev_info), 2611 #endif 2612 }; 2613 2614 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0); 2615 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2616 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1); 2617 MODULE_VERSION(snd_envy24ht, 1); 2618