⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mixer_oss.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  OSS emulation layer for the mixer interface *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * *   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 <sound/driver.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/string.h>#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)MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");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){	int cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));	snd_card_t *card;	snd_mixer_oss_file_t *fmixer;	int err;	if ((card = snd_cards[cardnum]) == NULL)		return -ENODEV;	if (card->mixer_oss == NULL)		return -ENODEV;	err = snd_card_file_add(card, file);	if (err < 0)		return err;	fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);	if (fmixer == NULL) {		snd_card_file_remove(card, file);		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);		return -EFAULT;	}	return 0;}static int snd_mixer_oss_release(struct inode *inode, struct file *file){	snd_mixer_oss_file_t *fmixer;	if (file->private_data) {		fmixer = (snd_mixer_oss_file_t *) file->private_data;		module_put(fmixer->card->module);		snd_card_file_remove(fmixer->card, file);		kfree(fmixer);	}	return 0;}static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer,			      mixer_info __user *_info){	snd_card_t *card = fmixer->card;	snd_mixer_oss_t *mixer = fmixer->mixer;	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;}static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer,				       _old_mixer_info __user *_info){	snd_card_t *card = fmixer->card;	snd_mixer_oss_t *mixer = fmixer->mixer;	_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;}static int snd_mixer_oss_caps(snd_mixer_oss_file_t *fmixer){	snd_mixer_oss_t *mixer = fmixer->mixer;	int result = 0;	if (mixer == NULL)		return -EIO;	if (mixer->get_recsrc && mixer->put_recsrc)		result |= SOUND_CAP_EXCL_INPUT;	return result;}static int snd_mixer_oss_devmask(snd_mixer_oss_file_t *fmixer){	snd_mixer_oss_t *mixer = fmixer->mixer;	snd_mixer_oss_slot_t *pslot;	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;}static int snd_mixer_oss_stereodevs(snd_mixer_oss_file_t *fmixer){	snd_mixer_oss_t *mixer = fmixer->mixer;	snd_mixer_oss_slot_t *pslot;	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;}static int snd_mixer_oss_recmask(snd_mixer_oss_file_t *fmixer){	snd_mixer_oss_t *mixer = fmixer->mixer;	int result = 0;	if (mixer == NULL)		return -EIO;	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */		result = mixer->mask_recsrc;	} else {		snd_mixer_oss_slot_t *pslot;		int chn;		for (chn = 0; chn < 31; chn++) {			pslot = &mixer->slots[chn];			if (pslot->put_recsrc)				result |= 1 << chn;		}	}	return result;}static int snd_mixer_oss_get_recsrc(snd_mixer_oss_file_t *fmixer){	snd_mixer_oss_t *mixer = fmixer->mixer;	int result = 0;	if (mixer == NULL)		return -EIO;	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */		int err;		if ((err = mixer->get_recsrc(fmixer, &result)) < 0)			return err;		result = 1 << result;	} else {		snd_mixer_oss_slot_t *pslot;		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;}static int snd_mixer_oss_set_recsrc(snd_mixer_oss_file_t *fmixer, int recsrc){	snd_mixer_oss_t *mixer = fmixer->mixer;	snd_mixer_oss_slot_t *pslot;	int chn, active;	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));		mixer->get_recsrc(fmixer, &result);		result = 1 << result;	}	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;}static int snd_mixer_oss_get_volume(snd_mixer_oss_file_t *fmixer, int slot){	snd_mixer_oss_t *mixer = fmixer->mixer;	snd_mixer_oss_slot_t *pslot;	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;	snd_assert(left >= 0 && left <= 100, return -EIO);	snd_assert(right >= 0 && right <= 100, return -EIO);	if (result >= 0) {		pslot->volume[0] = left;		pslot->volume[1] = right;	 	result = (left & 0xff) | ((right & 0xff) << 8);	}	return result;}static int snd_mixer_oss_set_volume(snd_mixer_oss_file_t *fmixer,				    int slot, int volume){	snd_mixer_oss_t *mixer = fmixer->mixer;	snd_mixer_oss_slot_t *pslot;	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);}static int snd_mixer_oss_ioctl1(snd_mixer_oss_file_t *fmixer, unsigned int cmd, unsigned long arg){	void __user *argp = (void __user *)arg;	int __user *p = argp;	int tmp;	snd_assert(fmixer != NULL, return -ENXIO);	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){	return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);}int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg){	snd_mixer_oss_file_t fmixer;		snd_assert(card != NULL, return -ENXIO);	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 */static struct file_operations snd_mixer_oss_f_ops ={	.owner =	THIS_MODULE,	.open =		snd_mixer_oss_open,	.release =	snd_mixer_oss_release,	.unlocked_ioctl =	snd_mixer_oss_ioctl,	.compat_ioctl =	snd_mixer_oss_ioctl_compat,};static snd_minor_t snd_mixer_oss_reg ={	.comment =	"mixer",	.f_ops =	&snd_mixer_oss_f_ops,};/* *  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 0static void snd_mixer_oss_recsrce_set(snd_card_t *card, int slot){	snd_mixer_oss_t *mixer = card->mixer_oss;	if (mixer)		mixer->mask_recsrc |= 1 << slot;}static int snd_mixer_oss_recsrce_get(snd_card_t *card, int slot){	snd_mixer_oss_t *mixer = card->mixer_oss;	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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -