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