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/smp_lock.h> 25 #include <linux/slab.h> 26 #include <linux/time.h> 27 #include <linux/string.h> 28 #include <sound/core.h> 29 #include <sound/minors.h> 30 #include <sound/control.h> 31 #include <sound/info.h> 32 #include <sound/mixer_oss.h> 33 #include <linux/soundcard.h> 34 35 #define OSS_ALSAEMULVER _SIOR ('M', 249, int) 36 37 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 38 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); 39 MODULE_LICENSE("GPL"); 40 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); 41 42 static int snd_mixer_oss_open(struct inode *inode, struct file *file) 43 { 44 int cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode)); 45 snd_card_t *card; 46 snd_mixer_oss_file_t *fmixer; 47 int err; 48 49 if ((card = snd_cards[cardnum]) == 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 = kcalloc(1, 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 snd_mixer_oss_file_t *fmixer; 75 76 if (file->private_data) { 77 fmixer = (snd_mixer_oss_file_t *) 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(snd_mixer_oss_file_t *fmixer, 86 mixer_info __user *_info) 87 { 88 snd_card_t *card = fmixer->card; 89 snd_mixer_oss_t *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(snd_mixer_oss_file_t *fmixer, 102 _old_mixer_info __user *_info) 103 { 104 snd_card_t *card = fmixer->card; 105 snd_mixer_oss_t *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(snd_mixer_oss_file_t *fmixer) 117 { 118 snd_mixer_oss_t *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(snd_mixer_oss_file_t *fmixer) 129 { 130 snd_mixer_oss_t *mixer = fmixer->mixer; 131 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer) 145 { 146 snd_mixer_oss_t *mixer = fmixer->mixer; 147 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer) 161 { 162 snd_mixer_oss_t *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 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer) 182 { 183 snd_mixer_oss_t *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 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer, int recsrc) 210 { 211 snd_mixer_oss_t *mixer = fmixer->mixer; 212 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer, int slot) 247 { 248 snd_mixer_oss_t *mixer = fmixer->mixer; 249 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer, 272 int slot, int volume) 273 { 274 snd_mixer_oss_t *mixer = fmixer->mixer; 275 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *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((snd_mixer_oss_file_t *) file->private_data, cmd, arg); 366 } 367 368 int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg) 369 { 370 snd_mixer_oss_file_t 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 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 static snd_minor_t snd_mixer_oss_reg = 402 { 403 .comment = "mixer", 404 .f_ops = &snd_mixer_oss_f_ops, 405 }; 406 407 /* 408 * utilities 409 */ 410 411 static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax) 412 { 413 long orange = omax - omin, nrange = nmax - nmin; 414 415 if (orange == 0) 416 return 0; 417 return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin; 418 } 419 420 /* convert from alsa native to oss values (0-100) */ 421 static long snd_mixer_oss_conv1(long val, long min, long max, int *old) 422 { 423 if (val == snd_mixer_oss_conv(*old, 0, 100, min, max)) 424 return *old; 425 return snd_mixer_oss_conv(val, min, max, 0, 100); 426 } 427 428 /* convert from oss to alsa native values */ 429 static long snd_mixer_oss_conv2(long val, long min, long max) 430 { 431 return snd_mixer_oss_conv(val, 0, 100, min, max); 432 } 433 434 #if 0 435 static void snd_mixer_oss_recsrce_set(snd_card_t *card, int slot) 436 { 437 snd_mixer_oss_t *mixer = card->mixer_oss; 438 if (mixer) 439 mixer->mask_recsrc |= 1 << slot; 440 } 441 442 static int snd_mixer_oss_recsrce_get(snd_card_t *card, int slot) 443 { 444 snd_mixer_oss_t *mixer = card->mixer_oss; 445 if (mixer && (mixer->mask_recsrc & (1 << slot))) 446 return 1; 447 return 0; 448 } 449 #endif 450 451 #define SNDRV_MIXER_OSS_SIGNATURE 0x65999250 452 453 #define SNDRV_MIXER_OSS_ITEM_GLOBAL 0 454 #define SNDRV_MIXER_OSS_ITEM_GSWITCH 1 455 #define SNDRV_MIXER_OSS_ITEM_GROUTE 2 456 #define SNDRV_MIXER_OSS_ITEM_GVOLUME 3 457 #define SNDRV_MIXER_OSS_ITEM_PSWITCH 4 458 #define SNDRV_MIXER_OSS_ITEM_PROUTE 5 459 #define SNDRV_MIXER_OSS_ITEM_PVOLUME 6 460 #define SNDRV_MIXER_OSS_ITEM_CSWITCH 7 461 #define SNDRV_MIXER_OSS_ITEM_CROUTE 8 462 #define SNDRV_MIXER_OSS_ITEM_CVOLUME 9 463 #define SNDRV_MIXER_OSS_ITEM_CAPTURE 10 464 465 #define SNDRV_MIXER_OSS_ITEM_COUNT 11 466 467 #define SNDRV_MIXER_OSS_PRESENT_GLOBAL (1<<0) 468 #define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1) 469 #define SNDRV_MIXER_OSS_PRESENT_GROUTE (1<<2) 470 #define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3) 471 #define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4) 472 #define SNDRV_MIXER_OSS_PRESENT_PROUTE (1<<5) 473 #define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6) 474 #define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7) 475 #define SNDRV_MIXER_OSS_PRESENT_CROUTE (1<<8) 476 #define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9) 477 #define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10) 478 479 struct slot { 480 unsigned int signature; 481 unsigned int present; 482 unsigned int channels; 483 unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; 484 unsigned int capture_item; 485 struct snd_mixer_oss_assign_table *assigned; 486 unsigned int allocated: 1; 487 }; 488 489 #define ID_UNKNOWN ((unsigned int)-1) 490 491 static snd_kcontrol_t *snd_mixer_oss_test_id(snd_mixer_oss_t *mixer, const char *name, int index) 492 { 493 snd_card_t * card = mixer->card; 494 snd_ctl_elem_id_t id; 495 496 memset(&id, 0, sizeof(id)); 497 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 498 strcpy(id.name, name); 499 id.index = index; 500 return snd_ctl_find_id(card, &id); 501 } 502 503 static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer, 504 snd_mixer_oss_slot_t *pslot, 505 unsigned int numid, 506 int *left, int *right) 507 { 508 snd_ctl_elem_info_t *uinfo; 509 snd_ctl_elem_value_t *uctl; 510 snd_kcontrol_t *kctl; 511 snd_card_t *card = fmixer->card; 512 513 if (numid == ID_UNKNOWN) 514 return; 515 down_read(&card->controls_rwsem); 516 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 517 up_read(&card->controls_rwsem); 518 return; 519 } 520 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 521 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 522 if (uinfo == NULL || uctl == NULL) 523 goto __unalloc; 524 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); 525 snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc); 526 snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc); 527 *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); 528 if (uinfo->count > 1) 529 *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); 530 __unalloc: 531 up_read(&card->controls_rwsem); 532 kfree(uctl); 533 kfree(uinfo); 534 } 535 536 static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer, 537 snd_mixer_oss_slot_t *pslot, 538 unsigned int numid, 539 int *left, int *right, 540 int route) 541 { 542 snd_ctl_elem_info_t *uinfo; 543 snd_ctl_elem_value_t *uctl; 544 snd_kcontrol_t *kctl; 545 snd_card_t *card = fmixer->card; 546 547 if (numid == ID_UNKNOWN) 548 return; 549 down_read(&card->controls_rwsem); 550 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 551 up_read(&card->controls_rwsem); 552 return; 553 } 554 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 555 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 556 if (uinfo == NULL || uctl == NULL) 557 goto __unalloc; 558 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); 559 snd_runtime_check(!kctl->get(kctl, uctl), 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(snd_mixer_oss_file_t *fmixer, 574 snd_mixer_oss_slot_t *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(snd_mixer_oss_file_t *fmixer, 600 snd_mixer_oss_slot_t *pslot, 601 unsigned int numid, 602 int left, int right) 603 { 604 snd_ctl_elem_info_t *uinfo; 605 snd_ctl_elem_value_t *uctl; 606 snd_kcontrol_t *kctl; 607 snd_card_t *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 = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 616 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 617 if (uinfo == NULL || uctl == NULL) 618 goto __unalloc; 619 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); 620 snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc); 621 uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); 622 if (uinfo->count > 1) 623 uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); 624 snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); 625 if (res > 0) 626 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 627 __unalloc: 628 up_read(&card->controls_rwsem); 629 kfree(uctl); 630 kfree(uinfo); 631 } 632 633 static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, 634 snd_mixer_oss_slot_t *pslot, 635 unsigned int numid, 636 int left, int right, 637 int route) 638 { 639 snd_ctl_elem_info_t *uinfo; 640 snd_ctl_elem_value_t *uctl; 641 snd_kcontrol_t *kctl; 642 snd_card_t *card = fmixer->card; 643 int res; 644 645 if (numid == ID_UNKNOWN) 646 return; 647 down_read(&card->controls_rwsem); 648 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 649 up_read(&fmixer->card->controls_rwsem); 650 return; 651 } 652 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 653 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 654 if (uinfo == NULL || uctl == NULL) 655 goto __unalloc; 656 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); 657 if (uinfo->count > 1) { 658 uctl->value.integer.value[0] = left > 0 ? 1 : 0; 659 uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; 660 if (route) { 661 uctl->value.integer.value[1] = 662 uctl->value.integer.value[2] = 0; 663 } 664 } else { 665 uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; 666 } 667 snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); 668 if (res > 0) 669 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 670 __unalloc: 671 up_read(&card->controls_rwsem); 672 kfree(uctl); 673 kfree(uinfo); 674 } 675 676 static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer, 677 snd_mixer_oss_slot_t *pslot, 678 int left, int right) 679 { 680 struct slot *slot = (struct slot *)pslot->private_data; 681 682 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { 683 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); 684 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) 685 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); 686 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { 687 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); 688 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { 689 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); 690 } 691 if (left || right) { 692 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) 693 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 694 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) 695 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 696 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) 697 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 698 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) 699 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 700 } else { 701 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { 702 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 703 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { 704 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 705 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { 706 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 707 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { 708 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 709 } 710 } 711 return 0; 712 } 713 714 static int snd_mixer_oss_get_recsrc1_sw(snd_mixer_oss_file_t *fmixer, 715 snd_mixer_oss_slot_t *pslot, 716 int *active) 717 { 718 struct slot *slot = (struct slot *)pslot->private_data; 719 int left, right; 720 721 left = right = 1; 722 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); 723 *active = (left || right) ? 1 : 0; 724 return 0; 725 } 726 727 static int snd_mixer_oss_get_recsrc1_route(snd_mixer_oss_file_t *fmixer, 728 snd_mixer_oss_slot_t *pslot, 729 int *active) 730 { 731 struct slot *slot = (struct slot *)pslot->private_data; 732 int left, right; 733 734 left = right = 1; 735 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); 736 *active = (left || right) ? 1 : 0; 737 return 0; 738 } 739 740 static int snd_mixer_oss_put_recsrc1_sw(snd_mixer_oss_file_t *fmixer, 741 snd_mixer_oss_slot_t *pslot, 742 int active) 743 { 744 struct slot *slot = (struct slot *)pslot->private_data; 745 746 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); 747 return 0; 748 } 749 750 static int snd_mixer_oss_put_recsrc1_route(snd_mixer_oss_file_t *fmixer, 751 snd_mixer_oss_slot_t *pslot, 752 int active) 753 { 754 struct slot *slot = (struct slot *)pslot->private_data; 755 756 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); 757 return 0; 758 } 759 760 static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int *active_index) 761 { 762 snd_card_t *card = fmixer->card; 763 snd_mixer_oss_t *mixer = fmixer->mixer; 764 snd_kcontrol_t *kctl; 765 snd_mixer_oss_slot_t *pslot; 766 struct slot *slot; 767 snd_ctl_elem_info_t *uinfo; 768 snd_ctl_elem_value_t *uctl; 769 int err, idx; 770 771 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 772 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 773 if (uinfo == NULL || uctl == NULL) { 774 err = -ENOMEM; 775 goto __unlock; 776 } 777 down_read(&card->controls_rwsem); 778 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 779 snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock); 780 snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock); 781 snd_runtime_check(!(err = kctl->get(kctl, uctl)), goto __unlock); 782 for (idx = 0; idx < 32; idx++) { 783 if (!(mixer->mask_recsrc & (1 << idx))) 784 continue; 785 pslot = &mixer->slots[idx]; 786 slot = (struct slot *)pslot->private_data; 787 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 788 continue; 789 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 790 continue; 791 if (slot->capture_item == uctl->value.enumerated.item[0]) { 792 *active_index = idx; 793 break; 794 } 795 } 796 err = 0; 797 __unlock: 798 up_read(&card->controls_rwsem); 799 kfree(uctl); 800 kfree(uinfo); 801 return err; 802 } 803 804 static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int active_index) 805 { 806 snd_card_t *card = fmixer->card; 807 snd_mixer_oss_t *mixer = fmixer->mixer; 808 snd_kcontrol_t *kctl; 809 snd_mixer_oss_slot_t *pslot; 810 struct slot *slot = NULL; 811 snd_ctl_elem_info_t *uinfo; 812 snd_ctl_elem_value_t *uctl; 813 int err; 814 unsigned int idx; 815 816 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); 817 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); 818 if (uinfo == NULL || uctl == NULL) { 819 err = -ENOMEM; 820 goto __unlock; 821 } 822 down_read(&card->controls_rwsem); 823 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 824 snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock); 825 snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock); 826 for (idx = 0; idx < 32; idx++) { 827 if (!(mixer->mask_recsrc & (1 << idx))) 828 continue; 829 pslot = &mixer->slots[idx]; 830 slot = (struct slot *)pslot->private_data; 831 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 832 continue; 833 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 834 continue; 835 if (idx == active_index) 836 break; 837 slot = NULL; 838 } 839 snd_runtime_check(slot != NULL, goto __unlock); 840 for (idx = 0; idx < uinfo->count; idx++) 841 uctl->value.enumerated.item[idx] = slot->capture_item; 842 snd_runtime_check((err = kctl->put(kctl, uctl)) >= 0, ); 843 if (err > 0) 844 snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 845 err = 0; 846 __unlock: 847 up_read(&card->controls_rwsem); 848 kfree(uctl); 849 kfree(uinfo); 850 return err; 851 } 852 853 struct snd_mixer_oss_assign_table { 854 int oss_id; 855 const char *name; 856 int index; 857 }; 858 859 static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, const char *name, int index, int item) 860 { 861 snd_ctl_elem_info_t *info; 862 snd_kcontrol_t *kcontrol; 863 snd_card_t *card = mixer->card; 864 int err; 865 866 down_read(&card->controls_rwsem); 867 kcontrol = snd_mixer_oss_test_id(mixer, name, index); 868 if (kcontrol == NULL) { 869 up_read(&card->controls_rwsem); 870 return 0; 871 } 872 info = kmalloc(sizeof(*info), GFP_KERNEL); 873 if (! info) { 874 up_read(&card->controls_rwsem); 875 return -ENOMEM; 876 } 877 if ((err = kcontrol->info(kcontrol, info)) < 0) { 878 up_read(&card->controls_rwsem); 879 kfree(info); 880 return err; 881 } 882 slot->numid[item] = kcontrol->id.numid; 883 up_read(&card->controls_rwsem); 884 if (info->count > slot->channels) 885 slot->channels = info->count; 886 slot->present |= 1 << item; 887 kfree(info); 888 return 0; 889 } 890 891 static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn) 892 { 893 struct slot *p = (struct slot *)chn->private_data; 894 if (p) { 895 if (p->allocated && p->assigned) { 896 kfree(p->assigned->name); 897 kfree(p->assigned); 898 } 899 kfree(p); 900 } 901 } 902 903 static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot) 904 { 905 int idx = rslot->number; /* remember this */ 906 if (rslot->private_free) 907 rslot->private_free(rslot); 908 memset(rslot, 0, sizeof(*rslot)); 909 rslot->number = idx; 910 } 911 912 /* 913 * build an OSS mixer element. 914 * ptr_allocated means the entry is dynamically allocated (change via proc file). 915 * when replace_old = 1, the old entry is replaced with the new one. 916 */ 917 static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) 918 { 919 struct slot slot; 920 struct slot *pslot; 921 snd_kcontrol_t *kctl; 922 snd_mixer_oss_slot_t *rslot; 923 char str[64]; 924 925 /* check if already assigned */ 926 if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) 927 return 0; 928 929 memset(&slot, 0, sizeof(slot)); 930 memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ 931 if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, 932 SNDRV_MIXER_OSS_ITEM_GLOBAL)) 933 return 0; 934 sprintf(str, "%s Switch", ptr->name); 935 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 936 SNDRV_MIXER_OSS_ITEM_GSWITCH)) 937 return 0; 938 sprintf(str, "%s Route", ptr->name); 939 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 940 SNDRV_MIXER_OSS_ITEM_GROUTE)) 941 return 0; 942 sprintf(str, "%s Volume", ptr->name); 943 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 944 SNDRV_MIXER_OSS_ITEM_GVOLUME)) 945 return 0; 946 sprintf(str, "%s Playback Switch", ptr->name); 947 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 948 SNDRV_MIXER_OSS_ITEM_PSWITCH)) 949 return 0; 950 sprintf(str, "%s Playback Route", ptr->name); 951 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 952 SNDRV_MIXER_OSS_ITEM_PROUTE)) 953 return 0; 954 sprintf(str, "%s Playback Volume", ptr->name); 955 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 956 SNDRV_MIXER_OSS_ITEM_PVOLUME)) 957 return 0; 958 sprintf(str, "%s Capture Switch", ptr->name); 959 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 960 SNDRV_MIXER_OSS_ITEM_CSWITCH)) 961 return 0; 962 sprintf(str, "%s Capture Route", ptr->name); 963 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 964 SNDRV_MIXER_OSS_ITEM_CROUTE)) 965 return 0; 966 sprintf(str, "%s Capture Volume", ptr->name); 967 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 968 SNDRV_MIXER_OSS_ITEM_CVOLUME)) 969 return 0; 970 down_read(&mixer->card->controls_rwsem); 971 if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { 972 snd_ctl_elem_info_t *uinfo; 973 974 uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); 975 if (! uinfo) { 976 up_read(&mixer->card->controls_rwsem); 977 return -ENOMEM; 978 } 979 980 memset(uinfo, 0, sizeof(*uinfo)); 981 if (kctl->info(kctl, uinfo)) { 982 up_read(&mixer->card->controls_rwsem); 983 return 0; 984 } 985 strcpy(str, ptr->name); 986 if (!strcmp(str, "Master")) 987 strcpy(str, "Mix"); 988 if (!strcmp(str, "Master Mono")) 989 strcpy(str, "Mix Mono"); 990 slot.capture_item = 0; 991 if (!strcmp(uinfo->value.enumerated.name, str)) { 992 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 993 } else { 994 for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { 995 uinfo->value.enumerated.item = slot.capture_item; 996 if (kctl->info(kctl, uinfo)) { 997 up_read(&mixer->card->controls_rwsem); 998 return 0; 999 } 1000 if (!strcmp(uinfo->value.enumerated.name, str)) { 1001 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 1002 break; 1003 } 1004 } 1005 } 1006 kfree(uinfo); 1007 } 1008 up_read(&mixer->card->controls_rwsem); 1009 if (slot.present != 0) { 1010 pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL); 1011 snd_runtime_check(pslot != NULL, return -ENOMEM); 1012 *pslot = slot; 1013 pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; 1014 pslot->assigned = ptr; 1015 pslot->allocated = ptr_allocated; 1016 rslot = &mixer->slots[ptr->oss_id]; 1017 mixer_slot_clear(rslot); 1018 rslot->stereo = slot.channels > 1 ? 1 : 0; 1019 rslot->get_volume = snd_mixer_oss_get_volume1; 1020 rslot->put_volume = snd_mixer_oss_put_volume1; 1021 /* note: ES18xx have both Capture Source and XX Capture Volume !!! */ 1022 if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { 1023 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; 1024 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; 1025 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { 1026 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; 1027 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; 1028 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { 1029 mixer->mask_recsrc |= 1 << ptr->oss_id; 1030 } 1031 rslot->private_data = pslot; 1032 rslot->private_free = snd_mixer_oss_slot_free; 1033 return 1; 1034 } 1035 return 0; 1036 } 1037 1038 /* 1039 */ 1040 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name 1041 static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { 1042 MIXER_VOL(VOLUME), 1043 MIXER_VOL(BASS), 1044 MIXER_VOL(TREBLE), 1045 MIXER_VOL(SYNTH), 1046 MIXER_VOL(PCM), 1047 MIXER_VOL(SPEAKER), 1048 MIXER_VOL(LINE), 1049 MIXER_VOL(MIC), 1050 MIXER_VOL(CD), 1051 MIXER_VOL(IMIX), 1052 MIXER_VOL(ALTPCM), 1053 MIXER_VOL(RECLEV), 1054 MIXER_VOL(IGAIN), 1055 MIXER_VOL(OGAIN), 1056 MIXER_VOL(LINE1), 1057 MIXER_VOL(LINE2), 1058 MIXER_VOL(LINE3), 1059 MIXER_VOL(DIGITAL1), 1060 MIXER_VOL(DIGITAL2), 1061 MIXER_VOL(DIGITAL3), 1062 MIXER_VOL(PHONEIN), 1063 MIXER_VOL(PHONEOUT), 1064 MIXER_VOL(VIDEO), 1065 MIXER_VOL(RADIO), 1066 MIXER_VOL(MONITOR), 1067 }; 1068 1069 /* 1070 * /proc interface 1071 */ 1072 1073 static void snd_mixer_oss_proc_read(snd_info_entry_t *entry, 1074 snd_info_buffer_t * buffer) 1075 { 1076 snd_mixer_oss_t *mixer = entry->private_data; 1077 int i; 1078 1079 down(&mixer->reg_mutex); 1080 for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { 1081 struct slot *p; 1082 1083 if (! oss_mixer_names[i]) 1084 continue; 1085 p = (struct slot *)mixer->slots[i].private_data; 1086 snd_iprintf(buffer, "%s ", oss_mixer_names[i]); 1087 if (p && p->assigned) 1088 snd_iprintf(buffer, "\"%s\" %d\n", 1089 p->assigned->name, 1090 p->assigned->index); 1091 else 1092 snd_iprintf(buffer, "\"\" 0\n"); 1093 } 1094 up(&mixer->reg_mutex); 1095 } 1096 1097 static void snd_mixer_oss_proc_write(snd_info_entry_t *entry, 1098 snd_info_buffer_t * buffer) 1099 { 1100 snd_mixer_oss_t *mixer = entry->private_data; 1101 char line[128], str[32], idxstr[16], *cptr; 1102 int ch, idx; 1103 struct snd_mixer_oss_assign_table *tbl; 1104 struct slot *slot; 1105 1106 while (!snd_info_get_line(buffer, line, sizeof(line))) { 1107 cptr = snd_info_get_str(str, line, sizeof(str)); 1108 for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) 1109 if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0) 1110 break; 1111 if (ch >= SNDRV_OSS_MAX_MIXERS) { 1112 snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str); 1113 continue; 1114 } 1115 cptr = snd_info_get_str(str, cptr, sizeof(str)); 1116 if (! *str) { 1117 /* remove the entry */ 1118 down(&mixer->reg_mutex); 1119 mixer_slot_clear(&mixer->slots[ch]); 1120 up(&mixer->reg_mutex); 1121 continue; 1122 } 1123 snd_info_get_str(idxstr, cptr, sizeof(idxstr)); 1124 idx = simple_strtoul(idxstr, NULL, 10); 1125 if (idx >= 0x4000) { /* too big */ 1126 snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx); 1127 continue; 1128 } 1129 down(&mixer->reg_mutex); 1130 slot = (struct slot *)mixer->slots[ch].private_data; 1131 if (slot && slot->assigned && 1132 slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) 1133 /* not changed */ 1134 goto __unlock; 1135 tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); 1136 if (! tbl) { 1137 snd_printk(KERN_ERR "mixer_oss: no memory\n"); 1138 goto __unlock; 1139 } 1140 tbl->oss_id = ch; 1141 tbl->name = kstrdup(str, GFP_KERNEL); 1142 if (! tbl->name) { 1143 kfree(tbl); 1144 goto __unlock; 1145 } 1146 tbl->index = idx; 1147 if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { 1148 kfree(tbl->name); 1149 kfree(tbl); 1150 } 1151 __unlock: 1152 up(&mixer->reg_mutex); 1153 } 1154 } 1155 1156 static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer) 1157 { 1158 snd_info_entry_t *entry; 1159 1160 entry = snd_info_create_card_entry(mixer->card, "oss_mixer", 1161 mixer->card->proc_root); 1162 if (! entry) 1163 return; 1164 entry->content = SNDRV_INFO_CONTENT_TEXT; 1165 entry->mode = S_IFREG | S_IRUGO | S_IWUSR; 1166 entry->c.text.read_size = 8192; 1167 entry->c.text.read = snd_mixer_oss_proc_read; 1168 entry->c.text.write_size = 8192; 1169 entry->c.text.write = snd_mixer_oss_proc_write; 1170 entry->private_data = mixer; 1171 if (snd_info_register(entry) < 0) { 1172 snd_info_free_entry(entry); 1173 entry = NULL; 1174 } 1175 mixer->proc_entry = entry; 1176 } 1177 1178 static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer) 1179 { 1180 if (mixer->proc_entry) { 1181 snd_info_unregister(mixer->proc_entry); 1182 mixer->proc_entry = NULL; 1183 } 1184 } 1185 1186 static void snd_mixer_oss_build(snd_mixer_oss_t *mixer) 1187 { 1188 static struct snd_mixer_oss_assign_table table[] = { 1189 { SOUND_MIXER_VOLUME, "Master", 0 }, 1190 { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ 1191 { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, 1192 { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, 1193 { SOUND_MIXER_SYNTH, "Synth", 0 }, 1194 { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ 1195 { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ 1196 { SOUND_MIXER_PCM, "PCM", 0 }, 1197 { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, 1198 { SOUND_MIXER_LINE, "Line", 0 }, 1199 { SOUND_MIXER_MIC, "Mic", 0 }, 1200 { SOUND_MIXER_CD, "CD", 0 }, 1201 { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, 1202 { SOUND_MIXER_ALTPCM, "PCM", 1 }, 1203 { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */ 1204 { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ 1205 { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, 1206 { SOUND_MIXER_IGAIN, "Capture", 0 }, 1207 { SOUND_MIXER_OGAIN, "Playback", 0 }, 1208 { SOUND_MIXER_LINE1, "Aux", 0 }, 1209 { SOUND_MIXER_LINE2, "Aux", 1 }, 1210 { SOUND_MIXER_LINE3, "Aux", 2 }, 1211 { SOUND_MIXER_DIGITAL1, "Digital", 0 }, 1212 { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */ 1213 { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */ 1214 { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */ 1215 { SOUND_MIXER_DIGITAL2, "Digital", 1 }, 1216 { SOUND_MIXER_DIGITAL3, "Digital", 2 }, 1217 { SOUND_MIXER_PHONEIN, "Phone", 0 }, 1218 { SOUND_MIXER_PHONEOUT, "Master Mono", 0 }, 1219 { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */ 1220 { SOUND_MIXER_VIDEO, "Video", 0 }, 1221 { SOUND_MIXER_RADIO, "Radio", 0 }, 1222 { SOUND_MIXER_MONITOR, "Monitor", 0 } 1223 }; 1224 unsigned int idx; 1225 1226 for (idx = 0; idx < ARRAY_SIZE(table); idx++) 1227 snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); 1228 if (mixer->mask_recsrc) { 1229 mixer->get_recsrc = snd_mixer_oss_get_recsrc2; 1230 mixer->put_recsrc = snd_mixer_oss_put_recsrc2; 1231 } 1232 } 1233 1234 /* 1235 * 1236 */ 1237 1238 static int snd_mixer_oss_free1(void *private) 1239 { 1240 snd_mixer_oss_t *mixer = private; 1241 snd_card_t * card; 1242 int idx; 1243 1244 snd_assert(mixer != NULL, return -ENXIO); 1245 card = mixer->card; 1246 snd_assert(mixer == card->mixer_oss, return -ENXIO); 1247 card->mixer_oss = NULL; 1248 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { 1249 snd_mixer_oss_slot_t *chn = &mixer->slots[idx]; 1250 if (chn->private_free) 1251 chn->private_free(chn); 1252 } 1253 kfree(mixer); 1254 return 0; 1255 } 1256 1257 static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd) 1258 { 1259 snd_mixer_oss_t *mixer; 1260 1261 if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { 1262 char name[128]; 1263 int idx, err; 1264 1265 mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); 1266 if (mixer == NULL) 1267 return -ENOMEM; 1268 init_MUTEX(&mixer->reg_mutex); 1269 sprintf(name, "mixer%i%i", card->number, 0); 1270 if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, 1271 card, 0, 1272 &snd_mixer_oss_reg, 1273 name)) < 0) { 1274 snd_printk("unable to register OSS mixer device %i:%i\n", card->number, 0); 1275 kfree(mixer); 1276 return err; 1277 } 1278 mixer->oss_dev_alloc = 1; 1279 mixer->card = card; 1280 if (*card->mixername) 1281 strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); 1282 else 1283 strlcpy(mixer->name, name, sizeof(mixer->name)); 1284 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1285 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, 1286 card->number, 1287 mixer->name); 1288 #endif 1289 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) 1290 mixer->slots[idx].number = idx; 1291 card->mixer_oss = mixer; 1292 snd_mixer_oss_build(mixer); 1293 snd_mixer_oss_proc_init(mixer); 1294 } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { 1295 mixer = card->mixer_oss; 1296 if (mixer == NULL || !mixer->oss_dev_alloc) 1297 return 0; 1298 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1299 mixer->oss_dev_alloc = 0; 1300 } else { /* free */ 1301 mixer = card->mixer_oss; 1302 if (mixer == NULL) 1303 return 0; 1304 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1305 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); 1306 #endif 1307 if (mixer->oss_dev_alloc) 1308 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1309 snd_mixer_oss_proc_done(mixer); 1310 return snd_mixer_oss_free1(mixer); 1311 } 1312 return 0; 1313 } 1314 1315 static int __init alsa_mixer_oss_init(void) 1316 { 1317 int idx; 1318 1319 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; 1320 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1321 if (snd_cards[idx]) 1322 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); 1323 } 1324 return 0; 1325 } 1326 1327 static void __exit alsa_mixer_oss_exit(void) 1328 { 1329 int idx; 1330 1331 snd_mixer_oss_notify_callback = NULL; 1332 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1333 if (snd_cards[idx]) 1334 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); 1335 } 1336 } 1337 1338 module_init(alsa_mixer_oss_init) 1339 module_exit(alsa_mixer_oss_exit) 1340 1341 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); 1342