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