📄 mixer_oss.c
字号:
/* * 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/slab.h>#include <linux/time.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>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");MODULE_LICENSE("GPL");static inline void dec_mod_count(struct module *module){ if (module) __MOD_DEC_USE_COUNT(module);}static int snd_mixer_oss_open(struct inode *inode, struct file *file){ int cardnum = SNDRV_MINOR_OSS_CARD(minor(inode->i_rdev)); snd_card_t *card; snd_mixer_oss_file_t *fmixer; if ((card = snd_cards[cardnum]) == NULL) return -ENODEV; if (card->mixer_oss == NULL) return -ENODEV; fmixer = (snd_mixer_oss_file_t *)snd_kcalloc(sizeof(*fmixer), GFP_KERNEL); if (fmixer == NULL) return -ENOMEM; fmixer->card = card; fmixer->mixer = card->mixer_oss; file->private_data = fmixer;#ifdef LINUX_2_2 MOD_INC_USE_COUNT;#endif if (!try_inc_mod_count(card->module)) { kfree(fmixer);#ifdef LINUX_2_2 MOD_DEC_USE_COUNT;#endif 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; dec_mod_count(fmixer->card->module);#ifdef LINUX_2_2 MOD_DEC_USE_COUNT;#endif kfree(fmixer); } return 0;}static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer, mixer_info *_info){ snd_card_t *card = fmixer->card; snd_mixer_oss_t *mixer = fmixer->mixer; struct mixer_info info; memset(&info, 0, sizeof(info)); strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1); strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1); 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 *_info){ snd_card_t *card = fmixer->card; snd_mixer_oss_t *mixer = fmixer->mixer; _old_mixer_info info; memset(&info, 0, sizeof(info)); strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1); strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1); 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; 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; } else { snd_mixer_oss_slot_t *pslot; int chn, active; 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); } } 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 = fmixer->volume[slot][0]; right = fmixer->volume[slot][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) { fmixer->volume[slot][0] = left; fmixer->volume[slot][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) left = right = left; if (pslot->put_volume) result = pslot->put_volume(fmixer, pslot, left, right); if (result < 0) return result; fmixer->volume[slot][0] = left; fmixer->volume[slot][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){ 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, (mixer_info *)arg); case SOUND_OLD_MIXER_INFO: return snd_mixer_oss_info_obsolete(fmixer, (_old_mixer_info *)arg); case SOUND_MIXER_WRITE_RECSRC: if (get_user(tmp, (int *)arg)) return -EFAULT; tmp = snd_mixer_oss_set_recsrc(fmixer, tmp); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; case OSS_GETVERSION: return put_user(SNDRV_OSS_VERSION, (int *) arg); case SOUND_MIXER_READ_DEVMASK: tmp = snd_mixer_oss_devmask(fmixer); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; case SOUND_MIXER_READ_STEREODEVS: tmp = snd_mixer_oss_stereodevs(fmixer); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; case SOUND_MIXER_READ_RECMASK: tmp = snd_mixer_oss_recmask(fmixer); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; case SOUND_MIXER_READ_CAPS: tmp = snd_mixer_oss_caps(fmixer); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; case SOUND_MIXER_READ_RECSRC: tmp = snd_mixer_oss_get_recsrc(fmixer); if (tmp < 0) return tmp; return put_user(tmp, (int *)arg) ? -EFAULT : 0; } } if (cmd & IOC_IN) { if (get_user(tmp, (int *)arg)) return -EFAULT; tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp); if (tmp < 0) return tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -