1
2
3
4
5
6
7#include <linux/init.h>
8#include <linux/export.h>
9#include <linux/slab.h>
10#include <sound/core.h>
11#include "seq_system.h"
12#include "seq_timer.h"
13#include "seq_queue.h"
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47static int sysclient = -1;
48
49
50static int announce_port = -1;
51
52
53
54
55static int setheader(struct snd_seq_event * ev, int client, int port)
56{
57 if (announce_port < 0)
58 return -ENODEV;
59
60 memset(ev, 0, sizeof(struct snd_seq_event));
61
62 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
63 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
64
65 ev->source.client = sysclient;
66 ev->source.port = announce_port;
67 ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
68
69
70
71 ev->data.addr.client = client;
72 ev->data.addr.port = port;
73
74 return 0;
75}
76
77
78
79void snd_seq_system_broadcast(int client, int port, int type)
80{
81 struct snd_seq_event ev;
82
83 if (setheader(&ev, client, port) < 0)
84 return;
85 ev.type = type;
86 snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
87}
88
89
90int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
91{
92 ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
93 ev->source.client = sysclient;
94 ev->source.port = announce_port;
95 ev->dest.client = client;
96 ev->dest.port = port;
97 return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
98}
99
100
101static int event_input_timer(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
102{
103 return snd_seq_control_queue(ev, atomic, hop);
104}
105
106
107int __init snd_seq_system_client_init(void)
108{
109 struct snd_seq_port_callback pcallbacks;
110 struct snd_seq_port_info *port;
111 int err;
112
113 port = kzalloc(sizeof(*port), GFP_KERNEL);
114 if (!port)
115 return -ENOMEM;
116
117 memset(&pcallbacks, 0, sizeof(pcallbacks));
118 pcallbacks.owner = THIS_MODULE;
119 pcallbacks.event_input = event_input_timer;
120
121
122 sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
123 if (sysclient < 0) {
124 kfree(port);
125 return sysclient;
126 }
127
128
129 strcpy(port->name, "Timer");
130 port->capability = SNDRV_SEQ_PORT_CAP_WRITE;
131 port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ;
132 port->kernel = &pcallbacks;
133 port->type = 0;
134 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
135 port->addr.client = sysclient;
136 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
137 err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
138 port);
139 if (err < 0)
140 goto error_port;
141
142
143 strcpy(port->name, "Announce");
144 port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ;
145 port->kernel = NULL;
146 port->type = 0;
147 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
148 port->addr.client = sysclient;
149 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
150 err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
151 port);
152 if (err < 0)
153 goto error_port;
154 announce_port = port->addr.port;
155
156 kfree(port);
157 return 0;
158
159 error_port:
160 snd_seq_system_client_done();
161 kfree(port);
162 return err;
163}
164
165
166
167void snd_seq_system_client_done(void)
168{
169 int oldsysclient = sysclient;
170
171 if (oldsysclient >= 0) {
172 sysclient = -1;
173 announce_port = -1;
174 snd_seq_delete_kernel_client(oldsysclient);
175 }
176}
177