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