cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mixer_oss.c (41938B)


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