envy24.c revision 160796
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: head/sys/dev/sound/pci/envy24.c 160796 2006-07-28 18:06:39Z netchild $ 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 39MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio"); 40 41/* -------------------------------------------------------------------- */ 42 43struct 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 57struct envy24_sample { 58 volatile u_int32_t buffer; 59}; 60 61typedef struct envy24_sample sample32_t; 62 63/* channel registers */ 64struct 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 */ 88struct 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 */ 98struct 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 */ 109struct 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 */ 177static void envy24_p8u(struct sc_chinfo *); 178static void envy24_p16sl(struct sc_chinfo *); 179static void envy24_p32sl(struct sc_chinfo *); 180static void envy24_r16sl(struct sc_chinfo *); 181static void envy24_r32sl(struct sc_chinfo *); 182 183/* channel interface */ 184static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 185static int envy24chan_setformat(kobj_t, void *, u_int32_t); 186static int envy24chan_setspeed(kobj_t, void *, u_int32_t); 187static int envy24chan_setblocksize(kobj_t, void *, u_int32_t); 188static int envy24chan_trigger(kobj_t, void *, int); 189static int envy24chan_getptr(kobj_t, void *); 190static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *); 191 192/* mixer interface */ 193static int envy24mixer_init(struct snd_mixer *); 194static int envy24mixer_reinit(struct snd_mixer *); 195static int envy24mixer_uninit(struct snd_mixer *); 196static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned); 197static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t); 198 199/* M-Audio Delta series AK4524 access interface */ 200static void *envy24_delta_ak4524_create(device_t, void *, int, int); 201static void envy24_delta_ak4524_destroy(void *); 202static void envy24_delta_ak4524_init(void *); 203static void envy24_delta_ak4524_reinit(void *); 204static 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 */ 213static 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 */ 228static 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 */ 257static 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 */ 263static 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 272static 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 311static u_int32_t envy24_recfmt[] = { 312 AFMT_STEREO | AFMT_S16_LE, 313 AFMT_STEREO | AFMT_S32_LE, 314 0 315}; 316static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0}; 317 318static 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 325static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0}; 326 327struct envy24_emldma { 328 u_int32_t format; 329 void (*emldma)(struct sc_chinfo *); 330 int unit; 331}; 332 333static 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 340static 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 */ 349static u_int32_t 350envy24_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 364static void 365envy24_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 380static u_int32_t 381envy24_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 395static void 396envy24_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 411static u_int32_t 412envy24_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 418static void 419envy24_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 429static int 430envy24_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 468static int 469envy24_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 504static int 505envy24_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 523static struct cfg_info * 524envy24_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 571static void 572envy24_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 585static int 586envy24_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 609static int 610envy24_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 634static int 635envy24_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 659static int 660envy24_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 681static kobj_method_t envy24_ac97_methods[] = { 682 KOBJMETHOD(ac97_read, envy24_rdcd), 683 KOBJMETHOD(ac97_write, envy24_wrcd), 684 {0, 0} 685}; 686AC97_DECLARE(envy24_ac97); 687#endif 688 689/* -------------------------------------------------------------------- */ 690 691/* GPIO access routines */ 692 693static u_int32_t 694envy24_gpiord(struct sc_info *sc) 695{ 696 return envy24_rdci(sc, ENVY24_CCI_GPIODAT); 697} 698 699static void 700envy24_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 711static u_int32_t 712envy24_gpiogetmask(struct sc_info *sc) 713{ 714 return envy24_rdci(sc, ENVY24_CCI_GPIOMASK); 715} 716#endif 717 718static void 719envy24_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 726static u_int32_t 727envy24_gpiogetdir(struct sc_info *sc) 728{ 729 return envy24_rdci(sc, ENVY24_CCI_GPIOCTL); 730} 731#endif 732 733static void 734envy24_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 744struct 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 752static void 753envy24_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 770static void * 771envy24_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 = 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 802static void 803envy24_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 824static void 825envy24_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 874static void 875envy24_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 887static void 888envy24_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 912static 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 932static int 933envy24_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 973static void 974envy24_setvolume(struct sc_info *sc, unsigned ch) 975{ 976#if(0) 977 device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch); 978#endif 979if (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 992static void 993envy24_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 1007static u_int32_t 1008envy24_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 1037static void 1038envy24_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 1088static void 1089envy24_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 1107static int 1108envy24_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 1134static void 1135envy24_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 1158static void 1159envy24_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 1177static int 1178envy24_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 */ 1236static void 1237envy24_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 1266static void 1267envy24_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 1311static void 1312envy24_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 1341static void 1342envy24_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 1371static void 1372envy24_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 */ 1404static void * 1405envy24chan_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 1446static int 1447envy24chan_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 1465static int 1466envy24chan_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*/ 1529static int 1530envy24chan_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 1554static int 1555envy24chan_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 */ 1587static int 1588envy24chan_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#if 0 1595 int i; 1596 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#if 0 1671 else if (ch->blk == sc->blk[slot]) { 1672 sc->blk[slot] = ENVY24_SAMPLE_NUM / 2; 1673 for (i = 0; i < ENVY24_CHAN_NUM; i++) { 1674 if (sc->chan[i].dir == ch->dir && 1675 sc->chan[i].run == 1 && 1676 sc->chan[i].blk < sc->blk[slot]) 1677 sc->blk[slot] = sc->chan[i].blk; 1678 } 1679 if (ch->blk != sc->blk[slot]) 1680 envy24_updintr(sc, ch->dir); 1681 } 1682#endif 1683 break; 1684 } 1685 snd_mtxunlock(sc->lock); 1686 1687 return 0; 1688} 1689 1690static int 1691envy24chan_getptr(kobj_t obj, void *data) 1692{ 1693 struct sc_chinfo *ch = data; 1694 struct sc_info *sc = ch->parent; 1695 u_int32_t ptr; 1696 int rtn; 1697 1698#if(0) 1699 device_printf(sc->dev, "envy24chan_getptr()\n"); 1700#endif 1701 snd_mtxlock(sc->lock); 1702 ptr = envy24_gethwptr(sc, ch->dir); 1703 rtn = ptr * ch->unit; 1704 snd_mtxunlock(sc->lock); 1705 1706#if(0) 1707 device_printf(sc->dev, "envy24chan_getptr(): return %d\n", 1708 rtn); 1709#endif 1710 return rtn; 1711} 1712 1713static struct pcmchan_caps * 1714envy24chan_getcaps(kobj_t obj, void *data) 1715{ 1716 struct sc_chinfo *ch = data; 1717 struct sc_info *sc = ch->parent; 1718 struct pcmchan_caps *rtn; 1719 1720#if(0) 1721 device_printf(sc->dev, "envy24chan_getcaps()\n"); 1722#endif 1723 snd_mtxlock(sc->lock); 1724 if (ch->dir == PCMDIR_PLAY) { 1725 if (sc->run[0] == 0) 1726 rtn = &envy24_playcaps; 1727 else 1728 rtn = &sc->caps[0]; 1729 } 1730 else { 1731 if (sc->run[1] == 0) 1732 rtn = &envy24_reccaps; 1733 else 1734 rtn = &sc->caps[1]; 1735 } 1736 snd_mtxunlock(sc->lock); 1737 1738 return rtn; 1739} 1740 1741static kobj_method_t envy24chan_methods[] = { 1742 KOBJMETHOD(channel_init, envy24chan_init), 1743 KOBJMETHOD(channel_free, envy24chan_free), 1744 KOBJMETHOD(channel_setformat, envy24chan_setformat), 1745 KOBJMETHOD(channel_setspeed, envy24chan_setspeed), 1746 KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize), 1747 KOBJMETHOD(channel_trigger, envy24chan_trigger), 1748 KOBJMETHOD(channel_getptr, envy24chan_getptr), 1749 KOBJMETHOD(channel_getcaps, envy24chan_getcaps), 1750 { 0, 0 } 1751}; 1752CHANNEL_DECLARE(envy24chan); 1753 1754/* -------------------------------------------------------------------- */ 1755 1756/* mixer interface */ 1757 1758static int 1759envy24mixer_init(struct snd_mixer *m) 1760{ 1761 struct sc_info *sc = mix_getdevinfo(m); 1762 1763#if(0) 1764 device_printf(sc->dev, "envy24mixer_init()\n"); 1765#endif 1766 if (sc == NULL) 1767 return -1; 1768 1769 /* set volume control rate */ 1770 snd_mtxlock(sc->lock); 1771 envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1772 1773 mix_setdevs(m, ENVY24_MIX_MASK); 1774 mix_setrecdevs(m, ENVY24_MIX_REC_MASK); 1775 snd_mtxunlock(sc->lock); 1776 1777 return 0; 1778} 1779 1780static int 1781envy24mixer_reinit(struct snd_mixer *m) 1782{ 1783 struct sc_info *sc = mix_getdevinfo(m); 1784 1785 if (sc == NULL) 1786 return -1; 1787#if(0) 1788 device_printf(sc->dev, "envy24mixer_reinit()\n"); 1789#endif 1790 1791 return 0; 1792} 1793 1794static int 1795envy24mixer_uninit(struct snd_mixer *m) 1796{ 1797 struct sc_info *sc = mix_getdevinfo(m); 1798 1799 if (sc == NULL) 1800 return -1; 1801#if(0) 1802 device_printf(sc->dev, "envy24mixer_uninit()\n"); 1803#endif 1804 1805 return 0; 1806} 1807 1808static int 1809envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1810{ 1811 struct sc_info *sc = mix_getdevinfo(m); 1812 int ch = envy24_mixmap[dev]; 1813 int hwch; 1814 int i; 1815 1816 if (sc == NULL) 1817 return -1; 1818 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1819 return -1; 1820 if (dev != 0 && ch == -1) 1821 return -1; 1822 hwch = envy24_chanmap[ch]; 1823#if(0) 1824 device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n", 1825 dev, left, right); 1826#endif 1827 1828 snd_mtxlock(sc->lock); 1829 if (dev == 0) { 1830 for (i = 0; i < sc->dacn; i++) { 1831 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1832 } 1833 } 1834 else { 1835 /* set volume value for hardware */ 1836 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN) 1837 sc->left[hwch] = ENVY24_VOL_MUTE; 1838 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN) 1839 sc->right[hwch] = ENVY24_VOL_MUTE; 1840 1841 /* set volume for record channel and running play channel */ 1842 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1843 envy24_setvolume(sc, hwch); 1844 } 1845 snd_mtxunlock(sc->lock); 1846 1847 return right << 8 | left; 1848} 1849 1850static u_int32_t 1851envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1852{ 1853 struct sc_info *sc = mix_getdevinfo(m); 1854 int ch = envy24_mixmap[src]; 1855#if(0) 1856 device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src); 1857#endif 1858 1859 if (ch > ENVY24_CHAN_PLAY_SPDIF) 1860 sc->src = ch; 1861 return src; 1862} 1863 1864static kobj_method_t envy24mixer_methods[] = { 1865 KOBJMETHOD(mixer_init, envy24mixer_init), 1866 KOBJMETHOD(mixer_reinit, envy24mixer_reinit), 1867 KOBJMETHOD(mixer_uninit, envy24mixer_uninit), 1868 KOBJMETHOD(mixer_set, envy24mixer_set), 1869 KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc), 1870 { 0, 0 } 1871}; 1872MIXER_DECLARE(envy24mixer); 1873 1874/* -------------------------------------------------------------------- */ 1875 1876/* The interrupt handler */ 1877static void 1878envy24_intr(void *p) 1879{ 1880 struct sc_info *sc = (struct sc_info *)p; 1881 struct sc_chinfo *ch; 1882 u_int32_t ptr, dsize, feed; 1883 int i; 1884 1885#if(0) 1886 device_printf(sc->dev, "envy24_intr()\n"); 1887#endif 1888 snd_mtxlock(sc->lock); 1889 if (envy24_checkintr(sc, PCMDIR_PLAY)) { 1890#if(0) 1891 device_printf(sc->dev, "envy24_intr(): play\n"); 1892#endif 1893 dsize = sc->psize / 4; 1894 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1; 1895#if(0) 1896 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr); 1897#endif 1898 ptr -= ptr % sc->blk[0]; 1899 feed = (ptr + dsize - sc->intr[0]) % dsize; 1900#if(0) 1901 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1902#endif 1903 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) { 1904 ch = &sc->chan[i]; 1905#if(0) 1906 if (ch->run) 1907 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk); 1908#endif 1909 if (ch->run && ch->blk <= feed) 1910 chn_intr(ch->channel); 1911 } 1912 sc->intr[0] = ptr; 1913 envy24_updintr(sc, PCMDIR_PLAY); 1914 } 1915 if (envy24_checkintr(sc, PCMDIR_REC)) { 1916#if(0) 1917 device_printf(sc->dev, "envy24_intr(): rec\n"); 1918#endif 1919 dsize = sc->rsize / 4; 1920 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1; 1921 ptr -= ptr % sc->blk[1]; 1922 feed = (ptr + dsize - sc->intr[1]) % dsize; 1923 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) { 1924 ch = &sc->chan[i]; 1925 if (ch->run && ch->blk <= feed) 1926 chn_intr(ch->channel); 1927 } 1928 sc->intr[1] = ptr; 1929 envy24_updintr(sc, PCMDIR_REC); 1930 } 1931 snd_mtxunlock(sc->lock); 1932 1933 return; 1934} 1935 1936/* 1937 * Probe and attach the card 1938 */ 1939 1940static int 1941envy24_pci_probe(device_t dev) 1942{ 1943 u_int16_t sv, sd; 1944 int i; 1945 1946#if(0) 1947 printf("envy24_pci_probe()\n"); 1948#endif 1949 if (pci_get_device(dev) == PCID_ENVY24 && 1950 pci_get_vendor(dev) == PCIV_ENVY24) { 1951 sv = pci_get_subvendor(dev); 1952 sd = pci_get_subdevice(dev); 1953 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 1954 if (cfg_table[i].subvendor == sv && 1955 cfg_table[i].subdevice == sd) { 1956 break; 1957 } 1958 } 1959 device_set_desc(dev, cfg_table[i].name); 1960#if(0) 1961 printf("envy24_pci_probe(): return 0\n"); 1962#endif 1963 return 0; 1964 } 1965 else { 1966#if(0) 1967 printf("envy24_pci_probe(): return ENXIO\n"); 1968#endif 1969 return ENXIO; 1970 } 1971} 1972 1973static void 1974envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1975{ 1976 struct sc_info *sc = (struct sc_info *)arg; 1977 1978#if(0) 1979 device_printf(sc->dev, "envy24_dmapsetmap()\n"); 1980#endif 1981 if (bootverbose) { 1982 printf("envy24(play): setmap %lx, %lx; ", 1983 (unsigned long)segs->ds_addr, 1984 (unsigned long)segs->ds_len); 1985 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 1986 } 1987} 1988 1989static void 1990envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1991{ 1992 struct sc_info *sc = (struct sc_info *)arg; 1993 1994#if(0) 1995 device_printf(sc->dev, "envy24_dmarsetmap()\n"); 1996#endif 1997 if (bootverbose) { 1998 printf("envy24(record): setmap %lx, %lx; ", 1999 (unsigned long)segs->ds_addr, 2000 (unsigned long)segs->ds_len); 2001 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2002 } 2003} 2004 2005static void 2006envy24_dmafree(struct sc_info *sc) 2007{ 2008#if(0) 2009 device_printf(sc->dev, "envy24_dmafree():"); 2010 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2011 else printf(" sc->rmap(null)"); 2012 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2013 else printf(" sc->pmap(null)"); 2014 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2015 else printf(" sc->rbuf(null)"); 2016 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2017 else printf(" sc->pbuf(null)\n"); 2018#endif 2019#if(0) 2020 if (sc->rmap) 2021 bus_dmamap_unload(sc->dmat, sc->rmap); 2022 if (sc->pmap) 2023 bus_dmamap_unload(sc->dmat, sc->pmap); 2024 if (sc->rbuf) 2025 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2026 if (sc->pbuf) 2027 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2028#else 2029 bus_dmamap_unload(sc->dmat, sc->rmap); 2030 bus_dmamap_unload(sc->dmat, sc->pmap); 2031 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2032 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2033#endif 2034 2035 sc->rmap = sc->pmap = NULL; 2036 sc->pbuf = NULL; 2037 sc->rbuf = NULL; 2038 2039 return; 2040} 2041 2042static int 2043envy24_dmainit(struct sc_info *sc) 2044{ 2045 u_int32_t addr; 2046 2047#if(0) 2048 device_printf(sc->dev, "envy24_dmainit()\n"); 2049#endif 2050 /* init values */ 2051 sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM; 2052 sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM; 2053 sc->pbuf = NULL; 2054 sc->rbuf = NULL; 2055 sc->pmap = sc->rmap = NULL; 2056 sc->blk[0] = sc->blk[1] = 0; 2057 2058 /* allocate DMA buffer */ 2059#if(0) 2060 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2061#endif 2062 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2063 goto bad; 2064#if(0) 2065 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2066#endif 2067 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2068 goto bad; 2069#if(0) 2070 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2071#endif 2072 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0)) 2073 goto bad; 2074#if(0) 2075 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2076#endif 2077 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0)) 2078 goto bad; 2079 bzero(sc->pbuf, sc->psize); 2080 bzero(sc->rbuf, sc->rsize); 2081 2082 /* set values to register */ 2083 addr = vtophys(sc->pbuf); 2084#if(0) 2085 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2086#endif 2087 envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4); 2088#if(0) 2089 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 2090 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2091#endif 2092 envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2); 2093#if(0) 2094 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 2095#endif 2096 addr = vtophys(sc->rbuf); 2097 envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4); 2098 envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2); 2099 2100 return 0; 2101 bad: 2102 envy24_dmafree(sc); 2103 return ENOSPC; 2104} 2105 2106static void 2107envy24_putcfg(struct sc_info *sc) 2108{ 2109 device_printf(sc->dev, "system configuration\n"); 2110 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2111 sc->cfg->subvendor, sc->cfg->subdevice); 2112 printf(" XIN2 Clock Source: "); 2113 switch (sc->cfg->scfg & PCIM_SCFG_XIN2) { 2114 case 0x00: 2115 printf("22.5792MHz(44.1kHz*512)\n"); 2116 break; 2117 case 0x40: 2118 printf("16.9344MHz(44.1kHz*384)\n"); 2119 break; 2120 case 0x80: 2121 printf("from external clock synthesizer chip\n"); 2122 break; 2123 default: 2124 printf("illeagal system setting\n"); 2125 } 2126 printf(" MPU-401 UART(s) #: "); 2127 if (sc->cfg->scfg & PCIM_SCFG_MPU) 2128 printf("2\n"); 2129 else 2130 printf("1\n"); 2131 printf(" AC'97 codec: "); 2132 if (sc->cfg->scfg & PCIM_SCFG_AC97) 2133 printf("not exist\n"); 2134 else 2135 printf("exist\n"); 2136 printf(" ADC #: "); 2137 printf("%d\n", sc->adcn); 2138 printf(" DAC #: "); 2139 printf("%d\n", sc->dacn); 2140 printf(" Multi-track converter type: "); 2141 if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) { 2142 printf("AC'97(SDATA_OUT:"); 2143 if (sc->cfg->acl & PCIM_ACL_OMODE) 2144 printf("packed"); 2145 else 2146 printf("split"); 2147 printf("|SDATA_IN:"); 2148 if (sc->cfg->acl & PCIM_ACL_IMODE) 2149 printf("packed"); 2150 else 2151 printf("split"); 2152 printf(")\n"); 2153 } 2154 else { 2155 printf("I2S("); 2156 if (sc->cfg->i2s & PCIM_I2S_VOL) 2157 printf("with volume, "); 2158 if (sc->cfg->i2s & PCIM_I2S_96KHZ) 2159 printf("96KHz support, "); 2160 switch (sc->cfg->i2s & PCIM_I2S_RES) { 2161 case PCIM_I2S_16BIT: 2162 printf("16bit resolution, "); 2163 break; 2164 case PCIM_I2S_18BIT: 2165 printf("18bit resolution, "); 2166 break; 2167 case PCIM_I2S_20BIT: 2168 printf("20bit resolution, "); 2169 break; 2170 case PCIM_I2S_24BIT: 2171 printf("24bit resolution, "); 2172 break; 2173 } 2174 printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID); 2175 } 2176 printf(" S/PDIF(IN/OUT): "); 2177 if (sc->cfg->spdif & PCIM_SPDIF_IN) 2178 printf("1/"); 2179 else 2180 printf("0/"); 2181 if (sc->cfg->spdif & PCIM_SPDIF_OUT) 2182 printf("1 "); 2183 else 2184 printf("0 "); 2185 if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT)) 2186 printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2); 2187 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2188 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2189} 2190 2191static int 2192envy24_init(struct sc_info *sc) 2193{ 2194 u_int32_t data; 2195#if(0) 2196 int rtn; 2197#endif 2198 int i; 2199 u_int32_t sv, sd; 2200 2201 2202#if(0) 2203 device_printf(sc->dev, "envy24_init()\n"); 2204#endif 2205 2206 /* reset chip */ 2207 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1); 2208 DELAY(200); 2209 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1); 2210 DELAY(200); 2211 2212 /* legacy hardware disable */ 2213 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2214 data |= PCIM_LAC_DISABLE; 2215 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2216 2217 /* check system configuration */ 2218 sc->cfg = NULL; 2219 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2220 /* 1st: search configuration from table */ 2221 sv = pci_get_subvendor(sc->dev); 2222 sd = pci_get_subdevice(sc->dev); 2223 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2224#if(0) 2225 device_printf(sc->dev, "Set configuration from table\n"); 2226#endif 2227 sc->cfg = &cfg_table[i]; 2228 break; 2229 } 2230 } 2231 if (sc->cfg == NULL) { 2232 /* 2nd: read configuration from table */ 2233 sc->cfg = envy24_rom2cfg(sc); 2234 } 2235 sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1; 2236 sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1; 2237 2238 if (1 /* bootverbose */) { 2239 envy24_putcfg(sc); 2240 } 2241 2242 /* set system configuration */ 2243 pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1); 2244 pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1); 2245 pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1); 2246 pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1); 2247 envy24_gpiosetmask(sc, sc->cfg->gpiomask); 2248 envy24_gpiosetdir(sc, sc->cfg->gpiodir); 2249 envy24_gpiowr(sc, sc->cfg->gpiostate); 2250 for (i = 0; i < sc->adcn; i++) { 2251 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2252 sc->cfg->codec->init(sc->adc[i]); 2253 } 2254 for (i = 0; i < sc->dacn; i++) { 2255 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2256 sc->cfg->codec->init(sc->dac[i]); 2257 } 2258 2259 /* initialize DMA buffer */ 2260#if(0) 2261 device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n"); 2262#endif 2263 if (envy24_dmainit(sc)) 2264 return ENOSPC; 2265 2266 /* initialize status */ 2267 sc->run[0] = sc->run[1] = 0; 2268 sc->intr[0] = sc->intr[1] = 0; 2269 sc->speed = 0; 2270 sc->caps[0].fmtlist = envy24_playfmt; 2271 sc->caps[1].fmtlist = envy24_recfmt; 2272 2273 /* set channel router */ 2274 envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0); 2275 envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0); 2276 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */ 2277 2278 /* set macro interrupt mask */ 2279 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2280 envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1); 2281 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2282#if(0) 2283 device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data); 2284#endif 2285 2286 return 0; 2287} 2288 2289static int 2290envy24_alloc_resource(struct sc_info *sc) 2291{ 2292 /* allocate I/O port resource */ 2293 sc->csid = PCIR_CCS; 2294 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2295 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2296 sc->ddmaid = PCIR_DDMA; 2297 sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2298 &sc->ddmaid, 0, ~0, 1, RF_ACTIVE); 2299 sc->dsid = PCIR_DS; 2300 sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2301 &sc->dsid, 0, ~0, 1, RF_ACTIVE); 2302 sc->mtid = PCIR_MT; 2303 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2304 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2305 if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) { 2306 device_printf(sc->dev, "unable to map IO port space\n"); 2307 return ENXIO; 2308 } 2309 sc->cst = rman_get_bustag(sc->cs); 2310 sc->csh = rman_get_bushandle(sc->cs); 2311 sc->ddmat = rman_get_bustag(sc->ddma); 2312 sc->ddmah = rman_get_bushandle(sc->ddma); 2313 sc->dst = rman_get_bustag(sc->ds); 2314 sc->dsh = rman_get_bushandle(sc->ds); 2315 sc->mtt = rman_get_bustag(sc->mt); 2316 sc->mth = rman_get_bushandle(sc->mt); 2317#if(0) 2318 device_printf(sc->dev, 2319 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n", 2320 pci_read_config(sc->dev, PCIR_CCS, 4), 2321 pci_read_config(sc->dev, PCIR_DDMA, 4), 2322 pci_read_config(sc->dev, PCIR_DS, 4), 2323 pci_read_config(sc->dev, PCIR_MT, 4)); 2324#endif 2325 2326 /* allocate interupt resource */ 2327 sc->irqid = 0; 2328 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2329 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2330 if (!sc->irq || 2331 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) { 2332 device_printf(sc->dev, "unable to map interrupt\n"); 2333 return ENXIO; 2334 } 2335 2336 /* allocate DMA resource */ 2337 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/4, /*boundary*/0, 2338 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2339 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2340 /*filter*/NULL, /*filterarg*/NULL, 2341 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2342 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2343 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2344 /*lockarg*/&Giant, &sc->dmat) != 0) { 2345 device_printf(sc->dev, "unable to create dma tag\n"); 2346 return ENXIO; 2347 } 2348 2349 return 0; 2350} 2351 2352static int 2353envy24_pci_attach(device_t dev) 2354{ 2355 u_int32_t data; 2356 struct sc_info *sc; 2357 char status[SND_STATUSLEN]; 2358 char name[ENVY24_NAMELEN]; 2359 int err = 0; 2360 int i; 2361 2362#if(0) 2363 device_printf(dev, "envy24_pci_attach()\n"); 2364#endif 2365 /* get sc_info data area */ 2366 if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) { 2367 device_printf(dev, "cannot allocate softc\n"); 2368 return ENXIO; 2369 } 2370 2371 bzero(sc, sizeof(*sc)); 2372 snprintf(name, ENVY24_NAMELEN, "%s:envy24", device_get_nameunit(dev)); 2373 sc->lock = snd_mtxcreate(name, name); 2374 sc->dev = dev; 2375 2376 /* initialize PCI interface */ 2377 data = pci_read_config(dev, PCIR_COMMAND, 2); 2378 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2379 pci_write_config(dev, PCIR_COMMAND, data, 2); 2380 data = pci_read_config(dev, PCIR_COMMAND, 2); 2381 2382 /* allocate resources */ 2383 err = envy24_alloc_resource(sc); 2384 if (err) { 2385 device_printf(dev, "unable to allocate system resources\n"); 2386 goto bad; 2387 } 2388 2389 /* initialize card */ 2390 err = envy24_init(sc); 2391 if (err) { 2392 device_printf(dev, "unable to initialize the card\n"); 2393 goto bad; 2394 } 2395 2396 /* set multi track mixer */ 2397 mixer_init(dev, &envy24mixer_class, sc); 2398 2399 /* set channel information */ 2400 err = pcm_register(dev, sc, 5, 2 + sc->adcn); 2401 if (err) 2402 goto bad; 2403 sc->chnum = 0; 2404 for (i = 0; i < 5; i++) { 2405 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); 2406 sc->chnum++; 2407 } 2408 for (i = 0; i < 2 + sc->adcn; i++) { 2409 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); 2410 sc->chnum++; 2411 } 2412 2413 /* set status iformation */ 2414 snprintf(status, SND_STATUSLEN, 2415 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld", 2416 rman_get_start(sc->cs), 2417 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2418 rman_get_start(sc->ddma), 2419 rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1, 2420 rman_get_start(sc->ds), 2421 rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1, 2422 rman_get_start(sc->mt), 2423 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2424 rman_get_start(sc->irq)); 2425 pcm_setstatus(dev, status); 2426 2427 return 0; 2428 2429bad: 2430 if (sc->ih) 2431 bus_teardown_intr(dev, sc->irq, sc->ih); 2432 if (sc->irq) 2433 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2434 envy24_dmafree(sc); 2435 if (sc->dmat) 2436 bus_dma_tag_destroy(sc->dmat); 2437 if (sc->cfg->codec->destroy != NULL) { 2438 for (i = 0; i < sc->adcn; i++) 2439 sc->cfg->codec->destroy(sc->adc[i]); 2440 for (i = 0; i < sc->dacn; i++) 2441 sc->cfg->codec->destroy(sc->dac[i]); 2442 } 2443 envy24_cfgfree(sc->cfg); 2444 if (sc->cs) 2445 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2446 if (sc->ddma) 2447 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2448 if (sc->ds) 2449 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2450 if (sc->mt) 2451 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2452 if (sc->lock) 2453 snd_mtxfree(sc->lock); 2454 free(sc, M_ENVY24); 2455 return err; 2456} 2457 2458static int 2459envy24_pci_detach(device_t dev) 2460{ 2461 struct sc_info *sc; 2462 int r; 2463 int i; 2464 2465#if(0) 2466 device_printf(dev, "envy24_pci_detach()\n"); 2467#endif 2468 sc = pcm_getdevinfo(dev); 2469 if (sc == NULL) 2470 return 0; 2471 r = pcm_unregister(dev); 2472 if (r) 2473 return r; 2474 2475 envy24_dmafree(sc); 2476 if (sc->cfg->codec->destroy != NULL) { 2477 for (i = 0; i < sc->adcn; i++) 2478 sc->cfg->codec->destroy(sc->adc[i]); 2479 for (i = 0; i < sc->dacn; i++) 2480 sc->cfg->codec->destroy(sc->dac[i]); 2481 } 2482 envy24_cfgfree(sc->cfg); 2483 bus_dma_tag_destroy(sc->dmat); 2484 bus_teardown_intr(dev, sc->irq, sc->ih); 2485 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2486 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2487 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2488 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2489 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2490 snd_mtxfree(sc->lock); 2491 free(sc, M_ENVY24); 2492 return 0; 2493} 2494 2495static device_method_t envy24_methods[] = { 2496 /* Device interface */ 2497 DEVMETHOD(device_probe, envy24_pci_probe), 2498 DEVMETHOD(device_attach, envy24_pci_attach), 2499 DEVMETHOD(device_detach, envy24_pci_detach), 2500 { 0, 0 } 2501}; 2502 2503static driver_t envy24_driver = { 2504 "pcm", 2505 envy24_methods, 2506#if __FreeBSD_version > 500000 2507 PCM_SOFTC_SIZE, 2508#else 2509 sizeof(struct snddev_info), 2510#endif 2511}; 2512 2513DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0); 2514MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2515MODULE_DEPEND(snd_envy24, snd_ak452x, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2516MODULE_VERSION(snd_envy24, 1); 2517