Linux Audio

Check our new training course

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