/* register new midi synth port */ int snd_seq_midisynth_register_port(snd_seq_device_t *dev) { seq_midisynth_client_t *client; seq_midisynth_t *msynth, *ms; snd_seq_port_info_t port; snd_rawmidi_info_t info; int newclient = 0, p, ports; snd_seq_client_callback_t callbacks; snd_seq_port_callback_t pcallbacks; snd_seq_client_info_t inf; snd_card_t *card = dev->card; int device = dev->device; unsigned int input_count = 0, output_count = 0; snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL); info.device = device; info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT; info.subdevice = 0; if (snd_rawmidi_info_select(card, &info) >= 0) output_count = info.subdevices_count; info.stream = SNDRV_RAWMIDI_STREAM_INPUT; if (snd_rawmidi_info_select(card, &info) >= 0) { input_count = info.subdevices_count; } ports = output_count; if (ports < input_count) ports = input_count; if (ports == 0) return -ENODEV; if (ports > (256 / SNDRV_RAWMIDI_DEVICES)) ports = 256 / SNDRV_RAWMIDI_DEVICES; down(®ister_mutex); client = synths[card->number]; if (client == NULL) { newclient = 1; client = snd_kcalloc(sizeof(seq_midisynth_client_t), GFP_KERNEL); if (client == NULL) { up(®ister_mutex); return -ENOMEM; } memset(&callbacks, 0, sizeof(callbacks)); callbacks.private_data = client; callbacks.allow_input = callbacks.allow_output = 1; client->seq_client = snd_seq_create_kernel_client(card, 0, &callbacks); if (client->seq_client < 0) { kfree(client); up(®ister_mutex); return -ENOMEM; } /* set our client name */ memset(&inf,0,sizeof(snd_seq_client_info_t)); inf.client = client->seq_client; inf.type = KERNEL_CLIENT; sprintf(inf.name, "External MIDI %i", card->number); snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &inf); } msynth = snd_kcalloc(sizeof(seq_midisynth_t) * ports, GFP_KERNEL); if (msynth == NULL) goto __nomem; for (p = 0; p < ports; p++) { ms = &msynth[p]; if (snd_seq_midisynth_new(ms, card, device, p) < 0) goto __nomem; /* declare port */ memset(&port, 0, sizeof(port)); port.addr.client = client->seq_client; port.addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p; port.flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; memset(&info, 0, sizeof(info)); info.device = device; if (p < output_count) info.stream = SNDRV_RAWMIDI_STREAM_OUTPUT; else info.stream = SNDRV_RAWMIDI_STREAM_INPUT; info.subdevice = p; if (snd_rawmidi_info_select(card, &info) >= 0) strcpy(port.name, info.subname); if (! port.name[0]) { if (ports > 1) sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p); else sprintf(port.name, "MIDI %d-%d", card->number, device); } if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count) port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; if ((info.flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count) port.capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; if ((port.capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && info.flags & SNDRV_RAWMIDI_INFO_DUPLEX) port.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; port.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; port.midi_channels = 16; memset(&pcallbacks, 0, sizeof(pcallbacks)); pcallbacks.owner = THIS_MODULE; pcallbacks.private_data = ms; pcallbacks.subscribe = midisynth_subscribe; pcallbacks.unsubscribe = midisynth_unsubscribe; pcallbacks.use = midisynth_use; pcallbacks.unuse = midisynth_unuse; pcallbacks.event_input = event_process_midi; port.kernel = &pcallbacks; if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &port)<0) goto __nomem; ms->seq_client = client->seq_client; ms->seq_port = port.addr.port; } client->ports_per_device[device] = ports; client->ports[device] = msynth; client->num_ports++; if (newclient) synths[card->number] = client; up(®ister_mutex); return 0; /* success */ __nomem: if (msynth != NULL) { for (p = 0; p < ports; p++) snd_seq_midisynth_delete(&msynth[p]); kfree(msynth); } if (newclient) { snd_seq_delete_kernel_client(client->seq_client); kfree(client); } up(®ister_mutex); return -ENOMEM; }
/* register new midi synth port */ static int snd_seq_midisynth_register_port(struct snd_seq_device *dev) { struct seq_midisynth_client *client; struct seq_midisynth *msynth, *ms; struct snd_seq_port_info *port; struct snd_rawmidi_info *info; struct snd_rawmidi *rmidi = dev->private_data; int newclient = 0; unsigned int p, ports; struct snd_seq_port_callback pcallbacks; struct snd_card *card = dev->card; int device = dev->device; unsigned int input_count = 0, output_count = 0; if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES)) return -EINVAL; info = kmalloc(sizeof(*info), GFP_KERNEL); if (! info) return -ENOMEM; info->device = device; info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; info->subdevice = 0; if (snd_rawmidi_info_select(card, info) >= 0) output_count = info->subdevices_count; info->stream = SNDRV_RAWMIDI_STREAM_INPUT; if (snd_rawmidi_info_select(card, info) >= 0) { input_count = info->subdevices_count; } ports = output_count; if (ports < input_count) ports = input_count; if (ports == 0) { kfree(info); return -ENODEV; } if (ports > (256 / SNDRV_RAWMIDI_DEVICES)) ports = 256 / SNDRV_RAWMIDI_DEVICES; mutex_lock(®ister_mutex); client = synths[card->number]; if (client == NULL) { newclient = 1; client = kzalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) { mutex_unlock(®ister_mutex); kfree(info); return -ENOMEM; } client->seq_client = snd_seq_create_kernel_client( card, 0, "%s", card->shortname[0] ? (const char *)card->shortname : "External MIDI"); if (client->seq_client < 0) { kfree(client); mutex_unlock(®ister_mutex); kfree(info); return -ENOMEM; } } msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL); port = kmalloc(sizeof(*port), GFP_KERNEL); if (msynth == NULL || port == NULL) goto __nomem; for (p = 0; p < ports; p++) { ms = &msynth[p]; if (snd_seq_midisynth_new(ms, card, device, p) < 0) goto __nomem; /* declare port */ memset(port, 0, sizeof(*port)); port->addr.client = client->seq_client; port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p; port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; memset(info, 0, sizeof(*info)); info->device = device; if (p < output_count) info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; else info->stream = SNDRV_RAWMIDI_STREAM_INPUT; info->subdevice = p; if (snd_rawmidi_info_select(card, info) >= 0) strcpy(port->name, info->subname); if (! port->name[0]) { if (info->name[0]) { if (ports > 1) snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p); else snprintf(port->name, sizeof(port->name), "%s", info->name); } else { /* last resort */ if (ports > 1) sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p); else sprintf(port->name, "MIDI %d-%d", card->number, device); } } if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count) port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count) port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && info->flags & SNDRV_RAWMIDI_INFO_DUPLEX) port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | SNDRV_SEQ_PORT_TYPE_HARDWARE | SNDRV_SEQ_PORT_TYPE_PORT; port->midi_channels = 16; memset(&pcallbacks, 0, sizeof(pcallbacks)); pcallbacks.owner = THIS_MODULE; pcallbacks.private_data = ms; pcallbacks.subscribe = midisynth_subscribe; pcallbacks.unsubscribe = midisynth_unsubscribe; pcallbacks.use = midisynth_use; pcallbacks.unuse = midisynth_unuse; pcallbacks.event_input = event_process_midi; port->kernel = &pcallbacks; if (rmidi->ops && rmidi->ops->get_port_info) rmidi->ops->get_port_info(rmidi, p, port); if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0) goto __nomem; ms->seq_client = client->seq_client; ms->seq_port = port->addr.port; } client->ports_per_device[device] = ports; client->ports[device] = msynth; client->num_ports++; if (newclient) synths[card->number] = client; mutex_unlock(®ister_mutex); kfree(info); kfree(port); return 0; /* success */ __nomem: if (msynth != NULL) { for (p = 0; p < ports; p++) snd_seq_midisynth_delete(&msynth[p]); kfree(msynth); } if (newclient) { snd_seq_delete_kernel_client(client->seq_client); kfree(client); } kfree(info); kfree(port); mutex_unlock(®ister_mutex); return -ENOMEM; }