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 <fcntl.h>
24 #include <sys/ioctl.h>
25 #include "seq_local.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 #define SNDRV_SEQ_VERSION_MAX SNDRV_PROTOCOL_VERSION(1, 0, 2)
36
37 typedef struct {
38 int fd;
39 int version;
40 } snd_seq_hw_t;
41 #endif /* DOC_HIDDEN */
42
snd_seq_hw_close(snd_seq_t * seq)43 static int snd_seq_hw_close(snd_seq_t *seq)
44 {
45 snd_seq_hw_t *hw = seq->private_data;
46 int err = 0;
47
48 if (close(hw->fd)) {
49 err = -errno;
50 SYSERR("close failed\n");
51 }
52 free(hw);
53 return err;
54 }
55
snd_seq_hw_nonblock(snd_seq_t * seq,int nonblock)56 static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock)
57 {
58 snd_seq_hw_t *hw = seq->private_data;
59 long flags;
60
61 if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
62 SYSERR("F_GETFL failed");
63 return -errno;
64 }
65 if (nonblock)
66 flags |= O_NONBLOCK;
67 else
68 flags &= ~O_NONBLOCK;
69 if (fcntl(hw->fd, F_SETFL, flags) < 0) {
70 SYSERR("F_SETFL for O_NONBLOCK failed");
71 return -errno;
72 }
73 return 0;
74 }
75
snd_seq_hw_client_id(snd_seq_t * seq)76 static int snd_seq_hw_client_id(snd_seq_t *seq)
77 {
78 snd_seq_hw_t *hw = seq->private_data;
79 int client;
80 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
81 SYSERR("SNDRV_SEQ_IOCTL_CLIENT_ID failed");
82 return -errno;
83 }
84 return client;
85 }
86
snd_seq_hw_system_info(snd_seq_t * seq,snd_seq_system_info_t * info)87 static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
88 {
89 snd_seq_hw_t *hw = seq->private_data;
90 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SYSTEM_INFO, info) < 0) {
91 SYSERR("SNDRV_SEQ_IOCTL_SYSTEM_INFO failed");
92 return -errno;
93 }
94 return 0;
95 }
96
snd_seq_hw_get_client_info(snd_seq_t * seq,snd_seq_client_info_t * info)97 static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
98 {
99 snd_seq_hw_t *hw = seq->private_data;
100 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) {
101 /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_INFO failed");*/
102 return -errno;
103 }
104 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) {
105 info->card = -1;
106 info->pid = -1;
107 }
108 return 0;
109 }
110
snd_seq_hw_set_client_info(snd_seq_t * seq,snd_seq_client_info_t * info)111 static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
112 {
113 snd_seq_hw_t *hw = seq->private_data;
114 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
115 /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_INFO failed");*/
116 return -errno;
117 }
118 return 0;
119 }
120
snd_seq_hw_create_port(snd_seq_t * seq,snd_seq_port_info_t * port)121 static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
122 {
123 snd_seq_hw_t *hw = seq->private_data;
124 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_PORT, port) < 0) {
125 /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_PORT failed");*/
126 return -errno;
127 }
128 return 0;
129 }
130
snd_seq_hw_delete_port(snd_seq_t * seq,snd_seq_port_info_t * port)131 static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
132 {
133 snd_seq_hw_t *hw = seq->private_data;
134 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_PORT, port) < 0) {
135 /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_PORT failed");*/
136 return -errno;
137 }
138 return 0;
139 }
140
snd_seq_hw_get_port_info(snd_seq_t * seq,snd_seq_port_info_t * info)141 static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
142 {
143 snd_seq_hw_t *hw = seq->private_data;
144 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_PORT_INFO, info) < 0) {
145 /*SYSERR("SNDRV_SEQ_IOCTL_GET_PORT_INFO failed");*/
146 return -errno;
147 }
148 return 0;
149 }
150
snd_seq_hw_set_port_info(snd_seq_t * seq,snd_seq_port_info_t * info)151 static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
152 {
153 snd_seq_hw_t *hw = seq->private_data;
154 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_PORT_INFO, info) < 0) {
155 /*SYSERR("SNDRV_SEQ_IOCTL_SET_PORT_INFO failed");*/
156 return -errno;
157 }
158 return 0;
159 }
160
snd_seq_hw_get_port_subscription(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)161 static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
162 {
163 snd_seq_hw_t *hw = seq->private_data;
164 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) {
165 /*SYSERR("SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION failed");*/
166 return -errno;
167 }
168 return 0;
169 }
170
snd_seq_hw_subscribe_port(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)171 static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
172 {
173 snd_seq_hw_t *hw = seq->private_data;
174 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) {
175 /*SYSERR("SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT failed");*/
176 return -errno;
177 }
178 return 0;
179 }
180
snd_seq_hw_unsubscribe_port(snd_seq_t * seq,snd_seq_port_subscribe_t * sub)181 static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
182 {
183 snd_seq_hw_t *hw = seq->private_data;
184 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) {
185 /*SYSERR("SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT failed");*/
186 return -errno;
187 }
188 return 0;
189 }
190
snd_seq_hw_query_port_subscribers(snd_seq_t * seq,snd_seq_query_subscribe_t * subs)191 static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs)
192 {
193 snd_seq_hw_t *hw = seq->private_data;
194 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_SUBS, subs) < 0) {
195 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_SUBS failed");*/
196 return -errno;
197 }
198 return 0;
199 }
200
snd_seq_hw_get_queue_status(snd_seq_t * seq,snd_seq_queue_status_t * status)201 static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status)
202 {
203 snd_seq_hw_t *hw = seq->private_data;
204 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) {
205 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS failed");*/
206 return -errno;
207 }
208 return 0;
209 }
210
snd_seq_hw_get_queue_tempo(snd_seq_t * seq,snd_seq_queue_tempo_t * tempo)211 static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
212 {
213 snd_seq_hw_t *hw = seq->private_data;
214 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) {
215 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
216 return -errno;
217 }
218 return 0;
219 }
220
snd_seq_hw_set_queue_tempo(snd_seq_t * seq,snd_seq_queue_tempo_t * tempo)221 static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
222 {
223 snd_seq_hw_t *hw = seq->private_data;
224 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
225 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
226 return -errno;
227 }
228 return 0;
229 }
230
snd_seq_hw_get_queue_timer(snd_seq_t * seq,snd_seq_queue_timer_t * timer)231 static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
232 {
233 snd_seq_hw_t *hw = seq->private_data;
234 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) {
235 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER failed");*/
236 return -errno;
237 }
238 return 0;
239 }
240
snd_seq_hw_set_queue_timer(snd_seq_t * seq,snd_seq_queue_timer_t * timer)241 static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
242 {
243 snd_seq_hw_t *hw = seq->private_data;
244 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) {
245 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER failed");*/
246 return -errno;
247 }
248 return 0;
249 }
250
snd_seq_hw_get_queue_client(snd_seq_t * seq,snd_seq_queue_client_t * info)251 static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
252 {
253 snd_seq_hw_t *hw = seq->private_data;
254 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) {
255 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT failed");*/
256 return -errno;
257 }
258 return 0;
259 }
260
snd_seq_hw_set_queue_client(snd_seq_t * seq,snd_seq_queue_client_t * info)261 static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
262 {
263 snd_seq_hw_t *hw = seq->private_data;
264 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) {
265 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT failed");*/
266 return -errno;
267 }
268 return 0;
269 }
270
snd_seq_hw_create_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)271 static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
272 {
273 snd_seq_hw_t *hw = seq->private_data;
274 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_CREATE_QUEUE, info) < 0) {
275 /*SYSERR("SNDRV_SEQ_IOCTL_CREATE_QUEUE failed");*/
276 return -errno;
277 }
278 return 0;
279 }
280
snd_seq_hw_delete_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)281 static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
282 {
283 snd_seq_hw_t *hw = seq->private_data;
284 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_DELETE_QUEUE, info) < 0) {
285 /*SYSERR("SNDRV_SEQ_IOCTL_DELETE_QUEUE failed");*/
286 return -errno;
287 }
288 return 0;
289 }
290
snd_seq_hw_get_queue_info(snd_seq_t * seq,snd_seq_queue_info_t * info)291 static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
292 {
293 snd_seq_hw_t *hw = seq->private_data;
294 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) {
295 /*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_INFO failed");*/
296 return -errno;
297 }
298 return 0;
299 }
300
snd_seq_hw_set_queue_info(snd_seq_t * seq,snd_seq_queue_info_t * info)301 static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
302 {
303 snd_seq_hw_t *hw = seq->private_data;
304 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) {
305 /*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_INFO failed");*/
306 return -errno;
307 }
308 return 0;
309 }
310
snd_seq_hw_get_named_queue(snd_seq_t * seq,snd_seq_queue_info_t * info)311 static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
312 {
313 snd_seq_hw_t *hw = seq->private_data;
314 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) {
315 /*SYSERR("SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE failed");*/
316 return -errno;
317 }
318 return 0;
319 }
320
snd_seq_hw_write(snd_seq_t * seq,void * buf,size_t len)321 static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len)
322 {
323 snd_seq_hw_t *hw = seq->private_data;
324 ssize_t result = write(hw->fd, buf, len);
325 if (result < 0)
326 return -errno;
327 return result;
328 }
329
snd_seq_hw_read(snd_seq_t * seq,void * buf,size_t len)330 static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len)
331 {
332 snd_seq_hw_t *hw = seq->private_data;
333 ssize_t result = read(hw->fd, buf, len);
334 if (result < 0)
335 return -errno;
336 return result;
337 }
338
snd_seq_hw_remove_events(snd_seq_t * seq,snd_seq_remove_events_t * rmp)339 static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
340 {
341 snd_seq_hw_t *hw = seq->private_data;
342 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) {
343 /*SYSERR("SNDRV_SEQ_IOCTL_REMOVE_EVENTS failed");*/
344 return -errno;
345 }
346 return 0;
347 }
348
snd_seq_hw_get_client_pool(snd_seq_t * seq,snd_seq_client_pool_t * info)349 static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
350 {
351 snd_seq_hw_t *hw = seq->private_data;
352 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) {
353 /*SYSERR("SNDRV_SEQ_IOCTL_GET_CLIENT_POOL failed");*/
354 return -errno;
355 }
356 return 0;
357 }
358
snd_seq_hw_set_client_pool(snd_seq_t * seq,snd_seq_client_pool_t * info)359 static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
360 {
361 snd_seq_hw_t *hw = seq->private_data;
362 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) {
363 /*SYSERR("SNDRV_SEQ_IOCTL_SET_CLIENT_POOL failed");*/
364 return -errno;
365 }
366 return 0;
367 }
368
snd_seq_hw_query_next_client(snd_seq_t * seq,snd_seq_client_info_t * info)369 static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
370 {
371 snd_seq_hw_t *hw = seq->private_data;
372 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) {
373 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT failed");*/
374 return -errno;
375 }
376 if (hw->version < SNDRV_PROTOCOL_VERSION(1, 0, 2)) {
377 info->card = -1;
378 info->pid = -1;
379 }
380 return 0;
381 }
382
snd_seq_hw_query_next_port(snd_seq_t * seq,snd_seq_port_info_t * info)383 static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
384 {
385 snd_seq_hw_t *hw = seq->private_data;
386 if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) {
387 /*SYSERR("SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT failed");*/
388 return -errno;
389 }
390 return 0;
391 }
392
393 static const snd_seq_ops_t snd_seq_hw_ops = {
394 .close = snd_seq_hw_close,
395 .nonblock = snd_seq_hw_nonblock,
396 .system_info = snd_seq_hw_system_info,
397 .get_client_info = snd_seq_hw_get_client_info,
398 .set_client_info = snd_seq_hw_set_client_info,
399 .create_port = snd_seq_hw_create_port,
400 .delete_port = snd_seq_hw_delete_port,
401 .get_port_info = snd_seq_hw_get_port_info,
402 .set_port_info = snd_seq_hw_set_port_info,
403 .get_port_subscription = snd_seq_hw_get_port_subscription,
404 .subscribe_port = snd_seq_hw_subscribe_port,
405 .unsubscribe_port = snd_seq_hw_unsubscribe_port,
406 .query_port_subscribers = snd_seq_hw_query_port_subscribers,
407 .get_queue_status = snd_seq_hw_get_queue_status,
408 .get_queue_tempo = snd_seq_hw_get_queue_tempo,
409 .set_queue_tempo = snd_seq_hw_set_queue_tempo,
410 .get_queue_timer = snd_seq_hw_get_queue_timer,
411 .set_queue_timer = snd_seq_hw_set_queue_timer,
412 .get_queue_client = snd_seq_hw_get_queue_client,
413 .set_queue_client = snd_seq_hw_set_queue_client,
414 .create_queue = snd_seq_hw_create_queue,
415 .delete_queue = snd_seq_hw_delete_queue,
416 .get_queue_info = snd_seq_hw_get_queue_info,
417 .set_queue_info = snd_seq_hw_set_queue_info,
418 .get_named_queue = snd_seq_hw_get_named_queue,
419 .write = snd_seq_hw_write,
420 .read = snd_seq_hw_read,
421 .remove_events = snd_seq_hw_remove_events,
422 .get_client_pool = snd_seq_hw_get_client_pool,
423 .set_client_pool = snd_seq_hw_set_client_pool,
424 .query_next_client = snd_seq_hw_query_next_client,
425 .query_next_port = snd_seq_hw_query_next_port,
426 };
427
snd_seq_hw_open(snd_seq_t ** handle,const char * name,int streams,int mode)428 int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
429 {
430 int fd, ver, client, fmode, ret;
431 const char *filename;
432 snd_seq_t *seq;
433 snd_seq_hw_t *hw;
434
435 *handle = NULL;
436
437 switch (streams) {
438 case SND_SEQ_OPEN_OUTPUT:
439 fmode = O_WRONLY;
440 break;
441 case SND_SEQ_OPEN_INPUT:
442 fmode = O_RDONLY;
443 break;
444 case SND_SEQ_OPEN_DUPLEX:
445 fmode = O_RDWR;
446 break;
447 default:
448 assert(0);
449 return -EINVAL;
450 }
451
452 if (mode & SND_SEQ_NONBLOCK)
453 fmode |= O_NONBLOCK;
454
455 filename = SNDRV_FILE_SEQ;
456 fd = snd_open_device(filename, fmode);
457 #ifdef SUPPORT_ALOAD
458 if (fd < 0) {
459 fd = snd_open_device(SNDRV_FILE_ALOADSEQ, fmode);
460 if (fd >= 0)
461 close(fd);
462 fd = snd_open_device(filename, fmode);
463 }
464 #endif
465 if (fd < 0) {
466 SYSERR("open %s failed", filename);
467 return -errno;
468 }
469 if (ioctl(fd, SNDRV_SEQ_IOCTL_PVERSION, &ver) < 0) {
470 SYSERR("SNDRV_SEQ_IOCTL_PVERSION failed");
471 ret = -errno;
472 close(fd);
473 return ret;
474 }
475 if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_SEQ_VERSION_MAX)) {
476 close(fd);
477 return -SND_ERROR_INCOMPATIBLE_VERSION;
478 }
479 hw = calloc(1, sizeof(snd_seq_hw_t));
480 if (hw == NULL) {
481 close(fd);
482 return -ENOMEM;
483 }
484
485 seq = calloc(1, sizeof(snd_seq_t));
486 if (seq == NULL) {
487 free(hw);
488 close(fd);
489 return -ENOMEM;
490 }
491 hw->fd = fd;
492 hw->version = ver;
493 if (streams & SND_SEQ_OPEN_OUTPUT) {
494 seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
495 if (!seq->obuf) {
496 free(hw);
497 free(seq);
498 close(fd);
499 return -ENOMEM;
500 }
501 }
502 if (streams & SND_SEQ_OPEN_INPUT) {
503 seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
504 if (!seq->ibuf) {
505 free(seq->obuf);
506 free(hw);
507 free(seq);
508 close(fd);
509 return -ENOMEM;
510 }
511 }
512 if (name)
513 seq->name = strdup(name);
514 seq->type = SND_SEQ_TYPE_HW;
515 seq->streams = streams;
516 seq->mode = mode;
517 seq->tmpbuf = NULL;
518 seq->tmpbufsize = 0;
519 seq->poll_fd = fd;
520 seq->ops = &snd_seq_hw_ops;
521 seq->private_data = hw;
522 client = snd_seq_hw_client_id(seq);
523 if (client < 0) {
524 snd_seq_close(seq);
525 return client;
526 } else
527 seq->client = client;
528
529 #ifdef SNDRV_SEQ_IOCTL_RUNNING_MODE
530 {
531 struct snd_seq_running_info run_mode;
532 /* check running mode */
533 memset(&run_mode, 0, sizeof(run_mode));
534 run_mode.client = client;
535 #ifdef SNDRV_BIG_ENDIAN
536 run_mode.big_endian = 1;
537 #else
538 run_mode.big_endian = 0;
539 #endif
540 run_mode.cpu_mode = sizeof(long);
541 ioctl(fd, SNDRV_SEQ_IOCTL_RUNNING_MODE, &run_mode);
542 }
543 #endif
544
545 *handle = seq;
546 return 0;
547 }
548
_snd_seq_hw_open(snd_seq_t ** handlep,char * name,snd_config_t * root ATTRIBUTE_UNUSED,snd_config_t * conf,int streams,int mode)549 int _snd_seq_hw_open(snd_seq_t **handlep, char *name,
550 snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
551 int streams, int mode)
552 {
553 snd_config_iterator_t i, next;
554 snd_config_for_each(i, next, conf) {
555 snd_config_t *n = snd_config_iterator_entry(i);
556 const char *id;
557 if (snd_config_get_id(n, &id) < 0)
558 continue;
559 if (_snd_conf_generic_id(id))
560 continue;
561 return -EINVAL;
562 }
563 return snd_seq_hw_open(handlep, name, streams, mode);
564 }
565 SND_DLSYM_BUILD_VERSION(_snd_seq_hw_open, SND_SEQ_DLSYM_VERSION);
566