📄 rawmidi.c
字号:
static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait){ struct snd_rawmidi_file *rfile; struct snd_rawmidi_runtime *runtime; unsigned int mask; rfile = file->private_data; if (rfile->input != NULL) { runtime = rfile->input->runtime; snd_rawmidi_input_trigger(rfile->input, 1); poll_wait(file, &runtime->sleep, wait); } if (rfile->output != NULL) { runtime = rfile->output->runtime; poll_wait(file, &runtime->sleep, wait); } mask = 0; if (rfile->input != NULL) { if (snd_rawmidi_ready(rfile->input)) mask |= POLLIN | POLLRDNORM; } if (rfile->output != NULL) { if (snd_rawmidi_ready(rfile->output)) mask |= POLLOUT | POLLWRNORM; } return mask;}/* */#ifdef CONFIG_COMPAT#include "rawmidi_compat.c"#else#define snd_rawmidi_ioctl_compat NULL#endif/* */static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *substream; struct snd_rawmidi_runtime *runtime; rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); mutex_lock(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, list) { snd_iprintf(buffer, "Output %d\n" " Tx bytes : %lu\n", substream->number, (unsigned long) substream->bytes); if (substream->opened) { runtime = substream->runtime; snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" " Avail : %lu\n", runtime->oss ? "OSS compatible" : "native", (unsigned long) runtime->buffer_size, (unsigned long) runtime->avail); } } } if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams, list) { snd_iprintf(buffer, "Input %d\n" " Rx bytes : %lu\n", substream->number, (unsigned long) substream->bytes); if (substream->opened) { runtime = substream->runtime; snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" " Overruns : %lu\n", (unsigned long) runtime->buffer_size, (unsigned long) runtime->avail, (unsigned long) runtime->xruns); } } } mutex_unlock(&rmidi->open_mutex);}/* * Register functions */static const struct file_operations snd_rawmidi_f_ops ={ .owner = THIS_MODULE, .read = snd_rawmidi_read, .write = snd_rawmidi_write, .open = snd_rawmidi_open, .release = snd_rawmidi_release, .poll = snd_rawmidi_poll, .unlocked_ioctl = snd_rawmidi_ioctl, .compat_ioctl = snd_rawmidi_ioctl_compat,};static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, struct snd_rawmidi_str *stream, int direction, int count){ struct snd_rawmidi_substream *substream; int idx; for (idx = 0; idx < count; idx++) { substream = kzalloc(sizeof(*substream), GFP_KERNEL); if (substream == NULL) { snd_printk(KERN_ERR "rawmidi: cannot allocate substream\n"); return -ENOMEM; } substream->stream = direction; substream->number = idx; substream->rmidi = rmidi; substream->pstr = stream; list_add_tail(&substream->list, &stream->substreams); stream->substream_count++; } return 0;}/** * snd_rawmidi_new - create a rawmidi instance * @card: the card instance * @id: the id string * @device: the device index * @output_count: the number of output streams * @input_count: the number of input streams * @rrawmidi: the pointer to store the new rawmidi instance * * Creates a new rawmidi instance. * Use snd_rawmidi_set_ops() to set the operators to the new instance. * * Returns zero if successful, or a negative error code on failure. */int snd_rawmidi_new(struct snd_card *card, char *id, int device, int output_count, int input_count, struct snd_rawmidi ** rrawmidi){ struct snd_rawmidi *rmidi; int err; static struct snd_device_ops ops = { .dev_free = snd_rawmidi_dev_free, .dev_register = snd_rawmidi_dev_register, .dev_disconnect = snd_rawmidi_dev_disconnect, }; snd_assert(rrawmidi != NULL, return -EINVAL); *rrawmidi = NULL; snd_assert(card != NULL, return -ENXIO); rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); if (rmidi == NULL) { snd_printk(KERN_ERR "rawmidi: cannot allocate\n"); return -ENOMEM; } rmidi->card = card; rmidi->device = device; mutex_init(&rmidi->open_mutex); init_waitqueue_head(&rmidi->open_wait); INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams); INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams); if (id != NULL) strlcpy(rmidi->id, id, sizeof(rmidi->id)); if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) { snd_rawmidi_free(rmidi); return err; } if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], SNDRV_RAWMIDI_STREAM_OUTPUT, output_count)) < 0) { snd_rawmidi_free(rmidi); return err; } if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) { snd_rawmidi_free(rmidi); return err; } *rrawmidi = rmidi; return 0;}static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream){ struct snd_rawmidi_substream *substream; while (!list_empty(&stream->substreams)) { substream = list_entry(stream->substreams.next, struct snd_rawmidi_substream, list); list_del(&substream->list); kfree(substream); }}static int snd_rawmidi_free(struct snd_rawmidi *rmidi){ snd_assert(rmidi != NULL, return -ENXIO); snd_info_free_entry(rmidi->proc_entry); rmidi->proc_entry = NULL; mutex_lock(®ister_mutex); if (rmidi->ops && rmidi->ops->dev_unregister) rmidi->ops->dev_unregister(rmidi); mutex_unlock(®ister_mutex); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); if (rmidi->private_free) rmidi->private_free(rmidi); kfree(rmidi); return 0;}static int snd_rawmidi_dev_free(struct snd_device *device){ struct snd_rawmidi *rmidi = device->device_data; return snd_rawmidi_free(rmidi);}#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device){ struct snd_rawmidi *rmidi = device->private_data; rmidi->seq_dev = NULL;}#endifstatic int snd_rawmidi_dev_register(struct snd_device *device){ int err; struct snd_info_entry *entry; char name[16]; struct snd_rawmidi *rmidi = device->device_data; if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; mutex_lock(®ister_mutex); if (snd_rawmidi_search(rmidi->card, rmidi->device)) { mutex_unlock(®ister_mutex); return -EBUSY; } list_add_tail(&rmidi->list, &snd_rawmidi_devices); sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device); if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_f_ops, rmidi, name)) < 0) { snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; } if (rmidi->ops && rmidi->ops->dev_register && (err = rmidi->ops->dev_register(rmidi)) < 0) { snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); list_del(&rmidi->list); mutex_unlock(®ister_mutex); return err; }#ifdef CONFIG_SND_OSSEMUL rmidi->ossreg = 0; if ((int)rmidi->device == midi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0, &snd_rawmidi_f_ops, rmidi, name) < 0) { snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0); } else { rmidi->ossreg++;#ifdef SNDRV_OSS_INFO_DEV_MIDI snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name);#endif } } if ((int)rmidi->device == amidi_map[rmidi->card->number]) { if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1, &snd_rawmidi_f_ops, rmidi, name) < 0) { snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1); } else { rmidi->ossreg++; } }#endif /* CONFIG_SND_OSSEMUL */ mutex_unlock(®ister_mutex); sprintf(name, "midi%d", rmidi->device); entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { entry->private_data = rmidi; entry->c.text.read = snd_rawmidi_proc_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } rmidi->proc_entry = entry;#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free; sprintf(rmidi->seq_dev->name, "MIDI %d-%d", rmidi->card->number, rmidi->device); snd_device_register(rmidi->card, rmidi->seq_dev); } }#endif return 0;}static int snd_rawmidi_dev_disconnect(struct snd_device *device){ struct snd_rawmidi *rmidi = device->device_data; mutex_lock(®ister_mutex); list_del_init(&rmidi->list);#ifdef CONFIG_SND_OSSEMUL if (rmidi->ossreg) { if ((int)rmidi->device == midi_map[rmidi->card->number]) { snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0);#ifdef SNDRV_OSS_INFO_DEV_MIDI snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number);#endif } if ((int)rmidi->device == amidi_map[rmidi->card->number]) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1); rmidi->ossreg = 0; }#endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); mutex_unlock(®ister_mutex); return 0;}/** * snd_rawmidi_set_ops - set the rawmidi operators * @rmidi: the rawmidi instance * @stream: the stream direction, SNDRV_RAWMIDI_STREAM_XXX * @ops: the operator table * * Sets the rawmidi operators for the given stream direction. */void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, struct snd_rawmidi_ops *ops){ struct snd_rawmidi_substream *substream; list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops;}/* * ENTRY functions */static int __init alsa_rawmidi_init(void){ snd_ctl_register_ioctl(snd_rawmidi_control_ioctl); snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);#ifdef CONFIG_SND_OSSEMUL { int i; /* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) { if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) { snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]); midi_map[i] = 0; } if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) { snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]); amidi_map[i] = 1; } } }#endif /* CONFIG_SND_OSSEMUL */ return 0;}static void __exit alsa_rawmidi_exit(void){ snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl); snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);}module_init(alsa_rawmidi_init)module_exit(alsa_rawmidi_exit)EXPORT_SYMBOL(snd_rawmidi_output_params);EXPORT_SYMBOL(snd_rawmidi_input_params);EXPORT_SYMBOL(snd_rawmidi_drop_output);EXPORT_SYMBOL(snd_rawmidi_drain_output);EXPORT_SYMBOL(snd_rawmidi_drain_input);EXPORT_SYMBOL(snd_rawmidi_receive);EXPORT_SYMBOL(snd_rawmidi_transmit_empty);EXPORT_SYMBOL(snd_rawmidi_transmit_peek);EXPORT_SYMBOL(snd_rawmidi_transmit_ack);EXPORT_SYMBOL(snd_rawmidi_transmit);EXPORT_SYMBOL(snd_rawmidi_new);EXPORT_SYMBOL(snd_rawmidi_set_ops);EXPORT_SYMBOL(snd_rawmidi_info_select);EXPORT_SYMBOL(snd_rawmidi_kernel_open);EXPORT_SYMBOL(snd_rawmidi_kernel_release);EXPORT_SYMBOL(snd_rawmidi_kernel_read);EXPORT_SYMBOL(snd_rawmidi_kernel_write);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -