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/ak452x.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 ak452x_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_PLAY && sc->adc[num] != NULL) 785 buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info; 786 else if (dir == PCMDIR_REC && sc->dac[num] != NULL) 787 buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info; 788 else 789 buff->info = ak452x_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->adc[ptr->num] == NULL) 814 ak452x_destroy(ptr->info); 815 } 816 else { 817 if (ptr->parent->dac[ptr->num] == NULL) 818 ak452x_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 #if 0 857 ptr->cdti = ENVY24_GPIO_AK4524_CDTI; 858 #endif 859 ptr->cdti = ptr->parent->cfg->cdti; 860 #if 0 861 ak452x_settype(ptr->info, AK452X_TYPE_4524); 862 #endif 863 ak452x_settype(ptr->info, ptr->parent->cfg->type); 864 #if 0 865 ak452x_setcif(ptr->info, ENVY24_DELTA_AK4524_CIF); 866 #endif 867 ak452x_setcif(ptr->info, ptr->parent->cfg->cif); 868 ak452x_setformat(ptr->info, 869 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 870 ak452x_setdvc(ptr->info, 0); 871 ak452x_init(ptr->info); 872 } 873 874 static void 875 envy24_delta_ak4524_reinit(void *codec) 876 { 877 struct envy24_delta_ak4524_codec *ptr = codec; 878 if (ptr == NULL) 879 return; 880 #if(0) 881 device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n"); 882 #endif 883 884 ak452x_reinit(ptr->info); 885 } 886 887 static void 888 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 889 { 890 struct envy24_delta_ak4524_codec *ptr = codec; 891 if (ptr == NULL) 892 return; 893 #if(0) 894 device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n"); 895 #endif 896 897 ak452x_set(ptr->info, dir, left, right); 898 } 899 900 /* 901 There is no need for AK452[48] codec to set sample rate 902 static void 903 envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate) 904 { 905 } 906 */ 907 908 /* -------------------------------------------------------------------- */ 909 910 /* hardware access routeines */ 911 912 static struct { 913 u_int32_t speed; 914 u_int32_t code; 915 } envy24_speedtab[] = { 916 {48000, ENVY24_MT_RATE_48000}, 917 {24000, ENVY24_MT_RATE_24000}, 918 {12000, ENVY24_MT_RATE_12000}, 919 {9600, ENVY24_MT_RATE_9600}, 920 {32000, ENVY24_MT_RATE_32000}, 921 {16000, ENVY24_MT_RATE_16000}, 922 {8000, ENVY24_MT_RATE_8000}, 923 {96000, ENVY24_MT_RATE_96000}, 924 {64000, ENVY24_MT_RATE_64000}, 925 {44100, ENVY24_MT_RATE_44100}, 926 {22050, ENVY24_MT_RATE_22050}, 927 {11025, ENVY24_MT_RATE_11025}, 928 {88200, ENVY24_MT_RATE_88200}, 929 {0, 0x10} 930 }; 931 932 static int 933 envy24_setspeed(struct sc_info *sc, u_int32_t speed) { 934 u_int32_t code; 935 int i = 0; 936 937 #if(0) 938 device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed); 939 #endif 940 if (speed == 0) { 941 code = ENVY24_MT_RATE_SPDIF; /* external master clock */ 942 envy24_slavecd(sc); 943 } 944 else { 945 for (i = 0; envy24_speedtab[i].speed != 0; i++) { 946 if (envy24_speedtab[i].speed == speed) 947 break; 948 } 949 code = envy24_speedtab[i].code; 950 } 951 #if(0) 952 device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code); 953 #endif 954 if (code < 0x10) { 955 envy24_wrmt(sc, ENVY24_MT_RATE, code, 1); 956 code = envy24_rdmt(sc, ENVY24_MT_RATE, 1); 957 code &= ENVY24_MT_RATE_MASK; 958 for (i = 0; envy24_speedtab[i].code < 0x10; i++) { 959 if (envy24_speedtab[i].code == code) 960 break; 961 } 962 speed = envy24_speedtab[i].speed; 963 } 964 else 965 speed = 0; 966 967 #if(0) 968 device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed); 969 #endif 970 return speed; 971 } 972 973 static void 974 envy24_setvolume(struct sc_info *sc, unsigned ch) 975 { 976 #if(0) 977 device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch); 978 #endif 979 if (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) { 980 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1); 981 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 982 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1); 983 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 984 } 985 986 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 987 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 988 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 989 envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 990 } 991 992 static void 993 envy24_mutevolume(struct sc_info *sc, unsigned ch) 994 { 995 u_int32_t vol; 996 997 #if(0) 998 device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch); 999 #endif 1000 vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE; 1001 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 1002 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 1003 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 1004 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 1005 } 1006 1007 static u_int32_t 1008 envy24_gethwptr(struct sc_info *sc, int dir) 1009 { 1010 int unit, regno; 1011 u_int32_t ptr, rtn; 1012 1013 #if(0) 1014 device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir); 1015 #endif 1016 if (dir == PCMDIR_PLAY) { 1017 rtn = sc->psize / 4; 1018 unit = ENVY24_PLAY_BUFUNIT / 4; 1019 regno = ENVY24_MT_PCNT; 1020 } 1021 else { 1022 rtn = sc->rsize / 4; 1023 unit = ENVY24_REC_BUFUNIT / 4; 1024 regno = ENVY24_MT_RCNT; 1025 } 1026 1027 ptr = envy24_rdmt(sc, regno, 2); 1028 rtn -= (ptr + 1); 1029 rtn /= unit; 1030 1031 #if(0) 1032 device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn); 1033 #endif 1034 return rtn; 1035 } 1036 1037 static void 1038 envy24_updintr(struct sc_info *sc, int dir) 1039 { 1040 int regptr, regintr; 1041 u_int32_t mask, intr; 1042 u_int32_t ptr, size, cnt; 1043 u_int16_t blk; 1044 1045 #if(0) 1046 device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir); 1047 #endif 1048 if (dir == PCMDIR_PLAY) { 1049 blk = sc->blk[0]; 1050 size = sc->psize / 4; 1051 regptr = ENVY24_MT_PCNT; 1052 regintr = ENVY24_MT_PTERM; 1053 mask = ~ENVY24_MT_INT_PMASK; 1054 } 1055 else { 1056 blk = sc->blk[1]; 1057 size = sc->rsize / 4; 1058 regptr = ENVY24_MT_RCNT; 1059 regintr = ENVY24_MT_RTERM; 1060 mask = ~ENVY24_MT_INT_RMASK; 1061 } 1062 1063 ptr = size - envy24_rdmt(sc, regptr, 2) - 1; 1064 /* 1065 cnt = blk - ptr % blk - 1; 1066 if (cnt == 0) 1067 cnt = blk - 1; 1068 */ 1069 cnt = blk - 1; 1070 #if(0) 1071 device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1072 #endif 1073 envy24_wrmt(sc, regintr, cnt, 2); 1074 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1075 #if(0) 1076 device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1077 #endif 1078 envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1); 1079 #if(0) 1080 device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n", 1081 envy24_rdmt(sc, ENVY24_MT_INT, 1)); 1082 #endif 1083 1084 return; 1085 } 1086 1087 #if 0 1088 static void 1089 envy24_maskintr(struct sc_info *sc, int dir) 1090 { 1091 u_int32_t mask, intr; 1092 1093 #if(0) 1094 device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir); 1095 #endif 1096 if (dir == PCMDIR_PLAY) 1097 mask = ENVY24_MT_INT_PMASK; 1098 else 1099 mask = ENVY24_MT_INT_RMASK; 1100 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1101 envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1); 1102 1103 return; 1104 } 1105 #endif 1106 1107 static int 1108 envy24_checkintr(struct sc_info *sc, int dir) 1109 { 1110 u_int32_t mask, stat, intr, rtn; 1111 1112 #if(0) 1113 device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir); 1114 #endif 1115 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1116 if (dir == PCMDIR_PLAY) { 1117 if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) { 1118 mask = ~ENVY24_MT_INT_RSTAT; 1119 stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK; 1120 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1121 } 1122 } 1123 else { 1124 if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) { 1125 mask = ~ENVY24_MT_INT_PSTAT; 1126 stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK; 1127 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1128 } 1129 } 1130 1131 return rtn; 1132 } 1133 1134 static void 1135 envy24_start(struct sc_info *sc, int dir) 1136 { 1137 u_int32_t stat, sw; 1138 1139 #if(0) 1140 device_printf(sc->dev, "envy24_start(sc, %d)\n", dir); 1141 #endif 1142 if (dir == PCMDIR_PLAY) 1143 sw = ENVY24_MT_PCTL_PSTART; 1144 else 1145 sw = ENVY24_MT_PCTL_RSTART; 1146 1147 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1148 envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1); 1149 #if(0) 1150 DELAY(100); 1151 device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 1152 device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 1153 #endif 1154 1155 return; 1156 } 1157 1158 static void 1159 envy24_stop(struct sc_info *sc, int dir) 1160 { 1161 u_int32_t stat, sw; 1162 1163 #if(0) 1164 device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir); 1165 #endif 1166 if (dir == PCMDIR_PLAY) 1167 sw = ~ENVY24_MT_PCTL_PSTART; 1168 else 1169 sw = ~ENVY24_MT_PCTL_RSTART; 1170 1171 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1172 envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1); 1173 1174 return; 1175 } 1176 1177 static int 1178 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1179 { 1180 u_int32_t reg, mask; 1181 u_int32_t left, right; 1182 1183 #if(0) 1184 device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n", 1185 dac, class, adc, rev); 1186 #endif 1187 /* parameter pattern check */ 1188 if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac) 1189 return -1; 1190 if (class == ENVY24_ROUTE_CLASS_MIX && 1191 (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF)) 1192 return -1; 1193 if (rev) { 1194 left = ENVY24_ROUTE_RIGHT; 1195 right = ENVY24_ROUTE_LEFT; 1196 } 1197 else { 1198 left = ENVY24_ROUTE_LEFT; 1199 right = ENVY24_ROUTE_RIGHT; 1200 } 1201 1202 if (dac == ENVY24_ROUTE_DAC_SPDIF) { 1203 reg = class | class << 2 | 1204 ((adc << 1 | left) | left << 3) << 8 | 1205 ((adc << 1 | right) | right << 3) << 12; 1206 #if(0) 1207 device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg); 1208 #endif 1209 envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2); 1210 } 1211 else { 1212 mask = ~(0x0303 << dac * 2); 1213 reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2); 1214 reg = (reg & mask) | ((class | class << 8) << dac * 2); 1215 #if(0) 1216 device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg); 1217 #endif 1218 envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2); 1219 mask = ~(0xff << dac * 8); 1220 reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4); 1221 reg = (reg & mask) | 1222 (((adc << 1 | left) | left << 3) | 1223 ((adc << 1 | right) | right << 3) << 4) << dac * 8; 1224 #if(0) 1225 device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); 1226 #endif 1227 envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); 1228 } 1229 1230 return 0; 1231 } 1232 1233 /* -------------------------------------------------------------------- */ 1234 1235 /* buffer copy routines */ 1236 static void 1237 envy24_p32sl(struct sc_chinfo *ch) 1238 { 1239 int length; 1240 sample32_t *dmabuf; 1241 u_int32_t *data; 1242 int src, dst, ssize, dsize, slot; 1243 int i; 1244 1245 length = sndbuf_getready(ch->buffer) / 8; 1246 dmabuf = ch->parent->pbuf; 1247 data = (u_int32_t *)ch->data; 1248 src = sndbuf_getreadyptr(ch->buffer) / 4; 1249 dst = src / 2 + ch->offset; 1250 ssize = ch->size / 4; 1251 dsize = ch->size / 8; 1252 slot = ch->num * 2; 1253 1254 for (i = 0; i < length; i++) { 1255 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src]; 1256 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1257 dst++; 1258 dst %= dsize; 1259 src += 2; 1260 src %= ssize; 1261 } 1262 1263 return; 1264 } 1265 1266 static void 1267 envy24_p16sl(struct sc_chinfo *ch) 1268 { 1269 int length; 1270 sample32_t *dmabuf; 1271 u_int16_t *data; 1272 int src, dst, ssize, dsize, slot; 1273 int i; 1274 1275 #if(0) 1276 device_printf(ch->parent->dev, "envy24_p16sl()\n"); 1277 #endif 1278 length = sndbuf_getready(ch->buffer) / 4; 1279 dmabuf = ch->parent->pbuf; 1280 data = (u_int16_t *)ch->data; 1281 src = sndbuf_getreadyptr(ch->buffer) / 2; 1282 dst = src / 2 + ch->offset; 1283 ssize = ch->size / 2; 1284 dsize = ch->size / 4; 1285 slot = ch->num * 2; 1286 #if(0) 1287 device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1288 #endif 1289 1290 for (i = 0; i < length; i++) { 1291 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1292 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1293 #if(0) 1294 if (i < 16) { 1295 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]); 1296 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]); 1297 } 1298 #endif 1299 dst++; 1300 dst %= dsize; 1301 src += 2; 1302 src %= ssize; 1303 } 1304 #if(0) 1305 printf("\n"); 1306 #endif 1307 1308 return; 1309 } 1310 1311 static void 1312 envy24_p8u(struct sc_chinfo *ch) 1313 { 1314 int length; 1315 sample32_t *dmabuf; 1316 u_int8_t *data; 1317 int src, dst, ssize, dsize, slot; 1318 int i; 1319 1320 length = sndbuf_getready(ch->buffer) / 2; 1321 dmabuf = ch->parent->pbuf; 1322 data = (u_int8_t *)ch->data; 1323 src = sndbuf_getreadyptr(ch->buffer); 1324 dst = src / 2 + ch->offset; 1325 ssize = ch->size; 1326 dsize = ch->size / 4; 1327 slot = ch->num * 2; 1328 1329 for (i = 0; i < length; i++) { 1330 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1331 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1332 dst++; 1333 dst %= dsize; 1334 src += 2; 1335 src %= ssize; 1336 } 1337 1338 return; 1339 } 1340 1341 static void 1342 envy24_r32sl(struct sc_chinfo *ch) 1343 { 1344 int length; 1345 sample32_t *dmabuf; 1346 u_int32_t *data; 1347 int src, dst, ssize, dsize, slot; 1348 int i; 1349 1350 length = sndbuf_getfree(ch->buffer) / 8; 1351 dmabuf = ch->parent->rbuf; 1352 data = (u_int32_t *)ch->data; 1353 dst = sndbuf_getfreeptr(ch->buffer) / 4; 1354 src = dst / 2 + ch->offset; 1355 dsize = ch->size / 4; 1356 ssize = ch->size / 8; 1357 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1358 1359 for (i = 0; i < length; i++) { 1360 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1361 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1362 dst += 2; 1363 dst %= dsize; 1364 src++; 1365 src %= ssize; 1366 } 1367 1368 return; 1369 } 1370 1371 static void 1372 envy24_r16sl(struct sc_chinfo *ch) 1373 { 1374 int length; 1375 sample32_t *dmabuf; 1376 u_int16_t *data; 1377 int src, dst, ssize, dsize, slot; 1378 int i; 1379 1380 length = sndbuf_getfree(ch->buffer) / 4; 1381 dmabuf = ch->parent->rbuf; 1382 data = (u_int16_t *)ch->data; 1383 dst = sndbuf_getfreeptr(ch->buffer) / 2; 1384 src = dst / 2 + ch->offset; 1385 dsize = ch->size / 2; 1386 ssize = ch->size / 8; 1387 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1388 1389 for (i = 0; i < length; i++) { 1390 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1391 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1392 dst += 2; 1393 dst %= dsize; 1394 src++; 1395 src %= ssize; 1396 } 1397 1398 return; 1399 } 1400 1401 /* -------------------------------------------------------------------- */ 1402 1403 /* channel interface */ 1404 static void * 1405 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1406 { 1407 struct sc_info *sc = (struct sc_info *)devinfo; 1408 struct sc_chinfo *ch; 1409 unsigned num; 1410 1411 #if(0) 1412 device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir); 1413 #endif 1414 snd_mtxlock(sc->lock); 1415 if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1416 (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1417 snd_mtxunlock(sc->lock); 1418 return NULL; 1419 } 1420 num = sc->chnum; 1421 1422 ch = &sc->chan[num]; 1423 ch->size = 8 * ENVY24_SAMPLE_NUM; 1424 ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT); 1425 if (ch->data == NULL) { 1426 ch->size = 0; 1427 ch = NULL; 1428 } 1429 else { 1430 ch->buffer = b; 1431 ch->channel = c; 1432 ch->parent = sc; 1433 ch->dir = dir; 1434 /* set channel map */ 1435 ch->num = envy24_chanmap[num]; 1436 sndbuf_setup(ch->buffer, ch->data, ch->size); 1437 /* these 2 values are dummy */ 1438 ch->unit = 4; 1439 ch->blk = 10240; 1440 } 1441 snd_mtxunlock(sc->lock); 1442 1443 return ch; 1444 } 1445 1446 static int 1447 envy24chan_free(kobj_t obj, void *data) 1448 { 1449 struct sc_chinfo *ch = data; 1450 struct sc_info *sc = ch->parent; 1451 1452 #if(0) 1453 device_printf(sc->dev, "envy24chan_free()\n"); 1454 #endif 1455 snd_mtxlock(sc->lock); 1456 if (ch->data != NULL) { 1457 free(ch->data, M_ENVY24); 1458 ch->data = NULL; 1459 } 1460 snd_mtxunlock(sc->lock); 1461 1462 return 0; 1463 } 1464 1465 static int 1466 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format) 1467 { 1468 struct sc_chinfo *ch = data; 1469 struct sc_info *sc = ch->parent; 1470 struct envy24_emldma *emltab; 1471 unsigned int bcnt, bsize; 1472 int i; 1473 1474 #if(0) 1475 device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format); 1476 #endif 1477 snd_mtxlock(sc->lock); 1478 /* check and get format related information */ 1479 if (ch->dir == PCMDIR_PLAY) 1480 emltab = envy24_pemltab; 1481 else 1482 emltab = envy24_remltab; 1483 if (emltab == NULL) { 1484 snd_mtxunlock(sc->lock); 1485 return -1; 1486 } 1487 for (i = 0; emltab[i].format != 0; i++) 1488 if (emltab[i].format == format) 1489 break; 1490 if (emltab[i].format == 0) { 1491 snd_mtxunlock(sc->lock); 1492 return -1; 1493 } 1494 1495 /* set format information */ 1496 ch->format = format; 1497 ch->emldma = emltab[i].emldma; 1498 if (ch->unit > emltab[i].unit) 1499 ch->blk *= ch->unit / emltab[i].unit; 1500 else 1501 ch->blk /= emltab[i].unit / ch->unit; 1502 ch->unit = emltab[i].unit; 1503 1504 /* set channel buffer information */ 1505 ch->size = ch->unit * ENVY24_SAMPLE_NUM; 1506 if (ch->dir == PCMDIR_PLAY) 1507 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1508 else 1509 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1510 bsize *= ch->unit; 1511 bcnt = ch->size / bsize; 1512 sndbuf_resize(ch->buffer, bcnt, bsize); 1513 snd_mtxunlock(sc->lock); 1514 1515 #if(0) 1516 device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0); 1517 #endif 1518 return 0; 1519 } 1520 1521 /* 1522 IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1523 of speed information value. And real hardware speed setting is done 1524 at start triggered(see envy24chan_trigger()). So, at this function 1525 is called, any value that ENVY24 can use is able to set. But, at 1526 start triggerd, some other channel is running, and that channel's 1527 speed isn't same with, then trigger function will fail. 1528 */ 1529 static int 1530 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1531 { 1532 struct sc_chinfo *ch = data; 1533 u_int32_t val, prev; 1534 int i; 1535 1536 #if(0) 1537 device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed); 1538 #endif 1539 prev = 0x7fffffff; 1540 for (i = 0; (val = envy24_speed[i]) != 0; i++) { 1541 if (abs(val - speed) < abs(prev - speed)) 1542 prev = val; 1543 else 1544 break; 1545 } 1546 ch->speed = prev; 1547 1548 #if(0) 1549 device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed); 1550 #endif 1551 return ch->speed; 1552 } 1553 1554 static int 1555 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1556 { 1557 struct sc_chinfo *ch = data; 1558 struct sc_info *sc = ch->parent; 1559 u_int32_t size, prev; 1560 1561 #if(0) 1562 device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize); 1563 #endif 1564 prev = 0x7fffffff; 1565 snd_mtxlock(sc->lock); 1566 for (size = ch->size / 2; size > 0; size /= 2) { 1567 if (abs(size - blocksize) < abs(prev - blocksize)) 1568 prev = size; 1569 else 1570 break; 1571 } 1572 1573 ch->blk = prev / ch->unit; 1574 if (ch->dir == PCMDIR_PLAY) 1575 ch->blk *= ENVY24_PLAY_BUFUNIT / 4; 1576 else 1577 ch->blk *= ENVY24_REC_BUFUNIT / 4; 1578 snd_mtxunlock(sc->lock); 1579 1580 #if(0) 1581 device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev); 1582 #endif 1583 return prev; 1584 } 1585 1586 /* semantic note: must start at beginning of buffer */ 1587 static int 1588 envy24chan_trigger(kobj_t obj, void *data, int go) 1589 { 1590 struct sc_chinfo *ch = data; 1591 struct sc_info *sc = ch->parent; 1592 u_int32_t ptr; 1593 int slot; 1594 int i; 1595 1596 #if(0) 1597 device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go); 1598 #endif 1599 snd_mtxlock(sc->lock); 1600 if (ch->dir == PCMDIR_PLAY) 1601 slot = 0; 1602 else 1603 slot = 1; 1604 switch (go) { 1605 case PCMTRIG_START: 1606 #if(0) 1607 device_printf(sc->dev, "envy24chan_trigger(): start\n"); 1608 #endif 1609 /* check or set channel speed */ 1610 if (sc->run[0] == 0 && sc->run[1] == 0) { 1611 sc->speed = envy24_setspeed(sc, ch->speed); 1612 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1613 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1614 } 1615 else if (ch->speed != 0 && ch->speed != sc->speed) 1616 return -1; 1617 if (ch->speed == 0) 1618 ch->channel->speed = sc->speed; 1619 /* start or enable channel */ 1620 sc->run[slot]++; 1621 if (sc->run[slot] == 1) { 1622 /* first channel */ 1623 ch->offset = 0; 1624 sc->blk[slot] = ch->blk; 1625 } 1626 else { 1627 ptr = envy24_gethwptr(sc, ch->dir); 1628 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1629 (ch->size / 4)) * 4 / ch->unit; 1630 if (ch->blk < sc->blk[slot]) 1631 sc->blk[slot] = ch->blk; 1632 } 1633 if (ch->dir == PCMDIR_PLAY) { 1634 ch->emldma(ch); 1635 envy24_setvolume(sc, ch->num); 1636 } 1637 envy24_updintr(sc, ch->dir); 1638 if (sc->run[slot] == 1) 1639 envy24_start(sc, ch->dir); 1640 ch->run = 1; 1641 break; 1642 case PCMTRIG_EMLDMAWR: 1643 #if(0) 1644 device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n"); 1645 #endif 1646 if (ch->run != 1) 1647 return -1; 1648 ch->emldma(ch); 1649 break; 1650 case PCMTRIG_EMLDMARD: 1651 #if(0) 1652 device_printf(sc->dev, "envy24chan_trigger(): emldmard\n"); 1653 #endif 1654 if (ch->run != 1) 1655 return -1; 1656 ch->emldma(ch); 1657 break; 1658 case PCMTRIG_ABORT: 1659 #if(0) 1660 device_printf(sc->dev, "envy24chan_trigger(): abort\n"); 1661 #endif 1662 ch->run = 0; 1663 sc->run[slot]--; 1664 if (ch->dir == PCMDIR_PLAY) 1665 envy24_mutevolume(sc, ch->num); 1666 if (sc->run[slot] == 0) { 1667 envy24_stop(sc, ch->dir); 1668 sc->intr[slot] = 0; 1669 } 1670 else if (ch->blk == sc->blk[slot]) { 1671 sc->blk[slot] = ENVY24_SAMPLE_NUM / 2; 1672 for (i = 0; i < ENVY24_CHAN_NUM; i++) { 1673 if (sc->chan[i].dir == ch->dir && 1674 sc->chan[i].run == 1 && 1675 sc->chan[i].blk < sc->blk[slot]) 1676 sc->blk[slot] = sc->chan[i].blk; 1677 } 1678 if (ch->blk != sc->blk[slot]) 1679 envy24_updintr(sc, ch->dir); 1680 } 1681 break; 1682 } 1683 snd_mtxunlock(sc->lock); 1684 1685 return 0; 1686 } 1687 1688 static int 1689 envy24chan_getptr(kobj_t obj, void *data) 1690 { 1691 struct sc_chinfo *ch = data; 1692 struct sc_info *sc = ch->parent; 1693 u_int32_t ptr; 1694 int rtn; 1695 1696 #if(0) 1697 device_printf(sc->dev, "envy24chan_getptr()\n"); 1698 #endif 1699 snd_mtxlock(sc->lock); 1700 ptr = envy24_gethwptr(sc, ch->dir); 1701 rtn = ptr * ch->unit; 1702 snd_mtxunlock(sc->lock); 1703 1704 #if(0) 1705 device_printf(sc->dev, "envy24chan_getptr(): return %d\n", 1706 rtn); 1707 #endif 1708 return rtn; 1709 } 1710 1711 static struct pcmchan_caps * 1712 envy24chan_getcaps(kobj_t obj, void *data) 1713 { 1714 struct sc_chinfo *ch = data; 1715 struct sc_info *sc = ch->parent; 1716 struct pcmchan_caps *rtn; 1717 1718 #if(0) 1719 device_printf(sc->dev, "envy24chan_getcaps()\n"); 1720 #endif 1721 snd_mtxlock(sc->lock); 1722 if (ch->dir == PCMDIR_PLAY) { 1723 if (sc->run[0] == 0) 1724 rtn = &envy24_playcaps; 1725 else 1726 rtn = &sc->caps[0]; 1727 } 1728 else { 1729 if (sc->run[1] == 0) 1730 rtn = &envy24_reccaps; 1731 else 1732 rtn = &sc->caps[1]; 1733 } 1734 snd_mtxunlock(sc->lock); 1735 1736 return rtn; 1737 } 1738 1739 static kobj_method_t envy24chan_methods[] = { 1740 KOBJMETHOD(channel_init, envy24chan_init), 1741 KOBJMETHOD(channel_free, envy24chan_free), 1742 KOBJMETHOD(channel_setformat, envy24chan_setformat), 1743 KOBJMETHOD(channel_setspeed, envy24chan_setspeed), 1744 KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize), 1745 KOBJMETHOD(channel_trigger, envy24chan_trigger), 1746 KOBJMETHOD(channel_getptr, envy24chan_getptr), 1747 KOBJMETHOD(channel_getcaps, envy24chan_getcaps), 1748 { 0, 0 } 1749 }; 1750 CHANNEL_DECLARE(envy24chan); 1751 1752 /* -------------------------------------------------------------------- */ 1753 1754 /* mixer interface */ 1755 1756 static int 1757 envy24mixer_init(struct snd_mixer *m) 1758 { 1759 struct sc_info *sc = mix_getdevinfo(m); 1760 1761 #if(0) 1762 device_printf(sc->dev, "envy24mixer_init()\n"); 1763 #endif 1764 if (sc == NULL) 1765 return -1; 1766 1767 /* set volume control rate */ 1768 snd_mtxlock(sc->lock); 1769 envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1770 1771 mix_setdevs(m, ENVY24_MIX_MASK); 1772 mix_setrecdevs(m, ENVY24_MIX_REC_MASK); 1773 snd_mtxunlock(sc->lock); 1774 1775 return 0; 1776 } 1777 1778 static int 1779 envy24mixer_reinit(struct snd_mixer *m) 1780 { 1781 struct sc_info *sc = mix_getdevinfo(m); 1782 1783 if (sc == NULL) 1784 return -1; 1785 #if(0) 1786 device_printf(sc->dev, "envy24mixer_reinit()\n"); 1787 #endif 1788 1789 return 0; 1790 } 1791 1792 static int 1793 envy24mixer_uninit(struct snd_mixer *m) 1794 { 1795 struct sc_info *sc = mix_getdevinfo(m); 1796 1797 if (sc == NULL) 1798 return -1; 1799 #if(0) 1800 device_printf(sc->dev, "envy24mixer_uninit()\n"); 1801 #endif 1802 1803 return 0; 1804 } 1805 1806 static int 1807 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1808 { 1809 struct sc_info *sc = mix_getdevinfo(m); 1810 int ch = envy24_mixmap[dev]; 1811 int hwch; 1812 int i; 1813 1814 if (sc == NULL) 1815 return -1; 1816 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1817 return -1; 1818 if (dev != 0 && ch == -1) 1819 return -1; 1820 hwch = envy24_chanmap[ch]; 1821 #if(0) 1822 device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n", 1823 dev, left, right); 1824 #endif 1825 1826 snd_mtxlock(sc->lock); 1827 if (dev == 0) { 1828 for (i = 0; i < sc->dacn; i++) { 1829 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1830 } 1831 } 1832 else { 1833 /* set volume value for hardware */ 1834 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN) 1835 sc->left[hwch] = ENVY24_VOL_MUTE; 1836 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN) 1837 sc->right[hwch] = ENVY24_VOL_MUTE; 1838 1839 /* set volume for record channel and running play channel */ 1840 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1841 envy24_setvolume(sc, hwch); 1842 } 1843 snd_mtxunlock(sc->lock); 1844 1845 return right << 8 | left; 1846 } 1847 1848 static u_int32_t 1849 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1850 { 1851 struct sc_info *sc = mix_getdevinfo(m); 1852 int ch = envy24_mixmap[src]; 1853 #if(0) 1854 device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src); 1855 #endif 1856 1857 if (ch > ENVY24_CHAN_PLAY_SPDIF) 1858 sc->src = ch; 1859 return src; 1860 } 1861 1862 static kobj_method_t envy24mixer_methods[] = { 1863 KOBJMETHOD(mixer_init, envy24mixer_init), 1864 KOBJMETHOD(mixer_reinit, envy24mixer_reinit), 1865 KOBJMETHOD(mixer_uninit, envy24mixer_uninit), 1866 KOBJMETHOD(mixer_set, envy24mixer_set), 1867 KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc), 1868 { 0, 0 } 1869 }; 1870 MIXER_DECLARE(envy24mixer); 1871 1872 /* -------------------------------------------------------------------- */ 1873 1874 /* The interrupt handler */ 1875 static void 1876 envy24_intr(void *p) 1877 { 1878 struct sc_info *sc = (struct sc_info *)p; 1879 struct sc_chinfo *ch; 1880 u_int32_t ptr, dsize, feed; 1881 int i; 1882 1883 #if(0) 1884 device_printf(sc->dev, "envy24_intr()\n"); 1885 #endif 1886 snd_mtxlock(sc->lock); 1887 if (envy24_checkintr(sc, PCMDIR_PLAY)) { 1888 #if(0) 1889 device_printf(sc->dev, "envy24_intr(): play\n"); 1890 #endif 1891 dsize = sc->psize / 4; 1892 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1; 1893 #if(0) 1894 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr); 1895 #endif 1896 ptr -= ptr % sc->blk[0]; 1897 feed = (ptr + dsize - sc->intr[0]) % dsize; 1898 #if(0) 1899 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1900 #endif 1901 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) { 1902 ch = &sc->chan[i]; 1903 #if(0) 1904 if (ch->run) 1905 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk); 1906 #endif 1907 if (ch->run && ch->blk <= feed) 1908 chn_intr(ch->channel); 1909 } 1910 sc->intr[0] = ptr; 1911 envy24_updintr(sc, PCMDIR_PLAY); 1912 } 1913 if (envy24_checkintr(sc, PCMDIR_REC)) { 1914 #if(0) 1915 device_printf(sc->dev, "envy24_intr(): rec\n"); 1916 #endif 1917 dsize = sc->rsize / 4; 1918 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1; 1919 ptr -= ptr % sc->blk[1]; 1920 feed = (ptr + dsize - sc->intr[1]) % dsize; 1921 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) { 1922 ch = &sc->chan[i]; 1923 if (ch->run && ch->blk <= feed) 1924 chn_intr(ch->channel); 1925 } 1926 sc->intr[1] = ptr; 1927 envy24_updintr(sc, PCMDIR_REC); 1928 } 1929 snd_mtxunlock(sc->lock); 1930 1931 return; 1932 } 1933 1934 /* 1935 * Probe and attach the card 1936 */ 1937 1938 static int 1939 envy24_pci_probe(device_t dev) 1940 { 1941 u_int16_t sv, sd; 1942 int i; 1943 1944 #if(0) 1945 printf("envy24_pci_probe()\n"); 1946 #endif 1947 if (pci_get_device(dev) == PCID_ENVY24 && 1948 pci_get_vendor(dev) == PCIV_ENVY24) { 1949 sv = pci_get_subvendor(dev); 1950 sd = pci_get_subdevice(dev); 1951 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 1952 if (cfg_table[i].subvendor == sv && 1953 cfg_table[i].subdevice == sd) { 1954 break; 1955 } 1956 } 1957 device_set_desc(dev, cfg_table[i].name); 1958 #if(0) 1959 printf("envy24_pci_probe(): return 0\n"); 1960 #endif 1961 return 0; 1962 } 1963 else { 1964 #if(0) 1965 printf("envy24_pci_probe(): return ENXIO\n"); 1966 #endif 1967 return ENXIO; 1968 } 1969 } 1970 1971 static void 1972 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1973 { 1974 struct sc_info *sc = (struct sc_info *)arg; 1975 1976 #if(0) 1977 device_printf(sc->dev, "envy24_dmapsetmap()\n"); 1978 #endif 1979 if (bootverbose) { 1980 printf("envy24(play): setmap %lx, %lx; ", 1981 (unsigned long)segs->ds_addr, 1982 (unsigned long)segs->ds_len); 1983 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 1984 } 1985 } 1986 1987 static void 1988 envy24_dmarsetmap(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_dmarsetmap()\n"); 1994 #endif 1995 if (bootverbose) { 1996 printf("envy24(record): setmap %lx, %lx; ", 1997 (unsigned long)segs->ds_addr, 1998 (unsigned long)segs->ds_len); 1999 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2000 } 2001 } 2002 2003 static void 2004 envy24_dmafree(struct sc_info *sc) 2005 { 2006 #if(0) 2007 device_printf(sc->dev, "envy24_dmafree():"); 2008 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2009 else printf(" sc->rmap(null)"); 2010 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2011 else printf(" sc->pmap(null)"); 2012 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2013 else printf(" sc->rbuf(null)"); 2014 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2015 else printf(" sc->pbuf(null)\n"); 2016 #endif 2017 #if(0) 2018 if (sc->rmap) 2019 bus_dmamap_unload(sc->dmat, sc->rmap); 2020 if (sc->pmap) 2021 bus_dmamap_unload(sc->dmat, sc->pmap); 2022 if (sc->rbuf) 2023 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2024 if (sc->pbuf) 2025 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2026 #else 2027 bus_dmamap_unload(sc->dmat, sc->rmap); 2028 bus_dmamap_unload(sc->dmat, sc->pmap); 2029 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2030 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2031 #endif 2032 2033 sc->rmap = sc->pmap = NULL; 2034 sc->pbuf = NULL; 2035 sc->rbuf = NULL; 2036 2037 return; 2038 } 2039 2040 static int 2041 envy24_dmainit(struct sc_info *sc) 2042 { 2043 u_int32_t addr; 2044 2045 #if(0) 2046 device_printf(sc->dev, "envy24_dmainit()\n"); 2047 #endif 2048 /* init values */ 2049 sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM; 2050 sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM; 2051 sc->pbuf = NULL; 2052 sc->rbuf = NULL; 2053 sc->pmap = sc->rmap = NULL; 2054 sc->blk[0] = sc->blk[1] = 0; 2055 2056 /* allocate DMA buffer */ 2057 #if(0) 2058 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2059 #endif 2060 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2061 goto bad; 2062 #if(0) 2063 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2064 #endif 2065 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2066 goto bad; 2067 #if(0) 2068 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2069 #endif 2070 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0)) 2071 goto bad; 2072 #if(0) 2073 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2074 #endif 2075 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0)) 2076 goto bad; 2077 bzero(sc->pbuf, sc->psize); 2078 bzero(sc->rbuf, sc->rsize); 2079 2080 /* set values to register */ 2081 addr = vtophys(sc->pbuf); 2082 #if(0) 2083 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2084 #endif 2085 envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4); 2086 #if(0) 2087 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 2088 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2089 #endif 2090 envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2); 2091 #if(0) 2092 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 2093 #endif 2094 addr = vtophys(sc->rbuf); 2095 envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4); 2096 envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2); 2097 2098 return 0; 2099 bad: 2100 envy24_dmafree(sc); 2101 return ENOSPC; 2102 } 2103 2104 static void 2105 envy24_putcfg(struct sc_info *sc) 2106 { 2107 device_printf(sc->dev, "system configuration\n"); 2108 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2109 sc->cfg->subvendor, sc->cfg->subdevice); 2110 printf(" XIN2 Clock Source: "); 2111 switch (sc->cfg->scfg & PCIM_SCFG_XIN2) { 2112 case 0x00: 2113 printf("22.5792MHz(44.1kHz*512)\n"); 2114 break; 2115 case 0x40: 2116 printf("16.9344MHz(44.1kHz*384)\n"); 2117 break; 2118 case 0x80: 2119 printf("from external clock synthesizer chip\n"); 2120 break; 2121 default: 2122 printf("illeagal system setting\n"); 2123 } 2124 printf(" MPU-401 UART(s) #: "); 2125 if (sc->cfg->scfg & PCIM_SCFG_MPU) 2126 printf("2\n"); 2127 else 2128 printf("1\n"); 2129 printf(" AC'97 codec: "); 2130 if (sc->cfg->scfg & PCIM_SCFG_AC97) 2131 printf("not exist\n"); 2132 else 2133 printf("exist\n"); 2134 printf(" ADC #: "); 2135 printf("%d\n", sc->adcn); 2136 printf(" DAC #: "); 2137 printf("%d\n", sc->dacn); 2138 printf(" Multi-track converter type: "); 2139 if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) { 2140 printf("AC'97(SDATA_OUT:"); 2141 if (sc->cfg->acl & PCIM_ACL_OMODE) 2142 printf("packed"); 2143 else 2144 printf("split"); 2145 printf("|SDATA_IN:"); 2146 if (sc->cfg->acl & PCIM_ACL_IMODE) 2147 printf("packed"); 2148 else 2149 printf("split"); 2150 printf(")\n"); 2151 } 2152 else { 2153 printf("I2S("); 2154 if (sc->cfg->i2s & PCIM_I2S_VOL) 2155 printf("with volume, "); 2156 if (sc->cfg->i2s & PCIM_I2S_96KHZ) 2157 printf("96KHz support, "); 2158 switch (sc->cfg->i2s & PCIM_I2S_RES) { 2159 case PCIM_I2S_16BIT: 2160 printf("16bit resolution, "); 2161 break; 2162 case PCIM_I2S_18BIT: 2163 printf("18bit resolution, "); 2164 break; 2165 case PCIM_I2S_20BIT: 2166 printf("20bit resolution, "); 2167 break; 2168 case PCIM_I2S_24BIT: 2169 printf("24bit resolution, "); 2170 break; 2171 } 2172 printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID); 2173 } 2174 printf(" S/PDIF(IN/OUT): "); 2175 if (sc->cfg->spdif & PCIM_SPDIF_IN) 2176 printf("1/"); 2177 else 2178 printf("0/"); 2179 if (sc->cfg->spdif & PCIM_SPDIF_OUT) 2180 printf("1 "); 2181 else 2182 printf("0 "); 2183 if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT)) 2184 printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2); 2185 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2186 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2187 } 2188 2189 static int 2190 envy24_init(struct sc_info *sc) 2191 { 2192 u_int32_t data; 2193 #if(0) 2194 int rtn; 2195 #endif 2196 int i; 2197 u_int32_t sv, sd; 2198 2199 2200 #if(0) 2201 device_printf(sc->dev, "envy24_init()\n"); 2202 #endif 2203 2204 /* reset chip */ 2205 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1); 2206 DELAY(200); 2207 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1); 2208 DELAY(200); 2209 2210 /* legacy hardware disable */ 2211 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2212 data |= PCIM_LAC_DISABLE; 2213 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2214 2215 /* check system configuration */ 2216 sc->cfg = NULL; 2217 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2218 /* 1st: search configuration from table */ 2219 sv = pci_get_subvendor(sc->dev); 2220 sd = pci_get_subdevice(sc->dev); 2221 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2222 #if(0) 2223 device_printf(sc->dev, "Set configuration from table\n"); 2224 #endif 2225 sc->cfg = &cfg_table[i]; 2226 break; 2227 } 2228 } 2229 if (sc->cfg == NULL) { 2230 /* 2nd: read configuration from table */ 2231 sc->cfg = envy24_rom2cfg(sc); 2232 } 2233 sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1; 2234 sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1; 2235 2236 if (1 /* bootverbose */) { 2237 envy24_putcfg(sc); 2238 } 2239 2240 /* set system configuration */ 2241 pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1); 2242 pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1); 2243 pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1); 2244 pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1); 2245 envy24_gpiosetmask(sc, sc->cfg->gpiomask); 2246 envy24_gpiosetdir(sc, sc->cfg->gpiodir); 2247 envy24_gpiowr(sc, sc->cfg->gpiostate); 2248 for (i = 0; i < sc->adcn; i++) { 2249 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2250 sc->cfg->codec->init(sc->adc[i]); 2251 } 2252 for (i = 0; i < sc->dacn; i++) { 2253 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2254 sc->cfg->codec->init(sc->dac[i]); 2255 } 2256 2257 /* initialize DMA buffer */ 2258 #if(0) 2259 device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n"); 2260 #endif 2261 if (envy24_dmainit(sc)) 2262 return ENOSPC; 2263 2264 /* initialize status */ 2265 sc->run[0] = sc->run[1] = 0; 2266 sc->intr[0] = sc->intr[1] = 0; 2267 sc->speed = 0; 2268 sc->caps[0].fmtlist = envy24_playfmt; 2269 sc->caps[1].fmtlist = envy24_recfmt; 2270 2271 /* set channel router */ 2272 envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0); 2273 envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0); 2274 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */ 2275 2276 /* set macro interrupt mask */ 2277 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2278 envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1); 2279 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2280 #if(0) 2281 device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data); 2282 #endif 2283 2284 return 0; 2285 } 2286 2287 static int 2288 envy24_alloc_resource(struct sc_info *sc) 2289 { 2290 /* allocate I/O port resource */ 2291 sc->csid = PCIR_CCS; 2292 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2293 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2294 sc->ddmaid = PCIR_DDMA; 2295 sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2296 &sc->ddmaid, 0, ~0, 1, RF_ACTIVE); 2297 sc->dsid = PCIR_DS; 2298 sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2299 &sc->dsid, 0, ~0, 1, RF_ACTIVE); 2300 sc->mtid = PCIR_MT; 2301 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2302 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2303 if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) { 2304 device_printf(sc->dev, "unable to map IO port space\n"); 2305 return ENXIO; 2306 } 2307 sc->cst = rman_get_bustag(sc->cs); 2308 sc->csh = rman_get_bushandle(sc->cs); 2309 sc->ddmat = rman_get_bustag(sc->ddma); 2310 sc->ddmah = rman_get_bushandle(sc->ddma); 2311 sc->dst = rman_get_bustag(sc->ds); 2312 sc->dsh = rman_get_bushandle(sc->ds); 2313 sc->mtt = rman_get_bustag(sc->mt); 2314 sc->mth = rman_get_bushandle(sc->mt); 2315 #if(0) 2316 device_printf(sc->dev, 2317 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n", 2318 pci_read_config(sc->dev, PCIR_CCS, 4), 2319 pci_read_config(sc->dev, PCIR_DDMA, 4), 2320 pci_read_config(sc->dev, PCIR_DS, 4), 2321 pci_read_config(sc->dev, PCIR_MT, 4)); 2322 #endif 2323 2324 /* allocate interupt resource */ 2325 sc->irqid = 0; 2326 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2327 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2328 if (!sc->irq || 2329 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) { 2330 device_printf(sc->dev, "unable to map interrupt\n"); 2331 return ENXIO; 2332 } 2333 2334 /* allocate DMA resource */ 2335 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/4, /*boundary*/0, 2336 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2337 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2338 /*filter*/NULL, /*filterarg*/NULL, 2339 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2340 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2341 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2342 /*lockarg*/&Giant, &sc->dmat) != 0) { 2343 device_printf(sc->dev, "unable to create dma tag\n"); 2344 return ENXIO; 2345 } 2346 2347 return 0; 2348 } 2349 2350 static int 2351 envy24_pci_attach(device_t dev) 2352 { 2353 u_int32_t data; 2354 struct sc_info *sc; 2355 char status[SND_STATUSLEN]; 2356 char name[ENVY24_NAMELEN]; 2357 int err = 0; 2358 int i; 2359 2360 #if(0) 2361 device_printf(dev, "envy24_pci_attach()\n"); 2362 #endif 2363 /* get sc_info data area */ 2364 if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) { 2365 device_printf(dev, "cannot allocate softc\n"); 2366 return ENXIO; 2367 } 2368 2369 bzero(sc, sizeof(*sc)); 2370 snprintf(name, ENVY24_NAMELEN, "%s:envy24", device_get_nameunit(dev)); 2371 sc->lock = snd_mtxcreate(name, name); 2372 sc->dev = dev; 2373 2374 /* initialize PCI interface */ 2375 data = pci_read_config(dev, PCIR_COMMAND, 2); 2376 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2377 pci_write_config(dev, PCIR_COMMAND, data, 2); 2378 data = pci_read_config(dev, PCIR_COMMAND, 2); 2379 2380 /* allocate resources */ 2381 err = envy24_alloc_resource(sc); 2382 if (err) { 2383 device_printf(dev, "unable to allocate system resources\n"); 2384 goto bad; 2385 } 2386 2387 /* initialize card */ 2388 err = envy24_init(sc); 2389 if (err) { 2390 device_printf(dev, "unable to initialize the card\n"); 2391 goto bad; 2392 } 2393 2394 /* set multi track mixer */ 2395 mixer_init(dev, &envy24mixer_class, sc); 2396 2397 /* set channel information */ 2398 err = pcm_register(dev, sc, 5, 2 + sc->adcn); 2399 if (err) 2400 goto bad; 2401 sc->chnum = 0; 2402 for (i = 0; i < 5; i++) { 2403 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); 2404 sc->chnum++; 2405 } 2406 for (i = 0; i < 2 + sc->adcn; i++) { 2407 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); 2408 sc->chnum++; 2409 } 2410 2411 /* set status iformation */ 2412 snprintf(status, SND_STATUSLEN, 2413 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld", 2414 rman_get_start(sc->cs), 2415 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2416 rman_get_start(sc->ddma), 2417 rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1, 2418 rman_get_start(sc->ds), 2419 rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1, 2420 rman_get_start(sc->mt), 2421 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2422 rman_get_start(sc->irq)); 2423 pcm_setstatus(dev, status); 2424 2425 return 0; 2426 2427 bad: 2428 if (sc->ih) 2429 bus_teardown_intr(dev, sc->irq, sc->ih); 2430 if (sc->irq) 2431 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2432 envy24_dmafree(sc); 2433 if (sc->dmat) 2434 bus_dma_tag_destroy(sc->dmat); 2435 envy24_cfgfree(sc->cfg); 2436 if (sc->cs) 2437 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2438 if (sc->ddma) 2439 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2440 if (sc->ds) 2441 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2442 if (sc->mt) 2443 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2444 if (sc->lock) 2445 snd_mtxfree(sc->lock); 2446 free(sc, M_ENVY24); 2447 return err; 2448 } 2449 2450 static int 2451 envy24_pci_detach(device_t dev) 2452 { 2453 struct sc_info *sc; 2454 int r; 2455 int i; 2456 2457 #if(0) 2458 device_printf(dev, "envy24_pci_detach()\n"); 2459 #endif 2460 sc = pcm_getdevinfo(dev); 2461 if (sc == NULL) 2462 return 0; 2463 r = pcm_unregister(dev); 2464 if (r) 2465 return r; 2466 2467 envy24_dmafree(sc); 2468 if (sc->cfg->codec->destroy != NULL) { 2469 for (i = 0; i < sc->adcn; i++) 2470 sc->cfg->codec->destroy(sc->adc[i]); 2471 for (i = 0; i < sc->dacn; i++) 2472 sc->cfg->codec->destroy(sc->dac[i]); 2473 } 2474 envy24_cfgfree(sc->cfg); 2475 bus_dma_tag_destroy(sc->dmat); 2476 bus_teardown_intr(dev, sc->irq, sc->ih); 2477 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2478 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2479 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2480 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2481 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2482 snd_mtxfree(sc->lock); 2483 free(sc, M_ENVY24); 2484 return 0; 2485 } 2486 2487 static device_method_t envy24_methods[] = { 2488 /* Device interface */ 2489 DEVMETHOD(device_probe, envy24_pci_probe), 2490 DEVMETHOD(device_attach, envy24_pci_attach), 2491 DEVMETHOD(device_detach, envy24_pci_detach), 2492 { 0, 0 } 2493 }; 2494 2495 static driver_t envy24_driver = { 2496 "pcm", 2497 envy24_methods, 2498 #if __FreeBSD_version > 500000 2499 PCM_SOFTC_SIZE, 2500 #else 2501 sizeof(struct snddev_info), 2502 #endif 2503 }; 2504 2505 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0); 2506 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2507 MODULE_DEPEND(snd_envy24, snd_ak452x, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2508 MODULE_VERSION(snd_envy24, 1); 2509