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