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