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