1/* 2 * sound/oss/sb_mixer.c 3 * 4 * The low level mixer driver for the Sound Blaster compatible cards. 5 */ 6/* 7 * Copyright (C) by Hannu Savolainen 1993-1997 8 * 9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 10 * Version 2 (June 1991). See the "COPYING" file distributed with this software 11 * for more info. 12 * 13 * 14 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) 15 * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] 16 * Stanislav Voronyi <stas@esc.kharkov.com> : Support for AWE 3DSE device (Jun 7 1999) 17 */ 18 19#include <linux/slab.h> 20 21#include "sound_config.h" 22 23#define __SB_MIXER_C__ 24 25#include "sb.h" 26#include "sb_mixer.h" 27 28#include "sb_ess.h" 29 30#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) 31 32/* Same as SB Pro, unless I find otherwise */ 33#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES 34 35#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ 36 SOUND_MASK_CD | SOUND_MASK_VOLUME) 37 38/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' 39 * channel is the COVOX/DisneySoundSource emulation volume control 40 * on the mixer. It does NOT control speaker volume. Should have own 41 * mask eventually? 42 */ 43#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ 44 SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) 45 46#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ 47 SOUND_MASK_CD) 48 49#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ 50 SOUND_MASK_CD) 51 52#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ 53 SOUND_MASK_CD | \ 54 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ 55 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ 56 SOUND_MASK_IMIX) 57 58/* These are the only devices that are working at the moment. Others could 59 * be added once they are identified and a method is found to control them. 60 */ 61#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ 62 SOUND_MASK_PCM | SOUND_MASK_MIC | \ 63 SOUND_MASK_CD | \ 64 SOUND_MASK_VOLUME) 65 66static mixer_tab sbpro_mix = { 67MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), 68MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), 69MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), 70MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), 71MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), 72MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), 73MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), 74MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), 75MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), 76MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), 77MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), 78MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) 79}; 80 81static mixer_tab sb16_mix = { 82MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), 83MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), 84MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), 85MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), 86MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), 87MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), 88MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), 89MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), 90MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), 91MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0), 92MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), 93MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ 94MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), 95MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) 96}; 97 98static mixer_tab als007_mix = 99{ 100MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4), 101MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), 102MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), 103MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), 104MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), 105MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), 106MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), 107MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0), 108MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), 109MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), 110MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), 111MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */ 112MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), 113MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) 114}; 115 116 117/* SM_GAMES Master volume is lower and PCM & FM volumes 118 higher than with SB Pro. This improves the 119 sound quality */ 120 121static int smg_default_levels[32] = 122{ 123 0x2020, /* Master Volume */ 124 0x4b4b, /* Bass */ 125 0x4b4b, /* Treble */ 126 0x6464, /* FM */ 127 0x6464, /* PCM */ 128 0x4b4b, /* PC Speaker */ 129 0x4b4b, /* Ext Line */ 130 0x0000, /* Mic */ 131 0x4b4b, /* CD */ 132 0x4b4b, /* Recording monitor */ 133 0x4b4b, /* SB PCM */ 134 0x4b4b, /* Recording level */ 135 0x4b4b, /* Input gain */ 136 0x4b4b, /* Output gain */ 137 0x4040, /* Line1 */ 138 0x4040, /* Line2 */ 139 0x1515 /* Line3 */ 140}; 141 142static int sb_default_levels[32] = 143{ 144 0x5a5a, /* Master Volume */ 145 0x4b4b, /* Bass */ 146 0x4b4b, /* Treble */ 147 0x4b4b, /* FM */ 148 0x4b4b, /* PCM */ 149 0x4b4b, /* PC Speaker */ 150 0x4b4b, /* Ext Line */ 151 0x1010, /* Mic */ 152 0x4b4b, /* CD */ 153 0x0000, /* Recording monitor */ 154 0x4b4b, /* SB PCM */ 155 0x4b4b, /* Recording level */ 156 0x4b4b, /* Input gain */ 157 0x4b4b, /* Output gain */ 158 0x4040, /* Line1 */ 159 0x4040, /* Line2 */ 160 0x1515 /* Line3 */ 161}; 162 163static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = 164{ 165 0x00, /* SOUND_MIXER_VOLUME */ 166 0x00, /* SOUND_MIXER_BASS */ 167 0x00, /* SOUND_MIXER_TREBLE */ 168 0x40, /* SOUND_MIXER_SYNTH */ 169 0x00, /* SOUND_MIXER_PCM */ 170 0x00, /* SOUND_MIXER_SPEAKER */ 171 0x10, /* SOUND_MIXER_LINE */ 172 0x01, /* SOUND_MIXER_MIC */ 173 0x04, /* SOUND_MIXER_CD */ 174 0x00, /* SOUND_MIXER_IMIX */ 175 0x00, /* SOUND_MIXER_ALTPCM */ 176 0x00, /* SOUND_MIXER_RECLEV */ 177 0x00, /* SOUND_MIXER_IGAIN */ 178 0x00 /* SOUND_MIXER_OGAIN */ 179}; 180 181static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = 182{ 183 0x00, /* SOUND_MIXER_VOLUME */ 184 0x00, /* SOUND_MIXER_BASS */ 185 0x00, /* SOUND_MIXER_TREBLE */ 186 0x20, /* SOUND_MIXER_SYNTH */ 187 0x00, /* SOUND_MIXER_PCM */ 188 0x00, /* SOUND_MIXER_SPEAKER */ 189 0x08, /* SOUND_MIXER_LINE */ 190 0x01, /* SOUND_MIXER_MIC */ 191 0x02, /* SOUND_MIXER_CD */ 192 0x00, /* SOUND_MIXER_IMIX */ 193 0x00, /* SOUND_MIXER_ALTPCM */ 194 0x00, /* SOUND_MIXER_RECLEV */ 195 0x00, /* SOUND_MIXER_IGAIN */ 196 0x00 /* SOUND_MIXER_OGAIN */ 197}; 198 199static char smw_mix_regs[] = /* Left mixer registers */ 200{ 201 0x0b, /* SOUND_MIXER_VOLUME */ 202 0x0d, /* SOUND_MIXER_BASS */ 203 0x0d, /* SOUND_MIXER_TREBLE */ 204 0x05, /* SOUND_MIXER_SYNTH */ 205 0x09, /* SOUND_MIXER_PCM */ 206 0x00, /* SOUND_MIXER_SPEAKER */ 207 0x03, /* SOUND_MIXER_LINE */ 208 0x01, /* SOUND_MIXER_MIC */ 209 0x07, /* SOUND_MIXER_CD */ 210 0x00, /* SOUND_MIXER_IMIX */ 211 0x00, /* SOUND_MIXER_ALTPCM */ 212 0x00, /* SOUND_MIXER_RECLEV */ 213 0x00, /* SOUND_MIXER_IGAIN */ 214 0x00, /* SOUND_MIXER_OGAIN */ 215 0x00, /* SOUND_MIXER_LINE1 */ 216 0x00, /* SOUND_MIXER_LINE2 */ 217 0x00 /* SOUND_MIXER_LINE3 */ 218}; 219 220static int sbmixnum = 1; 221 222static void sb_mixer_reset(sb_devc * devc); 223 224void sb_mixer_set_stereo(sb_devc * devc, int mode) 225{ 226 sb_chgmixer(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC)); 227} 228 229static int detect_mixer(sb_devc * devc) 230{ 231 /* Just trust the mixer is there */ 232 return 1; 233} 234 235static void oss_change_bits(sb_devc *devc, unsigned char *regval, int dev, int chn, int newval) 236{ 237 unsigned char mask; 238 int shift; 239 240 mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; 241 newval = (int) ((newval * mask) + 50) / 100; /* Scale */ 242 243 shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; 244 245 *regval &= ~(mask << shift); /* Mask out previous value */ 246 *regval |= (newval & mask) << shift; /* Set the new value */ 247} 248 249static int sb_mixer_get(sb_devc * devc, int dev) 250{ 251 if (!((1 << dev) & devc->supported_devices)) 252 return -EINVAL; 253 return devc->levels[dev]; 254} 255 256void smw_mixer_init(sb_devc * devc) 257{ 258 int i; 259 260 sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ 261 sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ 262 263 devc->supported_devices = 0; 264 for (i = 0; i < sizeof(smw_mix_regs); i++) 265 if (smw_mix_regs[i] != 0) 266 devc->supported_devices |= (1 << i); 267 268 devc->supported_rec_devices = devc->supported_devices & 269 ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); 270 sb_mixer_reset(devc); 271} 272 273int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right) 274{ 275 int regoffs; 276 unsigned char val; 277 278 if ((dev < 0) || (dev >= devc->iomap_sz)) 279 return -EINVAL; 280 281 regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; 282 283 if (regoffs == 0) 284 return -EINVAL; 285 286 val = sb_getmixer(devc, regoffs); 287 oss_change_bits(devc, &val, dev, LEFT_CHN, left); 288 289 if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* 290 * Change register 291 */ 292 { 293 sb_setmixer(devc, regoffs, val); /* 294 * Save the old one 295 */ 296 regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; 297 298 if (regoffs == 0) 299 return left | (left << 8); /* 300 * Just left channel present 301 */ 302 303 val = sb_getmixer(devc, regoffs); /* 304 * Read the new one 305 */ 306 } 307 oss_change_bits(devc, &val, dev, RIGHT_CHN, right); 308 309 sb_setmixer(devc, regoffs, val); 310 311 return left | (right << 8); 312} 313 314static int smw_mixer_set(sb_devc * devc, int dev, int left, int right) 315{ 316 int reg, val; 317 318 switch (dev) 319 { 320 case SOUND_MIXER_VOLUME: 321 sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ 322 sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); 323 break; 324 325 case SOUND_MIXER_BASS: 326 case SOUND_MIXER_TREBLE: 327 devc->levels[dev] = left | (right << 8); 328 /* Set left bass and treble values */ 329 val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; 330 val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; 331 sb_setmixer(devc, 0x0d, val); 332 333 /* Set right bass and treble values */ 334 val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; 335 val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; 336 sb_setmixer(devc, 0x0e, val); 337 338 break; 339 340 default: 341 /* bounds check */ 342 if (dev < 0 || dev >= ARRAY_SIZE(smw_mix_regs)) 343 return -EINVAL; 344 reg = smw_mix_regs[dev]; 345 if (reg == 0) 346 return -EINVAL; 347 sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ 348 sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); 349 } 350 351 devc->levels[dev] = left | (right << 8); 352 return left | (right << 8); 353} 354 355static int sb_mixer_set(sb_devc * devc, int dev, int value) 356{ 357 int left = value & 0x000000ff; 358 int right = (value & 0x0000ff00) >> 8; 359 int retval; 360 361 if (left > 100) 362 left = 100; 363 if (right > 100) 364 right = 100; 365 366 if ((dev < 0) || (dev > 31)) 367 return -EINVAL; 368 369 if (!(devc->supported_devices & (1 << dev))) /* 370 * Not supported 371 */ 372 return -EINVAL; 373 374 /* Differentiate depending on the chipsets */ 375 switch (devc->model) { 376 case MDL_SMW: 377 retval = smw_mixer_set(devc, dev, left, right); 378 break; 379 case MDL_ESS: 380 retval = ess_mixer_set(devc, dev, left, right); 381 break; 382 default: 383 retval = sb_common_mixer_set(devc, dev, left, right); 384 } 385 if (retval >= 0) devc->levels[dev] = retval; 386 387 return retval; 388} 389 390/* 391 * set_recsrc doesn't apply to ES188x 392 */ 393static void set_recsrc(sb_devc * devc, int src) 394{ 395 sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); 396} 397 398static int set_recmask(sb_devc * devc, int mask) 399{ 400 int devmask, i; 401 unsigned char regimageL, regimageR; 402 403 devmask = mask & devc->supported_rec_devices; 404 405 switch (devc->model) 406 { 407 case MDL_SBPRO: 408 case MDL_ESS: 409 case MDL_JAZZ: 410 case MDL_SMW: 411 if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) { 412 break; 413 } 414 if (devmask != SOUND_MASK_MIC && 415 devmask != SOUND_MASK_LINE && 416 devmask != SOUND_MASK_CD) 417 { 418 /* 419 * More than one device selected. Drop the 420 * previous selection 421 */ 422 devmask &= ~devc->recmask; 423 } 424 if (devmask != SOUND_MASK_MIC && 425 devmask != SOUND_MASK_LINE && 426 devmask != SOUND_MASK_CD) 427 { 428 /* 429 * More than one device selected. Default to 430 * mic 431 */ 432 devmask = SOUND_MASK_MIC; 433 } 434 if (devmask ^ devc->recmask) /* 435 * Input source changed 436 */ 437 { 438 switch (devmask) 439 { 440 case SOUND_MASK_MIC: 441 set_recsrc(devc, SRC__MIC); 442 break; 443 444 case SOUND_MASK_LINE: 445 set_recsrc(devc, SRC__LINE); 446 break; 447 448 case SOUND_MASK_CD: 449 set_recsrc(devc, SRC__CD); 450 break; 451 452 default: 453 set_recsrc(devc, SRC__MIC); 454 } 455 } 456 break; 457 458 case MDL_SB16: 459 if (!devmask) 460 devmask = SOUND_MASK_MIC; 461 462 if (devc->submodel == SUBMDL_ALS007) 463 { 464 switch (devmask) 465 { 466 case SOUND_MASK_LINE: 467 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE); 468 break; 469 case SOUND_MASK_CD: 470 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD); 471 break; 472 case SOUND_MASK_SYNTH: 473 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH); 474 break; 475 default: /* Also takes care of SOUND_MASK_MIC case */ 476 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC); 477 break; 478 } 479 } 480 else 481 { 482 regimageL = regimageR = 0; 483 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 484 { 485 if ((1 << i) & devmask) 486 { 487 regimageL |= sb16_recmasks_L[i]; 488 regimageR |= sb16_recmasks_R[i]; 489 } 490 sb_setmixer (devc, SB16_IMASK_L, regimageL); 491 sb_setmixer (devc, SB16_IMASK_R, regimageR); 492 } 493 } 494 break; 495 } 496 devc->recmask = devmask; 497 return devc->recmask; 498} 499 500static int set_outmask(sb_devc * devc, int mask) 501{ 502 int devmask, i; 503 unsigned char regimage; 504 505 devmask = mask & devc->supported_out_devices; 506 507 switch (devc->model) 508 { 509 case MDL_SB16: 510 if (devc->submodel == SUBMDL_ALS007) 511 break; 512 else 513 { 514 regimage = 0; 515 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 516 { 517 if ((1 << i) & devmask) 518 { 519 regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]); 520 } 521 sb_setmixer (devc, SB16_OMASK, regimage); 522 } 523 } 524 break; 525 default: 526 break; 527 } 528 529 devc->outmask = devmask; 530 return devc->outmask; 531} 532 533static int sb_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) 534{ 535 sb_devc *devc = mixer_devs[dev]->devc; 536 int val, ret; 537 int __user *p = arg; 538 539 /* 540 * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). 541 * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) 542 * or mode==2 put 3DSE state to mode. 543 */ 544 if (devc->model == MDL_SB16) { 545 if (cmd == SOUND_MIXER_AGC) 546 { 547 if (get_user(val, p)) 548 return -EFAULT; 549 sb_setmixer(devc, 0x43, (~val) & 0x01); 550 return 0; 551 } 552 if (cmd == SOUND_MIXER_3DSE) 553 { 554 /* I put here 15, but I don't know the exact version. 555 At least my 4.13 havn't 3DSE, 4.16 has it. */ 556 if (devc->minor < 15) 557 return -EINVAL; 558 if (get_user(val, p)) 559 return -EFAULT; 560 if (val == 0 || val == 1) 561 sb_chgmixer(devc, AWE_3DSE, 0x01, val); 562 else if (val == 2) 563 { 564 ret = sb_getmixer(devc, AWE_3DSE)&0x01; 565 return put_user(ret, p); 566 } 567 else 568 return -EINVAL; 569 return 0; 570 } 571 } 572 if (((cmd >> 8) & 0xff) == 'M') 573 { 574 if (_SIOC_DIR(cmd) & _SIOC_WRITE) 575 { 576 if (get_user(val, p)) 577 return -EFAULT; 578 switch (cmd & 0xff) 579 { 580 case SOUND_MIXER_RECSRC: 581 ret = set_recmask(devc, val); 582 break; 583 584 case SOUND_MIXER_OUTSRC: 585 ret = set_outmask(devc, val); 586 break; 587 588 default: 589 ret = sb_mixer_set(devc, cmd & 0xff, val); 590 } 591 } 592 else switch (cmd & 0xff) 593 { 594 case SOUND_MIXER_RECSRC: 595 ret = devc->recmask; 596 break; 597 598 case SOUND_MIXER_OUTSRC: 599 ret = devc->outmask; 600 break; 601 602 case SOUND_MIXER_DEVMASK: 603 ret = devc->supported_devices; 604 break; 605 606 case SOUND_MIXER_STEREODEVS: 607 ret = devc->supported_devices; 608 /* The ESS seems to have stereo mic controls */ 609 if (devc->model == MDL_ESS) 610 ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); 611 else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) 612 ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); 613 break; 614 615 case SOUND_MIXER_RECMASK: 616 ret = devc->supported_rec_devices; 617 break; 618 619 case SOUND_MIXER_OUTMASK: 620 ret = devc->supported_out_devices; 621 break; 622 623 case SOUND_MIXER_CAPS: 624 ret = devc->mixer_caps; 625 break; 626 627 default: 628 ret = sb_mixer_get(devc, cmd & 0xff); 629 break; 630 } 631 return put_user(ret, p); 632 } else 633 return -EINVAL; 634} 635 636static struct mixer_operations sb_mixer_operations = 637{ 638 .owner = THIS_MODULE, 639 .id = "SB", 640 .name = "Sound Blaster", 641 .ioctl = sb_mixer_ioctl 642}; 643 644static struct mixer_operations als007_mixer_operations = 645{ 646 .owner = THIS_MODULE, 647 .id = "ALS007", 648 .name = "Avance ALS-007", 649 .ioctl = sb_mixer_ioctl 650}; 651 652static void sb_mixer_reset(sb_devc * devc) 653{ 654 char name[32]; 655 int i; 656 657 sprintf(name, "SB_%d", devc->sbmixnum); 658 659 if (devc->sbmo.sm_games) 660 devc->levels = load_mixer_volumes(name, smg_default_levels, 1); 661 else 662 devc->levels = load_mixer_volumes(name, sb_default_levels, 1); 663 664 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 665 sb_mixer_set(devc, i, devc->levels[i]); 666 667 if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) { 668 set_recmask(devc, SOUND_MASK_MIC); 669 } 670} 671 672int sb_mixer_init(sb_devc * devc, struct module *owner) 673{ 674 int mixer_type = 0; 675 int m; 676 677 devc->sbmixnum = sbmixnum++; 678 devc->levels = NULL; 679 680 sb_setmixer(devc, 0x00, 0); /* Reset mixer */ 681 682 if (!(mixer_type = detect_mixer(devc))) 683 return 0; /* No mixer. Why? */ 684 685 switch (devc->model) 686 { 687 case MDL_ESSPCI: 688 case MDL_YMPCI: 689 case MDL_SBPRO: 690 case MDL_AZTECH: 691 case MDL_JAZZ: 692 devc->mixer_caps = SOUND_CAP_EXCL_INPUT; 693 devc->supported_devices = SBPRO_MIXER_DEVICES; 694 devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; 695 devc->iomap = &sbpro_mix; 696 devc->iomap_sz = ARRAY_SIZE(sbpro_mix); 697 break; 698 699 case MDL_ESS: 700 ess_mixer_init (devc); 701 break; 702 703 case MDL_SMW: 704 devc->mixer_caps = SOUND_CAP_EXCL_INPUT; 705 devc->supported_devices = 0; 706 devc->supported_rec_devices = 0; 707 devc->iomap = &sbpro_mix; 708 devc->iomap_sz = ARRAY_SIZE(sbpro_mix); 709 smw_mixer_init(devc); 710 break; 711 712 case MDL_SB16: 713 devc->mixer_caps = 0; 714 devc->supported_rec_devices = SB16_RECORDING_DEVICES; 715 devc->supported_out_devices = SB16_OUTFILTER_DEVICES; 716 if (devc->submodel != SUBMDL_ALS007) 717 { 718 devc->supported_devices = SB16_MIXER_DEVICES; 719 devc->iomap = &sb16_mix; 720 devc->iomap_sz = ARRAY_SIZE(sb16_mix); 721 } 722 else 723 { 724 devc->supported_devices = ALS007_MIXER_DEVICES; 725 devc->iomap = &als007_mix; 726 devc->iomap_sz = ARRAY_SIZE(als007_mix); 727 } 728 break; 729 730 default: 731 printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model); 732 return 0; 733 } 734 735 m = sound_alloc_mixerdev(); 736 if (m == -1) 737 return 0; 738 739 mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); 740 if (mixer_devs[m] == NULL) 741 { 742 printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); 743 sound_unload_mixerdev(m); 744 return 0; 745 } 746 747 if (devc->submodel != SUBMDL_ALS007) 748 memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations)); 749 else 750 memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); 751 752 mixer_devs[m]->devc = devc; 753 754 if (owner) 755 mixer_devs[m]->owner = owner; 756 757 devc->my_mixerdev = m; 758 sb_mixer_reset(devc); 759 return 1; 760} 761 762void sb_mixer_unload(sb_devc *devc) 763{ 764 if (devc->my_mixerdev == -1) 765 return; 766 767 kfree(mixer_devs[devc->my_mixerdev]); 768 sound_unload_mixerdev(devc->my_mixerdev); 769 sbmixnum--; 770} 771