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.2 2007/06/16 20:07:19 dillon 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.2 2007/06/16 20:07:19 dillon 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_NOWAIT); 620 if (buff == NULL) { 621 #if(0) 622 device_printf(sc->dev, "envy24ht_rom2cfg(): kmalloc()\n"); 623 #endif 624 return NULL; 625 } 626 buff->free = 1; 627 628 /* no valid e2prom, using default values */ 629 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8; 630 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1); 631 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8; 632 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1); 633 buff->scfg = 0x0b; 634 buff->acl = 0x80; 635 buff->i2s = 0xfc; 636 buff->spdif = 0xc3; 637 buff->gpiomask = 0x21efff; 638 buff->gpiostate = 0x7fffff; 639 buff->gpiodir = 0x5e1000; 640 buff->cdti = 0x40000; 641 buff->cclk = 0x80000; 642 buff->cs = 0x1000; 643 buff->cif = 0x00; 644 buff->type = 0x02; 645 646 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; 647 i++) 648 if (cfg_table[i].subvendor == buff->subvendor && 649 cfg_table[i].subdevice == buff->subdevice) 650 break; 651 buff->name = cfg_table[i].name; 652 buff->codec = cfg_table[i].codec; 653 654 return buff; 655 #if 0 656 return NULL; 657 #endif 658 } 659 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT); 660 if (buff == NULL) { 661 #if(0) 662 device_printf(sc->dev, "envy24ht_rom2cfg(): kmalloc()\n"); 663 #endif 664 return NULL; 665 } 666 buff->free = 1; 667 668 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8; 669 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1); 670 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8; 671 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1); 672 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG); 673 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL); 674 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S); 675 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF); 676 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \ 677 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \ 678 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16; 679 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \ 680 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \ 681 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16; 682 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \ 683 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \ 684 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16; 685 686 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) 687 if (cfg_table[i].subvendor == buff->subvendor && 688 cfg_table[i].subdevice == buff->subdevice) 689 break; 690 buff->name = cfg_table[i].name; 691 buff->codec = cfg_table[i].codec; 692 693 return buff; 694 } 695 696 static void 697 envy24ht_cfgfree(struct cfg_info *cfg) { 698 if (cfg == NULL) 699 return; 700 if (cfg->free) 701 kfree(cfg, M_ENVY24HT); 702 return; 703 } 704 705 /* -------------------------------------------------------------------- */ 706 707 /* AC'97 codec access routines */ 708 709 #if 0 710 static int 711 envy24ht_coldcd(struct sc_info *sc) 712 { 713 u_int32_t data; 714 int i; 715 716 #if(0) 717 device_printf(sc->dev, "envy24ht_coldcd()\n"); 718 #endif 719 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1); 720 DELAY(10); 721 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1); 722 DELAY(1000); 723 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 724 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 725 if (data & ENVY24HT_MT_AC97CMD_RDY) { 726 return 0; 727 } 728 } 729 730 return -1; 731 } 732 733 static int 734 envy24ht_slavecd(struct sc_info *sc) 735 { 736 u_int32_t data; 737 int i; 738 739 #if(0) 740 device_printf(sc->dev, "envy24ht_slavecd()\n"); 741 #endif 742 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 743 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1); 744 DELAY(10); 745 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1); 746 DELAY(1000); 747 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 748 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 749 if (data & ENVY24HT_MT_AC97CMD_RDY) { 750 return 0; 751 } 752 } 753 754 return -1; 755 } 756 757 static int 758 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno) 759 { 760 struct sc_info *sc = (struct sc_info *)devinfo; 761 u_int32_t data; 762 int i; 763 764 #if(0) 765 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno); 766 #endif 767 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1); 768 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1); 769 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 770 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 771 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0) 772 break; 773 } 774 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2); 775 776 #if(0) 777 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data); 778 #endif 779 return (int)data; 780 } 781 782 static int 783 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data) 784 { 785 struct sc_info *sc = (struct sc_info *)devinfo; 786 u_int32_t cmd; 787 int i; 788 789 #if(0) 790 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data); 791 #endif 792 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1); 793 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2); 794 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1); 795 for (i = 0; i < ENVY24HT_TIMEOUT; i++) { 796 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1); 797 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0) 798 break; 799 } 800 801 return 0; 802 } 803 804 static kobj_method_t envy24ht_ac97_methods[] = { 805 KOBJMETHOD(ac97_read, envy24ht_rdcd), 806 KOBJMETHOD(ac97_write, envy24ht_wrcd), 807 {0, 0} 808 }; 809 AC97_DECLARE(envy24ht_ac97); 810 #endif 811 812 /* -------------------------------------------------------------------- */ 813 814 /* GPIO access routines */ 815 816 static u_int32_t 817 envy24ht_gpiord(struct sc_info *sc) 818 { 819 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150) 820 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2); 821 else 822 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2)); 823 } 824 825 static void 826 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data) 827 { 828 #if(0) 829 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF); 830 return; 831 #endif 832 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2); 833 if (sc->cfg->subdevice != 0x1150) 834 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1); 835 return; 836 } 837 838 #if 0 839 static u_int32_t 840 envy24ht_gpiogetmask(struct sc_info *sc) 841 { 842 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2)); 843 } 844 #endif 845 846 static void 847 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask) 848 { 849 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2); 850 if (sc->cfg->subdevice != 0x1150) 851 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1); 852 return; 853 } 854 855 #if 0 856 static u_int32_t 857 envy24ht_gpiogetdir(struct sc_info *sc) 858 { 859 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4); 860 } 861 #endif 862 863 static void 864 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir) 865 { 866 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150) 867 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2); 868 else 869 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4); 870 return; 871 } 872 873 /* -------------------------------------------------------------------- */ 874 875 /* SPI codec access interface routine */ 876 877 struct envy24ht_spi_codec { 878 struct spicds_info *info; 879 struct sc_info *parent; 880 int dir; 881 int num; 882 int cs, cclk, cdti; 883 }; 884 885 static void 886 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) 887 { 888 u_int32_t data = 0; 889 struct envy24ht_spi_codec *ptr = codec; 890 891 #if(0) 892 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti); 893 #endif 894 data = envy24ht_gpiord(ptr->parent); 895 data &= ~(ptr->cs | ptr->cclk | ptr->cdti); 896 if (cs) data += ptr->cs; 897 if (cclk) data += ptr->cclk; 898 if (cdti) data += ptr->cdti; 899 envy24ht_gpiowr(ptr->parent, data); 900 return; 901 } 902 903 static void * 904 envy24ht_spi_create(device_t dev, void *info, int dir, int num) 905 { 906 struct sc_info *sc = info; 907 struct envy24ht_spi_codec *buff = NULL; 908 909 #if(0) 910 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num); 911 #endif 912 913 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT); 914 if (buff == NULL) 915 return NULL; 916 917 if (dir == PCMDIR_REC && sc->adc[num] != NULL) 918 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info; 919 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL) 920 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info; 921 else 922 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl); 923 if (buff->info == NULL) { 924 kfree(buff, M_ENVY24HT); 925 return NULL; 926 } 927 928 buff->parent = sc; 929 buff->dir = dir; 930 buff->num = num; 931 932 return (void *)buff; 933 } 934 935 static void 936 envy24ht_spi_destroy(void *codec) 937 { 938 struct envy24ht_spi_codec *ptr = codec; 939 if (ptr == NULL) 940 return; 941 #if(0) 942 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n"); 943 #endif 944 945 if (ptr->dir == PCMDIR_PLAY) { 946 if (ptr->parent->dac[ptr->num] != NULL) 947 spicds_destroy(ptr->info); 948 } 949 else { 950 if (ptr->parent->adc[ptr->num] != NULL) 951 spicds_destroy(ptr->info); 952 } 953 954 kfree(codec, M_ENVY24HT); 955 } 956 957 static void 958 envy24ht_spi_init(void *codec) 959 { 960 struct envy24ht_spi_codec *ptr = codec; 961 if (ptr == NULL) 962 return; 963 #if(0) 964 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n"); 965 #endif 966 ptr->cs = ptr->parent->cfg->cs; 967 ptr->cclk = ptr->parent->cfg->cclk; 968 ptr->cdti = ptr->parent->cfg->cdti; 969 spicds_settype(ptr->info, ptr->parent->cfg->type); 970 spicds_setcif(ptr->info, ptr->parent->cfg->cif); 971 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \ 972 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) { 973 spicds_setformat(ptr->info, 974 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 975 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF); 976 } 977 978 /* for the time being, init only first codec */ 979 if (ptr->num == 0) 980 spicds_init(ptr->info); 981 } 982 983 static void 984 envy24ht_spi_reinit(void *codec) 985 { 986 struct envy24ht_spi_codec *ptr = codec; 987 if (ptr == NULL) 988 return; 989 #if(0) 990 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n"); 991 #endif 992 993 spicds_reinit(ptr->info); 994 } 995 996 static void 997 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 998 { 999 struct envy24ht_spi_codec *ptr = codec; 1000 if (ptr == NULL) 1001 return; 1002 #if(0) 1003 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n"); 1004 #endif 1005 1006 spicds_set(ptr->info, dir, left, right); 1007 } 1008 1009 /* -------------------------------------------------------------------- */ 1010 1011 /* hardware access routeines */ 1012 1013 static struct { 1014 u_int32_t speed; 1015 u_int32_t code; 1016 } envy24ht_speedtab[] = { 1017 {48000, ENVY24HT_MT_RATE_48000}, 1018 {24000, ENVY24HT_MT_RATE_24000}, 1019 {12000, ENVY24HT_MT_RATE_12000}, 1020 {9600, ENVY24HT_MT_RATE_9600}, 1021 {32000, ENVY24HT_MT_RATE_32000}, 1022 {16000, ENVY24HT_MT_RATE_16000}, 1023 {8000, ENVY24HT_MT_RATE_8000}, 1024 {96000, ENVY24HT_MT_RATE_96000}, 1025 {192000, ENVY24HT_MT_RATE_192000}, 1026 {64000, ENVY24HT_MT_RATE_64000}, 1027 {44100, ENVY24HT_MT_RATE_44100}, 1028 {22050, ENVY24HT_MT_RATE_22050}, 1029 {11025, ENVY24HT_MT_RATE_11025}, 1030 {88200, ENVY24HT_MT_RATE_88200}, 1031 {176400, ENVY24HT_MT_RATE_176400}, 1032 {0, 0x10} 1033 }; 1034 1035 static int 1036 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) { 1037 u_int32_t code, i2sfmt; 1038 int i = 0; 1039 1040 #if(0) 1041 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed); 1042 if (speed == 0) { 1043 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */ 1044 envy24ht_slavecd(sc); 1045 } 1046 else { 1047 #endif 1048 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) { 1049 if (envy24ht_speedtab[i].speed == speed) 1050 break; 1051 } 1052 code = envy24ht_speedtab[i].code; 1053 #if 0 1054 } 1055 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code); 1056 #endif 1057 if (code < 0x10) { 1058 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1); 1059 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \ 1060 (code == ENVY24HT_MT_RATE_176400)) { 1061 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); 1062 i2sfmt |= ENVY24HT_MT_I2S_MLR128; 1063 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); 1064 } 1065 else { 1066 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); 1067 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128; 1068 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); 1069 } 1070 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1); 1071 code &= ENVY24HT_MT_RATE_MASK; 1072 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) { 1073 if (envy24ht_speedtab[i].code == code) 1074 break; 1075 } 1076 speed = envy24ht_speedtab[i].speed; 1077 } 1078 else 1079 speed = 0; 1080 1081 #if(0) 1082 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed); 1083 #endif 1084 return speed; 1085 } 1086 1087 static void 1088 envy24ht_setvolume(struct sc_info *sc, unsigned ch) 1089 { 1090 #if(0) 1091 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch); 1092 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1); 1093 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 1094 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1); 1095 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 1096 #endif 1097 } 1098 1099 static void 1100 envy24ht_mutevolume(struct sc_info *sc, unsigned ch) 1101 { 1102 #if 0 1103 u_int32_t vol; 1104 1105 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch); 1106 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE; 1107 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1); 1108 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2); 1109 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1); 1110 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2); 1111 #endif 1112 } 1113 1114 static u_int32_t 1115 envy24ht_gethwptr(struct sc_info *sc, int dir) 1116 { 1117 int unit, regno; 1118 u_int32_t ptr, rtn; 1119 1120 #if(0) 1121 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir); 1122 #endif 1123 if (dir == PCMDIR_PLAY) { 1124 rtn = sc->psize / 4; 1125 unit = ENVY24HT_PLAY_BUFUNIT / 4; 1126 regno = ENVY24HT_MT_PCNT; 1127 } 1128 else { 1129 rtn = sc->rsize / 4; 1130 unit = ENVY24HT_REC_BUFUNIT / 4; 1131 regno = ENVY24HT_MT_RCNT; 1132 } 1133 1134 ptr = envy24ht_rdmt(sc, regno, 2); 1135 rtn -= (ptr + 1); 1136 rtn /= unit; 1137 1138 #if(0) 1139 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn); 1140 #endif 1141 return rtn; 1142 } 1143 1144 static void 1145 envy24ht_updintr(struct sc_info *sc, int dir) 1146 { 1147 int regptr, regintr; 1148 u_int32_t mask, intr; 1149 u_int32_t ptr, size, cnt; 1150 u_int16_t blk; 1151 1152 #if(0) 1153 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir); 1154 #endif 1155 if (dir == PCMDIR_PLAY) { 1156 blk = sc->blk[0]; 1157 size = sc->psize / 4; 1158 regptr = ENVY24HT_MT_PCNT; 1159 regintr = ENVY24HT_MT_PTERM; 1160 mask = ~ENVY24HT_MT_INT_PMASK; 1161 } 1162 else { 1163 blk = sc->blk[1]; 1164 size = sc->rsize / 4; 1165 regptr = ENVY24HT_MT_RCNT; 1166 regintr = ENVY24HT_MT_RTERM; 1167 mask = ~ENVY24HT_MT_INT_RMASK; 1168 } 1169 1170 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1; 1171 /* 1172 cnt = blk - ptr % blk - 1; 1173 if (cnt == 0) 1174 cnt = blk - 1; 1175 */ 1176 cnt = blk - 1; 1177 #if(0) 1178 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1179 #endif 1180 envy24ht_wrmt(sc, regintr, cnt, 2); 1181 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1182 #if(0) 1183 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1184 #endif 1185 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1); 1186 #if(0) 1187 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n", 1188 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1)); 1189 #endif 1190 1191 return; 1192 } 1193 1194 #if 0 1195 static void 1196 envy24ht_maskintr(struct sc_info *sc, int dir) 1197 { 1198 u_int32_t mask, intr; 1199 1200 #if(0) 1201 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir); 1202 #endif 1203 if (dir == PCMDIR_PLAY) 1204 mask = ENVY24HT_MT_INT_PMASK; 1205 else 1206 mask = ENVY24HT_MT_INT_RMASK; 1207 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1); 1208 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1); 1209 1210 return; 1211 } 1212 #endif 1213 1214 static int 1215 envy24ht_checkintr(struct sc_info *sc, int dir) 1216 { 1217 u_int32_t mask, stat, intr, rtn; 1218 1219 #if(0) 1220 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir); 1221 #endif 1222 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1); 1223 if (dir == PCMDIR_PLAY) { 1224 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) { 1225 mask = ~ENVY24HT_MT_INT_RSTAT; 1226 envy24ht_wrmt(sc, 0x1a, 0x01, 1); 1227 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1); 1228 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1229 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1); 1230 } 1231 } 1232 else { 1233 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) { 1234 mask = ~ENVY24HT_MT_INT_PSTAT; 1235 #if 0 1236 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK; 1237 #endif 1238 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1); 1239 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1); 1240 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1); 1241 } 1242 } 1243 1244 return rtn; 1245 } 1246 1247 static void 1248 envy24ht_start(struct sc_info *sc, int dir) 1249 { 1250 u_int32_t stat, sw; 1251 1252 #if(0) 1253 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir); 1254 #endif 1255 if (dir == PCMDIR_PLAY) 1256 sw = ENVY24HT_MT_PCTL_PSTART; 1257 else 1258 sw = ENVY24HT_MT_PCTL_RSTART; 1259 1260 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1261 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1); 1262 #if(0) 1263 DELAY(100); 1264 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 1265 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 1266 #endif 1267 1268 return; 1269 } 1270 1271 static void 1272 envy24ht_stop(struct sc_info *sc, int dir) 1273 { 1274 u_int32_t stat, sw; 1275 1276 #if(0) 1277 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir); 1278 #endif 1279 if (dir == PCMDIR_PLAY) 1280 sw = ~ENVY24HT_MT_PCTL_PSTART; 1281 else 1282 sw = ~ENVY24HT_MT_PCTL_RSTART; 1283 1284 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1); 1285 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1); 1286 1287 return; 1288 } 1289 1290 #if 0 1291 static int 1292 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1293 { 1294 return 0; 1295 } 1296 #endif 1297 1298 /* -------------------------------------------------------------------- */ 1299 1300 /* buffer copy routines */ 1301 static void 1302 envy24ht_p32sl(struct sc_chinfo *ch) 1303 { 1304 int length; 1305 sample32_t *dmabuf; 1306 u_int32_t *data; 1307 int src, dst, ssize, dsize, slot; 1308 int i; 1309 1310 length = sndbuf_getready(ch->buffer) / 8; 1311 dmabuf = ch->parent->pbuf; 1312 data = (u_int32_t *)ch->data; 1313 src = sndbuf_getreadyptr(ch->buffer) / 4; 1314 dst = src / 2 + ch->offset; 1315 ssize = ch->size / 4; 1316 dsize = ch->size / 8; 1317 slot = ch->num * 2; 1318 1319 for (i = 0; i < length; i++) { 1320 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src]; 1321 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1322 dst++; 1323 dst %= dsize; 1324 src += 2; 1325 src %= ssize; 1326 } 1327 1328 return; 1329 } 1330 1331 static void 1332 envy24ht_p16sl(struct sc_chinfo *ch) 1333 { 1334 int length; 1335 sample32_t *dmabuf; 1336 u_int16_t *data; 1337 int src, dst, ssize, dsize, slot; 1338 int i; 1339 1340 #if(0) 1341 device_printf(ch->parent->dev, "envy24ht_p16sl()\n"); 1342 #endif 1343 length = sndbuf_getready(ch->buffer) / 4; 1344 dmabuf = ch->parent->pbuf; 1345 data = (u_int16_t *)ch->data; 1346 src = sndbuf_getreadyptr(ch->buffer) / 2; 1347 dst = src / 2 + ch->offset; 1348 ssize = ch->size / 2; 1349 dsize = ch->size / 4; 1350 slot = ch->num * 2; 1351 #if(0) 1352 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1353 #endif 1354 1355 for (i = 0; i < length; i++) { 1356 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1357 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1358 #if(0) 1359 if (i < 16) { 1360 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]); 1361 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]); 1362 } 1363 #endif 1364 dst++; 1365 dst %= dsize; 1366 src += 2; 1367 src %= ssize; 1368 } 1369 #if(0) 1370 kprintf("\n"); 1371 #endif 1372 1373 return; 1374 } 1375 1376 static void 1377 envy24ht_p8u(struct sc_chinfo *ch) 1378 { 1379 int length; 1380 sample32_t *dmabuf; 1381 u_int8_t *data; 1382 int src, dst, ssize, dsize, slot; 1383 int i; 1384 1385 length = sndbuf_getready(ch->buffer) / 2; 1386 dmabuf = ch->parent->pbuf; 1387 data = (u_int8_t *)ch->data; 1388 src = sndbuf_getreadyptr(ch->buffer); 1389 dst = src / 2 + ch->offset; 1390 ssize = ch->size; 1391 dsize = ch->size / 4; 1392 slot = ch->num * 2; 1393 1394 for (i = 0; i < length; i++) { 1395 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1396 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1397 dst++; 1398 dst %= dsize; 1399 src += 2; 1400 src %= ssize; 1401 } 1402 1403 return; 1404 } 1405 1406 static void 1407 envy24ht_r32sl(struct sc_chinfo *ch) 1408 { 1409 int length; 1410 sample32_t *dmabuf; 1411 u_int32_t *data; 1412 int src, dst, ssize, dsize, slot; 1413 int i; 1414 1415 length = sndbuf_getfree(ch->buffer) / 8; 1416 dmabuf = ch->parent->rbuf; 1417 data = (u_int32_t *)ch->data; 1418 dst = sndbuf_getfreeptr(ch->buffer) / 4; 1419 src = dst / 2 + ch->offset; 1420 dsize = ch->size / 4; 1421 ssize = ch->size / 8; 1422 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1423 1424 for (i = 0; i < length; i++) { 1425 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1426 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1427 dst += 2; 1428 dst %= dsize; 1429 src++; 1430 src %= ssize; 1431 } 1432 1433 return; 1434 } 1435 1436 static void 1437 envy24ht_r16sl(struct sc_chinfo *ch) 1438 { 1439 int length; 1440 sample32_t *dmabuf; 1441 u_int16_t *data; 1442 int src, dst, ssize, dsize, slot; 1443 int i; 1444 1445 length = sndbuf_getfree(ch->buffer) / 4; 1446 dmabuf = ch->parent->rbuf; 1447 data = (u_int16_t *)ch->data; 1448 dst = sndbuf_getfreeptr(ch->buffer) / 2; 1449 src = dst / 2 + ch->offset; 1450 dsize = ch->size / 2; 1451 ssize = ch->size / 8; 1452 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2; 1453 1454 for (i = 0; i < length; i++) { 1455 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer; 1456 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer; 1457 dst += 2; 1458 dst %= dsize; 1459 src++; 1460 src %= ssize; 1461 } 1462 1463 return; 1464 } 1465 1466 /* -------------------------------------------------------------------- */ 1467 1468 /* channel interface */ 1469 static void * 1470 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1471 { 1472 struct sc_info *sc = (struct sc_info *)devinfo; 1473 struct sc_chinfo *ch; 1474 unsigned num; 1475 1476 #if(0) 1477 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir); 1478 #endif 1479 snd_mtxlock(sc->lock); 1480 #if 0 1481 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1482 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1483 snd_mtxunlock(sc->lock); 1484 return NULL; 1485 } 1486 #endif 1487 num = sc->chnum; 1488 1489 ch = &sc->chan[num]; 1490 ch->size = 8 * ENVY24HT_SAMPLE_NUM; 1491 ch->data = kmalloc(ch->size, M_ENVY24HT, M_NOWAIT); 1492 if (ch->data == NULL) { 1493 ch->size = 0; 1494 ch = NULL; 1495 } 1496 else { 1497 ch->buffer = b; 1498 ch->channel = c; 1499 ch->parent = sc; 1500 ch->dir = dir; 1501 /* set channel map */ 1502 ch->num = envy24ht_chanmap[num]; 1503 snd_mtxunlock(sc->lock); 1504 sndbuf_setup(ch->buffer, ch->data, ch->size); 1505 snd_mtxlock(sc->lock); 1506 /* these 2 values are dummy */ 1507 ch->unit = 4; 1508 ch->blk = 10240; 1509 } 1510 snd_mtxunlock(sc->lock); 1511 1512 return ch; 1513 } 1514 1515 static int 1516 envy24htchan_free(kobj_t obj, void *data) 1517 { 1518 struct sc_chinfo *ch = data; 1519 struct sc_info *sc = ch->parent; 1520 1521 #if(0) 1522 device_printf(sc->dev, "envy24htchan_free()\n"); 1523 #endif 1524 snd_mtxlock(sc->lock); 1525 if (ch->data != NULL) { 1526 kfree(ch->data, M_ENVY24HT); 1527 ch->data = NULL; 1528 } 1529 snd_mtxunlock(sc->lock); 1530 1531 return 0; 1532 } 1533 1534 static int 1535 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format) 1536 { 1537 struct sc_chinfo *ch = data; 1538 struct sc_info *sc = ch->parent; 1539 struct envy24ht_emldma *emltab; 1540 /* unsigned int bcnt, bsize; */ 1541 int i; 1542 1543 #if(0) 1544 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format); 1545 #endif 1546 snd_mtxlock(sc->lock); 1547 /* check and get format related information */ 1548 if (ch->dir == PCMDIR_PLAY) 1549 emltab = envy24ht_pemltab; 1550 else 1551 emltab = envy24ht_remltab; 1552 if (emltab == NULL) { 1553 snd_mtxunlock(sc->lock); 1554 return -1; 1555 } 1556 for (i = 0; emltab[i].format != 0; i++) 1557 if (emltab[i].format == format) 1558 break; 1559 if (emltab[i].format == 0) { 1560 snd_mtxunlock(sc->lock); 1561 return -1; 1562 } 1563 1564 /* set format information */ 1565 ch->format = format; 1566 ch->emldma = emltab[i].emldma; 1567 if (ch->unit > emltab[i].unit) 1568 ch->blk *= ch->unit / emltab[i].unit; 1569 else 1570 ch->blk /= emltab[i].unit / ch->unit; 1571 ch->unit = emltab[i].unit; 1572 1573 /* set channel buffer information */ 1574 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; 1575 #if 0 1576 if (ch->dir == PCMDIR_PLAY) 1577 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1578 else 1579 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1580 bsize *= ch->unit; 1581 bcnt = ch->size / bsize; 1582 sndbuf_resize(ch->buffer, bcnt, bsize); 1583 #endif 1584 snd_mtxunlock(sc->lock); 1585 1586 #if(0) 1587 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0); 1588 #endif 1589 return 0; 1590 } 1591 1592 /* 1593 IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1594 of speed information value. And real hardware speed setting is done 1595 at start triggered(see envy24htchan_trigger()). So, at this function 1596 is called, any value that ENVY24 can use is able to set. But, at 1597 start triggerd, some other channel is running, and that channel's 1598 speed isn't same with, then trigger function will fail. 1599 */ 1600 static int 1601 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1602 { 1603 struct sc_chinfo *ch = data; 1604 u_int32_t val, prev; 1605 int i; 1606 1607 #if(0) 1608 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed); 1609 #endif 1610 prev = 0x7fffffff; 1611 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) { 1612 if (abs(val - speed) < abs(prev - speed)) 1613 prev = val; 1614 else 1615 break; 1616 } 1617 ch->speed = prev; 1618 1619 #if(0) 1620 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed); 1621 #endif 1622 return ch->speed; 1623 } 1624 1625 static int 1626 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1627 { 1628 struct sc_chinfo *ch = data; 1629 /* struct sc_info *sc = ch->parent; */ 1630 u_int32_t size, prev; 1631 unsigned int bcnt, bsize; 1632 1633 #if(0) 1634 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize); 1635 #endif 1636 prev = 0x7fffffff; 1637 /* snd_mtxlock(sc->lock); */ 1638 for (size = ch->size / 2; size > 0; size /= 2) { 1639 if (abs(size - blocksize) < abs(prev - blocksize)) 1640 prev = size; 1641 else 1642 break; 1643 } 1644 1645 ch->blk = prev / ch->unit; 1646 if (ch->dir == PCMDIR_PLAY) 1647 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4; 1648 else 1649 ch->blk *= ENVY24HT_REC_BUFUNIT / 4; 1650 /* set channel buffer information */ 1651 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */ 1652 if (ch->dir == PCMDIR_PLAY) 1653 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; 1654 else 1655 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT; 1656 bsize *= ch->unit; 1657 bcnt = ch->size / bsize; 1658 sndbuf_resize(ch->buffer, bcnt, bsize); 1659 /* snd_mtxunlock(sc->lock); */ 1660 1661 #if(0) 1662 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev); 1663 #endif 1664 return prev; 1665 } 1666 1667 /* semantic note: must start at beginning of buffer */ 1668 static int 1669 envy24htchan_trigger(kobj_t obj, void *data, int go) 1670 { 1671 struct sc_chinfo *ch = data; 1672 struct sc_info *sc = ch->parent; 1673 u_int32_t ptr; 1674 int slot; 1675 #if 0 1676 int i; 1677 1678 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go); 1679 #endif 1680 snd_mtxlock(sc->lock); 1681 if (ch->dir == PCMDIR_PLAY) 1682 slot = 0; 1683 else 1684 slot = 1; 1685 switch (go) { 1686 case PCMTRIG_START: 1687 #if(0) 1688 device_printf(sc->dev, "envy24htchan_trigger(): start\n"); 1689 #endif 1690 /* check or set channel speed */ 1691 if (sc->run[0] == 0 && sc->run[1] == 0) { 1692 sc->speed = envy24ht_setspeed(sc, ch->speed); 1693 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1694 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1695 } 1696 else if (ch->speed != 0 && ch->speed != sc->speed) 1697 return -1; 1698 if (ch->speed == 0) 1699 ch->channel->speed = sc->speed; 1700 /* start or enable channel */ 1701 sc->run[slot]++; 1702 if (sc->run[slot] == 1) { 1703 /* first channel */ 1704 ch->offset = 0; 1705 sc->blk[slot] = ch->blk; 1706 } 1707 else { 1708 ptr = envy24ht_gethwptr(sc, ch->dir); 1709 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1710 (ch->size / 4)) * 4 / ch->unit; 1711 if (ch->blk < sc->blk[slot]) 1712 sc->blk[slot] = ch->blk; 1713 } 1714 if (ch->dir == PCMDIR_PLAY) { 1715 ch->emldma(ch); 1716 envy24ht_setvolume(sc, ch->num); 1717 } 1718 envy24ht_updintr(sc, ch->dir); 1719 if (sc->run[slot] == 1) 1720 envy24ht_start(sc, ch->dir); 1721 ch->run = 1; 1722 break; 1723 case PCMTRIG_EMLDMAWR: 1724 #if(0) 1725 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n"); 1726 #endif 1727 if (ch->run != 1) 1728 return -1; 1729 ch->emldma(ch); 1730 break; 1731 case PCMTRIG_EMLDMARD: 1732 #if(0) 1733 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n"); 1734 #endif 1735 if (ch->run != 1) 1736 return -1; 1737 ch->emldma(ch); 1738 break; 1739 case PCMTRIG_ABORT: 1740 if (ch->run) { 1741 #if(0) 1742 device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); 1743 #endif 1744 ch->run = 0; 1745 sc->run[slot]--; 1746 if (ch->dir == PCMDIR_PLAY) 1747 envy24ht_mutevolume(sc, ch->num); 1748 if (sc->run[slot] == 0) { 1749 envy24ht_stop(sc, ch->dir); 1750 sc->intr[slot] = 0; 1751 } 1752 /* else if (ch->blk == sc->blk[slot]) { 1753 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2; 1754 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) { 1755 if (sc->chan[i].dir == ch->dir && 1756 sc->chan[i].run == 1 && 1757 sc->chan[i].blk < sc->blk[slot]) 1758 sc->blk[slot] = sc->chan[i].blk; 1759 } 1760 if (ch->blk != sc->blk[slot]) 1761 envy24ht_updintr(sc, ch->dir); 1762 }*/ 1763 } 1764 break; 1765 } 1766 snd_mtxunlock(sc->lock); 1767 1768 return 0; 1769 } 1770 1771 static int 1772 envy24htchan_getptr(kobj_t obj, void *data) 1773 { 1774 struct sc_chinfo *ch = data; 1775 struct sc_info *sc = ch->parent; 1776 u_int32_t ptr; 1777 int rtn; 1778 1779 #if(0) 1780 device_printf(sc->dev, "envy24htchan_getptr()\n"); 1781 #endif 1782 snd_mtxlock(sc->lock); 1783 ptr = envy24ht_gethwptr(sc, ch->dir); 1784 rtn = ptr * ch->unit; 1785 snd_mtxunlock(sc->lock); 1786 1787 #if(0) 1788 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n", 1789 rtn); 1790 #endif 1791 return rtn; 1792 } 1793 1794 static struct pcmchan_caps * 1795 envy24htchan_getcaps(kobj_t obj, void *data) 1796 { 1797 struct sc_chinfo *ch = data; 1798 struct sc_info *sc = ch->parent; 1799 struct pcmchan_caps *rtn; 1800 1801 #if(0) 1802 device_printf(sc->dev, "envy24htchan_getcaps()\n"); 1803 #endif 1804 snd_mtxlock(sc->lock); 1805 if (ch->dir == PCMDIR_PLAY) { 1806 if (sc->run[0] == 0) 1807 rtn = &envy24ht_playcaps; 1808 else 1809 rtn = &sc->caps[0]; 1810 } 1811 else { 1812 if (sc->run[1] == 0) 1813 rtn = &envy24ht_reccaps; 1814 else 1815 rtn = &sc->caps[1]; 1816 } 1817 snd_mtxunlock(sc->lock); 1818 1819 return rtn; 1820 } 1821 1822 static kobj_method_t envy24htchan_methods[] = { 1823 KOBJMETHOD(channel_init, envy24htchan_init), 1824 KOBJMETHOD(channel_free, envy24htchan_free), 1825 KOBJMETHOD(channel_setformat, envy24htchan_setformat), 1826 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed), 1827 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize), 1828 KOBJMETHOD(channel_trigger, envy24htchan_trigger), 1829 KOBJMETHOD(channel_getptr, envy24htchan_getptr), 1830 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps), 1831 { 0, 0 } 1832 }; 1833 CHANNEL_DECLARE(envy24htchan); 1834 1835 /* -------------------------------------------------------------------- */ 1836 1837 /* mixer interface */ 1838 1839 static int 1840 envy24htmixer_init(struct snd_mixer *m) 1841 { 1842 struct sc_info *sc = mix_getdevinfo(m); 1843 1844 #if(0) 1845 device_printf(sc->dev, "envy24htmixer_init()\n"); 1846 #endif 1847 if (sc == NULL) 1848 return -1; 1849 1850 /* set volume control rate */ 1851 snd_mtxlock(sc->lock); 1852 #if 0 1853 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1854 #endif 1855 1856 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL); 1857 1858 mix_setdevs(m, ENVY24HT_MIX_MASK); 1859 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); 1860 1861 snd_mtxunlock(sc->lock); 1862 1863 return 0; 1864 } 1865 1866 static int 1867 envy24htmixer_reinit(struct snd_mixer *m) 1868 { 1869 struct sc_info *sc = mix_getdevinfo(m); 1870 1871 if (sc == NULL) 1872 return -1; 1873 #if(0) 1874 device_printf(sc->dev, "envy24htmixer_reinit()\n"); 1875 #endif 1876 1877 return 0; 1878 } 1879 1880 static int 1881 envy24htmixer_uninit(struct snd_mixer *m) 1882 { 1883 struct sc_info *sc = mix_getdevinfo(m); 1884 1885 if (sc == NULL) 1886 return -1; 1887 #if(0) 1888 device_printf(sc->dev, "envy24htmixer_uninit()\n"); 1889 #endif 1890 1891 return 0; 1892 } 1893 1894 static int 1895 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1896 { 1897 struct sc_info *sc = mix_getdevinfo(m); 1898 int ch = envy24ht_mixmap[dev]; 1899 int hwch; 1900 int i; 1901 1902 if (sc == NULL) 1903 return -1; 1904 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1905 return -1; 1906 if (dev != 0 && ch == -1) 1907 return -1; 1908 hwch = envy24ht_chanmap[ch]; 1909 #if(0) 1910 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n", 1911 dev, left, right); 1912 #endif 1913 1914 snd_mtxlock(sc->lock); 1915 if (dev == 0) { 1916 for (i = 0; i < sc->dacn; i++) { 1917 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1918 } 1919 } 1920 else { 1921 /* set volume value for hardware */ 1922 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN) 1923 sc->left[hwch] = ENVY24HT_VOL_MUTE; 1924 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN) 1925 sc->right[hwch] = ENVY24HT_VOL_MUTE; 1926 1927 /* set volume for record channel and running play channel */ 1928 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1929 envy24ht_setvolume(sc, hwch); 1930 } 1931 snd_mtxunlock(sc->lock); 1932 1933 return right << 8 | left; 1934 } 1935 1936 static u_int32_t 1937 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1938 { 1939 struct sc_info *sc = mix_getdevinfo(m); 1940 int ch = envy24ht_mixmap[src]; 1941 #if(0) 1942 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src); 1943 #endif 1944 1945 if (ch > ENVY24HT_CHAN_PLAY_SPDIF) 1946 sc->src = ch; 1947 return src; 1948 } 1949 1950 static kobj_method_t envy24htmixer_methods[] = { 1951 KOBJMETHOD(mixer_init, envy24htmixer_init), 1952 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit), 1953 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit), 1954 KOBJMETHOD(mixer_set, envy24htmixer_set), 1955 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc), 1956 { 0, 0 } 1957 }; 1958 MIXER_DECLARE(envy24htmixer); 1959 1960 /* -------------------------------------------------------------------- */ 1961 1962 /* The interrupt handler */ 1963 static void 1964 envy24ht_intr(void *p) 1965 { 1966 struct sc_info *sc = (struct sc_info *)p; 1967 struct sc_chinfo *ch; 1968 u_int32_t ptr, dsize, feed; 1969 int i; 1970 1971 #if(0) 1972 device_printf(sc->dev, "envy24ht_intr()\n"); 1973 #endif 1974 snd_mtxlock(sc->lock); 1975 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) { 1976 #if(0) 1977 device_printf(sc->dev, "envy24ht_intr(): play\n"); 1978 #endif 1979 dsize = sc->psize / 4; 1980 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1; 1981 #if(0) 1982 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr); 1983 #endif 1984 ptr -= ptr % sc->blk[0]; 1985 feed = (ptr + dsize - sc->intr[0]) % dsize; 1986 #if(0) 1987 kprintf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1988 #endif 1989 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) { 1990 ch = &sc->chan[i]; 1991 #if(0) 1992 if (ch->run) 1993 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk); 1994 #endif 1995 if (ch->run && ch->blk <= feed) { 1996 snd_mtxunlock(sc->lock); 1997 chn_intr(ch->channel); 1998 snd_mtxlock(sc->lock); 1999 } 2000 } 2001 sc->intr[0] = ptr; 2002 envy24ht_updintr(sc, PCMDIR_PLAY); 2003 } 2004 if (envy24ht_checkintr(sc, PCMDIR_REC)) { 2005 #if(0) 2006 device_printf(sc->dev, "envy24ht_intr(): rec\n"); 2007 #endif 2008 dsize = sc->rsize / 4; 2009 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1; 2010 ptr -= ptr % sc->blk[1]; 2011 feed = (ptr + dsize - sc->intr[1]) % dsize; 2012 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) { 2013 ch = &sc->chan[i]; 2014 if (ch->run && ch->blk <= feed) { 2015 snd_mtxunlock(sc->lock); 2016 chn_intr(ch->channel); 2017 snd_mtxlock(sc->lock); 2018 } 2019 } 2020 sc->intr[1] = ptr; 2021 envy24ht_updintr(sc, PCMDIR_REC); 2022 } 2023 snd_mtxunlock(sc->lock); 2024 2025 return; 2026 } 2027 2028 /* 2029 * Probe and attach the card 2030 */ 2031 2032 static int 2033 envy24ht_pci_probe(device_t dev) 2034 { 2035 u_int16_t sv, sd; 2036 int i; 2037 2038 #if(0) 2039 kprintf("envy24ht_pci_probe()\n"); 2040 #endif 2041 if (pci_get_device(dev) == PCID_ENVY24HT && 2042 pci_get_vendor(dev) == PCIV_ENVY24) { 2043 sv = pci_get_subvendor(dev); 2044 sd = pci_get_subdevice(dev); 2045 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2046 if (cfg_table[i].subvendor == sv && 2047 cfg_table[i].subdevice == sd) { 2048 break; 2049 } 2050 } 2051 device_set_desc(dev, cfg_table[i].name); 2052 #if(0) 2053 kprintf("envy24ht_pci_probe(): return 0\n"); 2054 #endif 2055 return 0; 2056 } 2057 else { 2058 #if(0) 2059 kprintf("envy24ht_pci_probe(): return ENXIO\n"); 2060 #endif 2061 return ENXIO; 2062 } 2063 } 2064 2065 static void 2066 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2067 { 2068 /* struct sc_info *sc = (struct sc_info *)arg; */ 2069 2070 #if(0) 2071 device_printf(sc->dev, "envy24ht_dmapsetmap()\n"); 2072 if (bootverbose) { 2073 kprintf("envy24ht(play): setmap %lx, %lx; ", 2074 (unsigned long)segs->ds_addr, 2075 (unsigned long)segs->ds_len); 2076 kprintf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 2077 } 2078 #endif 2079 } 2080 2081 static void 2082 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2083 { 2084 /* struct sc_info *sc = (struct sc_info *)arg; */ 2085 2086 #if(0) 2087 device_printf(sc->dev, "envy24ht_dmarsetmap()\n"); 2088 if (bootverbose) { 2089 kprintf("envy24ht(record): setmap %lx, %lx; ", 2090 (unsigned long)segs->ds_addr, 2091 (unsigned long)segs->ds_len); 2092 kprintf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2093 } 2094 #endif 2095 } 2096 2097 static void 2098 envy24ht_dmafree(struct sc_info *sc) 2099 { 2100 #if(0) 2101 device_printf(sc->dev, "envy24ht_dmafree():"); 2102 if (sc->rmap) kprintf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2103 else kprintf(" sc->rmap(null)"); 2104 if (sc->pmap) kprintf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2105 else kprintf(" sc->pmap(null)"); 2106 if (sc->rbuf) kprintf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2107 else kprintf(" sc->rbuf(null)"); 2108 if (sc->pbuf) kprintf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2109 else kprintf(" sc->pbuf(null)\n"); 2110 #endif 2111 #if(0) 2112 if (sc->rmap) 2113 bus_dmamap_unload(sc->dmat, sc->rmap); 2114 if (sc->pmap) 2115 bus_dmamap_unload(sc->dmat, sc->pmap); 2116 if (sc->rbuf) 2117 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2118 if (sc->pbuf) 2119 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2120 #else 2121 bus_dmamap_unload(sc->dmat, sc->rmap); 2122 bus_dmamap_unload(sc->dmat, sc->pmap); 2123 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2124 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2125 #endif 2126 2127 sc->rmap = sc->pmap = NULL; 2128 sc->pbuf = NULL; 2129 sc->rbuf = NULL; 2130 2131 return; 2132 } 2133 2134 static int 2135 envy24ht_dmainit(struct sc_info *sc) 2136 { 2137 u_int32_t addr; 2138 2139 #if(0) 2140 device_printf(sc->dev, "envy24ht_dmainit()\n"); 2141 #endif 2142 /* init values */ 2143 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2144 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM; 2145 sc->pbuf = NULL; 2146 sc->rbuf = NULL; 2147 sc->pmap = sc->rmap = NULL; 2148 sc->blk[0] = sc->blk[1] = 0; 2149 2150 /* allocate DMA buffer */ 2151 #if(0) 2152 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2153 #endif 2154 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2155 goto bad; 2156 #if(0) 2157 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2158 #endif 2159 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2160 goto bad; 2161 #if(0) 2162 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2163 #endif 2164 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0)) 2165 goto bad; 2166 #if(0) 2167 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2168 #endif 2169 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0)) 2170 goto bad; 2171 bzero(sc->pbuf, sc->psize); 2172 bzero(sc->rbuf, sc->rsize); 2173 2174 /* set values to register */ 2175 addr = vtophys(sc->pbuf); 2176 #if(0) 2177 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2178 #endif 2179 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4); 2180 #if(0) 2181 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4)); 2182 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2183 #endif 2184 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2); 2185 #if(0) 2186 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2)); 2187 #endif 2188 addr = vtophys(sc->rbuf); 2189 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4); 2190 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2); 2191 2192 return 0; 2193 bad: 2194 envy24ht_dmafree(sc); 2195 return ENOSPC; 2196 } 2197 2198 static void 2199 envy24ht_putcfg(struct sc_info *sc) 2200 { 2201 device_printf(sc->dev, "system configuration\n"); 2202 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2203 sc->cfg->subvendor, sc->cfg->subdevice); 2204 kprintf(" XIN2 Clock Source: "); 2205 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) { 2206 case 0x00: 2207 kprintf("24.576MHz(96kHz*256)\n"); 2208 break; 2209 case 0x40: 2210 kprintf("49.152MHz(192kHz*256)\n"); 2211 break; 2212 case 0x80: 2213 kprintf("reserved\n"); 2214 break; 2215 default: 2216 kprintf("illeagal system setting\n"); 2217 } 2218 kprintf(" MPU-401 UART(s) #: "); 2219 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU) 2220 kprintf("1\n"); 2221 else 2222 kprintf("not implemented\n"); 2223 switch (sc->adcn) { 2224 case 0x01 || 0x02: 2225 kprintf(" ADC #: "); 2226 kprintf("%d\n", sc->adcn); 2227 break; 2228 case 0x03: 2229 kprintf(" ADC #: "); 2230 kprintf("%d", 1); 2231 kprintf(" and SPDIF receiver connected\n"); 2232 break; 2233 default: 2234 kprintf(" no physical inputs\n"); 2235 } 2236 kprintf(" DAC #: "); 2237 kprintf("%d\n", sc->dacn); 2238 kprintf(" Multi-track converter type: "); 2239 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) { 2240 kprintf("AC'97(SDATA_OUT:"); 2241 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE) 2242 kprintf("packed"); 2243 else 2244 kprintf("split"); 2245 kprintf(")\n"); 2246 } 2247 else { 2248 kprintf("I2S("); 2249 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL) 2250 kprintf("with volume, "); 2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ) 2252 kprintf("192KHz support, "); 2253 else 2254 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ) 2255 kprintf("192KHz support, "); 2256 else 2257 kprintf("48KHz support, "); 2258 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) { 2259 case ENVY24HT_CCSM_I2S_16BIT: 2260 kprintf("16bit resolution, "); 2261 break; 2262 case ENVY24HT_CCSM_I2S_18BIT: 2263 kprintf("18bit resolution, "); 2264 break; 2265 case ENVY24HT_CCSM_I2S_20BIT: 2266 kprintf("20bit resolution, "); 2267 break; 2268 case ENVY24HT_CCSM_I2S_24BIT: 2269 kprintf("24bit resolution, "); 2270 break; 2271 } 2272 kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID); 2273 } 2274 kprintf(" S/PDIF(IN/OUT): "); 2275 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN) 2276 kprintf("1/"); 2277 else 2278 kprintf("0/"); 2279 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT) 2280 kprintf("1 "); 2281 else 2282 kprintf("0 "); 2283 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT)) 2284 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2); 2285 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2286 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2287 } 2288 2289 static int 2290 envy24ht_init(struct sc_info *sc) 2291 { 2292 u_int32_t data; 2293 #if(0) 2294 int rtn; 2295 #endif 2296 int i; 2297 u_int32_t sv, sd; 2298 2299 2300 #if(0) 2301 device_printf(sc->dev, "envy24ht_init()\n"); 2302 #endif 2303 2304 /* reset chip */ 2305 #if 0 2306 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1); 2307 DELAY(200); 2308 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1); 2309 DELAY(200); 2310 2311 /* legacy hardware disable */ 2312 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2313 data |= PCIM_LAC_DISABLE; 2314 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2315 #endif 2316 2317 /* check system configuration */ 2318 sc->cfg = NULL; 2319 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2320 /* 1st: search configuration from table */ 2321 sv = pci_get_subvendor(sc->dev); 2322 sd = pci_get_subdevice(sc->dev); 2323 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2324 #if(0) 2325 device_printf(sc->dev, "Set configuration from table\n"); 2326 #endif 2327 sc->cfg = &cfg_table[i]; 2328 break; 2329 } 2330 } 2331 if (sc->cfg == NULL) { 2332 /* 2nd: read configuration from table */ 2333 sc->cfg = envy24ht_rom2cfg(sc); 2334 } 2335 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */ 2336 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1; 2337 2338 if (1 /* bootverbose */) { 2339 envy24ht_putcfg(sc); 2340 } 2341 2342 /* set system configuration */ 2343 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1); 2344 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1); 2345 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1); 2346 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1); 2347 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); 2348 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); 2349 envy24ht_gpiowr(sc, sc->cfg->gpiostate); 2350 2351 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { 2352 envy24ht_wri2c(sc, 0x22, 0x00, 0x07); 2353 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); 2354 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); 2355 } 2356 2357 for (i = 0; i < sc->adcn; i++) { 2358 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2359 sc->cfg->codec->init(sc->adc[i]); 2360 } 2361 for (i = 0; i < sc->dacn; i++) { 2362 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2363 sc->cfg->codec->init(sc->dac[i]); 2364 } 2365 2366 /* initialize DMA buffer */ 2367 #if(0) 2368 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n"); 2369 #endif 2370 if (envy24ht_dmainit(sc)) 2371 return ENOSPC; 2372 2373 /* initialize status */ 2374 sc->run[0] = sc->run[1] = 0; 2375 sc->intr[0] = sc->intr[1] = 0; 2376 sc->speed = 0; 2377 sc->caps[0].fmtlist = envy24ht_playfmt; 2378 sc->caps[1].fmtlist = envy24ht_recfmt; 2379 2380 /* set channel router */ 2381 #if 0 2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0); 2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0); 2385 #endif 2386 2387 /* set macro interrupt mask */ 2388 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2389 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1); 2390 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1); 2391 #if(0) 2392 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data); 2393 #endif 2394 2395 return 0; 2396 } 2397 2398 static int 2399 envy24ht_alloc_resource(struct sc_info *sc) 2400 { 2401 /* allocate I/O port resource */ 2402 sc->csid = PCIR_CCS; 2403 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2404 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2405 sc->mtid = ENVY24HT_PCIR_MT; 2406 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2407 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2408 if (!sc->cs || !sc->mt) { 2409 device_printf(sc->dev, "unable to map IO port space\n"); 2410 return ENXIO; 2411 } 2412 sc->cst = rman_get_bustag(sc->cs); 2413 sc->csh = rman_get_bushandle(sc->cs); 2414 sc->mtt = rman_get_bustag(sc->mt); 2415 sc->mth = rman_get_bushandle(sc->mt); 2416 #if(0) 2417 device_printf(sc->dev, 2418 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n", 2419 pci_read_config(sc->dev, PCIR_CCS, 4), 2420 pci_read_config(sc->dev, PCIR_MT, 4)); 2421 #endif 2422 2423 /* allocate interupt resource */ 2424 sc->irqid = 0; 2425 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2426 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2427 if (!sc->irq || 2428 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) { 2429 device_printf(sc->dev, "unable to map interrupt\n"); 2430 return ENXIO; 2431 } 2432 2433 /* allocate DMA resource */ 2434 if (bus_dma_tag_create(/*parent*/NULL, 2435 /*alignment*/4, 2436 /*boundary*/0, 2437 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2438 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2439 /*filter*/NULL, /*filterarg*/NULL, 2440 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2441 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2442 /*flags*/0 , &sc->dmat) != 0) { 2443 device_printf(sc->dev, "unable to create dma tag\n"); 2444 return ENXIO; 2445 } 2446 2447 return 0; 2448 } 2449 2450 static int 2451 envy24ht_pci_attach(device_t dev) 2452 { 2453 u_int32_t data; 2454 struct sc_info *sc; 2455 char status[SND_STATUSLEN]; 2456 int err = 0; 2457 int i; 2458 2459 #if(0) 2460 device_printf(dev, "envy24ht_pci_attach()\n"); 2461 #endif 2462 /* get sc_info data area */ 2463 if ((sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) { 2464 device_printf(dev, "cannot allocate softc\n"); 2465 return ENXIO; 2466 } 2467 2468 bzero(sc, sizeof(*sc)); 2469 sc->lock = snd_mtxcreate(device_get_nameunit(dev), 2470 "snd_envy24ht softc"); 2471 sc->dev = dev; 2472 2473 /* initialize PCI interface */ 2474 data = pci_read_config(dev, PCIR_COMMAND, 2); 2475 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2476 pci_write_config(dev, PCIR_COMMAND, data, 2); 2477 data = pci_read_config(dev, PCIR_COMMAND, 2); 2478 2479 /* allocate resources */ 2480 err = envy24ht_alloc_resource(sc); 2481 if (err) { 2482 device_printf(dev, "unable to allocate system resources\n"); 2483 goto bad; 2484 } 2485 2486 /* initialize card */ 2487 err = envy24ht_init(sc); 2488 if (err) { 2489 device_printf(dev, "unable to initialize the card\n"); 2490 goto bad; 2491 } 2492 2493 /* set multi track mixer */ 2494 mixer_init(dev, &envy24htmixer_class, sc); 2495 2496 /* set channel information */ 2497 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */ 2498 err = pcm_register(dev, sc, 1, 2 + sc->adcn); 2499 if (err) 2500 goto bad; 2501 sc->chnum = 0; 2502 /* for (i = 0; i < 5; i++) { */ 2503 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc); 2504 sc->chnum++; 2505 /* } */ 2506 for (i = 0; i < 2 + sc->adcn; i++) { 2507 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc); 2508 sc->chnum++; 2509 } 2510 2511 /* set status iformation */ 2512 ksnprintf(status, SND_STATUSLEN, 2513 "at io 0x%lx:%ld,0x%lx:%ld irq %ld", 2514 rman_get_start(sc->cs), 2515 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2516 rman_get_start(sc->mt), 2517 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2518 rman_get_start(sc->irq)); 2519 pcm_setstatus(dev, status); 2520 2521 return 0; 2522 2523 bad: 2524 if (sc->ih) 2525 bus_teardown_intr(dev, sc->irq, sc->ih); 2526 if (sc->irq) 2527 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2528 envy24ht_dmafree(sc); 2529 if (sc->dmat) 2530 bus_dma_tag_destroy(sc->dmat); 2531 if (sc->cfg->codec->destroy != NULL) { 2532 for (i = 0; i < sc->adcn; i++) 2533 sc->cfg->codec->destroy(sc->adc[i]); 2534 for (i = 0; i < sc->dacn; i++) 2535 sc->cfg->codec->destroy(sc->dac[i]); 2536 } 2537 envy24ht_cfgfree(sc->cfg); 2538 if (sc->cs) 2539 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2540 if (sc->mt) 2541 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2542 if (sc->lock) 2543 snd_mtxfree(sc->lock); 2544 kfree(sc, M_ENVY24HT); 2545 return err; 2546 } 2547 2548 static int 2549 envy24ht_pci_detach(device_t dev) 2550 { 2551 struct sc_info *sc; 2552 int r; 2553 int i; 2554 2555 #if(0) 2556 device_printf(dev, "envy24ht_pci_detach()\n"); 2557 #endif 2558 sc = pcm_getdevinfo(dev); 2559 if (sc == NULL) 2560 return 0; 2561 r = pcm_unregister(dev); 2562 if (r) 2563 return r; 2564 2565 envy24ht_dmafree(sc); 2566 if (sc->cfg->codec->destroy != NULL) { 2567 for (i = 0; i < sc->adcn; i++) 2568 sc->cfg->codec->destroy(sc->adc[i]); 2569 for (i = 0; i < sc->dacn; i++) 2570 sc->cfg->codec->destroy(sc->dac[i]); 2571 } 2572 envy24ht_cfgfree(sc->cfg); 2573 bus_dma_tag_destroy(sc->dmat); 2574 bus_teardown_intr(dev, sc->irq, sc->ih); 2575 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2576 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2577 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2578 snd_mtxfree(sc->lock); 2579 kfree(sc, M_ENVY24HT); 2580 return 0; 2581 } 2582 2583 static device_method_t envy24ht_methods[] = { 2584 /* Device interface */ 2585 DEVMETHOD(device_probe, envy24ht_pci_probe), 2586 DEVMETHOD(device_attach, envy24ht_pci_attach), 2587 DEVMETHOD(device_detach, envy24ht_pci_detach), 2588 { 0, 0 } 2589 }; 2590 2591 static driver_t envy24ht_driver = { 2592 "pcm", 2593 envy24ht_methods, 2594 #if __FreeBSD_version > 500000 2595 PCM_SOFTC_SIZE, 2596 #else 2597 sizeof(struct snddev_info), 2598 #endif 2599 }; 2600 2601 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0); 2602 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2603 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1); 2604 MODULE_VERSION(snd_envy24ht, 1); 2605