Linux Audio

Check our new training course

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