Linux Audio

Check our new training course

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