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

📄 rawmidi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		subdevice = -1;		down_read(&card->controls_rwsem);		list_for_each_entry(kctl, &card->ctl_files, list) {			if (kctl->pid == current->pid) {				subdevice = kctl->prefer_rawmidi_subdevice;				if (subdevice != -1)					break;			}		}		up_read(&card->controls_rwsem);		err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device,					      subdevice, fflags, rawmidi_file);		if (err >= 0)			break;		if (err == -EAGAIN) {			if (file->f_flags & O_NONBLOCK) {				err = -EBUSY;				break;			}		} else			break;		set_current_state(TASK_INTERRUPTIBLE);		mutex_unlock(&rmidi->open_mutex);		schedule();		mutex_lock(&rmidi->open_mutex);		if (signal_pending(current)) {			err = -ERESTARTSYS;			break;		}	}#ifdef CONFIG_SND_OSSEMUL	if (rawmidi_file->input && rawmidi_file->input->runtime)		rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);	if (rawmidi_file->output && rawmidi_file->output->runtime)		rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);#endif	remove_wait_queue(&rmidi->open_wait, &wait);	if (err >= 0) {		file->private_data = rawmidi_file;	} else {		snd_card_file_remove(card, file);		kfree(rawmidi_file);	}	mutex_unlock(&rmidi->open_mutex);	return err;}int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile){	struct snd_rawmidi *rmidi;	struct snd_rawmidi_substream *substream;	struct snd_rawmidi_runtime *runtime;	snd_assert(rfile != NULL, return -ENXIO);	snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);	rmidi = rfile->rmidi;	mutex_lock(&rmidi->open_mutex);	if (rfile->input != NULL) {		substream = rfile->input;		rfile->input = NULL;		runtime = substream->runtime;		snd_rawmidi_input_trigger(substream, 0);		substream->ops->close(substream);		if (runtime->private_free != NULL)			runtime->private_free(substream);		snd_rawmidi_runtime_free(substream);		substream->opened = 0;		rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;	}	if (rfile->output != NULL) {		substream = rfile->output;		rfile->output = NULL;		if (--substream->use_count == 0) {			runtime = substream->runtime;			if (substream->active_sensing) {				unsigned char buf = 0xfe;				/* sending single active sensing message to shut the device up */				snd_rawmidi_kernel_write(substream, &buf, 1);			}			if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)				snd_rawmidi_output_trigger(substream, 0);			substream->ops->close(substream);			if (runtime->private_free != NULL)				runtime->private_free(substream);			snd_rawmidi_runtime_free(substream);			substream->opened = 0;			substream->append = 0;		}		rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;	}	mutex_unlock(&rmidi->open_mutex);	module_put(rmidi->card->module);	return 0;}static int snd_rawmidi_release(struct inode *inode, struct file *file){	struct snd_rawmidi_file *rfile;	struct snd_rawmidi *rmidi;	int err;	rfile = file->private_data;	err = snd_rawmidi_kernel_release(rfile);	rmidi = rfile->rmidi;	wake_up(&rmidi->open_wait);	kfree(rfile);	snd_card_file_remove(rmidi->card, file);	return err;}static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,			    struct snd_rawmidi_info *info){	struct snd_rawmidi *rmidi;		if (substream == NULL)		return -ENODEV;	rmidi = substream->rmidi;	memset(info, 0, sizeof(*info));	info->card = rmidi->card->number;	info->device = rmidi->device;	info->subdevice = substream->number;	info->stream = substream->stream;	info->flags = rmidi->info_flags;	strcpy(info->id, rmidi->id);	strcpy(info->name, rmidi->name);	strcpy(info->subname, substream->name);	info->subdevices_count = substream->pstr->substream_count;	info->subdevices_avail = (substream->pstr->substream_count -				  substream->pstr->substream_opened);	return 0;}static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,				 struct snd_rawmidi_info __user * _info){	struct snd_rawmidi_info info;	int err;	if ((err = snd_rawmidi_info(substream, &info)) < 0)		return err;	if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))		return -EFAULT;	return 0;}int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info){	struct snd_rawmidi *rmidi;	struct snd_rawmidi_str *pstr;	struct snd_rawmidi_substream *substream;	mutex_lock(&register_mutex);	rmidi = snd_rawmidi_search(card, info->device);	mutex_unlock(&register_mutex);	if (!rmidi)		return -ENXIO;	if (info->stream < 0 || info->stream > 1)		return -EINVAL;	pstr = &rmidi->streams[info->stream];	if (pstr->substream_count == 0)		return -ENOENT;	if (info->subdevice >= pstr->substream_count)		return -ENXIO;	list_for_each_entry(substream, &pstr->substreams, list) {		if ((unsigned int)substream->number == info->subdevice)			return snd_rawmidi_info(substream, info);	}	return -ENXIO;}static int snd_rawmidi_info_select_user(struct snd_card *card,					struct snd_rawmidi_info __user *_info){	int err;	struct snd_rawmidi_info info;	if (get_user(info.device, &_info->device))		return -EFAULT;	if (get_user(info.stream, &_info->stream))		return -EFAULT;	if (get_user(info.subdevice, &_info->subdevice))		return -EFAULT;	if ((err = snd_rawmidi_info_select(card, &info)) < 0)		return err;	if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))		return -EFAULT;	return 0;}int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,			      struct snd_rawmidi_params * params){	char *newbuf;	struct snd_rawmidi_runtime *runtime = substream->runtime;		if (substream->append && substream->use_count > 1)		return -EBUSY;	snd_rawmidi_drain_output(substream);	if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {		return -EINVAL;	}	if (params->avail_min < 1 || params->avail_min > params->buffer_size) {		return -EINVAL;	}	if (params->buffer_size != runtime->buffer_size) {		newbuf = kmalloc(params->buffer_size, GFP_KERNEL);		if (!newbuf)			return -ENOMEM;		kfree(runtime->buffer);		runtime->buffer = newbuf;		runtime->buffer_size = params->buffer_size;		runtime->avail = runtime->buffer_size;	}	runtime->avail_min = params->avail_min;	substream->active_sensing = !params->no_active_sensing;	return 0;}int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,			     struct snd_rawmidi_params * params){	char *newbuf;	struct snd_rawmidi_runtime *runtime = substream->runtime;	snd_rawmidi_drain_input(substream);	if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {		return -EINVAL;	}	if (params->avail_min < 1 || params->avail_min > params->buffer_size) {		return -EINVAL;	}	if (params->buffer_size != runtime->buffer_size) {		newbuf = kmalloc(params->buffer_size, GFP_KERNEL);		if (!newbuf)			return -ENOMEM;		kfree(runtime->buffer);		runtime->buffer = newbuf;		runtime->buffer_size = params->buffer_size;	}	runtime->avail_min = params->avail_min;	return 0;}static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,				     struct snd_rawmidi_status * status){	struct snd_rawmidi_runtime *runtime = substream->runtime;	memset(status, 0, sizeof(*status));	status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;	spin_lock_irq(&runtime->lock);	status->avail = runtime->avail;	spin_unlock_irq(&runtime->lock);	return 0;}static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,				    struct snd_rawmidi_status * status){	struct snd_rawmidi_runtime *runtime = substream->runtime;	memset(status, 0, sizeof(*status));	status->stream = SNDRV_RAWMIDI_STREAM_INPUT;	spin_lock_irq(&runtime->lock);	status->avail = runtime->avail;	status->xruns = runtime->xruns;	runtime->xruns = 0;	spin_unlock_irq(&runtime->lock);	return 0;}static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	struct snd_rawmidi_file *rfile;	void __user *argp = (void __user *)arg;	rfile = file->private_data;	if (((cmd >> 8) & 0xff) != 'W')		return -ENOTTY;	switch (cmd) {	case SNDRV_RAWMIDI_IOCTL_PVERSION:		return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0;	case SNDRV_RAWMIDI_IOCTL_INFO:	{		int stream;		struct snd_rawmidi_info __user *info = argp;		if (get_user(stream, &info->stream))			return -EFAULT;		switch (stream) {		case SNDRV_RAWMIDI_STREAM_INPUT:			return snd_rawmidi_info_user(rfile->input, info);		case SNDRV_RAWMIDI_STREAM_OUTPUT:			return snd_rawmidi_info_user(rfile->output, info);		default:			return -EINVAL;		}	}	case SNDRV_RAWMIDI_IOCTL_PARAMS:	{		struct snd_rawmidi_params params;		if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))			return -EFAULT;		switch (params.stream) {		case SNDRV_RAWMIDI_STREAM_OUTPUT:			if (rfile->output == NULL)				return -EINVAL;			return snd_rawmidi_output_params(rfile->output, &params);		case SNDRV_RAWMIDI_STREAM_INPUT:			if (rfile->input == NULL)				return -EINVAL;			return snd_rawmidi_input_params(rfile->input, &params);		default:			return -EINVAL;		}	}	case SNDRV_RAWMIDI_IOCTL_STATUS:	{		int err = 0;		struct snd_rawmidi_status status;		if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))			return -EFAULT;		switch (status.stream) {		case SNDRV_RAWMIDI_STREAM_OUTPUT:			if (rfile->output == NULL)				return -EINVAL;			err = snd_rawmidi_output_status(rfile->output, &status);			break;		case SNDRV_RAWMIDI_STREAM_INPUT:			if (rfile->input == NULL)				return -EINVAL;			err = snd_rawmidi_input_status(rfile->input, &status);			break;		default:			return -EINVAL;		}		if (err < 0)			return err;		if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status)))			return -EFAULT;		return 0;	}	case SNDRV_RAWMIDI_IOCTL_DROP:	{		int val;		if (get_user(val, (int __user *) argp))			return -EFAULT;		switch (val) {		case SNDRV_RAWMIDI_STREAM_OUTPUT:			if (rfile->output == NULL)				return -EINVAL;			return snd_rawmidi_drop_output(rfile->output);		default:			return -EINVAL;		}	}	case SNDRV_RAWMIDI_IOCTL_DRAIN:	{		int val;		if (get_user(val, (int __user *) argp))			return -EFAULT;		switch (val) {		case SNDRV_RAWMIDI_STREAM_OUTPUT:			if (rfile->output == NULL)				return -EINVAL;			return snd_rawmidi_drain_output(rfile->output);		case SNDRV_RAWMIDI_STREAM_INPUT:			if (rfile->input == NULL)				return -EINVAL;			return snd_rawmidi_drain_input(rfile->input);		default:			return -EINVAL;		}	}#ifdef CONFIG_SND_DEBUG	default:		snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd);#endif	}	return -ENOTTY;}static int snd_rawmidi_control_ioctl(struct snd_card *card,				     struct snd_ctl_file *control,				     unsigned int cmd,				     unsigned long arg){	void __user *argp = (void __user *)arg;	switch (cmd) {	case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:	{		int device;				if (get_user(device, (int __user *)argp))			return -EFAULT;		mutex_lock(&register_mutex);		device = device < 0 ? 0 : device + 1;		while (device < SNDRV_RAWMIDI_DEVICES) {			if (snd_rawmidi_search(card, device))				break;			device++;		}		if (device == SNDRV_RAWMIDI_DEVICES)			device = -1;		mutex_unlock(&register_mutex);		if (put_user(device, (int __user *)argp))			return -EFAULT;		return 0;	}	case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:	{		int val;				if (get_user(val, (int __user *)argp))			return -EFAULT;		control->prefer_rawmidi_subdevice = val;		return 0;	}	case SNDRV_CTL_IOCTL_RAWMIDI_INFO:		return snd_rawmidi_info_select_user(card, argp);	}

⌨️ 快捷键说明

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