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