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