1 /* 2 * OSS emulation layer for the mixer interface 3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <sound/driver.h> 23 #include <linux/init.h> 24 #include <linux/slab.h> 25 #include <linux/time.h> 26 #include <linux/string.h> 27 #include <sound/core.h> 28 #include <sound/minors.h> 29 #include <sound/control.h> 30 #include <sound/info.h> 31 #include <sound/mixer_oss.h> 32 #include <linux/soundcard.h> 33 34 #define OSS_ALSAEMULVER _SIOR ('M', 249, int) 35 36 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 37 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); 38 MODULE_LICENSE("GPL"); 39 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); 40 41 static int snd_mixer_oss_open(struct inode *inode, struct file *file) 42 { 43 struct snd_card *card; 44 struct snd_mixer_oss_file *fmixer; 45 int err; 46 47 card = snd_lookup_oss_minor_data(iminor(inode), 48 SNDRV_OSS_DEVICE_TYPE_MIXER); 49 if (card == NULL) 50 return -ENODEV; 51 if (card->mixer_oss == NULL) 52 return -ENODEV; 53 err = snd_card_file_add(card, file); 54 if (err < 0) 55 return err; 56 fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); 57 if (fmixer == NULL) { 58 snd_card_file_remove(card, file); 59 return -ENOMEM; 60 } 61 fmixer->card = card; 62 fmixer->mixer = card->mixer_oss; 63 file->private_data = fmixer; 64 if (!try_module_get(card->module)) { 65 kfree(fmixer); 66 snd_card_file_remove(card, file); 67 return -EFAULT; 68 } 69 return 0; 70 } 71 72 static int snd_mixer_oss_release(struct inode *inode, struct file *file) 73 { 74 struct snd_mixer_oss_file *fmixer; 75 76 if (file->private_data) { 77 fmixer = (struct snd_mixer_oss_file *) file->private_data; 78 module_put(fmixer->card->module); 79 snd_card_file_remove(fmixer->card, file); 80 kfree(fmixer); 81 } 82 return 0; 83 } 84 85 static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer, 86 mixer_info __user *_info) 87 { 88 struct snd_card *card = fmixer->card; 89 struct snd_mixer_oss *mixer = fmixer->mixer; 90 struct mixer_info info; 91 92 memset(&info, 0, sizeof(info)); 93 strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); 94 strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); 95 info.modify_counter = card->mixer_oss_change_count; 96 if (copy_to_user(_info, &info, sizeof(info))) 97 return -EFAULT; 98 return 0; 99 } 100 101 static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer, 102 _old_mixer_info __user *_info) 103 { 104 struct snd_card *card = fmixer->card; 105 struct snd_mixer_oss *mixer = fmixer->mixer; 106 _old_mixer_info info; 107 108 memset(&info, 0, sizeof(info)); 109 strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); 110 strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); 111 if (copy_to_user(_info, &info, sizeof(info))) 112 return -EFAULT; 113 return 0; 114 } 115 116 static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer) 117 { 118 struct snd_mixer_oss *mixer = fmixer->mixer; 119 int result = 0; 120 121 if (mixer == NULL) 122 return -EIO; 123 if (mixer->get_recsrc && mixer->put_recsrc) 124 result |= SOUND_CAP_EXCL_INPUT; 125 return result; 126 } 127 128 static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer) 129 { 130 struct snd_mixer_oss *mixer = fmixer->mixer; 131 struct snd_mixer_oss_slot *pslot; 132 int result = 0, chn; 133 134 if (mixer == NULL) 135 return -EIO; 136 for (chn = 0; chn < 31; chn++) { 137 pslot = &mixer->slots[chn]; 138 if (pslot->put_volume || pslot->put_recsrc) 139 result |= 1 << chn; 140 } 141 return result; 142 } 143 144 static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer) 145 { 146 struct snd_mixer_oss *mixer = fmixer->mixer; 147 struct snd_mixer_oss_slot *pslot; 148 int result = 0, chn; 149 150 if (mixer == NULL) 151 return -EIO; 152 for (chn = 0; chn < 31; chn++) { 153 pslot = &mixer->slots[chn]; 154 if (pslot->put_volume && pslot->stereo) 155 result |= 1 << chn; 156 } 157 return result; 158 } 159 160 static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer) 161 { 162 struct snd_mixer_oss *mixer = fmixer->mixer; 163 int result = 0; 164 165 if (mixer == NULL) 166 return -EIO; 167 if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ 168 result = mixer->mask_recsrc; 169 } else { 170 struct snd_mixer_oss_slot *pslot; 171 int chn; 172 for (chn = 0; chn < 31; chn++) { 173 pslot = &mixer->slots[chn]; 174 if (pslot->put_recsrc) 175 result |= 1 << chn; 176 } 177 } 178 return result; 179 } 180 181 static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) 182 { 183 struct snd_mixer_oss *mixer = fmixer->mixer; 184 int result = 0; 185 186 if (mixer == NULL) 187 return -EIO; 188 if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ 189 int err; 190 if ((err = mixer->get_recsrc(fmixer, &result)) < 0) 191 return err; 192 result = 1 << result; 193 } else { 194 struct snd_mixer_oss_slot *pslot; 195 int chn; 196 for (chn = 0; chn < 31; chn++) { 197 pslot = &mixer->slots[chn]; 198 if (pslot->get_recsrc) { 199 int active = 0; 200 pslot->get_recsrc(fmixer, pslot, &active); 201 if (active) 202 result |= 1 << chn; 203 } 204 } 205 } 206 return mixer->oss_recsrc = result; 207 } 208 209 static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc) 210 { 211 struct snd_mixer_oss *mixer = fmixer->mixer; 212 struct snd_mixer_oss_slot *pslot; 213 int chn, active; 214 int result = 0; 215 216 if (mixer == NULL) 217 return -EIO; 218 if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */ 219 if (recsrc & ~mixer->oss_recsrc) 220 recsrc &= ~mixer->oss_recsrc; 221 mixer->put_recsrc(fmixer, ffz(~recsrc)); 222 mixer->get_recsrc(fmixer, &result); 223 result = 1 << result; 224 } 225 for (chn = 0; chn < 31; chn++) { 226 pslot = &mixer->slots[chn]; 227 if (pslot->put_recsrc) { 228 active = (recsrc & (1 << chn)) ? 1 : 0; 229 pslot->put_recsrc(fmixer, pslot, active); 230 } 231 } 232 if (! result) { 233 for (chn = 0; chn < 31; chn++) { 234 pslot = &mixer->slots[chn]; 235 if (pslot->get_recsrc) { 236 active = 0; 237 pslot->get_recsrc(fmixer, pslot, &active); 238 if (active) 239 result |= 1 << chn; 240 } 241 } 242 } 243 return result; 244 } 245 246 static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot) 247 { 248 struct snd_mixer_oss *mixer = fmixer->mixer; 249 struct snd_mixer_oss_slot *pslot; 250 int result = 0, left, right; 251 252 if (mixer == NULL || slot > 30) 253 return -EIO; 254 pslot = &mixer->slots[slot]; 255 left = pslot->volume[0]; 256 right = pslot->volume[1]; 257 if (pslot->get_volume) 258 result = pslot->get_volume(fmixer, pslot, &left, &right); 259 if (!pslot->stereo) 260 right = left; 261 snd_assert(left >= 0 && left <= 100, return -EIO); 262 snd_assert(right >= 0 && right <= 100, return -EIO); 263 if (result >= 0) { 264 pslot->volume[0] = left; 265 pslot->volume[1] = right; 266 result = (left & 0xff) | ((right & 0xff) << 8); 267 } 268 return result; 269 } 270 271 static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer, 272 int slot, int volume) 273 { 274 struct snd_mixer_oss *mixer = fmixer->mixer; 275 struct snd_mixer_oss_slot *pslot; 276 int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff; 277 278 if (mixer == NULL || slot > 30) 279 return -EIO; 280 pslot = &mixer->slots[slot]; 281 if (left > 100) 282 left = 100; 283 if (right > 100) 284 right = 100; 285 if (!pslot->stereo) 286 right = left; 287 if (pslot->put_volume) 288 result = pslot->put_volume(fmixer, pslot, left, right); 289 if (result < 0) 290 return result; 291 pslot->volume[0] = left; 292 pslot->volume[1] = right; 293 return (left & 0xff) | ((right & 0xff) << 8); 294 } 295 296 static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg) 297 { 298 void __user *argp = (void __user *)arg; 299 int __user *p = argp; 300 int tmp; 301 302 snd_assert(fmixer != NULL, return -ENXIO); 303 if (((cmd >> 8) & 0xff) == 'M') { 304 switch (cmd) { 305 case SOUND_MIXER_INFO: 306 return snd_mixer_oss_info(fmixer, argp); 307 case SOUND_OLD_MIXER_INFO: 308 return snd_mixer_oss_info_obsolete(fmixer, argp); 309 case SOUND_MIXER_WRITE_RECSRC: 310 if (get_user(tmp, p)) 311 return -EFAULT; 312 tmp = snd_mixer_oss_set_recsrc(fmixer, tmp); 313 if (tmp < 0) 314 return tmp; 315 return put_user(tmp, p); 316 case OSS_GETVERSION: 317 return put_user(SNDRV_OSS_VERSION, p); 318 case OSS_ALSAEMULVER: 319 return put_user(1, p); 320 case SOUND_MIXER_READ_DEVMASK: 321 tmp = snd_mixer_oss_devmask(fmixer); 322 if (tmp < 0) 323 return tmp; 324 return put_user(tmp, p); 325 case SOUND_MIXER_READ_STEREODEVS: 326 tmp = snd_mixer_oss_stereodevs(fmixer); 327 if (tmp < 0) 328 return tmp; 329 return put_user(tmp, p); 330 case SOUND_MIXER_READ_RECMASK: 331 tmp = snd_mixer_oss_recmask(fmixer); 332 if (tmp < 0) 333 return tmp; 334 return put_user(tmp, p); 335 case SOUND_MIXER_READ_CAPS: 336 tmp = snd_mixer_oss_caps(fmixer); 337 if (tmp < 0) 338 return tmp; 339 return put_user(tmp, p); 340 case SOUND_MIXER_READ_RECSRC: 341 tmp = snd_mixer_oss_get_recsrc(fmixer); 342 if (tmp < 0) 343 return tmp; 344 return put_user(tmp, p); 345 } 346 } 347 if (cmd & SIOC_IN) { 348 if (get_user(tmp, p)) 349 return -EFAULT; 350 tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp); 351 if (tmp < 0) 352 return tmp; 353 return put_user(tmp, p); 354 } else if (cmd & SIOC_OUT) { 355 tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff); 356 if (tmp < 0) 357 return tmp; 358 return put_user(tmp, p); 359 } 360 return -ENXIO; 361 } 362 363 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 364 { 365 return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); 366 } 367 368 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) 369 { 370 struct snd_mixer_oss_file fmixer; 371 372 snd_assert(card != NULL, return -ENXIO); 373 if (card->mixer_oss == NULL) 374 return -ENXIO; 375 memset(&fmixer, 0, sizeof(fmixer)); 376 fmixer.card = card; 377 fmixer.mixer = card->mixer_oss; 378 return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); 379 } 380 381 #ifdef CONFIG_COMPAT 382 /* all compatible */ 383 #define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl 384 #else 385 #define snd_mixer_oss_ioctl_compat NULL 386 #endif 387 388 /* 389 * REGISTRATION PART 390 */ 391 392 static const struct file_operations snd_mixer_oss_f_ops = 393 { 394 .owner = THIS_MODULE, 395 .open = snd_mixer_oss_open, 396 .release = snd_mixer_oss_release, 397 .unlocked_ioctl = snd_mixer_oss_ioctl, 398 .compat_ioctl = snd_mixer_oss_ioctl_compat, 399 }; 400 401 /* 402 * utilities 403 */ 404 405 static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax) 406 { 407 long orange = omax - omin, nrange = nmax - nmin; 408 409 if (orange == 0) 410 return 0; 411 return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin; 412 } 413 414 /* convert from alsa native to oss values (0-100) */ 415 static long snd_mixer_oss_conv1(long val, long min, long max, int *old) 416 { 417 if (val == snd_mixer_oss_conv(*old, 0, 100, min, max)) 418 return *old; 419 return snd_mixer_oss_conv(val, min, max, 0, 100); 420 } 421 422 /* convert from oss to alsa native values */ 423 static long snd_mixer_oss_conv2(long val, long min, long max) 424 { 425 return snd_mixer_oss_conv(val, 0, 100, min, max); 426 } 427 428 #if 0 429 static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot) 430 { 431 struct snd_mixer_oss *mixer = card->mixer_oss; 432 if (mixer) 433 mixer->mask_recsrc |= 1 << slot; 434 } 435 436 static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot) 437 { 438 struct snd_mixer_oss *mixer = card->mixer_oss; 439 if (mixer && (mixer->mask_recsrc & (1 << slot))) 440 return 1; 441 return 0; 442 } 443 #endif 444 445 #define SNDRV_MIXER_OSS_SIGNATURE 0x65999250 446 447 #define SNDRV_MIXER_OSS_ITEM_GLOBAL 0 448 #define SNDRV_MIXER_OSS_ITEM_GSWITCH 1 449 #define SNDRV_MIXER_OSS_ITEM_GROUTE 2 450 #define SNDRV_MIXER_OSS_ITEM_GVOLUME 3 451 #define SNDRV_MIXER_OSS_ITEM_PSWITCH 4 452 #define SNDRV_MIXER_OSS_ITEM_PROUTE 5 453 #define SNDRV_MIXER_OSS_ITEM_PVOLUME 6 454 #define SNDRV_MIXER_OSS_ITEM_CSWITCH 7 455 #define SNDRV_MIXER_OSS_ITEM_CROUTE 8 456 #define SNDRV_MIXER_OSS_ITEM_CVOLUME 9 457 #define SNDRV_MIXER_OSS_ITEM_CAPTURE 10 458 459 #define SNDRV_MIXER_OSS_ITEM_COUNT 11 460 461 #define SNDRV_MIXER_OSS_PRESENT_GLOBAL (1<<0) 462 #define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1) 463 #define SNDRV_MIXER_OSS_PRESENT_GROUTE (1<<2) 464 #define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3) 465 #define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4) 466 #define SNDRV_MIXER_OSS_PRESENT_PROUTE (1<<5) 467 #define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6) 468 #define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7) 469 #define SNDRV_MIXER_OSS_PRESENT_CROUTE (1<<8) 470 #define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9) 471 #define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10) 472 473 struct slot { 474 unsigned int signature; 475 unsigned int present; 476 unsigned int channels; 477 unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; 478 unsigned int capture_item; 479 struct snd_mixer_oss_assign_table *assigned; 480 unsigned int allocated: 1; 481 }; 482 483 #define ID_UNKNOWN ((unsigned int)-1) 484 485 static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index) 486 { 487 struct snd_card *card = mixer->card; 488 struct snd_ctl_elem_id id; 489 490 memset(&id, 0, sizeof(id)); 491 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 492 strcpy(id.name, name); 493 id.index = index; 494 return snd_ctl_find_id(card, &id); 495 } 496 497 static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, 498 struct snd_mixer_oss_slot *pslot, 499 unsigned int numid, 500 int *left, int *right) 501 { 502 struct snd_ctl_elem_info *uinfo; 503 struct snd_ctl_elem_value *uctl; 504 struct snd_kcontrol *kctl; 505 struct snd_card *card = fmixer->card; 506 507 if (numid == ID_UNKNOWN) 508 return; 509 down_read(&card->controls_rwsem); 510 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 511 up_read(&card->controls_rwsem); 512 return; 513 } 514 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 515 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 516 if (uinfo == NULL || uctl == NULL) 517 goto __unalloc; 518 if (kctl->info(kctl, uinfo)) 519 goto __unalloc; 520 if (kctl->get(kctl, uctl)) 521 goto __unalloc; 522 if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && 523 uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) 524 goto __unalloc; 525 *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); 526 if (uinfo->count > 1) 527 *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); 528 __unalloc: 529 up_read(&card->controls_rwsem); 530 kfree(uctl); 531 kfree(uinfo); 532 } 533 534 static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, 535 struct snd_mixer_oss_slot *pslot, 536 unsigned int numid, 537 int *left, int *right, 538 int route) 539 { 540 struct snd_ctl_elem_info *uinfo; 541 struct snd_ctl_elem_value *uctl; 542 struct snd_kcontrol *kctl; 543 struct snd_card *card = fmixer->card; 544 545 if (numid == ID_UNKNOWN) 546 return; 547 down_read(&card->controls_rwsem); 548 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 549 up_read(&card->controls_rwsem); 550 return; 551 } 552 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 553 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 554 if (uinfo == NULL || uctl == NULL) 555 goto __unalloc; 556 if (kctl->info(kctl, uinfo)) 557 goto __unalloc; 558 if (kctl->get(kctl, uctl)) 559 goto __unalloc; 560 if (!uctl->value.integer.value[0]) { 561 *left = 0; 562 if (uinfo->count == 1) 563 *right = 0; 564 } 565 if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) 566 *right = 0; 567 __unalloc: 568 up_read(&card->controls_rwsem); 569 kfree(uctl); 570 kfree(uinfo); 571 } 572 573 static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, 574 struct snd_mixer_oss_slot *pslot, 575 int *left, int *right) 576 { 577 struct slot *slot = (struct slot *)pslot->private_data; 578 579 *left = *right = 100; 580 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { 581 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); 582 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { 583 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); 584 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { 585 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); 586 } 587 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { 588 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 589 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { 590 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 591 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { 592 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 593 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { 594 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 595 } 596 return 0; 597 } 598 599 static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, 600 struct snd_mixer_oss_slot *pslot, 601 unsigned int numid, 602 int left, int right) 603 { 604 struct snd_ctl_elem_info *uinfo; 605 struct snd_ctl_elem_value *uctl; 606 struct snd_kcontrol *kctl; 607 struct snd_card *card = fmixer->card; 608 int res; 609 610 if (numid == ID_UNKNOWN) 611 return; 612 down_read(&card->controls_rwsem); 613 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) 614 return; 615 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 616 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 617 if (uinfo == NULL || uctl == NULL) 618 goto __unalloc; 619 if (kctl->info(kctl, uinfo)) 620 goto __unalloc; 621 if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && 622 uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) 623 goto __unalloc; 624 uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); 625 if (uinfo->count > 1) 626 uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); 627 if ((res = kctl->put(kctl, uctl)) < 0) 628 goto __unalloc; 629 if (res > 0) 630 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 631 __unalloc: 632 up_read(&card->controls_rwsem); 633 kfree(uctl); 634 kfree(uinfo); 635 } 636 637 static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, 638 struct snd_mixer_oss_slot *pslot, 639 unsigned int numid, 640 int left, int right, 641 int route) 642 { 643 struct snd_ctl_elem_info *uinfo; 644 struct snd_ctl_elem_value *uctl; 645 struct snd_kcontrol *kctl; 646 struct snd_card *card = fmixer->card; 647 int res; 648 649 if (numid == ID_UNKNOWN) 650 return; 651 down_read(&card->controls_rwsem); 652 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 653 up_read(&fmixer->card->controls_rwsem); 654 return; 655 } 656 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 657 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 658 if (uinfo == NULL || uctl == NULL) 659 goto __unalloc; 660 if (kctl->info(kctl, uinfo)) 661 goto __unalloc; 662 if (uinfo->count > 1) { 663 uctl->value.integer.value[0] = left > 0 ? 1 : 0; 664 uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; 665 if (route) { 666 uctl->value.integer.value[1] = 667 uctl->value.integer.value[2] = 0; 668 } 669 } else { 670 uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; 671 } 672 if ((res = kctl->put(kctl, uctl)) < 0) 673 goto __unalloc; 674 if (res > 0) 675 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 676 __unalloc: 677 up_read(&card->controls_rwsem); 678 kfree(uctl); 679 kfree(uinfo); 680 } 681 682 static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, 683 struct snd_mixer_oss_slot *pslot, 684 int left, int right) 685 { 686 struct slot *slot = (struct slot *)pslot->private_data; 687 688 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { 689 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); 690 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) 691 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); 692 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { 693 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); 694 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { 695 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); 696 } 697 if (left || right) { 698 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) 699 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 700 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) 701 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 702 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) 703 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 704 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) 705 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 706 } else { 707 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { 708 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 709 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { 710 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 711 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { 712 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 713 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { 714 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 715 } 716 } 717 return 0; 718 } 719 720 static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, 721 struct snd_mixer_oss_slot *pslot, 722 int *active) 723 { 724 struct slot *slot = (struct slot *)pslot->private_data; 725 int left, right; 726 727 left = right = 1; 728 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); 729 *active = (left || right) ? 1 : 0; 730 return 0; 731 } 732 733 static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, 734 struct snd_mixer_oss_slot *pslot, 735 int *active) 736 { 737 struct slot *slot = (struct slot *)pslot->private_data; 738 int left, right; 739 740 left = right = 1; 741 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); 742 *active = (left || right) ? 1 : 0; 743 return 0; 744 } 745 746 static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, 747 struct snd_mixer_oss_slot *pslot, 748 int active) 749 { 750 struct slot *slot = (struct slot *)pslot->private_data; 751 752 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); 753 return 0; 754 } 755 756 static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, 757 struct snd_mixer_oss_slot *pslot, 758 int active) 759 { 760 struct slot *slot = (struct slot *)pslot->private_data; 761 762 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); 763 return 0; 764 } 765 766 static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index) 767 { 768 struct snd_card *card = fmixer->card; 769 struct snd_mixer_oss *mixer = fmixer->mixer; 770 struct snd_kcontrol *kctl; 771 struct snd_mixer_oss_slot *pslot; 772 struct slot *slot; 773 struct snd_ctl_elem_info *uinfo; 774 struct snd_ctl_elem_value *uctl; 775 int err, idx; 776 777 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 778 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 779 if (uinfo == NULL || uctl == NULL) { 780 err = -ENOMEM; 781 goto __unlock; 782 } 783 down_read(&card->controls_rwsem); 784 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 785 if (! kctl) { 786 err = -ENOENT; 787 goto __unlock; 788 } 789 if ((err = kctl->info(kctl, uinfo)) < 0) 790 goto __unlock; 791 if ((err = kctl->get(kctl, uctl)) < 0) 792 goto __unlock; 793 for (idx = 0; idx < 32; idx++) { 794 if (!(mixer->mask_recsrc & (1 << idx))) 795 continue; 796 pslot = &mixer->slots[idx]; 797 slot = (struct slot *)pslot->private_data; 798 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 799 continue; 800 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 801 continue; 802 if (slot->capture_item == uctl->value.enumerated.item[0]) { 803 *active_index = idx; 804 break; 805 } 806 } 807 err = 0; 808 __unlock: 809 up_read(&card->controls_rwsem); 810 kfree(uctl); 811 kfree(uinfo); 812 return err; 813 } 814 815 static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index) 816 { 817 struct snd_card *card = fmixer->card; 818 struct snd_mixer_oss *mixer = fmixer->mixer; 819 struct snd_kcontrol *kctl; 820 struct snd_mixer_oss_slot *pslot; 821 struct slot *slot = NULL; 822 struct snd_ctl_elem_info *uinfo; 823 struct snd_ctl_elem_value *uctl; 824 int err; 825 unsigned int idx; 826 827 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 828 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 829 if (uinfo == NULL || uctl == NULL) { 830 err = -ENOMEM; 831 goto __unlock; 832 } 833 down_read(&card->controls_rwsem); 834 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 835 if (! kctl) { 836 err = -ENOENT; 837 goto __unlock; 838 } 839 if ((err = kctl->info(kctl, uinfo)) < 0) 840 goto __unlock; 841 for (idx = 0; idx < 32; idx++) { 842 if (!(mixer->mask_recsrc & (1 << idx))) 843 continue; 844 pslot = &mixer->slots[idx]; 845 slot = (struct slot *)pslot->private_data; 846 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 847 continue; 848 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 849 continue; 850 if (idx == active_index) 851 break; 852 slot = NULL; 853 } 854 if (! slot) 855 goto __unlock; 856 for (idx = 0; idx < uinfo->count; idx++) 857 uctl->value.enumerated.item[idx] = slot->capture_item; 858 err = kctl->put(kctl, uctl); 859 if (err > 0) 860 snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 861 err = 0; 862 __unlock: 863 up_read(&card->controls_rwsem); 864 kfree(uctl); 865 kfree(uinfo); 866 return err; 867 } 868 869 struct snd_mixer_oss_assign_table { 870 int oss_id; 871 const char *name; 872 int index; 873 }; 874 875 static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item) 876 { 877 struct snd_ctl_elem_info *info; 878 struct snd_kcontrol *kcontrol; 879 struct snd_card *card = mixer->card; 880 int err; 881 882 down_read(&card->controls_rwsem); 883 kcontrol = snd_mixer_oss_test_id(mixer, name, index); 884 if (kcontrol == NULL) { 885 up_read(&card->controls_rwsem); 886 return 0; 887 } 888 info = kmalloc(sizeof(*info), GFP_KERNEL); 889 if (! info) { 890 up_read(&card->controls_rwsem); 891 return -ENOMEM; 892 } 893 if ((err = kcontrol->info(kcontrol, info)) < 0) { 894 up_read(&card->controls_rwsem); 895 kfree(info); 896 return err; 897 } 898 slot->numid[item] = kcontrol->id.numid; 899 up_read(&card->controls_rwsem); 900 if (info->count > slot->channels) 901 slot->channels = info->count; 902 slot->present |= 1 << item; 903 kfree(info); 904 return 0; 905 } 906 907 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) 908 { 909 struct slot *p = (struct slot *)chn->private_data; 910 if (p) { 911 if (p->allocated && p->assigned) { 912 kfree(p->assigned->name); 913 kfree(p->assigned); 914 } 915 kfree(p); 916 } 917 } 918 919 static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot) 920 { 921 int idx = rslot->number; /* remember this */ 922 if (rslot->private_free) 923 rslot->private_free(rslot); 924 memset(rslot, 0, sizeof(*rslot)); 925 rslot->number = idx; 926 } 927 928 /* 929 * build an OSS mixer element. 930 * ptr_allocated means the entry is dynamically allocated (change via proc file). 931 * when replace_old = 1, the old entry is replaced with the new one. 932 */ 933 static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) 934 { 935 struct slot slot; 936 struct slot *pslot; 937 struct snd_kcontrol *kctl; 938 struct snd_mixer_oss_slot *rslot; 939 char str[64]; 940 941 /* check if already assigned */ 942 if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) 943 return 0; 944 945 memset(&slot, 0, sizeof(slot)); 946 memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ 947 if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, 948 SNDRV_MIXER_OSS_ITEM_GLOBAL)) 949 return 0; 950 sprintf(str, "%s Switch", ptr->name); 951 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 952 SNDRV_MIXER_OSS_ITEM_GSWITCH)) 953 return 0; 954 sprintf(str, "%s Route", ptr->name); 955 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 956 SNDRV_MIXER_OSS_ITEM_GROUTE)) 957 return 0; 958 sprintf(str, "%s Volume", ptr->name); 959 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 960 SNDRV_MIXER_OSS_ITEM_GVOLUME)) 961 return 0; 962 sprintf(str, "%s Playback Switch", ptr->name); 963 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 964 SNDRV_MIXER_OSS_ITEM_PSWITCH)) 965 return 0; 966 sprintf(str, "%s Playback Route", ptr->name); 967 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 968 SNDRV_MIXER_OSS_ITEM_PROUTE)) 969 return 0; 970 sprintf(str, "%s Playback Volume", ptr->name); 971 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 972 SNDRV_MIXER_OSS_ITEM_PVOLUME)) 973 return 0; 974 sprintf(str, "%s Capture Switch", ptr->name); 975 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 976 SNDRV_MIXER_OSS_ITEM_CSWITCH)) 977 return 0; 978 sprintf(str, "%s Capture Route", ptr->name); 979 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 980 SNDRV_MIXER_OSS_ITEM_CROUTE)) 981 return 0; 982 sprintf(str, "%s Capture Volume", ptr->name); 983 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 984 SNDRV_MIXER_OSS_ITEM_CVOLUME)) 985 return 0; 986 down_read(&mixer->card->controls_rwsem); 987 if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { 988 struct snd_ctl_elem_info *uinfo; 989 990 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 991 if (! uinfo) { 992 up_read(&mixer->card->controls_rwsem); 993 return -ENOMEM; 994 } 995 996 if (kctl->info(kctl, uinfo)) { 997 up_read(&mixer->card->controls_rwsem); 998 return 0; 999 } 1000 strcpy(str, ptr->name); 1001 if (!strcmp(str, "Master")) 1002 strcpy(str, "Mix"); 1003 if (!strcmp(str, "Master Mono")) 1004 strcpy(str, "Mix Mono"); 1005 slot.capture_item = 0; 1006 if (!strcmp(uinfo->value.enumerated.name, str)) { 1007 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 1008 } else { 1009 for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { 1010 uinfo->value.enumerated.item = slot.capture_item; 1011 if (kctl->info(kctl, uinfo)) { 1012 up_read(&mixer->card->controls_rwsem); 1013 return 0; 1014 } 1015 if (!strcmp(uinfo->value.enumerated.name, str)) { 1016 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 1017 break; 1018 } 1019 } 1020 } 1021 kfree(uinfo); 1022 } 1023 up_read(&mixer->card->controls_rwsem); 1024 if (slot.present != 0) { 1025 pslot = kmalloc(sizeof(slot), GFP_KERNEL); 1026 if (! pslot) 1027 return -ENOMEM; 1028 *pslot = slot; 1029 pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; 1030 pslot->assigned = ptr; 1031 pslot->allocated = ptr_allocated; 1032 rslot = &mixer->slots[ptr->oss_id]; 1033 mixer_slot_clear(rslot); 1034 rslot->stereo = slot.channels > 1 ? 1 : 0; 1035 rslot->get_volume = snd_mixer_oss_get_volume1; 1036 rslot->put_volume = snd_mixer_oss_put_volume1; 1037 /* note: ES18xx have both Capture Source and XX Capture Volume !!! */ 1038 if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { 1039 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; 1040 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; 1041 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { 1042 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; 1043 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; 1044 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { 1045 mixer->mask_recsrc |= 1 << ptr->oss_id; 1046 } 1047 rslot->private_data = pslot; 1048 rslot->private_free = snd_mixer_oss_slot_free; 1049 return 1; 1050 } 1051 return 0; 1052 } 1053 1054 #ifdef CONFIG_PROC_FS 1055 /* 1056 */ 1057 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name 1058 static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { 1059 MIXER_VOL(VOLUME), 1060 MIXER_VOL(BASS), 1061 MIXER_VOL(TREBLE), 1062 MIXER_VOL(SYNTH), 1063 MIXER_VOL(PCM), 1064 MIXER_VOL(SPEAKER), 1065 MIXER_VOL(LINE), 1066 MIXER_VOL(MIC), 1067 MIXER_VOL(CD), 1068 MIXER_VOL(IMIX), 1069 MIXER_VOL(ALTPCM), 1070 MIXER_VOL(RECLEV), 1071 MIXER_VOL(IGAIN), 1072 MIXER_VOL(OGAIN), 1073 MIXER_VOL(LINE1), 1074 MIXER_VOL(LINE2), 1075 MIXER_VOL(LINE3), 1076 MIXER_VOL(DIGITAL1), 1077 MIXER_VOL(DIGITAL2), 1078 MIXER_VOL(DIGITAL3), 1079 MIXER_VOL(PHONEIN), 1080 MIXER_VOL(PHONEOUT), 1081 MIXER_VOL(VIDEO), 1082 MIXER_VOL(RADIO), 1083 MIXER_VOL(MONITOR), 1084 }; 1085 1086 /* 1087 * /proc interface 1088 */ 1089 1090 static void snd_mixer_oss_proc_read(struct snd_info_entry *entry, 1091 struct snd_info_buffer *buffer) 1092 { 1093 struct snd_mixer_oss *mixer = entry->private_data; 1094 int i; 1095 1096 mutex_lock(&mixer->reg_mutex); 1097 for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { 1098 struct slot *p; 1099 1100 if (! oss_mixer_names[i]) 1101 continue; 1102 p = (struct slot *)mixer->slots[i].private_data; 1103 snd_iprintf(buffer, "%s ", oss_mixer_names[i]); 1104 if (p && p->assigned) 1105 snd_iprintf(buffer, "\"%s\" %d\n", 1106 p->assigned->name, 1107 p->assigned->index); 1108 else 1109 snd_iprintf(buffer, "\"\" 0\n"); 1110 } 1111 mutex_unlock(&mixer->reg_mutex); 1112 } 1113 1114 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, 1115 struct snd_info_buffer *buffer) 1116 { 1117 struct snd_mixer_oss *mixer = entry->private_data; 1118 char line[128], str[32], idxstr[16], *cptr; 1119 int ch, idx; 1120 struct snd_mixer_oss_assign_table *tbl; 1121 struct slot *slot; 1122 1123 while (!snd_info_get_line(buffer, line, sizeof(line))) { 1124 cptr = snd_info_get_str(str, line, sizeof(str)); 1125 for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) 1126 if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0) 1127 break; 1128 if (ch >= SNDRV_OSS_MAX_MIXERS) { 1129 snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str); 1130 continue; 1131 } 1132 cptr = snd_info_get_str(str, cptr, sizeof(str)); 1133 if (! *str) { 1134 /* remove the entry */ 1135 mutex_lock(&mixer->reg_mutex); 1136 mixer_slot_clear(&mixer->slots[ch]); 1137 mutex_unlock(&mixer->reg_mutex); 1138 continue; 1139 } 1140 snd_info_get_str(idxstr, cptr, sizeof(idxstr)); 1141 idx = simple_strtoul(idxstr, NULL, 10); 1142 if (idx >= 0x4000) { /* too big */ 1143 snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx); 1144 continue; 1145 } 1146 mutex_lock(&mixer->reg_mutex); 1147 slot = (struct slot *)mixer->slots[ch].private_data; 1148 if (slot && slot->assigned && 1149 slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) 1150 /* not changed */ 1151 goto __unlock; 1152 tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); 1153 if (! tbl) { 1154 snd_printk(KERN_ERR "mixer_oss: no memory\n"); 1155 goto __unlock; 1156 } 1157 tbl->oss_id = ch; 1158 tbl->name = kstrdup(str, GFP_KERNEL); 1159 if (! tbl->name) { 1160 kfree(tbl); 1161 goto __unlock; 1162 } 1163 tbl->index = idx; 1164 if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { 1165 kfree(tbl->name); 1166 kfree(tbl); 1167 } 1168 __unlock: 1169 mutex_unlock(&mixer->reg_mutex); 1170 } 1171 } 1172 1173 static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) 1174 { 1175 struct snd_info_entry *entry; 1176 1177 entry = snd_info_create_card_entry(mixer->card, "oss_mixer", 1178 mixer->card->proc_root); 1179 if (! entry) 1180 return; 1181 entry->content = SNDRV_INFO_CONTENT_TEXT; 1182 entry->mode = S_IFREG | S_IRUGO | S_IWUSR; 1183 entry->c.text.read = snd_mixer_oss_proc_read; 1184 entry->c.text.write = snd_mixer_oss_proc_write; 1185 entry->private_data = mixer; 1186 if (snd_info_register(entry) < 0) { 1187 snd_info_free_entry(entry); 1188 entry = NULL; 1189 } 1190 mixer->proc_entry = entry; 1191 } 1192 1193 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) 1194 { 1195 snd_info_free_entry(mixer->proc_entry); 1196 mixer->proc_entry = NULL; 1197 } 1198 #else /* !CONFIG_PROC_FS */ 1199 #define snd_mixer_oss_proc_init(mix) 1200 #define snd_mixer_oss_proc_done(mix) 1201 #endif /* CONFIG_PROC_FS */ 1202 1203 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) 1204 { 1205 static struct snd_mixer_oss_assign_table table[] = { 1206 { SOUND_MIXER_VOLUME, "Master", 0 }, 1207 { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ 1208 { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, 1209 { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, 1210 { SOUND_MIXER_SYNTH, "Synth", 0 }, 1211 { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ 1212 { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ 1213 { SOUND_MIXER_PCM, "PCM", 0 }, 1214 { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, 1215 { SOUND_MIXER_LINE, "Line", 0 }, 1216 { SOUND_MIXER_MIC, "Mic", 0 }, 1217 { SOUND_MIXER_CD, "CD", 0 }, 1218 { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, 1219 { SOUND_MIXER_ALTPCM, "PCM", 1 }, 1220 { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */ 1221 { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ 1222 { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, 1223 { SOUND_MIXER_IGAIN, "Capture", 0 }, 1224 { SOUND_MIXER_OGAIN, "Playback", 0 }, 1225 { SOUND_MIXER_LINE1, "Aux", 0 }, 1226 { SOUND_MIXER_LINE2, "Aux", 1 }, 1227 { SOUND_MIXER_LINE3, "Aux", 2 }, 1228 { SOUND_MIXER_DIGITAL1, "Digital", 0 }, 1229 { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */ 1230 { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */ 1231 { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */ 1232 { SOUND_MIXER_DIGITAL2, "Digital", 1 }, 1233 { SOUND_MIXER_DIGITAL3, "Digital", 2 }, 1234 { SOUND_MIXER_PHONEIN, "Phone", 0 }, 1235 { SOUND_MIXER_PHONEOUT, "Master Mono", 0 }, 1236 { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */ 1237 { SOUND_MIXER_VIDEO, "Video", 0 }, 1238 { SOUND_MIXER_RADIO, "Radio", 0 }, 1239 { SOUND_MIXER_MONITOR, "Monitor", 0 } 1240 }; 1241 unsigned int idx; 1242 1243 for (idx = 0; idx < ARRAY_SIZE(table); idx++) 1244 snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); 1245 if (mixer->mask_recsrc) { 1246 mixer->get_recsrc = snd_mixer_oss_get_recsrc2; 1247 mixer->put_recsrc = snd_mixer_oss_put_recsrc2; 1248 } 1249 } 1250 1251 /* 1252 * 1253 */ 1254 1255 static int snd_mixer_oss_free1(void *private) 1256 { 1257 struct snd_mixer_oss *mixer = private; 1258 struct snd_card *card; 1259 int idx; 1260 1261 snd_assert(mixer != NULL, return -ENXIO); 1262 card = mixer->card; 1263 snd_assert(mixer == card->mixer_oss, return -ENXIO); 1264 card->mixer_oss = NULL; 1265 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { 1266 struct snd_mixer_oss_slot *chn = &mixer->slots[idx]; 1267 if (chn->private_free) 1268 chn->private_free(chn); 1269 } 1270 kfree(mixer); 1271 return 0; 1272 } 1273 1274 static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) 1275 { 1276 struct snd_mixer_oss *mixer; 1277 1278 if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { 1279 char name[128]; 1280 int idx, err; 1281 1282 mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); 1283 if (mixer == NULL) 1284 return -ENOMEM; 1285 mutex_init(&mixer->reg_mutex); 1286 sprintf(name, "mixer%i%i", card->number, 0); 1287 if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, 1288 card, 0, 1289 &snd_mixer_oss_f_ops, card, 1290 name)) < 0) { 1291 snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n", 1292 card->number, 0); 1293 kfree(mixer); 1294 return err; 1295 } 1296 mixer->oss_dev_alloc = 1; 1297 mixer->card = card; 1298 if (*card->mixername) 1299 strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); 1300 else 1301 strlcpy(mixer->name, name, sizeof(mixer->name)); 1302 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1303 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, 1304 card->number, 1305 mixer->name); 1306 #endif 1307 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) 1308 mixer->slots[idx].number = idx; 1309 card->mixer_oss = mixer; 1310 snd_mixer_oss_build(mixer); 1311 snd_mixer_oss_proc_init(mixer); 1312 } else { 1313 mixer = card->mixer_oss; 1314 if (mixer == NULL) 1315 return 0; 1316 if (mixer->oss_dev_alloc) { 1317 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1318 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); 1319 #endif 1320 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1321 mixer->oss_dev_alloc = 0; 1322 } 1323 if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) 1324 return 0; 1325 snd_mixer_oss_proc_done(mixer); 1326 return snd_mixer_oss_free1(mixer); 1327 } 1328 return 0; 1329 } 1330 1331 static int __init alsa_mixer_oss_init(void) 1332 { 1333 int idx; 1334 1335 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; 1336 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1337 if (snd_cards[idx]) 1338 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); 1339 } 1340 return 0; 1341 } 1342 1343 static void __exit alsa_mixer_oss_exit(void) 1344 { 1345 int idx; 1346 1347 snd_mixer_oss_notify_callback = NULL; 1348 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1349 if (snd_cards[idx]) 1350 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); 1351 } 1352 } 1353 1354 module_init(alsa_mixer_oss_init) 1355 module_exit(alsa_mixer_oss_exit) 1356 1357 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); 1358