| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  OSS emulation layer for the mixer interface | 
					
						
							| 
									
										
										
										
											2007-10-15 09:50:19 +02:00
										 |  |  |  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz> | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *   the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *   (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *   GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *   along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/time.h>
 | 
					
						
							| 
									
										
										
										
											2005-06-23 00:09:02 -07:00
										 |  |  | #include <linux/string.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-15 12:38:28 -04:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <sound/core.h>
 | 
					
						
							|  |  |  | #include <sound/minors.h>
 | 
					
						
							|  |  |  | #include <sound/control.h>
 | 
					
						
							|  |  |  | #include <sound/info.h>
 | 
					
						
							|  |  |  | #include <sound/mixer_oss.h>
 | 
					
						
							|  |  |  | #include <linux/soundcard.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-15 09:50:19 +02:00
										 |  |  | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); | 
					
						
							|  |  |  | MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_mixer_oss_open(struct inode *inode, struct file *file) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_file *fmixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-13 11:49:04 +02:00
										 |  |  | 	err = nonseekable_open(inode, file); | 
					
						
							|  |  |  | 	if (err < 0) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-20 14:06:59 +01:00
										 |  |  | 	card = snd_lookup_oss_minor_data(iminor(inode), | 
					
						
							|  |  |  | 					 SNDRV_OSS_DEVICE_TYPE_MIXER); | 
					
						
							|  |  |  | 	if (card == NULL) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -ENODEV; | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 	if (card->mixer_oss == NULL) { | 
					
						
							|  |  |  | 		snd_card_unref(card); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -ENODEV; | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	err = snd_card_file_add(card, file); | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 	if (err < 0) { | 
					
						
							|  |  |  | 		snd_card_unref(card); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return err; | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (fmixer == NULL) { | 
					
						
							|  |  |  | 		snd_card_file_remove(card, file); | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 		snd_card_unref(card); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmixer->card = card; | 
					
						
							|  |  |  | 	fmixer->mixer = card->mixer_oss; | 
					
						
							|  |  |  | 	file->private_data = fmixer; | 
					
						
							|  |  |  | 	if (!try_module_get(card->module)) { | 
					
						
							|  |  |  | 		kfree(fmixer); | 
					
						
							|  |  |  | 		snd_card_file_remove(card, file); | 
					
						
							| 
									
										
										
										
											2012-10-16 13:05:59 +02:00
										 |  |  | 		snd_card_unref(card); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-11-08 14:36:18 +01:00
										 |  |  | 	snd_card_unref(card); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_mixer_oss_release(struct inode *inode, struct file *file) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss_file *fmixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (file->private_data) { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 		fmixer = file->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		module_put(fmixer->card->module); | 
					
						
							|  |  |  | 		snd_card_file_remove(fmixer->card, file); | 
					
						
							|  |  |  | 		kfree(fmixer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			      mixer_info __user *_info) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							|  |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	struct mixer_info info; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	memset(&info, 0, sizeof(info)); | 
					
						
							|  |  |  | 	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); | 
					
						
							|  |  |  | 	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); | 
					
						
							|  |  |  | 	info.modify_counter = card->mixer_oss_change_count; | 
					
						
							|  |  |  | 	if (copy_to_user(_info, &info, sizeof(info))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				       _old_mixer_info __user *_info) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							|  |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	_old_mixer_info info; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	memset(&info, 0, sizeof(info)); | 
					
						
							|  |  |  | 	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id)); | 
					
						
							|  |  |  | 	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name)); | 
					
						
							|  |  |  | 	if (copy_to_user(_info, &info, sizeof(info))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	if (mixer->get_recsrc && mixer->put_recsrc) | 
					
						
							|  |  |  | 		result |= SOUND_CAP_EXCL_INPUT; | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0, chn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 		pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 		if (pslot->put_volume || pslot->put_recsrc) | 
					
						
							|  |  |  | 			result |= 1 << chn; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0, chn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 		pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 		if (pslot->put_volume && pslot->stereo) | 
					
						
							|  |  |  | 			result |= 1 << chn; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */ | 
					
						
							|  |  |  | 		result = mixer->mask_recsrc; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 		struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		int chn; | 
					
						
							|  |  |  | 		for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 			pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 			if (pslot->put_recsrc) | 
					
						
							|  |  |  | 				result |= 1 << chn; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */ | 
					
						
							|  |  |  | 		int err; | 
					
						
							| 
									
										
										
										
											2011-02-14 11:00:47 +01:00
										 |  |  | 		unsigned int index; | 
					
						
							|  |  |  | 		if ((err = mixer->get_recsrc(fmixer, &index)) < 0) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			return err; | 
					
						
							| 
									
										
										
										
											2011-02-14 11:00:47 +01:00
										 |  |  | 		result = 1 << index; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 		struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		int chn; | 
					
						
							|  |  |  | 		for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 			pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 			if (pslot->get_recsrc) { | 
					
						
							|  |  |  | 				int active = 0; | 
					
						
							|  |  |  | 				pslot->get_recsrc(fmixer, pslot, &active); | 
					
						
							|  |  |  | 				if (active) | 
					
						
							|  |  |  | 					result |= 1 << chn; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return mixer->oss_recsrc = result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int chn, active; | 
					
						
							| 
									
										
										
										
											2011-02-14 11:00:47 +01:00
										 |  |  | 	unsigned int index; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	if (mixer->get_recsrc && mixer->put_recsrc) {	/* exclusive input */ | 
					
						
							|  |  |  | 		if (recsrc & ~mixer->oss_recsrc) | 
					
						
							|  |  |  | 			recsrc &= ~mixer->oss_recsrc; | 
					
						
							|  |  |  | 		mixer->put_recsrc(fmixer, ffz(~recsrc)); | 
					
						
							| 
									
										
										
										
											2011-02-14 11:00:47 +01:00
										 |  |  | 		mixer->get_recsrc(fmixer, &index); | 
					
						
							|  |  |  | 		result = 1 << index; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 		pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 		if (pslot->put_recsrc) { | 
					
						
							|  |  |  | 			active = (recsrc & (1 << chn)) ? 1 : 0; | 
					
						
							|  |  |  | 			pslot->put_recsrc(fmixer, pslot, active); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (! result) { | 
					
						
							|  |  |  | 		for (chn = 0; chn < 31; chn++) { | 
					
						
							|  |  |  | 			pslot = &mixer->slots[chn]; | 
					
						
							|  |  |  | 			if (pslot->get_recsrc) { | 
					
						
							|  |  |  | 				active = 0; | 
					
						
							|  |  |  | 				pslot->get_recsrc(fmixer, pslot, &active); | 
					
						
							|  |  |  | 				if (active) | 
					
						
							|  |  |  | 					result |= 1 << chn; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0, left, right; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL || slot > 30) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	pslot = &mixer->slots[slot]; | 
					
						
							|  |  |  | 	left = pslot->volume[0]; | 
					
						
							|  |  |  | 	right = pslot->volume[1]; | 
					
						
							|  |  |  | 	if (pslot->get_volume) | 
					
						
							|  |  |  | 		result = pslot->get_volume(fmixer, pslot, &left, &right); | 
					
						
							|  |  |  | 	if (!pslot->stereo) | 
					
						
							|  |  |  | 		right = left; | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(left < 0 || left > 100)) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	if (snd_BUG_ON(right < 0 || right > 100)) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (result >= 0) { | 
					
						
							|  |  |  | 		pslot->volume[0] = left; | 
					
						
							|  |  |  | 		pslot->volume[1] = right; | 
					
						
							|  |  |  | 	 	result = (left & 0xff) | ((right & 0xff) << 8); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				    int slot, int volume) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mixer == NULL || slot > 30) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	pslot = &mixer->slots[slot]; | 
					
						
							|  |  |  | 	if (left > 100) | 
					
						
							|  |  |  | 		left = 100; | 
					
						
							|  |  |  | 	if (right > 100) | 
					
						
							|  |  |  | 		right = 100; | 
					
						
							|  |  |  | 	if (!pslot->stereo) | 
					
						
							|  |  |  | 		right = left; | 
					
						
							|  |  |  | 	if (pslot->put_volume) | 
					
						
							|  |  |  | 		result = pslot->put_volume(fmixer, pslot, left, right); | 
					
						
							|  |  |  | 	if (result < 0) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	pslot->volume[0] = left; | 
					
						
							|  |  |  | 	pslot->volume[1] = right; | 
					
						
							|  |  |  |  	return (left & 0xff) | ((right & 0xff) << 8); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	void __user *argp = (void __user *)arg; | 
					
						
							|  |  |  | 	int __user *p = argp; | 
					
						
							|  |  |  | 	int tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!fmixer)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (((cmd >> 8) & 0xff) == 'M') { | 
					
						
							|  |  |  | 		switch (cmd) { | 
					
						
							|  |  |  | 		case SOUND_MIXER_INFO: | 
					
						
							|  |  |  | 			return snd_mixer_oss_info(fmixer, argp); | 
					
						
							|  |  |  | 		case SOUND_OLD_MIXER_INFO: | 
					
						
							|  |  |  |  			return snd_mixer_oss_info_obsolete(fmixer, argp); | 
					
						
							|  |  |  | 		case SOUND_MIXER_WRITE_RECSRC: | 
					
						
							|  |  |  | 			if (get_user(tmp, p)) | 
					
						
							|  |  |  | 				return -EFAULT; | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_set_recsrc(fmixer, tmp); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		case OSS_GETVERSION: | 
					
						
							|  |  |  | 			return put_user(SNDRV_OSS_VERSION, p); | 
					
						
							|  |  |  | 		case OSS_ALSAEMULVER: | 
					
						
							|  |  |  | 			return put_user(1, p); | 
					
						
							|  |  |  | 		case SOUND_MIXER_READ_DEVMASK: | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_devmask(fmixer); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		case SOUND_MIXER_READ_STEREODEVS: | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_stereodevs(fmixer); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		case SOUND_MIXER_READ_RECMASK: | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_recmask(fmixer); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		case SOUND_MIXER_READ_CAPS: | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_caps(fmixer); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		case SOUND_MIXER_READ_RECSRC: | 
					
						
							|  |  |  | 			tmp = snd_mixer_oss_get_recsrc(fmixer); | 
					
						
							|  |  |  | 			if (tmp < 0) | 
					
						
							|  |  |  | 				return tmp; | 
					
						
							|  |  |  | 			return put_user(tmp, p); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (cmd & SIOC_IN) { | 
					
						
							|  |  |  | 		if (get_user(tmp, p)) | 
					
						
							|  |  |  | 			return -EFAULT; | 
					
						
							|  |  |  | 		tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp); | 
					
						
							|  |  |  | 		if (tmp < 0) | 
					
						
							|  |  |  | 			return tmp; | 
					
						
							|  |  |  | 		return put_user(tmp, p); | 
					
						
							|  |  |  | 	} else if (cmd & SIOC_OUT) { | 
					
						
							|  |  |  | 		tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff); | 
					
						
							|  |  |  | 		if (tmp < 0) | 
					
						
							|  |  |  | 			return tmp; | 
					
						
							|  |  |  | 		return put_user(tmp, p); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return -ENXIO; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss_file fmixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(!card)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (card->mixer_oss == NULL) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	memset(&fmixer, 0, sizeof(fmixer)); | 
					
						
							|  |  |  | 	fmixer.card = card; | 
					
						
							|  |  |  | 	fmixer.mixer = card->mixer_oss; | 
					
						
							|  |  |  | 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_COMPAT
 | 
					
						
							|  |  |  | /* all compatible */ | 
					
						
							|  |  |  | #define snd_mixer_oss_ioctl_compat	snd_mixer_oss_ioctl
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define snd_mixer_oss_ioctl_compat	NULL
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *  REGISTRATION PART | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-12 00:55:37 -08:00
										 |  |  | static const struct file_operations snd_mixer_oss_f_ops = | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	.owner =	THIS_MODULE, | 
					
						
							|  |  |  | 	.open =		snd_mixer_oss_open, | 
					
						
							|  |  |  | 	.release =	snd_mixer_oss_release, | 
					
						
							| 
									
										
										
										
											2010-04-13 11:49:04 +02:00
										 |  |  | 	.llseek =	no_llseek, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	.unlocked_ioctl =	snd_mixer_oss_ioctl, | 
					
						
							|  |  |  | 	.compat_ioctl =	snd_mixer_oss_ioctl_compat, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *  utilities | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	long orange = omax - omin, nrange = nmax - nmin; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (orange == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* convert from alsa native to oss values (0-100) */ | 
					
						
							|  |  |  | static long snd_mixer_oss_conv1(long val, long min, long max, int *old) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (val == snd_mixer_oss_conv(*old, 0, 100, min, max)) | 
					
						
							|  |  |  | 		return *old; | 
					
						
							|  |  |  | 	return snd_mixer_oss_conv(val, min, max, 0, 100); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* convert from oss to alsa native values */ | 
					
						
							|  |  |  | static long snd_mixer_oss_conv2(long val, long min, long max) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return snd_mixer_oss_conv(val, 0, 100, min, max); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = card->mixer_oss; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (mixer) | 
					
						
							|  |  |  | 		mixer->mask_recsrc |= 1 << slot; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = card->mixer_oss; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (mixer && (mixer->mask_recsrc & (1 << slot))) | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_SIGNATURE		0x65999250
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_GLOBAL	0
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_GSWITCH	1
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_GROUTE	2
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_GVOLUME	3
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_PSWITCH	4
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_PROUTE	5
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_PVOLUME	6
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_CSWITCH	7
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_CROUTE	8
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_CVOLUME	9
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_CAPTURE	10
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_ITEM_COUNT	11
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_GLOBAL	(1<<0)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_GSWITCH	(1<<1)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_GROUTE	(1<<2)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_GVOLUME	(1<<3)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_PSWITCH	(1<<4)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_PROUTE	(1<<5)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_PVOLUME	(1<<6)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_CSWITCH	(1<<7)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_CROUTE	(1<<8)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_CVOLUME	(1<<9)
 | 
					
						
							|  |  |  | #define SNDRV_MIXER_OSS_PRESENT_CAPTURE	(1<<10)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct slot { | 
					
						
							|  |  |  | 	unsigned int signature; | 
					
						
							|  |  |  | 	unsigned int present; | 
					
						
							|  |  |  | 	unsigned int channels; | 
					
						
							|  |  |  | 	unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; | 
					
						
							|  |  |  | 	unsigned int capture_item; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_assign_table *assigned; | 
					
						
							|  |  |  | 	unsigned int allocated: 1; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ID_UNKNOWN	((unsigned int)-1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card = mixer->card; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_id id; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	memset(&id, 0, sizeof(id)); | 
					
						
							|  |  |  | 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 
					
						
							| 
									
										
										
										
											2011-10-04 09:29:39 +03:00
										 |  |  | 	strlcpy(id.name, name, sizeof(id.name)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	id.index = index; | 
					
						
							|  |  |  | 	return snd_ctl_find_id(card, &id); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					  struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					  unsigned int numid, | 
					
						
							|  |  |  | 					  int *left, int *right) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (numid == ID_UNKNOWN) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (kctl->info(kctl, uinfo)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							|  |  |  | 	if (kctl->get(kctl, uctl)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							|  |  |  | 	if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && | 
					
						
							|  |  |  | 	    uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); | 
					
						
							|  |  |  | 	if (uinfo->count > 1) | 
					
						
							|  |  |  | 		*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); | 
					
						
							|  |  |  |       __unalloc: | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							|  |  |  |       	kfree(uctl); | 
					
						
							|  |  |  |       	kfree(uinfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					 struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					 unsigned int numid, | 
					
						
							|  |  |  | 					 int *left, int *right, | 
					
						
							|  |  |  | 					 int route) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (numid == ID_UNKNOWN) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (kctl->info(kctl, uinfo)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							|  |  |  | 	if (kctl->get(kctl, uctl)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (!uctl->value.integer.value[0]) { | 
					
						
							|  |  |  | 		*left = 0; | 
					
						
							|  |  |  | 		if (uinfo->count == 1) | 
					
						
							|  |  |  | 			*right = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) | 
					
						
							|  |  |  | 		*right = 0; | 
					
						
							|  |  |  |       __unalloc: | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							|  |  |  |       	kfree(uctl); | 
					
						
							|  |  |  | 	kfree(uinfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 				     struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				     int *left, int *right) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	*left = *right = 100; | 
					
						
							|  |  |  | 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { | 
					
						
							|  |  |  | 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					  struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					  unsigned int numid, | 
					
						
							|  |  |  | 					  int left, int right) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (numid == ID_UNKNOWN) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  | 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (kctl->info(kctl, uinfo)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							|  |  |  | 	if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && | 
					
						
							|  |  |  | 	    uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); | 
					
						
							|  |  |  | 	if (uinfo->count > 1) | 
					
						
							|  |  |  | 		uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if ((res = kctl->put(kctl, uctl)) < 0) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (res > 0) | 
					
						
							|  |  |  | 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); | 
					
						
							|  |  |  |       __unalloc: | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							|  |  |  |       	kfree(uctl); | 
					
						
							|  |  |  | 	kfree(uinfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					 struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					 unsigned int numid, | 
					
						
							|  |  |  | 					 int left, int right, | 
					
						
							|  |  |  | 					 int route) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (numid == ID_UNKNOWN) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (kctl->info(kctl, uinfo)) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo->count > 1) { | 
					
						
							|  |  |  | 		uctl->value.integer.value[0] = left > 0 ? 1 : 0; | 
					
						
							|  |  |  | 		uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; | 
					
						
							|  |  |  | 		if (route) { | 
					
						
							|  |  |  | 			uctl->value.integer.value[1] = | 
					
						
							|  |  |  | 			uctl->value.integer.value[2] = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if ((res = kctl->put(kctl, uctl)) < 0) | 
					
						
							|  |  |  | 		goto __unalloc; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (res > 0) | 
					
						
							|  |  |  | 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); | 
					
						
							|  |  |  |       __unalloc: | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							|  |  |  |       	kfree(uctl); | 
					
						
							|  |  |  | 	kfree(uinfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 				     struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				     int left, int right) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 
					
						
							|  |  |  | 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); | 
					
						
							|  |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); | 
					
						
							| 
									
										
										
										
											2009-03-10 15:43:18 +01:00
										 |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) { | 
					
						
							|  |  |  | 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, | 
					
						
							|  |  |  | 			slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { | 
					
						
							|  |  |  | 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); | 
					
						
							|  |  |  | 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { | 
					
						
							|  |  |  | 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (left || right) { | 
					
						
							|  |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); | 
					
						
							| 
									
										
										
										
											2009-04-04 18:08:28 +05:30
										 |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); | 
					
						
							|  |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); | 
					
						
							| 
									
										
										
										
											2009-04-04 18:08:28 +05:30
										 |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); | 
					
						
							| 
									
										
										
										
											2009-04-04 18:08:28 +05:30
										 |  |  | 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); | 
					
						
							|  |  |  | 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); | 
					
						
							| 
									
										
										
										
											2009-04-04 18:08:28 +05:30
										 |  |  | 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { | 
					
						
							|  |  |  | 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					int *active) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int left, right; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	left = right = 1; | 
					
						
							|  |  |  | 	snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); | 
					
						
							|  |  |  | 	*active = (left || right) ? 1 : 0; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					   struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					   int *active) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int left, right; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	left = right = 1; | 
					
						
							|  |  |  | 	snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); | 
					
						
							|  |  |  | 	*active = (left || right) ? 1 : 0; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					int active) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, | 
					
						
							|  |  |  | 					   struct snd_mixer_oss_slot *pslot, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					   int active) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							|  |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	struct slot *slot; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int err, idx; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) { | 
					
						
							|  |  |  | 		err = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  | 		goto __free_only; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (! kctl) { | 
					
						
							|  |  |  | 		err = -ENOENT; | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ((err = kctl->info(kctl, uinfo)) < 0) | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							|  |  |  | 	if ((err = kctl->get(kctl, uctl)) < 0) | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (idx = 0; idx < 32; idx++) { | 
					
						
							|  |  |  | 		if (!(mixer->mask_recsrc & (1 << idx))) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		pslot = &mixer->slots[idx]; | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 		slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (slot->capture_item == uctl->value.enumerated.item[0]) { | 
					
						
							|  |  |  | 			*active_index = idx; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = 0; | 
					
						
							|  |  |  |       __unlock: | 
					
						
							|  |  |  |      	up_read(&card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  |       __free_only: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |       	kfree(uctl); | 
					
						
							|  |  |  |       	kfree(uinfo); | 
					
						
							|  |  |  |       	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_card *card = fmixer->card; | 
					
						
							|  |  |  | 	struct snd_mixer_oss *mixer = fmixer->mixer; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	struct slot *slot = NULL; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *uinfo; | 
					
						
							|  |  |  | 	struct snd_ctl_elem_value *uctl; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int err; | 
					
						
							|  |  |  | 	unsigned int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-09 14:20:23 +02:00
										 |  |  | 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							|  |  |  | 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (uinfo == NULL || uctl == NULL) { | 
					
						
							|  |  |  | 		err = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  | 		goto __free_only; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (! kctl) { | 
					
						
							|  |  |  | 		err = -ENOENT; | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ((err = kctl->info(kctl, uinfo)) < 0) | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (idx = 0; idx < 32; idx++) { | 
					
						
							|  |  |  | 		if (!(mixer->mask_recsrc & (1 << idx))) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		pslot = &mixer->slots[idx]; | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 		slot = pslot->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (idx == active_index) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		slot = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	if (! slot) | 
					
						
							|  |  |  | 		goto __unlock; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (idx = 0; idx < uinfo->count; idx++) | 
					
						
							|  |  |  | 		uctl->value.enumerated.item[idx] = slot->capture_item; | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 	err = kctl->put(kctl, uctl); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (err > 0) | 
					
						
							|  |  |  | 		snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); | 
					
						
							|  |  |  | 	err = 0; | 
					
						
							|  |  |  |       __unlock: | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2010-10-08 10:48:50 +02:00
										 |  |  |       __free_only: | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	kfree(uctl); | 
					
						
							|  |  |  | 	kfree(uinfo); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct snd_mixer_oss_assign_table { | 
					
						
							|  |  |  | 	int oss_id; | 
					
						
							|  |  |  | 	const char *name; | 
					
						
							|  |  |  | 	int index; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_ctl_elem_info *info; | 
					
						
							|  |  |  | 	struct snd_kcontrol *kcontrol; | 
					
						
							|  |  |  | 	struct snd_card *card = mixer->card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	down_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	kcontrol = snd_mixer_oss_test_id(mixer, name, index); | 
					
						
							|  |  |  | 	if (kcontrol == NULL) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	info = kmalloc(sizeof(*info), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (! info) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ((err = kcontrol->info(kcontrol, info)) < 0) { | 
					
						
							|  |  |  | 		up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 		kfree(info); | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	slot->numid[item] = kcontrol->id.numid; | 
					
						
							|  |  |  | 	up_read(&card->controls_rwsem); | 
					
						
							|  |  |  | 	if (info->count > slot->channels) | 
					
						
							|  |  |  | 		slot->channels = info->count; | 
					
						
							|  |  |  | 	slot->present |= 1 << item; | 
					
						
							|  |  |  | 	kfree(info); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-04 18:52:54 -07:00
										 |  |  | 	struct slot *p = chn->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (p) { | 
					
						
							|  |  |  | 		if (p->allocated && p->assigned) { | 
					
						
							|  |  |  | 			kfree(p->assigned->name); | 
					
						
							|  |  |  | 			kfree(p->assigned); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		kfree(p); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int idx = rslot->number; /* remember this */ | 
					
						
							|  |  |  | 	if (rslot->private_free) | 
					
						
							|  |  |  | 		rslot->private_free(rslot); | 
					
						
							|  |  |  | 	memset(rslot, 0, sizeof(*rslot)); | 
					
						
							|  |  |  | 	rslot->number = idx; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-08 15:33:10 -08:00
										 |  |  | /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
 | 
					
						
							|  |  |  |    snd_mixer_oss_build_input! */ | 
					
						
							|  |  |  | static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer, | 
					
						
							|  |  |  | 					struct snd_mixer_oss_assign_table *ptr, | 
					
						
							|  |  |  | 					struct slot *slot) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char str[64]; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_GLOBAL); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Switch", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_GSWITCH); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Route", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_GROUTE); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Volume", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_GVOLUME); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Playback Switch", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_PSWITCH); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Playback Route", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_PROUTE); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Playback Volume", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_PVOLUME); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Capture Switch", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_CSWITCH); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Capture Route", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_CROUTE); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	sprintf(str, "%s Capture Volume", ptr->name); | 
					
						
							|  |  |  | 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index, | 
					
						
							|  |  |  | 				       SNDRV_MIXER_OSS_ITEM_CVOLUME); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * build an OSS mixer element. | 
					
						
							|  |  |  |  * ptr_allocated means the entry is dynamically allocated (change via proc file). | 
					
						
							|  |  |  |  * when replace_old = 1, the old entry is replaced with the new one. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct slot slot; | 
					
						
							|  |  |  | 	struct slot *pslot; | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_kcontrol *kctl; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_slot *rslot; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	char str[64];	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* check if already assigned */ | 
					
						
							|  |  |  | 	if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&slot, 0, sizeof(slot)); | 
					
						
							|  |  |  | 	memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ | 
					
						
							| 
									
										
										
										
											2008-01-08 15:33:10 -08:00
										 |  |  | 	if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	down_read(&mixer->card->controls_rwsem); | 
					
						
							|  |  |  | 	if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 		struct snd_ctl_elem_info *uinfo; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-25 15:28:03 +02:00
										 |  |  | 		uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (! uinfo) { | 
					
						
							|  |  |  | 			up_read(&mixer->card->controls_rwsem); | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		if (kctl->info(kctl, uinfo)) { | 
					
						
							|  |  |  | 			up_read(&mixer->card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2012-09-02 22:10:27 +08:00
										 |  |  | 			kfree(uinfo); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		strcpy(str, ptr->name); | 
					
						
							|  |  |  | 		if (!strcmp(str, "Master")) | 
					
						
							|  |  |  | 			strcpy(str, "Mix"); | 
					
						
							|  |  |  | 		if (!strcmp(str, "Master Mono")) | 
					
						
							|  |  |  | 			strcpy(str, "Mix Mono"); | 
					
						
							|  |  |  | 		slot.capture_item = 0; | 
					
						
							|  |  |  | 		if (!strcmp(uinfo->value.enumerated.name, str)) { | 
					
						
							|  |  |  | 			slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { | 
					
						
							|  |  |  | 				uinfo->value.enumerated.item = slot.capture_item; | 
					
						
							|  |  |  | 				if (kctl->info(kctl, uinfo)) { | 
					
						
							|  |  |  | 					up_read(&mixer->card->controls_rwsem); | 
					
						
							| 
									
										
										
										
											2012-09-02 22:10:27 +08:00
										 |  |  | 					kfree(uinfo); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					return 0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!strcmp(uinfo->value.enumerated.name, str)) { | 
					
						
							|  |  |  | 					slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		kfree(uinfo); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	up_read(&mixer->card->controls_rwsem); | 
					
						
							|  |  |  | 	if (slot.present != 0) { | 
					
						
							| 
									
										
										
										
											2006-12-13 00:35:56 -08:00
										 |  |  | 		pslot = kmalloc(sizeof(slot), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-10-10 11:46:31 +02:00
										 |  |  | 		if (! pslot) | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		*pslot = slot; | 
					
						
							|  |  |  | 		pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; | 
					
						
							|  |  |  | 		pslot->assigned = ptr; | 
					
						
							|  |  |  | 		pslot->allocated = ptr_allocated; | 
					
						
							|  |  |  | 		rslot = &mixer->slots[ptr->oss_id]; | 
					
						
							|  |  |  | 		mixer_slot_clear(rslot); | 
					
						
							|  |  |  | 		rslot->stereo = slot.channels > 1 ? 1 : 0; | 
					
						
							|  |  |  | 		rslot->get_volume = snd_mixer_oss_get_volume1; | 
					
						
							|  |  |  | 		rslot->put_volume = snd_mixer_oss_put_volume1; | 
					
						
							|  |  |  | 		/* note: ES18xx have both Capture Source and XX Capture Volume !!! */ | 
					
						
							|  |  |  | 		if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { | 
					
						
							|  |  |  | 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; | 
					
						
							|  |  |  | 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; | 
					
						
							|  |  |  | 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { | 
					
						
							|  |  |  | 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; | 
					
						
							|  |  |  | 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; | 
					
						
							|  |  |  | 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { | 
					
						
							|  |  |  | 			mixer->mask_recsrc |= 1 << ptr->oss_id; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rslot->private_data = pslot; | 
					
						
							|  |  |  | 		rslot->private_free = snd_mixer_oss_slot_free; | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-27 19:45:45 +08:00
										 |  |  | #ifdef CONFIG_SND_PROC_FS
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
 | 
					
						
							|  |  |  | static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { | 
					
						
							|  |  |  | 	MIXER_VOL(VOLUME), | 
					
						
							|  |  |  | 	MIXER_VOL(BASS), | 
					
						
							|  |  |  | 	MIXER_VOL(TREBLE), | 
					
						
							|  |  |  | 	MIXER_VOL(SYNTH), | 
					
						
							|  |  |  | 	MIXER_VOL(PCM), | 
					
						
							|  |  |  | 	MIXER_VOL(SPEAKER), | 
					
						
							|  |  |  | 	MIXER_VOL(LINE), | 
					
						
							|  |  |  | 	MIXER_VOL(MIC), | 
					
						
							|  |  |  | 	MIXER_VOL(CD), | 
					
						
							|  |  |  | 	MIXER_VOL(IMIX), | 
					
						
							|  |  |  | 	MIXER_VOL(ALTPCM), | 
					
						
							|  |  |  | 	MIXER_VOL(RECLEV), | 
					
						
							|  |  |  | 	MIXER_VOL(IGAIN), | 
					
						
							|  |  |  | 	MIXER_VOL(OGAIN), | 
					
						
							|  |  |  | 	MIXER_VOL(LINE1), | 
					
						
							|  |  |  | 	MIXER_VOL(LINE2), | 
					
						
							|  |  |  | 	MIXER_VOL(LINE3), | 
					
						
							|  |  |  | 	MIXER_VOL(DIGITAL1), | 
					
						
							|  |  |  | 	MIXER_VOL(DIGITAL2), | 
					
						
							|  |  |  | 	MIXER_VOL(DIGITAL3), | 
					
						
							|  |  |  | 	MIXER_VOL(PHONEIN), | 
					
						
							|  |  |  | 	MIXER_VOL(PHONEOUT), | 
					
						
							|  |  |  | 	MIXER_VOL(VIDEO), | 
					
						
							|  |  |  | 	MIXER_VOL(RADIO), | 
					
						
							|  |  |  | 	MIXER_VOL(MONITOR), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *  /proc interface | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_proc_read(struct snd_info_entry *entry, | 
					
						
							|  |  |  | 				    struct snd_info_buffer *buffer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = entry->private_data; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 	mutex_lock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { | 
					
						
							|  |  |  | 		struct slot *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (! oss_mixer_names[i]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		p = (struct slot *)mixer->slots[i].private_data; | 
					
						
							|  |  |  | 		snd_iprintf(buffer, "%s ", oss_mixer_names[i]); | 
					
						
							|  |  |  | 		if (p && p->assigned) | 
					
						
							|  |  |  | 			snd_iprintf(buffer, "\"%s\" %d\n", | 
					
						
							|  |  |  | 				    p->assigned->name, | 
					
						
							|  |  |  | 				    p->assigned->index); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			snd_iprintf(buffer, "\"\" 0\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 	mutex_unlock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, | 
					
						
							|  |  |  | 				     struct snd_info_buffer *buffer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = entry->private_data; | 
					
						
							| 
									
										
										
										
											2009-09-08 14:29:58 +02:00
										 |  |  | 	char line[128], str[32], idxstr[16]; | 
					
						
							|  |  |  | 	const char *cptr; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int ch, idx; | 
					
						
							|  |  |  | 	struct snd_mixer_oss_assign_table *tbl; | 
					
						
							|  |  |  | 	struct slot *slot; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (!snd_info_get_line(buffer, line, sizeof(line))) { | 
					
						
							|  |  |  | 		cptr = snd_info_get_str(str, line, sizeof(str)); | 
					
						
							|  |  |  | 		for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) | 
					
						
							|  |  |  | 			if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		if (ch >= SNDRV_OSS_MAX_MIXERS) { | 
					
						
							| 
									
										
										
										
											2014-02-04 18:22:11 +01:00
										 |  |  | 			pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n", | 
					
						
							|  |  |  | 			       str); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cptr = snd_info_get_str(str, cptr, sizeof(str)); | 
					
						
							|  |  |  | 		if (! *str) { | 
					
						
							|  |  |  | 			/* remove the entry */ | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 			mutex_lock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			mixer_slot_clear(&mixer->slots[ch]); | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 			mutex_unlock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		snd_info_get_str(idxstr, cptr, sizeof(idxstr)); | 
					
						
							|  |  |  | 		idx = simple_strtoul(idxstr, NULL, 10); | 
					
						
							|  |  |  | 		if (idx >= 0x4000) { /* too big */ | 
					
						
							| 
									
										
										
										
											2014-02-04 18:22:11 +01:00
										 |  |  | 			pr_err("ALSA: mixer_oss: invalid index %d\n", idx); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 		mutex_lock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		slot = (struct slot *)mixer->slots[ch].private_data; | 
					
						
							|  |  |  | 		if (slot && slot->assigned && | 
					
						
							|  |  |  | 		    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) | 
					
						
							|  |  |  | 			/* not changed */ | 
					
						
							|  |  |  | 			goto __unlock; | 
					
						
							|  |  |  | 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2015-03-10 15:42:14 +01:00
										 |  |  | 		if (!tbl) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			goto __unlock; | 
					
						
							|  |  |  | 		tbl->oss_id = ch; | 
					
						
							| 
									
										
										
										
											2005-06-23 00:09:02 -07:00
										 |  |  | 		tbl->name = kstrdup(str, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (! tbl->name) { | 
					
						
							|  |  |  | 			kfree(tbl); | 
					
						
							|  |  |  | 			goto __unlock; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tbl->index = idx; | 
					
						
							|  |  |  | 		if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { | 
					
						
							|  |  |  | 			kfree(tbl->name); | 
					
						
							|  |  |  | 			kfree(tbl); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	__unlock: | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 		mutex_unlock(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_info_entry *entry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	entry = snd_info_create_card_entry(mixer->card, "oss_mixer", | 
					
						
							|  |  |  | 					   mixer->card->proc_root); | 
					
						
							|  |  |  | 	if (! entry) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	entry->content = SNDRV_INFO_CONTENT_TEXT; | 
					
						
							|  |  |  | 	entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 
					
						
							|  |  |  | 	entry->c.text.read = snd_mixer_oss_proc_read; | 
					
						
							|  |  |  | 	entry->c.text.write = snd_mixer_oss_proc_write; | 
					
						
							|  |  |  | 	entry->private_data = mixer; | 
					
						
							|  |  |  | 	if (snd_info_register(entry) < 0) { | 
					
						
							|  |  |  | 		snd_info_free_entry(entry); | 
					
						
							|  |  |  | 		entry = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mixer->proc_entry = entry; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-23 14:37:59 +02:00
										 |  |  | 	snd_info_free_entry(mixer->proc_entry); | 
					
						
							|  |  |  | 	mixer->proc_entry = NULL; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-27 19:45:45 +08:00
										 |  |  | #else /* !CONFIG_SND_PROC_FS */
 | 
					
						
							| 
									
										
										
										
											2005-12-01 10:43:51 +01:00
										 |  |  | #define snd_mixer_oss_proc_init(mix)
 | 
					
						
							|  |  |  | #define snd_mixer_oss_proc_done(mix)
 | 
					
						
							| 
									
										
										
										
											2015-05-27 19:45:45 +08:00
										 |  |  | #endif /* CONFIG_SND_PROC_FS */
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	static struct snd_mixer_oss_assign_table table[] = { | 
					
						
							|  |  |  | 		{ SOUND_MIXER_VOLUME, 	"Master",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_VOLUME, 	"Front",		0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_BASS,	"Tone Control - Bass",	0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_TREBLE,	"Tone Control - Treble", 0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_SYNTH,	"Synth",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_SYNTH,	"FM",			0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_SYNTH,	"Music",		0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_PCM,	"PCM",			0 }, | 
					
						
							| 
									
										
										
										
											2009-11-03 15:47:25 +01:00
										 |  |  | 		{ SOUND_MIXER_SPEAKER,	"Beep", 		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_SPEAKER,	"PC Speaker", 		0 }, /* fallback */ | 
					
						
							| 
									
										
										
										
											2009-11-04 14:30:36 +01:00
										 |  |  | 		{ SOUND_MIXER_SPEAKER,	"Speaker", 		0 }, /* fallback */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		{ SOUND_MIXER_LINE,	"Line", 		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_MIC,	"Mic", 			0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_CD,	"CD", 			0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_IMIX,	"Monitor Mix", 		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_ALTPCM,	"PCM",			1 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_ALTPCM,	"Headphone",		0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_ALTPCM,	"Wave",			0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_RECLEV,	"-- nothing --",	0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_IGAIN,	"Capture",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_OGAIN,	"Playback",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_LINE1,	"Aux",			0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_LINE2,	"Aux",			1 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_LINE3,	"Aux",			2 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL1,	"Digital",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL1,	"IEC958",		0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Optical",	0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Coaxial",	0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL2,	"Digital",		1 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_DIGITAL3,	"Digital",		2 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_PHONEIN,	"Phone",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_PHONEOUT,	"Master Mono",		0 }, | 
					
						
							| 
									
										
										
										
											2008-02-04 12:44:11 +01:00
										 |  |  | 		{ SOUND_MIXER_PHONEOUT,	"Speaker",		0 }, /*fallback*/ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_PHONEOUT,	"Mono",			0 }, /*fallback*/ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		{ SOUND_MIXER_PHONEOUT,	"Phone",		0 }, /* fallback */ | 
					
						
							|  |  |  | 		{ SOUND_MIXER_VIDEO,	"Video",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_RADIO,	"Radio",		0 }, | 
					
						
							|  |  |  | 		{ SOUND_MIXER_MONITOR,	"Monitor",		0 } | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	unsigned int idx; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	for (idx = 0; idx < ARRAY_SIZE(table); idx++) | 
					
						
							|  |  |  | 		snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); | 
					
						
							|  |  |  | 	if (mixer->mask_recsrc) { | 
					
						
							|  |  |  | 		mixer->get_recsrc = snd_mixer_oss_get_recsrc2; | 
					
						
							|  |  |  | 		mixer->put_recsrc = snd_mixer_oss_put_recsrc2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int snd_mixer_oss_free1(void *private) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer = private; | 
					
						
							|  |  |  | 	struct snd_card *card; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int idx; | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (!mixer) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	card = mixer->card; | 
					
						
							| 
									
										
										
										
											2008-08-08 17:09:09 +02:00
										 |  |  | 	if (snd_BUG_ON(mixer != card->mixer_oss)) | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	card->mixer_oss = NULL; | 
					
						
							|  |  |  | 	for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 		struct snd_mixer_oss_slot *chn = &mixer->slots[idx]; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (chn->private_free) | 
					
						
							|  |  |  | 			chn->private_free(chn); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	kfree(mixer); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-17 14:01:22 +01:00
										 |  |  | 	struct snd_mixer_oss *mixer; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { | 
					
						
							|  |  |  | 		int idx, err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); | 
					
						
							|  |  |  | 		if (mixer == NULL) | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2006-01-16 16:29:08 +01:00
										 |  |  | 		mutex_init(&mixer->reg_mutex); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, | 
					
						
							|  |  |  | 						   card, 0, | 
					
						
							| 
									
										
										
										
											2014-02-04 13:51:45 +01:00
										 |  |  | 						   &snd_mixer_oss_f_ops, card)) < 0) { | 
					
						
							| 
									
										
										
										
											2014-02-04 18:22:11 +01:00
										 |  |  | 			dev_err(card->dev, | 
					
						
							|  |  |  | 				"unable to register OSS mixer device %i:%i\n", | 
					
						
							|  |  |  | 				card->number, 0); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			kfree(mixer); | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		mixer->oss_dev_alloc = 1; | 
					
						
							|  |  |  | 		mixer->card = card; | 
					
						
							|  |  |  | 		if (*card->mixername) | 
					
						
							|  |  |  | 			strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); | 
					
						
							|  |  |  | 		else | 
					
						
							| 
									
										
										
										
											2014-02-04 13:51:45 +01:00
										 |  |  | 			snprintf(mixer->name, sizeof(mixer->name), | 
					
						
							|  |  |  | 				 "mixer%i", card->number); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #ifdef SNDRV_OSS_INFO_DEV_MIXERS
 | 
					
						
							|  |  |  | 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, | 
					
						
							|  |  |  | 				      card->number, | 
					
						
							|  |  |  | 				      mixer->name); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) | 
					
						
							|  |  |  | 			mixer->slots[idx].number = idx; | 
					
						
							|  |  |  | 		card->mixer_oss = mixer; | 
					
						
							|  |  |  | 		snd_mixer_oss_build(mixer); | 
					
						
							|  |  |  | 		snd_mixer_oss_proc_init(mixer); | 
					
						
							| 
									
										
										
										
											2006-06-23 14:38:23 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		mixer = card->mixer_oss; | 
					
						
							|  |  |  | 		if (mixer == NULL) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-06-23 14:38:23 +02:00
										 |  |  | 		if (mixer->oss_dev_alloc) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #ifdef SNDRV_OSS_INFO_DEV_MIXERS
 | 
					
						
							| 
									
										
										
										
											2006-06-23 14:38:23 +02:00
										 |  |  | 			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); | 
					
						
							| 
									
										
										
										
											2006-06-23 14:38:23 +02:00
										 |  |  | 			mixer->oss_dev_alloc = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		snd_mixer_oss_proc_done(mixer); | 
					
						
							|  |  |  | 		return snd_mixer_oss_free1(mixer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init alsa_mixer_oss_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; | 
					
						
							|  |  |  | 	for (idx = 0; idx < SNDRV_CARDS; idx++) { | 
					
						
							|  |  |  | 		if (snd_cards[idx]) | 
					
						
							|  |  |  | 			snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __exit alsa_mixer_oss_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snd_mixer_oss_notify_callback = NULL; | 
					
						
							|  |  |  | 	for (idx = 0; idx < SNDRV_CARDS; idx++) { | 
					
						
							|  |  |  | 		if (snd_cards[idx]) | 
					
						
							|  |  |  | 			snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module_init(alsa_mixer_oss_init) | 
					
						
							|  |  |  | module_exit(alsa_mixer_oss_exit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); |