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