1 /*
2 * Sequencer Interface - main file
3 * Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
4 * Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 */
22
23 #include "seq_local.h"
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26
27 #ifndef PIC
28 /* entry for static linking */
29 const char *_snd_module_seq_hw = "";
30 #endif
31
32 #ifndef DOC_HIDDEN
33 #define SNDRV_FILE_SEQ ALSA_DEVICE_DIRECTORY "seq"
34 #define SNDRV_FILE_ALOADSEQ ALOAD_DEVICE_DIRECTORY "aloadSEQ"
35
36 typedef struct {
37 int fd;
38 int version;
39 } snd_seq_hw_t;
40 #endif /* DOC_HIDDEN */
41
snd_seq_hw_close(snd_seq_t * seq)42 static int snd_seq_hw_close(snd_seq_t *seq)
43 {
44 snd_seq_hw_t *hw = seq->private_data;
45 int err = 0;
46
47 if (close(hw->fd)) {
48 err = -errno;
49 SYSERR("close failed\n");
50 }
51 free(hw);
52 return err;
53 }
54
snd_seq_hw_nonblock(snd_seq_t * seq,int nonblock)55 static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock)
56 {
57 snd_seq_hw_t *hw = seq->private_data;
58 long flags;
59
60 if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
61 SYSERR("F_GETFL failed");
62 return -errno;
63 }
64 if (nonblock)
65 flags |= O_NONBLOCK;
66 else
67 flags &= ~O_NONBLOCK;
68 if (fcntl(hw->fd, F_SETFL, flags) < 0) {
69 SYSERR("F_SETFL for O_NONBLOCK failed");
70 return -errno;
71 }
72 return 0;
73 }
74
snd_seq_hw_client_id(snd_seq_t * seq)75 static int snd_seq_hw_client_id(snd_seq_t *seq)
76 {
77 snd_seq_hw_t *hw = seq->private_data;
78 int client;
79 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
80 SYSERR("SNDRV_SEQ_IOCTL_CLIENT_ID failed");
81 return -errno;
82 }
83 return client;
84 }
85
snd_seq_hw_system_info(snd_seq_t * seq,snd_seq_system_info_t * info)86 static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
87 {
88 snd_seq_hw_t *hw = seq->private_data;
89 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SYSTEM_INFO, info) < 0) {
90 SYSERR("SNDRV_SEQ_IOCTL_SYSTEM_INFO failed");
91 return -errno;
92 }
93 return 0;
94 }
95
update_midi_version(snd_seq_t * seq,snd_seq_client_info_t * info)96 static void update_midi_version(snd_seq_t *seq, snd_seq_client_info_t *info)
97 {
98 snd_seq_hw_t *hw = seq->private_data;
99
100 if (SNDRV_PROTOCOL_VERSION(1, 0, 3) <= hw->version &&
101 seq->midi_version != (int)info->midi_version) {
102 seq->midi_version = info->midi_version;
103 if (info->midi_version > 0)
104 seq->packet_size = sizeof(snd_seq_ump_event_t);
105 else
106 seq->packet_size = sizeof(snd_seq_event_t);
107 }
108 }
109
snd_seq_hw_get_client_info(snd_seq_t * seq,snd_seq_client_info_t * info)110 static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
111 {
112 snd_seq_hw_t *hw = seq->private_data;
113 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) {
114 /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_INFO failed");*/
115 return -errno;
116 }
117 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) {
118 info->card = -1;
119 info->pid = -1;
120 }
121 return 0;
122 }
123
snd_seq_hw_set_client_info(snd_seq_t * seq,snd_seq_client_info_t * info)124 static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
125 {
126 snd_seq_hw_t *hw = seq->private_data;
127
128 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
129 /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/
130 return -errno;
131 }
132 update_midi_version(seq, info);
133 return 0;
134 }
135
snd_seq_hw_get_ump_info(snd_seq_t * seq,int client,int type,void * info)136 static int snd_seq_hw_get_ump_info(snd_seq_t *seq, int client, int type, void *info)
137 {
138 snd_seq_hw_t *hw = seq->private_data;
139 struct snd_seq_client_ump_info buf;
140 size_t size;
141
142 if (type < 0 || type >= SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + 32)
143 return -EINVAL;
144 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 3))
145 return -ENOTTY;
146 if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
147 size = sizeof(struct snd_ump_endpoint_info);
148 else
149 size = sizeof(struct snd_ump_block_info);
150 buf.client = client;
151 buf.type = type;
152 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO, &buf) < 0)
153 return -errno;
154 memcpy(info, buf.info, size);
155 return 0;
156 }
157
snd_seq_hw_set_ump_info(snd_seq_t * seq,int type,const void * info)158 static int snd_seq_hw_set_ump_info(snd_seq_t *seq, int type, const void *info)
159 {
160 snd_seq_hw_t *hw = seq->private_data;
161 struct snd_seq_client_ump_info buf;
162 size_t size;
163
164 if (type < 0 || type >= SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK + 32)
165 return -EINVAL;
166 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 3))
167 return -ENOTTY;
168 if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
169 size = sizeof(struct snd_ump_endpoint_info);
170 else
171 size = sizeof(struct snd_ump_block_info);
172 buf.client = seq->client;
173 buf.type = type;
174 memcpy(buf.info, info, size);
175 *(int *)buf.info = -1; /* invalidate the card number */
176 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO, &buf) < 0)
177 return -errno;
178 return 0;
179 }
180
snd_seq_hw_create_port(snd_seq_t * seq,snd_seq_port_info_t * port)181 static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
182 {
183 snd_seq_hw_t *hw = seq->private_data;
184 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_PORT, port) < 0) {
185 /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_PORT failed");*/
186 return -errno;
187 }
188 return 0;
189 }
190
snd_seq_hw_delete_port(snd_seq_t * seq,snd_seq_port_info_t * port)191 static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
192 {
193 snd_seq_hw_t *hw = seq->private_data;
194 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_PORT, port) < 0) {
195 /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_PORT failed");*/
196 return -errno;
197 }
198 return 0;
199 }
200
snd_seq_hw_get_port_info(snd_seq_t * seq,snd_seq_port_info_t * info)201 static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
202 {
203 snd_seq_hw_t *hw = seq->private_data;
204 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_PORT_INFO, info) < 0) {
205 /*SYSERR("SNDRV_SEQ_IOCTL_GET_PORT_INFO failed");*/
206 return -errno;
207 }
208 return 0;
209 }
210
snd_seq_hw_set_port_info(snd_seq_t * seq,snd_seq_port_info_t * info)211 static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
212 {
213 snd_seq_hw_t *hw = seq->private_data;
214 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_PORT_INFO, info) < 0) {
215 /*SYSERR("SNDRV_SEQ_IOCTL_SET_PORT_INFO failed");*/
216 return -errno;
217 }
218 return 0;
219 }
220
snd_seq_hw_get_port_subscription(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)221 static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
222 {
223 snd_seq_hw_t *hw = seq->private_data;
224 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) {
225 /*SYSERR("SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION failed");*/
226 return -errno;
227 }
228 return 0;
229 }
230
snd_seq_hw_subscribe_port(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)231 static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
232 {
233 snd_seq_hw_t *hw = seq->private_data;
234 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) {
235 /*SYSERR("SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT failed");*/
236 return -errno;
237 }
238 return 0;
239 }
240
snd_seq_hw_unsubscribe_port(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)241 static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
242 {
243 snd_seq_hw_t *hw = seq->private_data;
244 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) {
245 /*SYSERR("SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT failed");*/
246 return -errno;
247 }
248 return 0;
249 }
250
snd_seq_hw_query_port_subscribers(snd_seq_t * seq,snd_seq_query_subscribe_t * subs)251 static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs)
252 {
253 snd_seq_hw_t *hw = seq->private_data;
254 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_SUBS, subs) < 0) {
255 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_SUBS failed");*/
256 return -errno;
257 }
258 return 0;
259 }
260
snd_seq_hw_get_queue_status(snd_seq_t * seq,snd_seq_queue_status_t * status)261 static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status)
262 {
263 snd_seq_hw_t *hw = seq->private_data;
264 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) {
265 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS failed");*/
266 return -errno;
267 }
268 return 0;
269 }
270
snd_seq_hw_get_queue_tempo(snd_seq_t * seq,snd_seq_queue_tempo_t * tempo)271 static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
272 {
273 snd_seq_hw_t *hw = seq->private_data;
274 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) {
275 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
276 return -errno;
277 }
278 return 0;
279 }
280
snd_seq_hw_set_queue_tempo(snd_seq_t * seq,snd_seq_queue_tempo_t * tempo)281 static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
282 {
283 snd_seq_hw_t *hw = seq->private_data;
284 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
285 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
286 return -errno;
287 }
288 return 0;
289 }
290
snd_seq_hw_get_queue_timer(snd_seq_t * seq,snd_seq_queue_timer_t * timer)291 static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
292 {
293 snd_seq_hw_t *hw = seq->private_data;
294 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) {
295 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER failed");*/
296 return -errno;
297 }
298 return 0;
299 }
300
snd_seq_hw_set_queue_timer(snd_seq_t * seq,snd_seq_queue_timer_t * timer)301 static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
302 {
303 snd_seq_hw_t *hw = seq->private_data;
304 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) {
305 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER failed");*/
306 return -errno;
307 }
308 return 0;
309 }
310
snd_seq_hw_get_queue_client(snd_seq_t * seq,snd_seq_queue_client_t * info)311 static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
312 {
313 snd_seq_hw_t *hw = seq->private_data;
314 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) {
315 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT failed");*/
316 return -errno;
317 }
318 return 0;
319 }
320
snd_seq_hw_set_queue_client(snd_seq_t * seq,snd_seq_queue_client_t * info)321 static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
322 {
323 snd_seq_hw_t *hw = seq->private_data;
324 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) {
325 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT failed");*/
326 return -errno;
327 }
328 return 0;
329 }
330
snd_seq_hw_create_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)331 static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
332 {
333 snd_seq_hw_t *hw = seq->private_data;
334 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_QUEUE, info) < 0) {
335 /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_QUEUE failed");*/
336 return -errno;
337 }
338 return 0;
339 }
340
snd_seq_hw_delete_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)341 static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
342 {
343 snd_seq_hw_t *hw = seq->private_data;
344 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_QUEUE, info) < 0) {
345 /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_QUEUE failed");*/
346 return -errno;
347 }
348 return 0;
349 }
350
snd_seq_hw_get_queue_info(snd_seq_t * seq,snd_seq_queue_info_t * info)351 static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
352 {
353 snd_seq_hw_t *hw = seq->private_data;
354 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) {
355 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_INFO failed");*/
356 return -errno;
357 }
358 return 0;
359 }
360
snd_seq_hw_set_queue_info(snd_seq_t * seq,snd_seq_queue_info_t * info)361 static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
362 {
363 snd_seq_hw_t *hw = seq->private_data;
364 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) {
365 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_INFO failed");*/
366 return -errno;
367 }
368 return 0;
369 }
370
snd_seq_hw_get_named_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)371 static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
372 {
373 snd_seq_hw_t *hw = seq->private_data;
374 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) {
375 /*SYSERR("SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE failed");*/
376 return -errno;
377 }
378 return 0;
379 }
380
snd_seq_hw_write(snd_seq_t * seq,void * buf,size_t len)381 static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len)
382 {
383 snd_seq_hw_t *hw = seq->private_data;
384 ssize_t result = write(hw->fd, buf, len);
385 if (result < 0)
386 return -errno;
387 return result;
388 }
389
snd_seq_hw_read(snd_seq_t * seq,void * buf,size_t len)390 static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len)
391 {
392 snd_seq_hw_t *hw = seq->private_data;
393 ssize_t result = read(hw->fd, buf, len);
394 if (result < 0)
395 return -errno;
396 return result;
397 }
398
snd_seq_hw_remove_events(snd_seq_t * seq,snd_seq_remove_events_t * rmp)399 static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
400 {
401 snd_seq_hw_t *hw = seq->private_data;
402 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) {
403 /*SYSERR("SNDRV_SEQ_IOCTL_REMOVE_EVENTS failed");*/
404 return -errno;
405 }
406 return 0;
407 }
408
snd_seq_hw_get_client_pool(snd_seq_t * seq,snd_seq_client_pool_t * info)409 static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
410 {
411 snd_seq_hw_t *hw = seq->private_data;
412 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) {
413 /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_POOL failed");*/
414 return -errno;
415 }
416 return 0;
417 }
418
snd_seq_hw_set_client_pool(snd_seq_t * seq,snd_seq_client_pool_t * info)419 static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
420 {
421 snd_seq_hw_t *hw = seq->private_data;
422 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) {
423 /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_POOL failed");*/
424 return -errno;
425 }
426 return 0;
427 }
428
snd_seq_hw_query_next_client(snd_seq_t * seq,snd_seq_client_info_t * info)429 static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
430 {
431 snd_seq_hw_t *hw = seq->private_data;
432 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) {
433 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT failed");*/
434 return -errno;
435 }
436 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) {
437 info->card = -1;
438 info->pid = -1;
439 }
440 return 0;
441 }
442
snd_seq_hw_query_next_port(snd_seq_t * seq,snd_seq_port_info_t * info)443 static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
444 {
445 snd_seq_hw_t *hw = seq->private_data;
446 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) {
447 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT failed");*/
448 return -errno;
449 }
450 return 0;
451 }
452
453 static const snd_seq_ops_t snd_seq_hw_ops = {
454 .close = snd_seq_hw_close,
455 .nonblock = snd_seq_hw_nonblock,
456 .system_info = snd_seq_hw_system_info,
457 .get_client_info = snd_seq_hw_get_client_info,
458 .set_client_info = snd_seq_hw_set_client_info,
459 .get_ump_info = snd_seq_hw_get_ump_info,
460 .set_ump_info = snd_seq_hw_set_ump_info,
461 .create_port = snd_seq_hw_create_port,
462 .delete_port = snd_seq_hw_delete_port,
463 .get_port_info = snd_seq_hw_get_port_info,
464 .set_port_info = snd_seq_hw_set_port_info,
465 .get_port_subscription = snd_seq_hw_get_port_subscription,
466 .subscribe_port = snd_seq_hw_subscribe_port,
467 .unsubscribe_port = snd_seq_hw_unsubscribe_port,
468 .query_port_subscribers = snd_seq_hw_query_port_subscribers,
469 .get_queue_status = snd_seq_hw_get_queue_status,
470 .get_queue_tempo = snd_seq_hw_get_queue_tempo,
471 .set_queue_tempo = snd_seq_hw_set_queue_tempo,
472 .get_queue_timer = snd_seq_hw_get_queue_timer,
473 .set_queue_timer = snd_seq_hw_set_queue_timer,
474 .get_queue_client = snd_seq_hw_get_queue_client,
475 .set_queue_client = snd_seq_hw_set_queue_client,
476 .create_queue = snd_seq_hw_create_queue,
477 .delete_queue = snd_seq_hw_delete_queue,
478 .get_queue_info = snd_seq_hw_get_queue_info,
479 .set_queue_info = snd_seq_hw_set_queue_info,
480 .get_named_queue = snd_seq_hw_get_named_queue,
481 .write = snd_seq_hw_write,
482 .read = snd_seq_hw_read,
483 .remove_events = snd_seq_hw_remove_events,
484 .get_client_pool = snd_seq_hw_get_client_pool,
485 .set_client_pool = snd_seq_hw_set_client_pool,
486 .query_next_client = snd_seq_hw_query_next_client,
487 .query_next_port = snd_seq_hw_query_next_port,
488 };
489
snd_seq_hw_open(snd_seq_t ** handle,const char * name,int streams,int mode)490 int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
491 {
492 int fd, ver, client, fmode, ret;
493 const char *filename;
494 snd_seq_t *seq;
495 snd_seq_hw_t *hw;
496
497 *handle = NULL;
498
499 switch (streams) {
500 case SND_SEQ_OPEN_OUTPUT:
501 fmode = O_WRONLY;
502 break;
503 case SND_SEQ_OPEN_INPUT:
504 fmode = O_RDONLY;
505 break;
506 case SND_SEQ_OPEN_DUPLEX:
507 fmode = O_RDWR;
508 break;
509 default:
510 assert(0);
511 return -EINVAL;
512 }
513
514 if (mode & SND_SEQ_NONBLOCK)
515 fmode |= O_NONBLOCK;
516
517 filename = SNDRV_FILE_SEQ;
518 fd = snd_open_device(filename, fmode);
519 #ifdef SUPPORT_ALOAD
520 if (fd < 0) {
521 fd = snd_open_device(SNDRV_FILE_ALOADSEQ, fmode);
522 if (fd >= 0)
523 close(fd);
524 fd = snd_open_device(filename, fmode);
525 }
526 #endif
527 if (fd < 0) {
528 SYSERR("open %s failed", filename);
529 return -errno;
530 }
531 if (ioctl(fd, SNDRV_SEQ_IOCTL_PVERSION, &ver) < 0) {
532 SYSERR("SNDRV_SEQ_IOCTL_PVERSION failed");
533 ret = -errno;
534 close(fd);
535 return ret;
536 }
537 if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_SEQ_VERSION)) {
538 close(fd);
539 return -SND_ERROR_INCOMPATIBLE_VERSION;
540 }
541 if (SNDRV_PROTOCOL_VERSION(1, 0, 3) <= ver) {
542 /* inform the protocol version we're supporting */
543 unsigned int user_ver = SNDRV_SEQ_VERSION;
544 ioctl(fd, SNDRV_SEQ_IOCTL_USER_PVERSION, &user_ver);
545 }
546 hw = calloc(1, sizeof(snd_seq_hw_t));
547 if (hw == NULL) {
548 close(fd);
549 return -ENOMEM;
550 }
551
552 seq = calloc(1, sizeof(snd_seq_t));
553 if (seq == NULL) {
554 free(hw);
555 close(fd);
556 return -ENOMEM;
557 }
558 hw->fd = fd;
559 hw->version = ver;
560 if (streams & SND_SEQ_OPEN_OUTPUT) {
561 seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
562 if (!seq->obuf) {
563 free(hw);
564 free(seq);
565 close(fd);
566 return -ENOMEM;
567 }
568 }
569 if (streams & SND_SEQ_OPEN_INPUT) {
570 seq->ibuf = (char *) calloc(sizeof(snd_seq_ump_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
571 if (!seq->ibuf) {
572 free(seq->obuf);
573 free(hw);
574 free(seq);
575 close(fd);
576 return -ENOMEM;
577 }
578 }
579 if (name)
580 seq->name = strdup(name);
581 seq->type = SND_SEQ_TYPE_HW;
582 seq->streams = streams;
583 seq->mode = mode;
584 seq->tmpbuf = NULL;
585 seq->tmpbufsize = 0;
586 seq->poll_fd = fd;
587 seq->ops = &snd_seq_hw_ops;
588 seq->private_data = hw;
589 seq->packet_size = sizeof(snd_seq_event_t);
590 client = snd_seq_hw_client_id(seq);
591 if (client < 0) {
592 snd_seq_close(seq);
593 return client;
594 } else
595 seq->client = client;
596
597 #ifdef SNDRV_SEQ_IOCTL_RUNNING_MODE
598 {
599 struct snd_seq_running_info run_mode;
600 /* check running mode */
601 memset(&run_mode, 0, sizeof(run_mode));
602 run_mode.client = client;
603 #ifdef SNDRV_BIG_ENDIAN
604 run_mode.big_endian = 1;
605 #else
606 run_mode.big_endian = 0;
607 #endif
608 run_mode.cpu_mode = sizeof(long);
609 ioctl(fd, SNDRV_SEQ_IOCTL_RUNNING_MODE, &run_mode);
610 }
611 #endif
612
613 *handle = seq;
614 return 0;
615 }
616
_snd_seq_hw_open(snd_seq_t ** handlep,char * name,snd_config_t * root ATTRIBUTE_UNUSED,snd_config_t * conf,int streams,int mode)617 int _snd_seq_hw_open(snd_seq_t **handlep, char *name,
618 snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
619 int streams, int mode)
620 {
621 snd_config_iterator_t i, next;
622 snd_config_for_each(i, next, conf) {
623 snd_config_t *n = snd_config_iterator_entry(i);
624 const char *id;
625 if (snd_config_get_id(n, &id) < 0)
626 continue;
627 if (_snd_conf_generic_id(id))
628 continue;
629 return -EINVAL;
630 }
631 return snd_seq_hw_open(handlep, name, streams, mode);
632 }
633 SND_DLSYM_BUILD_VERSION(_snd_seq_hw_open, SND_SEQ_DLSYM_VERSION);
634