Linux Audio

Check our new training course

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