rawmidi.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,674 行 · 第 1/4 页

C
1,674
字号
		if (err >= 0)			break;		if (err == -EAGAIN) {			if (file->f_flags & O_NONBLOCK) {				err = -EBUSY;				break;			}		} else			break;		set_current_state(TASK_INTERRUPTIBLE);		up(&rmidi->open_mutex);		schedule();		down(&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);	}	up(&rmidi->open_mutex);	return err;}int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile){	snd_rawmidi_t *rmidi;	snd_rawmidi_substream_t *substream;	snd_rawmidi_runtime_t *runtime;	snd_assert(rfile != NULL, return -ENXIO);	snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);	rmidi = rfile->rmidi;	down(&rmidi->open_mutex);	if (rfile->input != NULL) {		substream = rfile->input;		rfile->input = NULL;		runtime = substream->runtime;		runtime->trigger = 0;		substream->ops->trigger(substream, 0);		substream->ops->close(substream);		snd_rawmidi_done_buffer(runtime);		if (runtime->private_free != NULL)			runtime->private_free(substream);		kfree(runtime);		substream->runtime = NULL;		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)				substream->ops->trigger(substream, 0);			substream->ops->close(substream);			snd_rawmidi_done_buffer(runtime);			if (runtime->private_free != NULL)				runtime->private_free(substream);			kfree(runtime);			substream->runtime = NULL;			substream->opened = 0;			substream->append = 0;		}		rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;	}	up(&rmidi->open_mutex);	module_put(rmidi->card->module);	return 0;}static int snd_rawmidi_release(struct inode *inode, struct file *file){	snd_rawmidi_file_t *rfile;	snd_rawmidi_t *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;}int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *info){	snd_rawmidi_t *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(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t __user * _info){	snd_rawmidi_info_t info;	int err;	if ((err = snd_rawmidi_info(substream, &info)) < 0)		return err;	if (copy_to_user(_info, &info, sizeof(snd_rawmidi_info_t)))		return -EFAULT;	return 0;}int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info){	snd_rawmidi_t *rmidi;	snd_rawmidi_str_t *pstr;	snd_rawmidi_substream_t *substream;	struct list_head *list;	if (info->device >= SNDRV_RAWMIDI_DEVICES)		return -ENXIO;	rmidi = snd_rawmidi_devices[card->number * SNDRV_RAWMIDI_DEVICES + info->device];	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(list, &pstr->substreams) {		substream = list_entry(list, snd_rawmidi_substream_t, list);		if ((unsigned int)substream->number == info->subdevice)			return snd_rawmidi_info(substream, info);	}	return -ENXIO;}static int snd_rawmidi_info_select_user(snd_card_t *card,					snd_rawmidi_info_t __user *_info){	int err;	snd_rawmidi_info_t 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(snd_rawmidi_info_t)))		return -EFAULT;	return 0;}int snd_rawmidi_output_params(snd_rawmidi_substream_t * substream,			      snd_rawmidi_params_t * params){	char *newbuf;	snd_rawmidi_runtime_t *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) {		if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)			return -ENOMEM;		kfree(runtime->buffer);		runtime->buffer = newbuf;		runtime->buffer_size = params->buffer_size;	}	runtime->avail_min = params->avail_min;	substream->active_sensing = !params->no_active_sensing;	return 0;}int snd_rawmidi_input_params(snd_rawmidi_substream_t * substream,			     snd_rawmidi_params_t * params){	char *newbuf;	snd_rawmidi_runtime_t *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) {		if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)			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(snd_rawmidi_substream_t * substream,				     snd_rawmidi_status_t * status){	snd_rawmidi_runtime_t *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(snd_rawmidi_substream_t * substream,				    snd_rawmidi_status_t * status){	snd_rawmidi_runtime_t *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 inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,				     unsigned int cmd, unsigned long arg){	snd_rawmidi_file_t *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:	{		snd_rawmidi_stream_t stream;		snd_rawmidi_info_t __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:	{		snd_rawmidi_params_t params;		if (copy_from_user(&params, argp, sizeof(snd_rawmidi_params_t)))			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;		snd_rawmidi_status_t status;		if (copy_from_user(&status, argp, sizeof(snd_rawmidi_status_t)))			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(snd_rawmidi_status_t)))			return -EFAULT;		return 0;	}	case SNDRV_RAWMIDI_IOCTL_DROP:	{		int val;		if (get_user(val, (long __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, (long __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;}/* FIXME: need to unlock BKL to allow preemption */static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,			     unsigned int cmd, unsigned long arg){	int err;	unlock_kernel();	err = _snd_rawmidi_ioctl(inode, file, cmd, arg);	lock_kernel();	return err;}int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,			      unsigned int cmd, unsigned long arg){	void __user *argp = (void __user *)arg;	unsigned int tmp;	tmp = card->number * SNDRV_RAWMIDI_DEVICES;	switch (cmd) {	case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:	{		int device;				if (get_user(device, (int __user *)argp))			return -EFAULT;		device = device < 0 ? 0 : device + 1;		while (device < SNDRV_RAWMIDI_DEVICES) {			if (snd_rawmidi_devices[tmp + device])				break;			device++;		}		if (device == SNDRV_RAWMIDI_DEVICES)			device = -1;		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);	}	return -ENOIOCTLCMD;}

⌨️ 快捷键说明

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