1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ALSA sequencer Timing queue handling 4 * Copyright (c) 1998-1999 by Frank van de Pol <[email protected]> 5 * 6 * MAJOR CHANGES 7 * Nov. 13, 1999 Takashi Iwai <[email protected]> 8 * - Queues are allocated dynamically via ioctl. 9 * - When owner client is deleted, all owned queues are deleted, too. 10 * - Owner of unlocked queue is kept unmodified even if it is 11 * manipulated by other clients. 12 * - Owner field in SET_QUEUE_OWNER ioctl must be identical with the 13 * caller client. i.e. Changing owner to a third client is not 14 * allowed. 15 * 16 * Aug. 30, 2000 Takashi Iwai 17 * - Queues are managed in static array again, but with better way. 18 * The API itself is identical. 19 * - The queue is locked when struct snd_seq_queue pointer is returned via 20 * queueptr(). This pointer *MUST* be released afterward by 21 * queuefree(ptr). 22 * - Addition of experimental sync support. 23 */ 24 25 #include <linux/init.h> 26 #include <linux/slab.h> 27 #include <sound/core.h> 28 29 #include "seq_memory.h" 30 #include "seq_queue.h" 31 #include "seq_clientmgr.h" 32 #include "seq_fifo.h" 33 #include "seq_timer.h" 34 #include "seq_info.h" 35 36 /* list of allocated queues */ 37 static struct snd_seq_queue *queue_list[SNDRV_SEQ_MAX_QUEUES]; 38 static DEFINE_SPINLOCK(queue_list_lock); 39 /* number of queues allocated */ 40 static int num_queues; 41 42 int snd_seq_queue_get_cur_queues(void) 43 { 44 return num_queues; 45 } 46 47 /*----------------------------------------------------------------*/ 48 49 /* assign queue id and insert to list */ 50 static int queue_list_add(struct snd_seq_queue *q) 51 { 52 int i; 53 unsigned long flags; 54 55 spin_lock_irqsave(&queue_list_lock, flags); 56 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 57 if (! queue_list[i]) { 58 queue_list[i] = q; 59 q->queue = i; 60 num_queues++; 61 spin_unlock_irqrestore(&queue_list_lock, flags); 62 return i; 63 } 64 } 65 spin_unlock_irqrestore(&queue_list_lock, flags); 66 return -1; 67 } 68 69 static struct snd_seq_queue *queue_list_remove(int id, int client) 70 { 71 struct snd_seq_queue *q; 72 unsigned long flags; 73 74 spin_lock_irqsave(&queue_list_lock, flags); 75 q = queue_list[id]; 76 if (q) { 77 spin_lock(&q->owner_lock); 78 if (q->owner == client) { 79 /* found */ 80 q->klocked = 1; 81 spin_unlock(&q->owner_lock); 82 queue_list[id] = NULL; 83 num_queues--; 84 spin_unlock_irqrestore(&queue_list_lock, flags); 85 return q; 86 } 87 spin_unlock(&q->owner_lock); 88 } 89 spin_unlock_irqrestore(&queue_list_lock, flags); 90 return NULL; 91 } 92 93 /*----------------------------------------------------------------*/ 94 95 /* create new queue (constructor) */ 96 static struct snd_seq_queue *queue_new(int owner, int locked) 97 { 98 struct snd_seq_queue *q; 99 100 q = kzalloc(sizeof(*q), GFP_KERNEL); 101 if (!q) 102 return NULL; 103 104 spin_lock_init(&q->owner_lock); 105 spin_lock_init(&q->check_lock); 106 mutex_init(&q->timer_mutex); 107 snd_use_lock_init(&q->use_lock); 108 q->queue = -1; 109 110 q->tickq = snd_seq_prioq_new(); 111 q->timeq = snd_seq_prioq_new(); 112 q->timer = snd_seq_timer_new(); 113 if (q->tickq == NULL || q->timeq == NULL || q->timer == NULL) { 114 snd_seq_prioq_delete(&q->tickq); 115 snd_seq_prioq_delete(&q->timeq); 116 snd_seq_timer_delete(&q->timer); 117 kfree(q); 118 return NULL; 119 } 120 121 q->owner = owner; 122 q->locked = locked; 123 q->klocked = 0; 124 125 return q; 126 } 127 128 /* delete queue (destructor) */ 129 static void queue_delete(struct snd_seq_queue *q) 130 { 131 /* stop and release the timer */ 132 mutex_lock(&q->timer_mutex); 133 snd_seq_timer_stop(q->timer); 134 snd_seq_timer_close(q); 135 mutex_unlock(&q->timer_mutex); 136 /* wait until access free */ 137 snd_use_lock_sync(&q->use_lock); 138 /* release resources... */ 139 snd_seq_prioq_delete(&q->tickq); 140 snd_seq_prioq_delete(&q->timeq); 141 snd_seq_timer_delete(&q->timer); 142 143 kfree(q); 144 } 145 146 147 /*----------------------------------------------------------------*/ 148 149 /* delete all existing queues */ 150 void snd_seq_queues_delete(void) 151 { 152 int i; 153 154 /* clear list */ 155 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 156 if (queue_list[i]) 157 queue_delete(queue_list[i]); 158 } 159 } 160 161 static void queue_use(struct snd_seq_queue *queue, int client, int use); 162 163 /* allocate a new queue - 164 * return pointer to new queue or ERR_PTR(-errno) for error 165 * The new queue's use_lock is set to 1. It is the caller's responsibility to 166 * call snd_use_lock_free(&q->use_lock). 167 */ 168 struct snd_seq_queue *snd_seq_queue_alloc(int client, int locked, unsigned int info_flags) 169 { 170 struct snd_seq_queue *q; 171 172 q = queue_new(client, locked); 173 if (q == NULL) 174 return ERR_PTR(-ENOMEM); 175 q->info_flags = info_flags; 176 queue_use(q, client, 1); 177 snd_use_lock_use(&q->use_lock); 178 if (queue_list_add(q) < 0) { 179 snd_use_lock_free(&q->use_lock); 180 queue_delete(q); 181 return ERR_PTR(-ENOMEM); 182 } 183 return q; 184 } 185 186 /* delete a queue - queue must be owned by the client */ 187 int snd_seq_queue_delete(int client, int queueid) 188 { 189 struct snd_seq_queue *q; 190 191 if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) 192 return -EINVAL; 193 q = queue_list_remove(queueid, client); 194 if (q == NULL) 195 return -EINVAL; 196 queue_delete(q); 197 198 return 0; 199 } 200 201 202 /* return pointer to queue structure for specified id */ 203 struct snd_seq_queue *queueptr(int queueid) 204 { 205 struct snd_seq_queue *q; 206 unsigned long flags; 207 208 if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) 209 return NULL; 210 spin_lock_irqsave(&queue_list_lock, flags); 211 q = queue_list[queueid]; 212 if (q) 213 snd_use_lock_use(&q->use_lock); 214 spin_unlock_irqrestore(&queue_list_lock, flags); 215 return q; 216 } 217 218 /* return the (first) queue matching with the specified name */ 219 struct snd_seq_queue *snd_seq_queue_find_name(char *name) 220 { 221 int i; 222 struct snd_seq_queue *q; 223 224 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 225 if ((q = queueptr(i)) != NULL) { 226 if (strncmp(q->name, name, sizeof(q->name)) == 0) 227 return q; 228 queuefree(q); 229 } 230 } 231 return NULL; 232 } 233 234 235 /* -------------------------------------------------------- */ 236 237 void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) 238 { 239 unsigned long flags; 240 struct snd_seq_event_cell *cell; 241 242 if (q == NULL) 243 return; 244 245 /* make this function non-reentrant */ 246 spin_lock_irqsave(&q->check_lock, flags); 247 if (q->check_blocked) { 248 q->check_again = 1; 249 spin_unlock_irqrestore(&q->check_lock, flags); 250 return; /* other thread is already checking queues */ 251 } 252 q->check_blocked = 1; 253 spin_unlock_irqrestore(&q->check_lock, flags); 254 255 __again: 256 /* Process tick queue... */ 257 for (;;) { 258 cell = snd_seq_prioq_cell_out(q->tickq, 259 &q->timer->tick.cur_tick); 260 if (!cell) 261 break; 262 snd_seq_dispatch_event(cell, atomic, hop); 263 } 264 265 /* Process time queue... */ 266 for (;;) { 267 cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time); 268 if (!cell) 269 break; 270 snd_seq_dispatch_event(cell, atomic, hop); 271 } 272 273 /* free lock */ 274 spin_lock_irqsave(&q->check_lock, flags); 275 if (q->check_again) { 276 q->check_again = 0; 277 spin_unlock_irqrestore(&q->check_lock, flags); 278 goto __again; 279 } 280 q->check_blocked = 0; 281 spin_unlock_irqrestore(&q->check_lock, flags); 282 } 283 284 285 /* enqueue a event to singe queue */ 286 int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop) 287 { 288 int dest, err; 289 struct snd_seq_queue *q; 290 291 if (snd_BUG_ON(!cell)) 292 return -EINVAL; 293 dest = cell->event.queue; /* destination queue */ 294 q = queueptr(dest); 295 if (q == NULL) 296 return -EINVAL; 297 /* handle relative time stamps, convert them into absolute */ 298 if ((cell->event.flags & SNDRV_SEQ_TIME_MODE_MASK) == SNDRV_SEQ_TIME_MODE_REL) { 299 switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { 300 case SNDRV_SEQ_TIME_STAMP_TICK: 301 cell->event.time.tick += q->timer->tick.cur_tick; 302 break; 303 304 case SNDRV_SEQ_TIME_STAMP_REAL: 305 snd_seq_inc_real_time(&cell->event.time.time, 306 &q->timer->cur_time); 307 break; 308 } 309 cell->event.flags &= ~SNDRV_SEQ_TIME_MODE_MASK; 310 cell->event.flags |= SNDRV_SEQ_TIME_MODE_ABS; 311 } 312 /* enqueue event in the real-time or midi queue */ 313 switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { 314 case SNDRV_SEQ_TIME_STAMP_TICK: 315 err = snd_seq_prioq_cell_in(q->tickq, cell); 316 break; 317 318 case SNDRV_SEQ_TIME_STAMP_REAL: 319 default: 320 err = snd_seq_prioq_cell_in(q->timeq, cell); 321 break; 322 } 323 324 if (err < 0) { 325 queuefree(q); /* unlock */ 326 return err; 327 } 328 329 /* trigger dispatching */ 330 snd_seq_check_queue(q, atomic, hop); 331 332 queuefree(q); /* unlock */ 333 334 return 0; 335 } 336 337 338 /*----------------------------------------------------------------*/ 339 340 static inline int check_access(struct snd_seq_queue *q, int client) 341 { 342 return (q->owner == client) || (!q->locked && !q->klocked); 343 } 344 345 /* check if the client has permission to modify queue parameters. 346 * if it does, lock the queue 347 */ 348 static int queue_access_lock(struct snd_seq_queue *q, int client) 349 { 350 unsigned long flags; 351 int access_ok; 352 353 spin_lock_irqsave(&q->owner_lock, flags); 354 access_ok = check_access(q, client); 355 if (access_ok) 356 q->klocked = 1; 357 spin_unlock_irqrestore(&q->owner_lock, flags); 358 return access_ok; 359 } 360 361 /* unlock the queue */ 362 static inline void queue_access_unlock(struct snd_seq_queue *q) 363 { 364 unsigned long flags; 365 366 spin_lock_irqsave(&q->owner_lock, flags); 367 q->klocked = 0; 368 spin_unlock_irqrestore(&q->owner_lock, flags); 369 } 370 371 /* exported - only checking permission */ 372 int snd_seq_queue_check_access(int queueid, int client) 373 { 374 struct snd_seq_queue *q = queueptr(queueid); 375 int access_ok; 376 unsigned long flags; 377 378 if (! q) 379 return 0; 380 spin_lock_irqsave(&q->owner_lock, flags); 381 access_ok = check_access(q, client); 382 spin_unlock_irqrestore(&q->owner_lock, flags); 383 queuefree(q); 384 return access_ok; 385 } 386 387 /*----------------------------------------------------------------*/ 388 389 /* 390 * change queue's owner and permission 391 */ 392 int snd_seq_queue_set_owner(int queueid, int client, int locked) 393 { 394 struct snd_seq_queue *q = queueptr(queueid); 395 unsigned long flags; 396 397 if (q == NULL) 398 return -EINVAL; 399 400 if (! queue_access_lock(q, client)) { 401 queuefree(q); 402 return -EPERM; 403 } 404 405 spin_lock_irqsave(&q->owner_lock, flags); 406 q->locked = locked ? 1 : 0; 407 q->owner = client; 408 spin_unlock_irqrestore(&q->owner_lock, flags); 409 queue_access_unlock(q); 410 queuefree(q); 411 412 return 0; 413 } 414 415 416 /*----------------------------------------------------------------*/ 417 418 /* open timer - 419 * q->use mutex should be down before calling this function to avoid 420 * confliction with snd_seq_queue_use() 421 */ 422 int snd_seq_queue_timer_open(int queueid) 423 { 424 int result = 0; 425 struct snd_seq_queue *queue; 426 struct snd_seq_timer *tmr; 427 428 queue = queueptr(queueid); 429 if (queue == NULL) 430 return -EINVAL; 431 tmr = queue->timer; 432 if ((result = snd_seq_timer_open(queue)) < 0) { 433 snd_seq_timer_defaults(tmr); 434 result = snd_seq_timer_open(queue); 435 } 436 queuefree(queue); 437 return result; 438 } 439 440 /* close timer - 441 * q->use mutex should be down before calling this function 442 */ 443 int snd_seq_queue_timer_close(int queueid) 444 { 445 struct snd_seq_queue *queue; 446 int result = 0; 447 448 queue = queueptr(queueid); 449 if (queue == NULL) 450 return -EINVAL; 451 snd_seq_timer_close(queue); 452 queuefree(queue); 453 return result; 454 } 455 456 /* change queue tempo and ppq */ 457 int snd_seq_queue_timer_set_tempo(int queueid, int client, 458 struct snd_seq_queue_tempo *info) 459 { 460 struct snd_seq_queue *q = queueptr(queueid); 461 int result; 462 463 if (q == NULL) 464 return -EINVAL; 465 if (! queue_access_lock(q, client)) { 466 queuefree(q); 467 return -EPERM; 468 } 469 470 result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq); 471 if (result >= 0 && info->skew_base > 0) 472 result = snd_seq_timer_set_skew(q->timer, info->skew_value, 473 info->skew_base); 474 queue_access_unlock(q); 475 queuefree(q); 476 return result; 477 } 478 479 /* use or unuse this queue */ 480 static void queue_use(struct snd_seq_queue *queue, int client, int use) 481 { 482 if (use) { 483 if (!test_and_set_bit(client, queue->clients_bitmap)) 484 queue->clients++; 485 } else { 486 if (test_and_clear_bit(client, queue->clients_bitmap)) 487 queue->clients--; 488 } 489 if (queue->clients) { 490 if (use && queue->clients == 1) 491 snd_seq_timer_defaults(queue->timer); 492 snd_seq_timer_open(queue); 493 } else { 494 snd_seq_timer_close(queue); 495 } 496 } 497 498 /* use or unuse this queue - 499 * if it is the first client, starts the timer. 500 * if it is not longer used by any clients, stop the timer. 501 */ 502 int snd_seq_queue_use(int queueid, int client, int use) 503 { 504 struct snd_seq_queue *queue; 505 506 queue = queueptr(queueid); 507 if (queue == NULL) 508 return -EINVAL; 509 mutex_lock(&queue->timer_mutex); 510 queue_use(queue, client, use); 511 mutex_unlock(&queue->timer_mutex); 512 queuefree(queue); 513 return 0; 514 } 515 516 /* 517 * check if queue is used by the client 518 * return negative value if the queue is invalid. 519 * return 0 if not used, 1 if used. 520 */ 521 int snd_seq_queue_is_used(int queueid, int client) 522 { 523 struct snd_seq_queue *q; 524 int result; 525 526 q = queueptr(queueid); 527 if (q == NULL) 528 return -EINVAL; /* invalid queue */ 529 result = test_bit(client, q->clients_bitmap) ? 1 : 0; 530 queuefree(q); 531 return result; 532 } 533 534 535 /*----------------------------------------------------------------*/ 536 537 /* notification that client has left the system - 538 * stop the timer on all queues owned by this client 539 */ 540 void snd_seq_queue_client_termination(int client) 541 { 542 unsigned long flags; 543 int i; 544 struct snd_seq_queue *q; 545 bool matched; 546 547 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 548 if ((q = queueptr(i)) == NULL) 549 continue; 550 spin_lock_irqsave(&q->owner_lock, flags); 551 matched = (q->owner == client); 552 if (matched) 553 q->klocked = 1; 554 spin_unlock_irqrestore(&q->owner_lock, flags); 555 if (matched) { 556 if (q->timer->running) 557 snd_seq_timer_stop(q->timer); 558 snd_seq_timer_reset(q->timer); 559 } 560 queuefree(q); 561 } 562 } 563 564 /* final stage notification - 565 * remove cells for no longer exist client (for non-owned queue) 566 * or delete this queue (for owned queue) 567 */ 568 void snd_seq_queue_client_leave(int client) 569 { 570 int i; 571 struct snd_seq_queue *q; 572 573 /* delete own queues from queue list */ 574 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 575 if ((q = queue_list_remove(i, client)) != NULL) 576 queue_delete(q); 577 } 578 579 /* remove cells from existing queues - 580 * they are not owned by this client 581 */ 582 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 583 if ((q = queueptr(i)) == NULL) 584 continue; 585 if (test_bit(client, q->clients_bitmap)) { 586 snd_seq_prioq_leave(q->tickq, client, 0); 587 snd_seq_prioq_leave(q->timeq, client, 0); 588 snd_seq_queue_use(q->queue, client, 0); 589 } 590 queuefree(q); 591 } 592 } 593 594 595 596 /*----------------------------------------------------------------*/ 597 598 /* remove cells from all queues */ 599 void snd_seq_queue_client_leave_cells(int client) 600 { 601 int i; 602 struct snd_seq_queue *q; 603 604 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 605 if ((q = queueptr(i)) == NULL) 606 continue; 607 snd_seq_prioq_leave(q->tickq, client, 0); 608 snd_seq_prioq_leave(q->timeq, client, 0); 609 queuefree(q); 610 } 611 } 612 613 /* remove cells based on flush criteria */ 614 void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info) 615 { 616 int i; 617 struct snd_seq_queue *q; 618 619 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 620 if ((q = queueptr(i)) == NULL) 621 continue; 622 if (test_bit(client, q->clients_bitmap) && 623 (! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) || 624 q->queue == info->queue)) { 625 snd_seq_prioq_remove_events(q->tickq, client, info); 626 snd_seq_prioq_remove_events(q->timeq, client, info); 627 } 628 queuefree(q); 629 } 630 } 631 632 /*----------------------------------------------------------------*/ 633 634 /* 635 * send events to all subscribed ports 636 */ 637 static void queue_broadcast_event(struct snd_seq_queue *q, struct snd_seq_event *ev, 638 int atomic, int hop) 639 { 640 struct snd_seq_event sev; 641 642 sev = *ev; 643 644 sev.flags = SNDRV_SEQ_TIME_STAMP_TICK|SNDRV_SEQ_TIME_MODE_ABS; 645 sev.time.tick = q->timer->tick.cur_tick; 646 sev.queue = q->queue; 647 sev.data.queue.queue = q->queue; 648 649 /* broadcast events from Timer port */ 650 sev.source.client = SNDRV_SEQ_CLIENT_SYSTEM; 651 sev.source.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; 652 sev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; 653 snd_seq_kernel_client_dispatch(SNDRV_SEQ_CLIENT_SYSTEM, &sev, atomic, hop); 654 } 655 656 /* 657 * process a received queue-control event. 658 * this function is exported for seq_sync.c. 659 */ 660 static void snd_seq_queue_process_event(struct snd_seq_queue *q, 661 struct snd_seq_event *ev, 662 int atomic, int hop) 663 { 664 switch (ev->type) { 665 case SNDRV_SEQ_EVENT_START: 666 snd_seq_prioq_leave(q->tickq, ev->source.client, 1); 667 snd_seq_prioq_leave(q->timeq, ev->source.client, 1); 668 if (! snd_seq_timer_start(q->timer)) 669 queue_broadcast_event(q, ev, atomic, hop); 670 break; 671 672 case SNDRV_SEQ_EVENT_CONTINUE: 673 if (! snd_seq_timer_continue(q->timer)) 674 queue_broadcast_event(q, ev, atomic, hop); 675 break; 676 677 case SNDRV_SEQ_EVENT_STOP: 678 snd_seq_timer_stop(q->timer); 679 queue_broadcast_event(q, ev, atomic, hop); 680 break; 681 682 case SNDRV_SEQ_EVENT_TEMPO: 683 snd_seq_timer_set_tempo(q->timer, ev->data.queue.param.value); 684 queue_broadcast_event(q, ev, atomic, hop); 685 break; 686 687 case SNDRV_SEQ_EVENT_SETPOS_TICK: 688 if (snd_seq_timer_set_position_tick(q->timer, ev->data.queue.param.time.tick) == 0) { 689 queue_broadcast_event(q, ev, atomic, hop); 690 } 691 break; 692 693 case SNDRV_SEQ_EVENT_SETPOS_TIME: 694 if (snd_seq_timer_set_position_time(q->timer, ev->data.queue.param.time.time) == 0) { 695 queue_broadcast_event(q, ev, atomic, hop); 696 } 697 break; 698 case SNDRV_SEQ_EVENT_QUEUE_SKEW: 699 if (snd_seq_timer_set_skew(q->timer, 700 ev->data.queue.param.skew.value, 701 ev->data.queue.param.skew.base) == 0) { 702 queue_broadcast_event(q, ev, atomic, hop); 703 } 704 break; 705 } 706 } 707 708 709 /* 710 * Queue control via timer control port: 711 * this function is exported as a callback of timer port. 712 */ 713 int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop) 714 { 715 struct snd_seq_queue *q; 716 717 if (snd_BUG_ON(!ev)) 718 return -EINVAL; 719 q = queueptr(ev->data.queue.queue); 720 721 if (q == NULL) 722 return -EINVAL; 723 724 if (! queue_access_lock(q, ev->source.client)) { 725 queuefree(q); 726 return -EPERM; 727 } 728 729 snd_seq_queue_process_event(q, ev, atomic, hop); 730 731 queue_access_unlock(q); 732 queuefree(q); 733 return 0; 734 } 735 736 737 /*----------------------------------------------------------------*/ 738 739 #ifdef CONFIG_SND_PROC_FS 740 /* exported to seq_info.c */ 741 void snd_seq_info_queues_read(struct snd_info_entry *entry, 742 struct snd_info_buffer *buffer) 743 { 744 int i, bpm; 745 struct snd_seq_queue *q; 746 struct snd_seq_timer *tmr; 747 bool locked; 748 int owner; 749 750 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { 751 if ((q = queueptr(i)) == NULL) 752 continue; 753 754 tmr = q->timer; 755 if (tmr->tempo) 756 bpm = 60000000 / tmr->tempo; 757 else 758 bpm = 0; 759 760 spin_lock_irq(&q->owner_lock); 761 locked = q->locked; 762 owner = q->owner; 763 spin_unlock_irq(&q->owner_lock); 764 765 snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name); 766 snd_iprintf(buffer, "owned by client : %d\n", owner); 767 snd_iprintf(buffer, "lock status : %s\n", locked ? "Locked" : "Free"); 768 snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq)); 769 snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq)); 770 snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped"); 771 snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq); 772 snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo); 773 snd_iprintf(buffer, "current BPM : %d\n", bpm); 774 snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec); 775 snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick); 776 snd_iprintf(buffer, "\n"); 777 queuefree(q); 778 } 779 } 780 #endif /* CONFIG_SND_PROC_FS */ 781 782