• 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 "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