📄 rawmidi.c
字号:
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(®ister_mutex); rmidi = snd_rawmidi_search(card, info->device); mutex_unlock(®ister_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(¶ms, 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, ¶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; 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(®ister_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(®ister_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 + -