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