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(¶ms, 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, ¶ms); case SNDRV_RAWMIDI_STREAM_INPUT: if (rfile->input == NULL) return -EINVAL; return snd_rawmidi_input_params(rfile->input, ¶ms); 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 + -
显示快捷键?