0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <sound/core.h>
0011 #include "seq_clientmgr.h"
0012 #include <sound/initval.h>
0013 #include <sound/asoundef.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0049 MODULE_DESCRIPTION("ALSA sequencer MIDI-through client");
0050 MODULE_LICENSE("GPL");
0051 MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
0052
0053 static int ports = 1;
0054 static bool duplex;
0055
0056 module_param(ports, int, 0444);
0057 MODULE_PARM_DESC(ports, "number of ports to be created");
0058 module_param(duplex, bool, 0444);
0059 MODULE_PARM_DESC(duplex, "create DUPLEX ports");
0060
0061 struct snd_seq_dummy_port {
0062 int client;
0063 int port;
0064 int duplex;
0065 int connect;
0066 };
0067
0068 static int my_client = -1;
0069
0070
0071
0072
0073 static int
0074 dummy_input(struct snd_seq_event *ev, int direct, void *private_data,
0075 int atomic, int hop)
0076 {
0077 struct snd_seq_dummy_port *p;
0078 struct snd_seq_event tmpev;
0079
0080 p = private_data;
0081 if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM ||
0082 ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
0083 return 0;
0084 tmpev = *ev;
0085 if (p->duplex)
0086 tmpev.source.port = p->connect;
0087 else
0088 tmpev.source.port = p->port;
0089 tmpev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
0090 return snd_seq_kernel_client_dispatch(p->client, &tmpev, atomic, hop);
0091 }
0092
0093
0094
0095
0096 static void
0097 dummy_free(void *private_data)
0098 {
0099 kfree(private_data);
0100 }
0101
0102
0103
0104
0105 static struct snd_seq_dummy_port __init *
0106 create_port(int idx, int type)
0107 {
0108 struct snd_seq_port_info pinfo;
0109 struct snd_seq_port_callback pcb;
0110 struct snd_seq_dummy_port *rec;
0111
0112 rec = kzalloc(sizeof(*rec), GFP_KERNEL);
0113 if (!rec)
0114 return NULL;
0115
0116 rec->client = my_client;
0117 rec->duplex = duplex;
0118 rec->connect = 0;
0119 memset(&pinfo, 0, sizeof(pinfo));
0120 pinfo.addr.client = my_client;
0121 if (duplex)
0122 sprintf(pinfo.name, "Midi Through Port-%d:%c", idx,
0123 (type ? 'B' : 'A'));
0124 else
0125 sprintf(pinfo.name, "Midi Through Port-%d", idx);
0126 pinfo.capability = SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
0127 pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
0128 if (duplex)
0129 pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
0130 pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
0131 | SNDRV_SEQ_PORT_TYPE_SOFTWARE
0132 | SNDRV_SEQ_PORT_TYPE_PORT;
0133 memset(&pcb, 0, sizeof(pcb));
0134 pcb.owner = THIS_MODULE;
0135 pcb.event_input = dummy_input;
0136 pcb.private_free = dummy_free;
0137 pcb.private_data = rec;
0138 pinfo.kernel = &pcb;
0139 if (snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo) < 0) {
0140 kfree(rec);
0141 return NULL;
0142 }
0143 rec->port = pinfo.addr.port;
0144 return rec;
0145 }
0146
0147
0148
0149
0150 static int __init
0151 register_client(void)
0152 {
0153 struct snd_seq_dummy_port *rec1, *rec2;
0154 int i;
0155
0156 if (ports < 1) {
0157 pr_err("ALSA: seq_dummy: invalid number of ports %d\n", ports);
0158 return -EINVAL;
0159 }
0160
0161
0162 my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY,
0163 "Midi Through");
0164 if (my_client < 0)
0165 return my_client;
0166
0167
0168 for (i = 0; i < ports; i++) {
0169 rec1 = create_port(i, 0);
0170 if (rec1 == NULL) {
0171 snd_seq_delete_kernel_client(my_client);
0172 return -ENOMEM;
0173 }
0174 if (duplex) {
0175 rec2 = create_port(i, 1);
0176 if (rec2 == NULL) {
0177 snd_seq_delete_kernel_client(my_client);
0178 return -ENOMEM;
0179 }
0180 rec1->connect = rec2->port;
0181 rec2->connect = rec1->port;
0182 }
0183 }
0184
0185 return 0;
0186 }
0187
0188
0189
0190
0191 static void __exit
0192 delete_client(void)
0193 {
0194 if (my_client >= 0)
0195 snd_seq_delete_kernel_client(my_client);
0196 }
0197
0198
0199
0200
0201
0202 static int __init alsa_seq_dummy_init(void)
0203 {
0204 return register_client();
0205 }
0206
0207 static void __exit alsa_seq_dummy_exit(void)
0208 {
0209 delete_client();
0210 }
0211
0212 module_init(alsa_seq_dummy_init)
0213 module_exit(alsa_seq_dummy_exit)