• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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