Linux Audio

Check our new training course

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