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 = kzalloc(sizeof(*fmixer), GFP_KERNEL); 57 if (fmixer == NULL) { 58 snd_card_file_remove(card, file); 59 return -ENOMEM; 60 } 61 fmixer->card = card; 62 fmixer->mixer = card->mixer_oss; 63 file->private_data = fmixer; 64 if (!try_module_get(card->module)) { 65 kfree(fmixer); 66 snd_card_file_remove(card, file); 67 return -EFAULT; 68 } 69 return 0; 70 } 71 72 static int snd_mixer_oss_release(struct inode *inode, struct file *file) 73 { 74 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 = kzalloc(sizeof(*uinfo), GFP_KERNEL); 521 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 522 if (uinfo == NULL || uctl == NULL) 523 goto __unalloc; 524 if (kctl->info(kctl, uinfo)) 525 goto __unalloc; 526 if (kctl->get(kctl, uctl)) 527 goto __unalloc; 528 if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && 529 uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) 530 goto __unalloc; 531 *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); 532 if (uinfo->count > 1) 533 *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); 534 __unalloc: 535 up_read(&card->controls_rwsem); 536 kfree(uctl); 537 kfree(uinfo); 538 } 539 540 static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer, 541 snd_mixer_oss_slot_t *pslot, 542 unsigned int numid, 543 int *left, int *right, 544 int route) 545 { 546 snd_ctl_elem_info_t *uinfo; 547 snd_ctl_elem_value_t *uctl; 548 snd_kcontrol_t *kctl; 549 snd_card_t *card = fmixer->card; 550 551 if (numid == ID_UNKNOWN) 552 return; 553 down_read(&card->controls_rwsem); 554 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 555 up_read(&card->controls_rwsem); 556 return; 557 } 558 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 559 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 560 if (uinfo == NULL || uctl == NULL) 561 goto __unalloc; 562 if (kctl->info(kctl, uinfo)) 563 goto __unalloc; 564 if (kctl->get(kctl, uctl)) 565 goto __unalloc; 566 if (!uctl->value.integer.value[0]) { 567 *left = 0; 568 if (uinfo->count == 1) 569 *right = 0; 570 } 571 if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) 572 *right = 0; 573 __unalloc: 574 up_read(&card->controls_rwsem); 575 kfree(uctl); 576 kfree(uinfo); 577 } 578 579 static int snd_mixer_oss_get_volume1(snd_mixer_oss_file_t *fmixer, 580 snd_mixer_oss_slot_t *pslot, 581 int *left, int *right) 582 { 583 struct slot *slot = (struct slot *)pslot->private_data; 584 585 *left = *right = 100; 586 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { 587 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); 588 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { 589 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); 590 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { 591 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); 592 } 593 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { 594 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 595 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { 596 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 597 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { 598 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 599 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { 600 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 601 } 602 return 0; 603 } 604 605 static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer, 606 snd_mixer_oss_slot_t *pslot, 607 unsigned int numid, 608 int left, int right) 609 { 610 snd_ctl_elem_info_t *uinfo; 611 snd_ctl_elem_value_t *uctl; 612 snd_kcontrol_t *kctl; 613 snd_card_t *card = fmixer->card; 614 int res; 615 616 if (numid == ID_UNKNOWN) 617 return; 618 down_read(&card->controls_rwsem); 619 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) 620 return; 621 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 622 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 623 if (uinfo == NULL || uctl == NULL) 624 goto __unalloc; 625 if (kctl->info(kctl, uinfo)) 626 goto __unalloc; 627 if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && 628 uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) 629 goto __unalloc; 630 uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); 631 if (uinfo->count > 1) 632 uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); 633 if ((res = kctl->put(kctl, uctl)) < 0) 634 goto __unalloc; 635 if (res > 0) 636 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 637 __unalloc: 638 up_read(&card->controls_rwsem); 639 kfree(uctl); 640 kfree(uinfo); 641 } 642 643 static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, 644 snd_mixer_oss_slot_t *pslot, 645 unsigned int numid, 646 int left, int right, 647 int route) 648 { 649 snd_ctl_elem_info_t *uinfo; 650 snd_ctl_elem_value_t *uctl; 651 snd_kcontrol_t *kctl; 652 snd_card_t *card = fmixer->card; 653 int res; 654 655 if (numid == ID_UNKNOWN) 656 return; 657 down_read(&card->controls_rwsem); 658 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { 659 up_read(&fmixer->card->controls_rwsem); 660 return; 661 } 662 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 663 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 664 if (uinfo == NULL || uctl == NULL) 665 goto __unalloc; 666 if (kctl->info(kctl, uinfo)) 667 goto __unalloc; 668 if (uinfo->count > 1) { 669 uctl->value.integer.value[0] = left > 0 ? 1 : 0; 670 uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; 671 if (route) { 672 uctl->value.integer.value[1] = 673 uctl->value.integer.value[2] = 0; 674 } 675 } else { 676 uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; 677 } 678 if ((res = kctl->put(kctl, uctl)) < 0) 679 goto __unalloc; 680 if (res > 0) 681 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 682 __unalloc: 683 up_read(&card->controls_rwsem); 684 kfree(uctl); 685 kfree(uinfo); 686 } 687 688 static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer, 689 snd_mixer_oss_slot_t *pslot, 690 int left, int right) 691 { 692 struct slot *slot = (struct slot *)pslot->private_data; 693 694 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { 695 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); 696 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) 697 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); 698 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { 699 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); 700 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { 701 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); 702 } 703 if (left || right) { 704 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) 705 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 706 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) 707 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 708 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) 709 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 710 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) 711 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 712 } else { 713 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { 714 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); 715 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { 716 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); 717 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { 718 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); 719 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { 720 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); 721 } 722 } 723 return 0; 724 } 725 726 static int snd_mixer_oss_get_recsrc1_sw(snd_mixer_oss_file_t *fmixer, 727 snd_mixer_oss_slot_t *pslot, 728 int *active) 729 { 730 struct slot *slot = (struct slot *)pslot->private_data; 731 int left, right; 732 733 left = right = 1; 734 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); 735 *active = (left || right) ? 1 : 0; 736 return 0; 737 } 738 739 static int snd_mixer_oss_get_recsrc1_route(snd_mixer_oss_file_t *fmixer, 740 snd_mixer_oss_slot_t *pslot, 741 int *active) 742 { 743 struct slot *slot = (struct slot *)pslot->private_data; 744 int left, right; 745 746 left = right = 1; 747 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); 748 *active = (left || right) ? 1 : 0; 749 return 0; 750 } 751 752 static int snd_mixer_oss_put_recsrc1_sw(snd_mixer_oss_file_t *fmixer, 753 snd_mixer_oss_slot_t *pslot, 754 int active) 755 { 756 struct slot *slot = (struct slot *)pslot->private_data; 757 758 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); 759 return 0; 760 } 761 762 static int snd_mixer_oss_put_recsrc1_route(snd_mixer_oss_file_t *fmixer, 763 snd_mixer_oss_slot_t *pslot, 764 int active) 765 { 766 struct slot *slot = (struct slot *)pslot->private_data; 767 768 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); 769 return 0; 770 } 771 772 static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int *active_index) 773 { 774 snd_card_t *card = fmixer->card; 775 snd_mixer_oss_t *mixer = fmixer->mixer; 776 snd_kcontrol_t *kctl; 777 snd_mixer_oss_slot_t *pslot; 778 struct slot *slot; 779 snd_ctl_elem_info_t *uinfo; 780 snd_ctl_elem_value_t *uctl; 781 int err, idx; 782 783 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 784 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 785 if (uinfo == NULL || uctl == NULL) { 786 err = -ENOMEM; 787 goto __unlock; 788 } 789 down_read(&card->controls_rwsem); 790 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 791 if (! kctl) { 792 err = -ENOENT; 793 goto __unlock; 794 } 795 if ((err = kctl->info(kctl, uinfo)) < 0) 796 goto __unlock; 797 if ((err = kctl->get(kctl, uctl)) < 0) 798 goto __unlock; 799 for (idx = 0; idx < 32; idx++) { 800 if (!(mixer->mask_recsrc & (1 << idx))) 801 continue; 802 pslot = &mixer->slots[idx]; 803 slot = (struct slot *)pslot->private_data; 804 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 805 continue; 806 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 807 continue; 808 if (slot->capture_item == uctl->value.enumerated.item[0]) { 809 *active_index = idx; 810 break; 811 } 812 } 813 err = 0; 814 __unlock: 815 up_read(&card->controls_rwsem); 816 kfree(uctl); 817 kfree(uinfo); 818 return err; 819 } 820 821 static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int active_index) 822 { 823 snd_card_t *card = fmixer->card; 824 snd_mixer_oss_t *mixer = fmixer->mixer; 825 snd_kcontrol_t *kctl; 826 snd_mixer_oss_slot_t *pslot; 827 struct slot *slot = NULL; 828 snd_ctl_elem_info_t *uinfo; 829 snd_ctl_elem_value_t *uctl; 830 int err; 831 unsigned int idx; 832 833 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); 834 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 835 if (uinfo == NULL || uctl == NULL) { 836 err = -ENOMEM; 837 goto __unlock; 838 } 839 down_read(&card->controls_rwsem); 840 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); 841 if (! kctl) { 842 err = -ENOENT; 843 goto __unlock; 844 } 845 if ((err = kctl->info(kctl, uinfo)) < 0) 846 goto __unlock; 847 for (idx = 0; idx < 32; idx++) { 848 if (!(mixer->mask_recsrc & (1 << idx))) 849 continue; 850 pslot = &mixer->slots[idx]; 851 slot = (struct slot *)pslot->private_data; 852 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) 853 continue; 854 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) 855 continue; 856 if (idx == active_index) 857 break; 858 slot = NULL; 859 } 860 if (! slot) 861 goto __unlock; 862 for (idx = 0; idx < uinfo->count; idx++) 863 uctl->value.enumerated.item[idx] = slot->capture_item; 864 err = kctl->put(kctl, uctl); 865 if (err > 0) 866 snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 867 err = 0; 868 __unlock: 869 up_read(&card->controls_rwsem); 870 kfree(uctl); 871 kfree(uinfo); 872 return err; 873 } 874 875 struct snd_mixer_oss_assign_table { 876 int oss_id; 877 const char *name; 878 int index; 879 }; 880 881 static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, const char *name, int index, int item) 882 { 883 snd_ctl_elem_info_t *info; 884 snd_kcontrol_t *kcontrol; 885 snd_card_t *card = mixer->card; 886 int err; 887 888 down_read(&card->controls_rwsem); 889 kcontrol = snd_mixer_oss_test_id(mixer, name, index); 890 if (kcontrol == NULL) { 891 up_read(&card->controls_rwsem); 892 return 0; 893 } 894 info = kmalloc(sizeof(*info), GFP_KERNEL); 895 if (! info) { 896 up_read(&card->controls_rwsem); 897 return -ENOMEM; 898 } 899 if ((err = kcontrol->info(kcontrol, info)) < 0) { 900 up_read(&card->controls_rwsem); 901 kfree(info); 902 return err; 903 } 904 slot->numid[item] = kcontrol->id.numid; 905 up_read(&card->controls_rwsem); 906 if (info->count > slot->channels) 907 slot->channels = info->count; 908 slot->present |= 1 << item; 909 kfree(info); 910 return 0; 911 } 912 913 static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn) 914 { 915 struct slot *p = (struct slot *)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(snd_mixer_oss_slot_t *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 /* 935 * build an OSS mixer element. 936 * ptr_allocated means the entry is dynamically allocated (change via proc file). 937 * when replace_old = 1, the old entry is replaced with the new one. 938 */ 939 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) 940 { 941 struct slot slot; 942 struct slot *pslot; 943 snd_kcontrol_t *kctl; 944 snd_mixer_oss_slot_t *rslot; 945 char str[64]; 946 947 /* check if already assigned */ 948 if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) 949 return 0; 950 951 memset(&slot, 0, sizeof(slot)); 952 memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ 953 if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, 954 SNDRV_MIXER_OSS_ITEM_GLOBAL)) 955 return 0; 956 sprintf(str, "%s Switch", ptr->name); 957 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 958 SNDRV_MIXER_OSS_ITEM_GSWITCH)) 959 return 0; 960 sprintf(str, "%s Route", ptr->name); 961 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 962 SNDRV_MIXER_OSS_ITEM_GROUTE)) 963 return 0; 964 sprintf(str, "%s Volume", ptr->name); 965 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 966 SNDRV_MIXER_OSS_ITEM_GVOLUME)) 967 return 0; 968 sprintf(str, "%s Playback Switch", ptr->name); 969 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 970 SNDRV_MIXER_OSS_ITEM_PSWITCH)) 971 return 0; 972 sprintf(str, "%s Playback Route", ptr->name); 973 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 974 SNDRV_MIXER_OSS_ITEM_PROUTE)) 975 return 0; 976 sprintf(str, "%s Playback Volume", ptr->name); 977 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 978 SNDRV_MIXER_OSS_ITEM_PVOLUME)) 979 return 0; 980 sprintf(str, "%s Capture Switch", ptr->name); 981 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 982 SNDRV_MIXER_OSS_ITEM_CSWITCH)) 983 return 0; 984 sprintf(str, "%s Capture Route", ptr->name); 985 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 986 SNDRV_MIXER_OSS_ITEM_CROUTE)) 987 return 0; 988 sprintf(str, "%s Capture Volume", ptr->name); 989 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, 990 SNDRV_MIXER_OSS_ITEM_CVOLUME)) 991 return 0; 992 down_read(&mixer->card->controls_rwsem); 993 if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { 994 snd_ctl_elem_info_t *uinfo; 995 996 uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); 997 if (! uinfo) { 998 up_read(&mixer->card->controls_rwsem); 999 return -ENOMEM; 1000 } 1001 1002 memset(uinfo, 0, sizeof(*uinfo)); 1003 if (kctl->info(kctl, uinfo)) { 1004 up_read(&mixer->card->controls_rwsem); 1005 return 0; 1006 } 1007 strcpy(str, ptr->name); 1008 if (!strcmp(str, "Master")) 1009 strcpy(str, "Mix"); 1010 if (!strcmp(str, "Master Mono")) 1011 strcpy(str, "Mix Mono"); 1012 slot.capture_item = 0; 1013 if (!strcmp(uinfo->value.enumerated.name, str)) { 1014 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 1015 } else { 1016 for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { 1017 uinfo->value.enumerated.item = slot.capture_item; 1018 if (kctl->info(kctl, uinfo)) { 1019 up_read(&mixer->card->controls_rwsem); 1020 return 0; 1021 } 1022 if (!strcmp(uinfo->value.enumerated.name, str)) { 1023 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; 1024 break; 1025 } 1026 } 1027 } 1028 kfree(uinfo); 1029 } 1030 up_read(&mixer->card->controls_rwsem); 1031 if (slot.present != 0) { 1032 pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL); 1033 if (! pslot) 1034 return -ENOMEM; 1035 *pslot = slot; 1036 pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; 1037 pslot->assigned = ptr; 1038 pslot->allocated = ptr_allocated; 1039 rslot = &mixer->slots[ptr->oss_id]; 1040 mixer_slot_clear(rslot); 1041 rslot->stereo = slot.channels > 1 ? 1 : 0; 1042 rslot->get_volume = snd_mixer_oss_get_volume1; 1043 rslot->put_volume = snd_mixer_oss_put_volume1; 1044 /* note: ES18xx have both Capture Source and XX Capture Volume !!! */ 1045 if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { 1046 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; 1047 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; 1048 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { 1049 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; 1050 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; 1051 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { 1052 mixer->mask_recsrc |= 1 << ptr->oss_id; 1053 } 1054 rslot->private_data = pslot; 1055 rslot->private_free = snd_mixer_oss_slot_free; 1056 return 1; 1057 } 1058 return 0; 1059 } 1060 1061 /* 1062 */ 1063 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name 1064 static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { 1065 MIXER_VOL(VOLUME), 1066 MIXER_VOL(BASS), 1067 MIXER_VOL(TREBLE), 1068 MIXER_VOL(SYNTH), 1069 MIXER_VOL(PCM), 1070 MIXER_VOL(SPEAKER), 1071 MIXER_VOL(LINE), 1072 MIXER_VOL(MIC), 1073 MIXER_VOL(CD), 1074 MIXER_VOL(IMIX), 1075 MIXER_VOL(ALTPCM), 1076 MIXER_VOL(RECLEV), 1077 MIXER_VOL(IGAIN), 1078 MIXER_VOL(OGAIN), 1079 MIXER_VOL(LINE1), 1080 MIXER_VOL(LINE2), 1081 MIXER_VOL(LINE3), 1082 MIXER_VOL(DIGITAL1), 1083 MIXER_VOL(DIGITAL2), 1084 MIXER_VOL(DIGITAL3), 1085 MIXER_VOL(PHONEIN), 1086 MIXER_VOL(PHONEOUT), 1087 MIXER_VOL(VIDEO), 1088 MIXER_VOL(RADIO), 1089 MIXER_VOL(MONITOR), 1090 }; 1091 1092 /* 1093 * /proc interface 1094 */ 1095 1096 static void snd_mixer_oss_proc_read(snd_info_entry_t *entry, 1097 snd_info_buffer_t * buffer) 1098 { 1099 snd_mixer_oss_t *mixer = entry->private_data; 1100 int i; 1101 1102 down(&mixer->reg_mutex); 1103 for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { 1104 struct slot *p; 1105 1106 if (! oss_mixer_names[i]) 1107 continue; 1108 p = (struct slot *)mixer->slots[i].private_data; 1109 snd_iprintf(buffer, "%s ", oss_mixer_names[i]); 1110 if (p && p->assigned) 1111 snd_iprintf(buffer, "\"%s\" %d\n", 1112 p->assigned->name, 1113 p->assigned->index); 1114 else 1115 snd_iprintf(buffer, "\"\" 0\n"); 1116 } 1117 up(&mixer->reg_mutex); 1118 } 1119 1120 static void snd_mixer_oss_proc_write(snd_info_entry_t *entry, 1121 snd_info_buffer_t * buffer) 1122 { 1123 snd_mixer_oss_t *mixer = entry->private_data; 1124 char line[128], str[32], idxstr[16], *cptr; 1125 int ch, idx; 1126 struct snd_mixer_oss_assign_table *tbl; 1127 struct slot *slot; 1128 1129 while (!snd_info_get_line(buffer, line, sizeof(line))) { 1130 cptr = snd_info_get_str(str, line, sizeof(str)); 1131 for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) 1132 if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0) 1133 break; 1134 if (ch >= SNDRV_OSS_MAX_MIXERS) { 1135 snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str); 1136 continue; 1137 } 1138 cptr = snd_info_get_str(str, cptr, sizeof(str)); 1139 if (! *str) { 1140 /* remove the entry */ 1141 down(&mixer->reg_mutex); 1142 mixer_slot_clear(&mixer->slots[ch]); 1143 up(&mixer->reg_mutex); 1144 continue; 1145 } 1146 snd_info_get_str(idxstr, cptr, sizeof(idxstr)); 1147 idx = simple_strtoul(idxstr, NULL, 10); 1148 if (idx >= 0x4000) { /* too big */ 1149 snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx); 1150 continue; 1151 } 1152 down(&mixer->reg_mutex); 1153 slot = (struct slot *)mixer->slots[ch].private_data; 1154 if (slot && slot->assigned && 1155 slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) 1156 /* not changed */ 1157 goto __unlock; 1158 tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); 1159 if (! tbl) { 1160 snd_printk(KERN_ERR "mixer_oss: no memory\n"); 1161 goto __unlock; 1162 } 1163 tbl->oss_id = ch; 1164 tbl->name = kstrdup(str, GFP_KERNEL); 1165 if (! tbl->name) { 1166 kfree(tbl); 1167 goto __unlock; 1168 } 1169 tbl->index = idx; 1170 if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { 1171 kfree(tbl->name); 1172 kfree(tbl); 1173 } 1174 __unlock: 1175 up(&mixer->reg_mutex); 1176 } 1177 } 1178 1179 static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer) 1180 { 1181 snd_info_entry_t *entry; 1182 1183 entry = snd_info_create_card_entry(mixer->card, "oss_mixer", 1184 mixer->card->proc_root); 1185 if (! entry) 1186 return; 1187 entry->content = SNDRV_INFO_CONTENT_TEXT; 1188 entry->mode = S_IFREG | S_IRUGO | S_IWUSR; 1189 entry->c.text.read_size = 8192; 1190 entry->c.text.read = snd_mixer_oss_proc_read; 1191 entry->c.text.write_size = 8192; 1192 entry->c.text.write = snd_mixer_oss_proc_write; 1193 entry->private_data = mixer; 1194 if (snd_info_register(entry) < 0) { 1195 snd_info_free_entry(entry); 1196 entry = NULL; 1197 } 1198 mixer->proc_entry = entry; 1199 } 1200 1201 static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer) 1202 { 1203 if (mixer->proc_entry) { 1204 snd_info_unregister(mixer->proc_entry); 1205 mixer->proc_entry = NULL; 1206 } 1207 } 1208 1209 static void snd_mixer_oss_build(snd_mixer_oss_t *mixer) 1210 { 1211 static struct snd_mixer_oss_assign_table table[] = { 1212 { SOUND_MIXER_VOLUME, "Master", 0 }, 1213 { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ 1214 { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, 1215 { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, 1216 { SOUND_MIXER_SYNTH, "Synth", 0 }, 1217 { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ 1218 { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ 1219 { SOUND_MIXER_PCM, "PCM", 0 }, 1220 { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, 1221 { SOUND_MIXER_LINE, "Line", 0 }, 1222 { SOUND_MIXER_MIC, "Mic", 0 }, 1223 { SOUND_MIXER_CD, "CD", 0 }, 1224 { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, 1225 { SOUND_MIXER_ALTPCM, "PCM", 1 }, 1226 { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */ 1227 { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ 1228 { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, 1229 { SOUND_MIXER_IGAIN, "Capture", 0 }, 1230 { SOUND_MIXER_OGAIN, "Playback", 0 }, 1231 { SOUND_MIXER_LINE1, "Aux", 0 }, 1232 { SOUND_MIXER_LINE2, "Aux", 1 }, 1233 { SOUND_MIXER_LINE3, "Aux", 2 }, 1234 { SOUND_MIXER_DIGITAL1, "Digital", 0 }, 1235 { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */ 1236 { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */ 1237 { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */ 1238 { SOUND_MIXER_DIGITAL2, "Digital", 1 }, 1239 { SOUND_MIXER_DIGITAL3, "Digital", 2 }, 1240 { SOUND_MIXER_PHONEIN, "Phone", 0 }, 1241 { SOUND_MIXER_PHONEOUT, "Master Mono", 0 }, 1242 { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */ 1243 { SOUND_MIXER_VIDEO, "Video", 0 }, 1244 { SOUND_MIXER_RADIO, "Radio", 0 }, 1245 { SOUND_MIXER_MONITOR, "Monitor", 0 } 1246 }; 1247 unsigned int idx; 1248 1249 for (idx = 0; idx < ARRAY_SIZE(table); idx++) 1250 snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); 1251 if (mixer->mask_recsrc) { 1252 mixer->get_recsrc = snd_mixer_oss_get_recsrc2; 1253 mixer->put_recsrc = snd_mixer_oss_put_recsrc2; 1254 } 1255 } 1256 1257 /* 1258 * 1259 */ 1260 1261 static int snd_mixer_oss_free1(void *private) 1262 { 1263 snd_mixer_oss_t *mixer = private; 1264 snd_card_t * card; 1265 int idx; 1266 1267 snd_assert(mixer != NULL, return -ENXIO); 1268 card = mixer->card; 1269 snd_assert(mixer == card->mixer_oss, return -ENXIO); 1270 card->mixer_oss = NULL; 1271 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { 1272 snd_mixer_oss_slot_t *chn = &mixer->slots[idx]; 1273 if (chn->private_free) 1274 chn->private_free(chn); 1275 } 1276 kfree(mixer); 1277 return 0; 1278 } 1279 1280 static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd) 1281 { 1282 snd_mixer_oss_t *mixer; 1283 1284 if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { 1285 char name[128]; 1286 int idx, err; 1287 1288 mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); 1289 if (mixer == NULL) 1290 return -ENOMEM; 1291 init_MUTEX(&mixer->reg_mutex); 1292 sprintf(name, "mixer%i%i", card->number, 0); 1293 if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, 1294 card, 0, 1295 &snd_mixer_oss_reg, 1296 name)) < 0) { 1297 snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n", 1298 card->number, 0); 1299 kfree(mixer); 1300 return err; 1301 } 1302 mixer->oss_dev_alloc = 1; 1303 mixer->card = card; 1304 if (*card->mixername) 1305 strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); 1306 else 1307 strlcpy(mixer->name, name, sizeof(mixer->name)); 1308 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1309 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, 1310 card->number, 1311 mixer->name); 1312 #endif 1313 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) 1314 mixer->slots[idx].number = idx; 1315 card->mixer_oss = mixer; 1316 snd_mixer_oss_build(mixer); 1317 snd_mixer_oss_proc_init(mixer); 1318 } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { 1319 mixer = card->mixer_oss; 1320 if (mixer == NULL || !mixer->oss_dev_alloc) 1321 return 0; 1322 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1323 mixer->oss_dev_alloc = 0; 1324 } else { /* free */ 1325 mixer = card->mixer_oss; 1326 if (mixer == NULL) 1327 return 0; 1328 #ifdef SNDRV_OSS_INFO_DEV_MIXERS 1329 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); 1330 #endif 1331 if (mixer->oss_dev_alloc) 1332 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1333 snd_mixer_oss_proc_done(mixer); 1334 return snd_mixer_oss_free1(mixer); 1335 } 1336 return 0; 1337 } 1338 1339 static int __init alsa_mixer_oss_init(void) 1340 { 1341 int idx; 1342 1343 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; 1344 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1345 if (snd_cards[idx]) 1346 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); 1347 } 1348 return 0; 1349 } 1350 1351 static void __exit alsa_mixer_oss_exit(void) 1352 { 1353 int idx; 1354 1355 snd_mixer_oss_notify_callback = NULL; 1356 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1357 if (snd_cards[idx]) 1358 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); 1359 } 1360 } 1361 1362 module_init(alsa_mixer_oss_init) 1363 module_exit(alsa_mixer_oss_exit) 1364 1365 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); 1366