xref: /third_party/alsa-lib/src/seq/seq_hw.c (revision d5ac70f0)
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 */
29const 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
36typedef struct {
37	int fd;
38	int version;
39} snd_seq_hw_t;
40#endif /* DOC_HIDDEN */
41
42static 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
55static 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
75static 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
86static 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
96static 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
110static 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
124static 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
136static 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
158static 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
181static 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
191static 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
201static 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
211static 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
221static 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
231static 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
241static 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
251static 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
261static 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
271static 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
281static 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
291static 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
301static 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
311static 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
321static 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
331static 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
341static 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
351static 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
361static 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
371static 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
381static 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
390static 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
399static 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
409static 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
419static 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
429static 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
443static 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
453static 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
490int 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
617int _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}
633SND_DLSYM_BUILD_VERSION(_snd_seq_hw_open, SND_SEQ_DLSYM_VERSION);
634