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