0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/export.h>
0009 #include <linux/slab.h>
0010 #include <sound/core.h>
0011 #include "seq_system.h"
0012 #include "seq_timer.h"
0013 #include "seq_queue.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 static int sysclient = -1;
0048
0049
0050 static int announce_port = -1;
0051
0052
0053
0054
0055 static int setheader(struct snd_seq_event * ev, int client, int port)
0056 {
0057 if (announce_port < 0)
0058 return -ENODEV;
0059
0060 memset(ev, 0, sizeof(struct snd_seq_event));
0061
0062 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
0063 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
0064
0065 ev->source.client = sysclient;
0066 ev->source.port = announce_port;
0067 ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
0068
0069
0070
0071 ev->data.addr.client = client;
0072 ev->data.addr.port = port;
0073
0074 return 0;
0075 }
0076
0077
0078
0079 void snd_seq_system_broadcast(int client, int port, int type)
0080 {
0081 struct snd_seq_event ev;
0082
0083 if (setheader(&ev, client, port) < 0)
0084 return;
0085 ev.type = type;
0086 snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
0087 }
0088
0089
0090 int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
0091 {
0092 ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
0093 ev->source.client = sysclient;
0094 ev->source.port = announce_port;
0095 ev->dest.client = client;
0096 ev->dest.port = port;
0097 return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
0098 }
0099
0100
0101 static int event_input_timer(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
0102 {
0103 return snd_seq_control_queue(ev, atomic, hop);
0104 }
0105
0106
0107 int __init snd_seq_system_client_init(void)
0108 {
0109 struct snd_seq_port_callback pcallbacks;
0110 struct snd_seq_port_info *port;
0111 int err;
0112
0113 port = kzalloc(sizeof(*port), GFP_KERNEL);
0114 if (!port)
0115 return -ENOMEM;
0116
0117 memset(&pcallbacks, 0, sizeof(pcallbacks));
0118 pcallbacks.owner = THIS_MODULE;
0119 pcallbacks.event_input = event_input_timer;
0120
0121
0122 sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
0123 if (sysclient < 0) {
0124 kfree(port);
0125 return sysclient;
0126 }
0127
0128
0129 strcpy(port->name, "Timer");
0130 port->capability = SNDRV_SEQ_PORT_CAP_WRITE;
0131 port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ;
0132 port->kernel = &pcallbacks;
0133 port->type = 0;
0134 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
0135 port->addr.client = sysclient;
0136 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
0137 err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
0138 port);
0139 if (err < 0)
0140 goto error_port;
0141
0142
0143 strcpy(port->name, "Announce");
0144 port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ;
0145 port->kernel = NULL;
0146 port->type = 0;
0147 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
0148 port->addr.client = sysclient;
0149 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
0150 err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
0151 port);
0152 if (err < 0)
0153 goto error_port;
0154 announce_port = port->addr.port;
0155
0156 kfree(port);
0157 return 0;
0158
0159 error_port:
0160 snd_seq_system_client_done();
0161 kfree(port);
0162 return err;
0163 }
0164
0165
0166
0167 void snd_seq_system_client_done(void)
0168 {
0169 int oldsysclient = sysclient;
0170
0171 if (oldsysclient >= 0) {
0172 sysclient = -1;
0173 announce_port = -1;
0174 snd_seq_delete_kernel_client(oldsysclient);
0175 }
0176 }