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 regptr, regintr; 1160 u_int32_t mask, intr; 1161 u_int32_t ptr, size, 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 size = sc->psize / 4; 1170 regptr = ENVY24HT_MT_PCNT; 1171 regintr = ENVY24HT_MT_PTERM; 1172 mask = ~ENVY24HT_MT_INT_PMASK; 1173 } 1174 else { 1175 blk = sc->blk[1]; 1176 size = sc->rsize / 4; 1177 regptr = ENVY24HT_MT_RCNT; 1178 regintr = ENVY24HT_MT_RTERM; 1179 mask = ~ENVY24HT_MT_INT_RMASK; 1180 } 1181 1182 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1; 1183 /* 1184 cnt = blk - ptr % blk - 1; 1185 if (cnt == 0) 1186 cnt = blk - 1; 1187 */ 1188 cnt = blk - 1; 1189 #if(0) 1190 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1191 #endif 1192 envy24ht_wrmt(sc, regintr, cnt, 2); 1193 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1194 #if(0) 1195 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1196 #endif 1197 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1); 1198 #if(0) 1199 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n", 1200 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1)); 1201 #endif 1202 1203 return; 1204 } 1205 1206 #if 0 1207 static void 1208 envy24ht_maskintr(struct sc_info *sc, int dir) 1209 { 1210 u_int32_t mask, intr; 1211 1212 #if(0) 1213 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir); 1214 #endif 1215 if (dir == PCMDIR_PLAY) 1216 mask = ENVY24HT_MT_INT_PMASK; 1217 else 1218 mask = ENVY24HT_MT_INT_RMASK; 1219 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1); 1220 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1); 1221 1222 return; 1223 } 1224 #endif 1225 1226 static int 1227 envy24ht_checkintr(struct sc_info *sc, int dir) 1228 { 1229 u_int32_t mask, stat, intr, rtn; 1230 1231 #if(0) 1232 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir); 1233 #endif 1234 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1); 1235 if (dir == PCMDIR_PLAY) { 1236 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) { 1237 mask = ~ENVY24HT_MT_INT_RSTAT; 1238 envy24ht_wrmt(sc, 0x1a, 0x01, 1); 1239 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1); 1240 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1241 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1); 1242 } 1243 } 1244 else { 1245 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) { 1246 mask = ~ENVY24HT_MT_INT_PSTAT; 1247 #if 0 1248 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK; 1249 #endif 1250 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1); 1251 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1252 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1); 1253 } 1254 } 1255 1256 return rtn; 1257 } 1258 1259 static void 1260 envy24ht_start(struct sc_info *sc, int dir) 1261 { 1262 u_int32_t stat, sw; 1263 1264 #if(0) 1265 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir); 1266 #endif 1267 if (dir == PCMDIR_PLAY) 1268 sw = ENVY24HT_MT_PCTL_PSTART; 1269 else 1270 sw = ENVY24HT_MT_PCTL_RSTART; 1271 1272 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1273 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1); 1274 #if(0) 1275 DELAY(100); 1276 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 1277 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 1278 #endif 1279 1280 return; 1281 } 1282 1283 static void 1284 envy24ht_stop(struct sc_info *sc, int dir) 1285 { 1286 u_int32_t stat, sw; 1287 1288 #if(0) 1289 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir); 1290 #endif 1291 if (dir == PCMDIR_PLAY) 1292 sw = ~ENVY24HT_MT_PCTL_PSTART; 1293 else 1294 sw = ~ENVY24HT_MT_PCTL_RSTART; 1295 1296 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1297 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1); 1298 1299 return; 1300 } 1301 1302 #if 0 1303 static int 1304 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1305 { 1306 return 0; 1307 } 1308 #endif 1309 1310 /* -------------------------------------------------------------------- */ 1311 1312 /* buffer copy routines */ 1313 static void 1314 envy24ht_p32sl(struct sc_chinfo *ch) 1315 { 1316 int length; 1317 sample32_t *dmabuf; 1318 u_int32_t *data; 1319 int src, dst, ssize, dsize, slot; 1320 int i; 1321 1322 length = sndbuf_getready(ch->buffer) / 8; 1323 dmabuf = ch->parent->pbuf; 1324 data = (u_int32_t *)ch->data; 1325 src = sndbuf_getreadyptr(ch->buffer) / 4; 1326 dst = src / 2 + ch->offset; 1327 ssize = ch->size / 4; 1328 dsize = ch->size / 8; 1329 slot = ch->num * 2; 1330 1331 for (i = 0; i < length; i++) { 1332 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src]; 1333 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1334 dst++; 1335 dst %= dsize; 1336 src += 2; 1337 src %= ssize; 1338 } 1339 1340 return; 1341 } 1342 1343 static void 1344 envy24ht_p16sl(struct sc_chinfo *ch) 1345 { 1346 int length; 1347 sample32_t *dmabuf; 1348 u_int16_t *data; 1349 int src, dst, ssize, dsize, slot; 1350 int i; 1351 1352 #if(0) 1353 device_printf(ch->parent->dev, "envy24ht_p16sl()\n"); 1354 #endif 1355 length = sndbuf_getready(ch->buffer) / 4; 1356 dmabuf = ch->parent->pbuf; 1357 data = (u_int16_t *)ch->data; 1358 src = sndbuf_getreadyptr(ch->buffer) / 2; 1359 dst = src / 2 + ch->offset; 1360 ssize = ch->size / 2; 1361 dsize = ch->size / 4; 1362 slot = ch->num * 2; 1363 #if(0) 1364 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1365 #endif 1366 1367 for (i = 0; i < length; i++) { 1368 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1369 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1370 #if(0) 1371 if (i < 16) { 1372 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]); 1373 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]); 1374 } 1375 #endif 1376 dst++; 1377 dst %= dsize; 1378 src += 2; 1379 src %= ssize; 1380 } 1381 #if(0) 1382 printf("\n"); 1383 #endif 1384 1385 return; 1386 } 1387 1388 static void 1389 envy24ht_p8u(struct sc_chinfo *ch) 1390 { 1391 int length; 1392 sample32_t *dmabuf; 1393 u_int8_t *data; 1394 int src, dst, ssize, dsize, slot; 1395 int i; 1396 1397 length = sndbuf_getready(ch->buffer) / 2; 1398 dmabuf = ch->parent->pbuf; 1399 data = (u_int8_t *)ch->data; 1400 src = sndbuf_getreadyptr(ch->buffer); 1401 dst = src / 2 + ch->offset; 1402 ssize = ch->size; 1403 dsize = ch->size / 4; 1404 slot = ch->num * 2; 1405 1406 for (i = 0; i < length; i++) { 1407 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1408 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1409 dst++; 1410 dst %= dsize; 1411 src += 2; 1412 src %= ssize; 1413 } 1414 1415 return; 1416 } 1417 1418 static void 1419 envy24ht_r32sl(struct sc_chinfo *ch) 1420 { 1421 int length; 1422 sample32_t *dmabuf; 1423 u_int32_t *data; 1424 int src, dst, ssize, dsize, slot; 1425 int i; 1426 1427 length = sndbuf_getfree(ch->buffer) / 8; 1428 dmabuf = ch->parent->rbuf; 1429 data = (u_int32_t *)ch->data; 1430 dst = sndbuf_getfreeptr(ch->buffer) / 4; 1431 src = dst / 2 + ch->offset; 1432 dsize = ch->size / 4; 1433 ssize = ch->size / 8; 1434 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1435 1436 for (i = 0; i < length; i++) { 1437 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1438 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1439 dst += 2; 1440 dst %= dsize; 1441 src++; 1442 src %= ssize; 1443 } 1444 1445 return; 1446 } 1447 1448 static void 1449 envy24ht_r16sl(struct sc_chinfo *ch) 1450 { 1451 int length; 1452 sample32_t *dmabuf; 1453 u_int16_t *data; 1454 int src, dst, ssize, dsize, slot; 1455 int i; 1456 1457 length = sndbuf_getfree(ch->buffer) / 4; 1458 dmabuf = ch->parent->rbuf; 1459 data = (u_int16_t *)ch->data; 1460 dst = sndbuf_getfreeptr(ch->buffer) / 2; 1461 src = dst / 2 + ch->offset; 1462 dsize = ch->size / 2; 1463 ssize = ch->size / 8; 1464 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1465 1466 for (i = 0; i < length; i++) { 1467 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1468 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1469 dst += 2; 1470 dst %= dsize; 1471 src++; 1472 src %= ssize; 1473 } 1474 1475 return; 1476 } 1477 1478 /* -------------------------------------------------------------------- */ 1479 1480 /* channel interface */ 1481 static void * 1482 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1483 { 1484 struct sc_info *sc = (struct sc_info *)devinfo; 1485 struct sc_chinfo *ch; 1486 unsigned num; 1487 1488 #if(0) 1489 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir); 1490 #endif 1491 snd_mtxlock(sc->lock); 1492 #if 0 1493 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1494 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1495 snd_mtxunlock(sc->lock); 1496 return NULL; 1497 } 1498 #endif 1499 num = sc->chnum; 1500 1501 ch = &sc->chan[num]; 1502 ch->size = 8 * ENVY24HT_SAMPLE_NUM; 1503 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT); 1504 if (ch->data == NULL) { 1505 ch->size = 0; 1506 ch = NULL; 1507 } 1508 else { 1509 ch->buffer = b; 1510 ch->channel = c; 1511 ch->parent = sc; 1512 ch->dir = dir; 1513 /* set channel map */ 1514 ch->num = envy24ht_chanmap[num]; 1515 snd_mtxunlock(sc->lock); 1516 sndbuf_setup(ch->buffer, ch->data, ch->size); 1517 snd_mtxlock(sc->lock); 1518 /* these 2 values are dummy */ 1519 ch->unit = 4; 1520 ch->blk = 10240; 1521 } 1522 snd_mtxunlock(sc->lock); 1523 1524 return ch; 1525 } 1526 1527 static int 1528 envy24htchan_free(kobj_t obj, void *data) 1529 { 1530 struct sc_chinfo *ch = data; 1531 struct sc_info *sc = ch->parent; 1532 1533 #if(0) 1534 device_printf(sc->dev, "envy24htchan_free()\n"); 1535 #endif 1536 snd_mtxlock(sc->lock); 1537 if (ch->data != NULL) { 1538 free(ch->data, M_ENVY24HT); 1539 ch->data = NULL; 1540 } 1541 snd_mtxunlock(sc->lock); 1542 1543 return 0; 1544 } 1545 1546 static int 1547 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format) 1548 { 1549 struct sc_chinfo *ch = data; 1550 struct sc_info *sc = ch->parent; 1551 struct envy24ht_emldma *emltab; 1552 /* unsigned int bcnt, bsize; */ 1553 int i; 1554 1555 #if(0) 1556 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format); 1557 #endif 1558 snd_mtxlock(sc->lock); 1559 /* check and get format related information */ 1560 if (ch->dir == PCMDIR_PLAY) 1561 emltab = envy24ht_pemltab; 1562 else 1563 emltab = envy24ht_remltab; 1564 if (emltab == NULL) { 1565 snd_mtxunlock(sc->lock); 1566 return -1; 1567 } 1568 for (i = 0; emltab[i].format != 0; i++) 1569 if (emltab[i].format == format) 1570 break; 1571 if (emltab[i].format == 0) { 1572 snd_mtxunlock(sc->lock); 1573 return -1; 1574 } 1575 1576 /* set format information */ 1577 ch->format = format; 1578 ch->emldma = emltab[i].emldma; 1579 if (ch->unit > emltab[i].unit) 1580 ch->blk *= ch->unit / emltab[i].unit; 1581 else 1582 ch->blk /= emltab[i].unit / ch->unit; 1583 ch->unit = emltab[i].unit; 1584 1585 /* set channel buffer information */ 1586 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; 1587 #if 0 1588 if (ch->dir == PCMDIR_PLAY) 1589 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1590 else 1591 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1592 bsize *= ch->unit; 1593 bcnt = ch->size / bsize; 1594 sndbuf_resize(ch->buffer, bcnt, bsize); 1595 #endif 1596 snd_mtxunlock(sc->lock); 1597 1598 #if(0) 1599 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0); 1600 #endif 1601 return 0; 1602 } 1603 1604 /* 1605 IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1606 of speed information value. And real hardware speed setting is done 1607 at start triggered(see envy24htchan_trigger()). So, at this function 1608 is called, any value that ENVY24 can use is able to set. But, at 1609 start triggerd, some other channel is running, and that channel's 1610 speed isn't same with, then trigger function will fail. 1611 */ 1612 static u_int32_t 1613 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1614 { 1615 struct sc_chinfo *ch = data; 1616 u_int32_t val, prev; 1617 int i; 1618 1619 #if(0) 1620 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed); 1621 #endif 1622 prev = 0x7fffffff; 1623 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) { 1624 if (abs(val - speed) < abs(prev - speed)) 1625 prev = val; 1626 else 1627 break; 1628 } 1629 ch->speed = prev; 1630 1631 #if(0) 1632 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed); 1633 #endif 1634 return ch->speed; 1635 } 1636 1637 static u_int32_t 1638 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1639 { 1640 struct sc_chinfo *ch = data; 1641 /* struct sc_info *sc = ch->parent; */ 1642 u_int32_t size, prev; 1643 unsigned int bcnt, bsize; 1644 1645 #if(0) 1646 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize); 1647 #endif 1648 prev = 0x7fffffff; 1649 /* snd_mtxlock(sc->lock); */ 1650 for (size = ch->size / 2; size > 0; size /= 2) { 1651 if (abs(size - blocksize) < abs(prev - blocksize)) 1652 prev = size; 1653 else 1654 break; 1655 } 1656 1657 ch->blk = prev / ch->unit; 1658 if (ch->dir == PCMDIR_PLAY) 1659 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4; 1660 else 1661 ch->blk *= ENVY24HT_REC_BUFUNIT / 4; 1662 /* set channel buffer information */ 1663 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */ 1664 if (ch->dir == PCMDIR_PLAY) 1665 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1666 else 1667 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1668 bsize *= ch->unit; 1669 bcnt = ch->size / bsize; 1670 sndbuf_resize(ch->buffer, bcnt, bsize); 1671 /* snd_mtxunlock(sc->lock); */ 1672 1673 #if(0) 1674 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev); 1675 #endif 1676 return prev; 1677 } 1678 1679 /* semantic note: must start at beginning of buffer */ 1680 static int 1681 envy24htchan_trigger(kobj_t obj, void *data, int go) 1682 { 1683 struct sc_chinfo *ch = data; 1684 struct sc_info *sc = ch->parent; 1685 u_int32_t ptr; 1686 int slot; 1687 int error = 0; 1688 #if 0 1689 int i; 1690 1691 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go); 1692 #endif 1693 snd_mtxlock(sc->lock); 1694 if (ch->dir == PCMDIR_PLAY) 1695 slot = 0; 1696 else 1697 slot = 1; 1698 switch (go) { 1699 case PCMTRIG_START: 1700 #if(0) 1701 device_printf(sc->dev, "envy24htchan_trigger(): start\n"); 1702 #endif 1703 /* check or set channel speed */ 1704 if (sc->run[0] == 0 && sc->run[1] == 0) { 1705 sc->speed = envy24ht_setspeed(sc, ch->speed); 1706 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1707 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1708 } 1709 else if (ch->speed != 0 && ch->speed != sc->speed) { 1710 error = -1; 1711 goto fail; 1712 } 1713 if (ch->speed == 0) 1714 ch->channel->speed = sc->speed; 1715 /* start or enable channel */ 1716 sc->run[slot]++; 1717 if (sc->run[slot] == 1) { 1718 /* first channel */ 1719 ch->offset = 0; 1720 sc->blk[slot] = ch->blk; 1721 } 1722 else { 1723 ptr = envy24ht_gethwptr(sc, ch->dir); 1724 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1725 (ch->size / 4)) * 4 / ch->unit; 1726 if (ch->blk < sc->blk[slot]) 1727 sc->blk[slot] = ch->blk; 1728 } 1729 if (ch->dir == PCMDIR_PLAY) { 1730 ch->emldma(ch); 1731 envy24ht_setvolume(sc, ch->num); 1732 } 1733 envy24ht_updintr(sc, ch->dir); 1734 if (sc->run[slot] == 1) 1735 envy24ht_start(sc, ch->dir); 1736 ch->run = 1; 1737 break; 1738 case PCMTRIG_EMLDMAWR: 1739 #if(0) 1740 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n"); 1741 #endif 1742 if (ch->run != 1) { 1743 error = -1; 1744 goto fail; 1745 } 1746 ch->emldma(ch); 1747 break; 1748 case PCMTRIG_EMLDMARD: 1749 #if(0) 1750 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n"); 1751 #endif 1752 if (ch->run != 1) { 1753 error = -1; 1754 goto fail; 1755 } 1756 ch->emldma(ch); 1757 break; 1758 case PCMTRIG_ABORT: 1759 if (ch->run) { 1760 #if(0) 1761 device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); 1762 #endif 1763 ch->run = 0; 1764 sc->run[slot]--; 1765 if (ch->dir == PCMDIR_PLAY) 1766 envy24ht_mutevolume(sc, ch->num); 1767 if (sc->run[slot] == 0) { 1768 envy24ht_stop(sc, ch->dir); 1769 sc->intr[slot] = 0; 1770 } 1771 /* else if (ch->blk == sc->blk[slot]) { 1772 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2; 1773 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) { 1774 if (sc->chan[i].dir == ch->dir && 1775 sc->chan[i].run == 1 && 1776 sc->chan[i].blk < sc->blk[slot]) 1777 sc->blk[slot] = sc->chan[i].blk; 1778 } 1779 if (ch->blk != sc->blk[slot]) 1780 envy24ht_updintr(sc, ch->dir); 1781 }*/ 1782 } 1783 break; 1784 } 1785 fail: 1786 snd_mtxunlock(sc->lock); 1787 return (error); 1788 } 1789 1790 static u_int32_t 1791 envy24htchan_getptr(kobj_t obj, void *data) 1792 { 1793 struct sc_chinfo *ch = data; 1794 struct sc_info *sc = ch->parent; 1795 u_int32_t ptr, rtn; 1796 1797 #if(0) 1798 device_printf(sc->dev, "envy24htchan_getptr()\n"); 1799 #endif 1800 snd_mtxlock(sc->lock); 1801 ptr = envy24ht_gethwptr(sc, ch->dir); 1802 rtn = ptr * ch->unit; 1803 snd_mtxunlock(sc->lock); 1804 1805 #if(0) 1806 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n", 1807 rtn); 1808 #endif 1809 return rtn; 1810 } 1811 1812 static struct pcmchan_caps * 1813 envy24htchan_getcaps(kobj_t obj, void *data) 1814 { 1815 struct sc_chinfo *ch = data; 1816 struct sc_info *sc = ch->parent; 1817 struct pcmchan_caps *rtn; 1818 1819 #if(0) 1820 device_printf(sc->dev, "envy24htchan_getcaps()\n"); 1821 #endif 1822 snd_mtxlock(sc->lock); 1823 if (ch->dir == PCMDIR_PLAY) { 1824 if (sc->run[0] == 0) 1825 rtn = &envy24ht_playcaps; 1826 else 1827 rtn = &sc->caps[0]; 1828 } 1829 else { 1830 if (sc->run[1] == 0) 1831 rtn = &envy24ht_reccaps; 1832 else 1833 rtn = &sc->caps[1]; 1834 } 1835 snd_mtxunlock(sc->lock); 1836 1837 return rtn; 1838 } 1839 1840 static kobj_method_t envy24htchan_methods[] = { 1841 KOBJMETHOD(channel_init, envy24htchan_init), 1842 KOBJMETHOD(channel_free, envy24htchan_free), 1843 KOBJMETHOD(channel_setformat, envy24htchan_setformat), 1844 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed), 1845 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize), 1846 KOBJMETHOD(channel_trigger, envy24htchan_trigger), 1847 KOBJMETHOD(channel_getptr, envy24htchan_getptr), 1848 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps), 1849 KOBJMETHOD_END 1850 }; 1851 CHANNEL_DECLARE(envy24htchan); 1852 1853 /* -------------------------------------------------------------------- */ 1854 1855 /* mixer interface */ 1856 1857 static int 1858 envy24htmixer_init(struct snd_mixer *m) 1859 { 1860 struct sc_info *sc = mix_getdevinfo(m); 1861 1862 #if(0) 1863 device_printf(sc->dev, "envy24htmixer_init()\n"); 1864 #endif 1865 if (sc == NULL) 1866 return -1; 1867 1868 /* set volume control rate */ 1869 snd_mtxlock(sc->lock); 1870 #if 0 1871 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1872 #endif 1873 1874 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL); 1875 1876 mix_setdevs(m, ENVY24HT_MIX_MASK); 1877 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); 1878 1879 snd_mtxunlock(sc->lock); 1880 1881 return 0; 1882 } 1883 1884 static int 1885 envy24htmixer_reinit(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_reinit()\n"); 1893 #endif 1894 1895 return 0; 1896 } 1897 1898 static int 1899 envy24htmixer_uninit(struct snd_mixer *m) 1900 { 1901 struct sc_info *sc = mix_getdevinfo(m); 1902 1903 if (sc == NULL) 1904 return -1; 1905 #if(0) 1906 device_printf(sc->dev, "envy24htmixer_uninit()\n"); 1907 #endif 1908 1909 return 0; 1910 } 1911 1912 static int 1913 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1914 { 1915 struct sc_info *sc = mix_getdevinfo(m); 1916 int ch = envy24ht_mixmap[dev]; 1917 int hwch; 1918 int i; 1919 1920 if (sc == NULL) 1921 return -1; 1922 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1923 return -1; 1924 if (dev != 0 && ch == -1) 1925 return -1; 1926 hwch = envy24ht_chanmap[ch]; 1927 #if(0) 1928 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n", 1929 dev, left, right); 1930 #endif 1931 1932 snd_mtxlock(sc->lock); 1933 if (dev == 0) { 1934 for (i = 0; i < sc->dacn; i++) { 1935 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1936 } 1937 } 1938 else { 1939 /* set volume value for hardware */ 1940 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN) 1941 sc->left[hwch] = ENVY24HT_VOL_MUTE; 1942 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN) 1943 sc->right[hwch] = ENVY24HT_VOL_MUTE; 1944 1945 /* set volume for record channel and running play channel */ 1946 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1947 envy24ht_setvolume(sc, hwch); 1948 } 1949 snd_mtxunlock(sc->lock); 1950 1951 return right << 8 | left; 1952 } 1953 1954 static u_int32_t 1955 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1956 { 1957 struct sc_info *sc = mix_getdevinfo(m); 1958 int ch = envy24ht_mixmap[src]; 1959 #if(0) 1960 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src); 1961 #endif 1962 1963 if (ch > ENVY24HT_CHAN_PLAY_SPDIF) 1964 sc->src = ch; 1965 return src; 1966 } 1967 1968 static kobj_method_t envy24htmixer_methods[] = { 1969 KOBJMETHOD(mixer_init, envy24htmixer_init), 1970 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit), 1971 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit), 1972 KOBJMETHOD(mixer_set, envy24htmixer_set), 1973 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc), 1974 KOBJMETHOD_END 1975 }; 1976 MIXER_DECLARE(envy24htmixer); 1977 1978 /* -------------------------------------------------------------------- */ 1979 1980 /* The interrupt handler */ 1981 static void 1982 envy24ht_intr(void *p) 1983 { 1984 struct sc_info *sc = (struct sc_info *)p; 1985 struct sc_chinfo *ch; 1986 u_int32_t ptr, dsize, feed; 1987 int i; 1988 1989 #if(0) 1990 device_printf(sc->dev, "envy24ht_intr()\n"); 1991 #endif 1992 snd_mtxlock(sc->lock); 1993 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) { 1994 #if(0) 1995 device_printf(sc->dev, "envy24ht_intr(): play\n"); 1996 #endif 1997 dsize = sc->psize / 4; 1998 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1; 1999 #if(0) 2000 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr); 2001 #endif 2002 ptr -= ptr % sc->blk[0]; 2003 feed = (ptr + dsize - sc->intr[0]) % dsize; 2004 #if(0) 2005 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 2006 #endif 2007 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) { 2008 ch = &sc->chan[i]; 2009 #if(0) 2010 if (ch->run) 2011 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk); 2012 #endif 2013 if (ch->run && ch->blk <= feed) { 2014 snd_mtxunlock(sc->lock); 2015 chn_intr(ch->channel); 2016 snd_mtxlock(sc->lock); 2017 } 2018 } 2019 sc->intr[0] = ptr; 2020 envy24ht_updintr(sc, PCMDIR_PLAY); 2021 } 2022 if (envy24ht_checkintr(sc, PCMDIR_REC)) { 2023 #if(0) 2024 device_printf(sc->dev, "envy24ht_intr(): rec\n"); 2025 #endif 2026 dsize = sc->rsize / 4; 2027 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1; 2028 ptr -= ptr % sc->blk[1]; 2029 feed = (ptr + dsize - sc->intr[1]) % dsize; 2030 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) { 2031 ch = &sc->chan[i]; 2032 if (ch->run && ch->blk <= feed) { 2033 snd_mtxunlock(sc->lock); 2034 chn_intr(ch->channel); 2035 snd_mtxlock(sc->lock); 2036 } 2037 } 2038 sc->intr[1] = ptr; 2039 envy24ht_updintr(sc, PCMDIR_REC); 2040 } 2041 snd_mtxunlock(sc->lock); 2042 2043 return; 2044 } 2045 2046 /* 2047 * Probe and attach the card 2048 */ 2049 2050 static int 2051 envy24ht_pci_probe(device_t dev) 2052 { 2053 u_int16_t sv, sd; 2054 int i; 2055 2056 #if(0) 2057 printf("envy24ht_pci_probe()\n"); 2058 #endif 2059 if (pci_get_device(dev) == PCID_ENVY24HT && 2060 pci_get_vendor(dev) == PCIV_ENVY24) { 2061 sv = pci_get_subvendor(dev); 2062 sd = pci_get_subdevice(dev); 2063 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2064 if (cfg_table[i].subvendor == sv && 2065 cfg_table[i].subdevice == sd) { 2066 break; 2067 } 2068 } 2069 device_set_desc(dev, cfg_table[i].name); 2070 #if(0) 2071 printf("envy24ht_pci_probe(): return 0\n"); 2072 #endif 2073 return 0; 2074 } 2075 else { 2076 #if(0) 2077 printf("envy24ht_pci_probe(): return ENXIO\n"); 2078 #endif 2079 return ENXIO; 2080 } 2081 } 2082 2083 static void 2084 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2085 { 2086 struct sc_info *sc = arg; 2087 2088 sc->paddr = segs->ds_addr; 2089 #if(0) 2090 device_printf(sc->dev, "envy24ht_dmapsetmap()\n"); 2091 if (bootverbose) { 2092 printf("envy24ht(play): setmap %lx, %lx; ", 2093 (unsigned long)segs->ds_addr, 2094 (unsigned long)segs->ds_len); 2095 } 2096 #endif 2097 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4); 2098 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2); 2099 } 2100 2101 static void 2102 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2103 { 2104 struct sc_info *sc = arg; 2105 2106 sc->raddr = segs->ds_addr; 2107 #if(0) 2108 device_printf(sc->dev, "envy24ht_dmarsetmap()\n"); 2109 if (bootverbose) { 2110 printf("envy24ht(record): setmap %lx, %lx; ", 2111 (unsigned long)segs->ds_addr, 2112 (unsigned long)segs->ds_len); 2113 } 2114 #endif 2115 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4); 2116 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2); 2117 } 2118 2119 static void 2120 envy24ht_dmafree(struct sc_info *sc) 2121 { 2122 #if(0) 2123 device_printf(sc->dev, "envy24ht_dmafree():"); 2124 printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr); 2125 printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr); 2126 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2127 else printf(" sc->rbuf(null)"); 2128 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2129 else printf(" sc->pbuf(null)\n"); 2130 #endif 2131 #if(0) 2132 if (sc->raddr) 2133 bus_dmamap_unload(sc->dmat, sc->rmap); 2134 if (sc->paddr) 2135 bus_dmamap_unload(sc->dmat, sc->pmap); 2136 if (sc->rbuf) 2137 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2138 if (sc->pbuf) 2139 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2140 #else 2141 bus_dmamap_unload(sc->dmat, sc->rmap); 2142 bus_dmamap_unload(sc->dmat, sc->pmap); 2143 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2144 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2145 #endif 2146 2147 sc->raddr = sc->paddr = 0; 2148 sc->pbuf = NULL; 2149 sc->rbuf = NULL; 2150 2151 return; 2152 } 2153 2154 static int 2155 envy24ht_dmainit(struct sc_info *sc) 2156 { 2157 2158 #if(0) 2159 device_printf(sc->dev, "envy24ht_dmainit()\n"); 2160 #endif 2161 /* init values */ 2162 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2163 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2164 sc->pbuf = NULL; 2165 sc->rbuf = NULL; 2166 sc->paddr = sc->raddr = 0; 2167 sc->blk[0] = sc->blk[1] = 0; 2168 2169 /* allocate DMA buffer */ 2170 #if(0) 2171 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2172 #endif 2173 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2174 goto bad; 2175 #if(0) 2176 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2177 #endif 2178 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2179 goto bad; 2180 #if(0) 2181 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2182 #endif 2183 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT)) 2184 goto bad; 2185 #if(0) 2186 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2187 #endif 2188 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT)) 2189 goto bad; 2190 bzero(sc->pbuf, sc->psize); 2191 bzero(sc->rbuf, sc->rsize); 2192 2193 return 0; 2194 bad: 2195 envy24ht_dmafree(sc); 2196 return ENOSPC; 2197 } 2198 2199 static void 2200 envy24ht_putcfg(struct sc_info *sc) 2201 { 2202 device_printf(sc->dev, "system configuration\n"); 2203 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2204 sc->cfg->subvendor, sc->cfg->subdevice); 2205 printf(" XIN2 Clock Source: "); 2206 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) { 2207 case 0x00: 2208 printf("24.576MHz(96kHz*256)\n"); 2209 break; 2210 case 0x40: 2211 printf("49.152MHz(192kHz*256)\n"); 2212 break; 2213 case 0x80: 2214 printf("reserved\n"); 2215 break; 2216 default: 2217 printf("illegal system setting\n"); 2218 } 2219 printf(" MPU-401 UART(s) #: "); 2220 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU) 2221 printf("1\n"); 2222 else 2223 printf("not implemented\n"); 2224 switch (sc->adcn) { 2225 case 0x01: 2226 case 0x02: 2227 printf(" ADC #: "); 2228 printf("%d\n", sc->adcn); 2229 break; 2230 case 0x03: 2231 printf(" ADC #: "); 2232 printf("%d", 1); 2233 printf(" and SPDIF receiver connected\n"); 2234 break; 2235 default: 2236 printf(" no physical inputs\n"); 2237 } 2238 printf(" DAC #: "); 2239 printf("%d\n", sc->dacn); 2240 printf(" Multi-track converter type: "); 2241 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) { 2242 printf("AC'97(SDATA_OUT:"); 2243 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE) 2244 printf("packed"); 2245 else 2246 printf("split"); 2247 printf(")\n"); 2248 } 2249 else { 2250 printf("I2S("); 2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL) 2252 printf("with volume, "); 2253 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ) 2254 printf("192KHz support, "); 2255 else 2256 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ) 2257 printf("192KHz support, "); 2258 else 2259 printf("48KHz support, "); 2260 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) { 2261 case ENVY24HT_CCSM_I2S_16BIT: 2262 printf("16bit resolution, "); 2263 break; 2264 case ENVY24HT_CCSM_I2S_18BIT: 2265 printf("18bit resolution, "); 2266 break; 2267 case ENVY24HT_CCSM_I2S_20BIT: 2268 printf("20bit resolution, "); 2269 break; 2270 case ENVY24HT_CCSM_I2S_24BIT: 2271 printf("24bit resolution, "); 2272 break; 2273 } 2274 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID); 2275 } 2276 printf(" S/PDIF(IN/OUT): "); 2277 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN) 2278 printf("1/"); 2279 else 2280 printf("0/"); 2281 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT) 2282 printf("1 "); 2283 else 2284 printf("0 "); 2285 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT)) 2286 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2); 2287 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2288 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2289 } 2290 2291 static int 2292 envy24ht_init(struct sc_info *sc) 2293 { 2294 u_int32_t data; 2295 #if(0) 2296 int rtn; 2297 #endif 2298 int i; 2299 u_int32_t sv, sd; 2300 2301 2302 #if(0) 2303 device_printf(sc->dev, "envy24ht_init()\n"); 2304 #endif 2305 2306 /* reset chip */ 2307 #if 0 2308 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1); 2309 DELAY(200); 2310 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1); 2311 DELAY(200); 2312 2313 /* legacy hardware disable */ 2314 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2315 data |= PCIM_LAC_DISABLE; 2316 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2317 #endif 2318 2319 /* check system configuration */ 2320 sc->cfg = NULL; 2321 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2322 /* 1st: search configuration from table */ 2323 sv = pci_get_subvendor(sc->dev); 2324 sd = pci_get_subdevice(sc->dev); 2325 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2326 #if(0) 2327 device_printf(sc->dev, "Set configuration from table\n"); 2328 #endif 2329 sc->cfg = &cfg_table[i]; 2330 break; 2331 } 2332 } 2333 if (sc->cfg == NULL) { 2334 /* 2nd: read configuration from table */ 2335 sc->cfg = envy24ht_rom2cfg(sc); 2336 } 2337 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */ 2338 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1; 2339 2340 if (1 /* bootverbose */) { 2341 envy24ht_putcfg(sc); 2342 } 2343 2344 /* set system configuration */ 2345 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1); 2346 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1); 2347 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1); 2348 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1); 2349 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); 2350 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); 2351 envy24ht_gpiowr(sc, sc->cfg->gpiostate); 2352 2353 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { 2354 envy24ht_wri2c(sc, 0x22, 0x00, 0x07); 2355 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); 2356 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); 2357 } 2358 2359 for (i = 0; i < sc->adcn; i++) { 2360 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2361 sc->cfg->codec->init(sc->adc[i]); 2362 } 2363 for (i = 0; i < sc->dacn; i++) { 2364 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2365 sc->cfg->codec->init(sc->dac[i]); 2366 } 2367 2368 /* initialize DMA buffer */ 2369 #if(0) 2370 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n"); 2371 #endif 2372 if (envy24ht_dmainit(sc)) 2373 return ENOSPC; 2374 2375 /* initialize status */ 2376 sc->run[0] = sc->run[1] = 0; 2377 sc->intr[0] = sc->intr[1] = 0; 2378 sc->speed = 0; 2379 sc->caps[0].fmtlist = envy24ht_playfmt; 2380 sc->caps[1].fmtlist = envy24ht_recfmt; 2381 2382 /* set channel router */ 2383 #if 0 2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2385 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0); 2386 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2387 #endif 2388 2389 /* set macro interrupt mask */ 2390 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2391 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1); 2392 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2393 #if(0) 2394 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data); 2395 #endif 2396 2397 return 0; 2398 } 2399 2400 static int 2401 envy24ht_alloc_resource(struct sc_info *sc) 2402 { 2403 /* allocate I/O port resource */ 2404 sc->csid = PCIR_CCS; 2405 sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT, 2406 &sc->csid, RF_ACTIVE); 2407 sc->mtid = ENVY24HT_PCIR_MT; 2408 sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT, 2409 &sc->mtid, RF_ACTIVE); 2410 if (!sc->cs || !sc->mt) { 2411 device_printf(sc->dev, "unable to map IO port space\n"); 2412 return ENXIO; 2413 } 2414 sc->cst = rman_get_bustag(sc->cs); 2415 sc->csh = rman_get_bushandle(sc->cs); 2416 sc->mtt = rman_get_bustag(sc->mt); 2417 sc->mth = rman_get_bushandle(sc->mt); 2418 #if(0) 2419 device_printf(sc->dev, 2420 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n", 2421 pci_read_config(sc->dev, PCIR_CCS, 4), 2422 pci_read_config(sc->dev, PCIR_MT, 4)); 2423 #endif 2424 2425 /* allocate interrupt resource */ 2426 sc->irqid = 0; 2427 sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid, 2428 RF_ACTIVE | RF_SHAREABLE); 2429 if (!sc->irq || 2430 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) { 2431 device_printf(sc->dev, "unable to map interrupt\n"); 2432 return ENXIO; 2433 } 2434 2435 /* allocate DMA resource */ 2436 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2437 /*alignment*/4, 2438 /*boundary*/0, 2439 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 2440 /*highaddr*/BUS_SPACE_MAXADDR, 2441 /*filter*/NULL, /*filterarg*/NULL, 2442 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2443 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2444 /*flags*/0, /*lockfunc*/NULL, 2445 /*lockarg*/NULL, &sc->dmat) != 0) { 2446 device_printf(sc->dev, "unable to create dma tag\n"); 2447 return ENXIO; 2448 } 2449 2450 return 0; 2451 } 2452 2453 static int 2454 envy24ht_pci_attach(device_t dev) 2455 { 2456 struct sc_info *sc; 2457 char status[SND_STATUSLEN]; 2458 int err = 0; 2459 int i; 2460 2461 #if(0) 2462 device_printf(dev, "envy24ht_pci_attach()\n"); 2463 #endif 2464 /* get sc_info data area */ 2465 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) { 2466 device_printf(dev, "cannot allocate softc\n"); 2467 return ENXIO; 2468 } 2469 2470 bzero(sc, sizeof(*sc)); 2471 sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2472 "snd_envy24ht softc"); 2473 sc->dev = dev; 2474 2475 /* initialize PCI interface */ 2476 pci_enable_busmaster(dev); 2477 2478 /* allocate resources */ 2479 err = envy24ht_alloc_resource(sc); 2480 if (err) { 2481 device_printf(dev, "unable to allocate system resources\n"); 2482 goto bad; 2483 } 2484 2485 /* initialize card */ 2486 err = envy24ht_init(sc); 2487 if (err) { 2488 device_printf(dev, "unable to initialize the card\n"); 2489 goto bad; 2490 } 2491 2492 /* set multi track mixer */ 2493 mixer_init(dev, &envy24htmixer_class, sc); 2494 2495 /* set channel information */ 2496 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */ 2497 err = pcm_register(dev, sc, 1, 2 + sc->adcn); 2498 if (err) 2499 goto bad; 2500 sc->chnum = 0; 2501 /* for (i = 0; i < 5; i++) { */ 2502 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc); 2503 sc->chnum++; 2504 /* } */ 2505 for (i = 0; i < 2 + sc->adcn; i++) { 2506 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc); 2507 sc->chnum++; 2508 } 2509 2510 /* set status iformation */ 2511 snprintf(status, SND_STATUSLEN, 2512 "at io 0x%jx:%jd,0x%jx:%jd irq %jd", 2513 rman_get_start(sc->cs), 2514 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2515 rman_get_start(sc->mt), 2516 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2517 rman_get_start(sc->irq)); 2518 pcm_setstatus(dev, status); 2519 2520 return 0; 2521 2522 bad: 2523 if (sc->ih) 2524 bus_teardown_intr(dev, sc->irq, sc->ih); 2525 if (sc->irq) 2526 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2527 envy24ht_dmafree(sc); 2528 if (sc->dmat) 2529 bus_dma_tag_destroy(sc->dmat); 2530 if (sc->cfg->codec->destroy != NULL) { 2531 for (i = 0; i < sc->adcn; i++) 2532 sc->cfg->codec->destroy(sc->adc[i]); 2533 for (i = 0; i < sc->dacn; i++) 2534 sc->cfg->codec->destroy(sc->dac[i]); 2535 } 2536 envy24ht_cfgfree(sc->cfg); 2537 if (sc->cs) 2538 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2539 if (sc->mt) 2540 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2541 if (sc->lock) 2542 snd_mtxfree(sc->lock); 2543 free(sc, M_ENVY24HT); 2544 return err; 2545 } 2546 2547 static int 2548 envy24ht_pci_detach(device_t dev) 2549 { 2550 struct sc_info *sc; 2551 int r; 2552 int i; 2553 2554 #if(0) 2555 device_printf(dev, "envy24ht_pci_detach()\n"); 2556 #endif 2557 sc = pcm_getdevinfo(dev); 2558 if (sc == NULL) 2559 return 0; 2560 r = pcm_unregister(dev); 2561 if (r) 2562 return r; 2563 2564 envy24ht_dmafree(sc); 2565 if (sc->cfg->codec->destroy != NULL) { 2566 for (i = 0; i < sc->adcn; i++) 2567 sc->cfg->codec->destroy(sc->adc[i]); 2568 for (i = 0; i < sc->dacn; i++) 2569 sc->cfg->codec->destroy(sc->dac[i]); 2570 } 2571 envy24ht_cfgfree(sc->cfg); 2572 bus_dma_tag_destroy(sc->dmat); 2573 bus_teardown_intr(dev, sc->irq, sc->ih); 2574 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2575 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2576 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2577 snd_mtxfree(sc->lock); 2578 free(sc, M_ENVY24HT); 2579 return 0; 2580 } 2581 2582 static device_method_t envy24ht_methods[] = { 2583 /* Device interface */ 2584 DEVMETHOD(device_probe, envy24ht_pci_probe), 2585 DEVMETHOD(device_attach, envy24ht_pci_attach), 2586 DEVMETHOD(device_detach, envy24ht_pci_detach), 2587 { 0, 0 } 2588 }; 2589 2590 static driver_t envy24ht_driver = { 2591 "pcm", 2592 envy24ht_methods, 2593 PCM_SOFTC_SIZE, 2594 }; 2595 2596 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0); 2597 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2598 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1); 2599 MODULE_VERSION(snd_envy24ht, 1); 2600