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