/* list of allocated queues */ staticstruct snd_seq_queue *queue_list[SNDRV_SEQ_MAX_QUEUES]; static DEFINE_SPINLOCK(queue_list_lock); /* number of queues allocated */ staticint num_queues;
int snd_seq_queue_get_cur_queues(void)
{ return num_queues;
}
/* return pointer to queue structure for specified id */ struct snd_seq_queue *queueptr(int queueid)
{ struct snd_seq_queue *q;
if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) return NULL;
guard(spinlock_irqsave)(&queue_list_lock);
q = queue_list[queueid]; if (q)
snd_use_lock_use(&q->use_lock); return q;
}
/* return the (first) queue matching with the specified name */ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
{ int i; struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
q = queueptr(i); if (q) { if (strncmp(q->name, name, sizeof(q->name)) == 0) return q;
queuefree(q);
}
} return NULL;
}
void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
{ struct snd_seq_event_cell *cell;
snd_seq_tick_time_t cur_tick;
snd_seq_real_time_t cur_time; int processed = 0;
if (q == NULL) return;
/* make this function non-reentrant */
scoped_guard(spinlock_irqsave, &q->check_lock) { if (q->check_blocked) {
q->check_again = 1; return; /* other thread is already checking queues */
}
q->check_blocked = 1;
}
__again: /* Process tick queue... */
cur_tick = snd_seq_timer_get_cur_tick(q->timer); for (;;) {
cell = snd_seq_prioq_cell_out(q->tickq, &cur_tick); if (!cell) break;
snd_seq_dispatch_event(cell, atomic, hop); if (++processed >= MAX_CELL_PROCESSES_IN_QUEUE) goto out; /* the rest processed at the next batch */
}
/* Process time queue... */
cur_time = snd_seq_timer_get_cur_time(q->timer, false); for (;;) {
cell = snd_seq_prioq_cell_out(q->timeq, &cur_time); if (!cell) break;
snd_seq_dispatch_event(cell, atomic, hop); if (++processed >= MAX_CELL_PROCESSES_IN_QUEUE) goto out; /* the rest processed at the next batch */
}
/* enqueue a event to singe queue */ int snd_seq_enqueue_event(struct snd_seq_event_cell *cell, int atomic, int hop)
{ int dest, err; struct snd_seq_queue *q;
if (snd_BUG_ON(!cell)) return -EINVAL;
dest = cell->event.queue; /* destination queue */
q = queueptr(dest); if (q == NULL) return -EINVAL; /* handle relative time stamps, convert them into absolute */ if ((cell->event.flags & SNDRV_SEQ_TIME_MODE_MASK) == SNDRV_SEQ_TIME_MODE_REL) { switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { case SNDRV_SEQ_TIME_STAMP_TICK:
cell->event.time.tick += q->timer->tick.cur_tick; break;
case SNDRV_SEQ_TIME_STAMP_REAL:
snd_seq_inc_real_time(&cell->event.time.time,
&q->timer->cur_time); break;
}
cell->event.flags &= ~SNDRV_SEQ_TIME_MODE_MASK;
cell->event.flags |= SNDRV_SEQ_TIME_MODE_ABS;
} /* enqueue event in the real-time or midi queue */ switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { case SNDRV_SEQ_TIME_STAMP_TICK:
err = snd_seq_prioq_cell_in(q->tickq, cell); break;
case SNDRV_SEQ_TIME_STAMP_REAL: default:
err = snd_seq_prioq_cell_in(q->timeq, cell); break;
}
/* check if the client has permission to modify queue parameters. *ifitdoes,lockthequeue
*/ staticint queue_access_lock(struct snd_seq_queue *q, int client)
{ int access_ok;
/* exported - only checking permission */ int snd_seq_queue_check_access(int queueid, int client)
{ struct snd_seq_queue *q = queueptr(queueid); int access_ok;
/* open timer - *q->usemutexshouldbedownbeforecallingthisfunctiontoavoid *conflictionwithsnd_seq_queue_use()
*/ int snd_seq_queue_timer_open(int queueid)
{ int result = 0; struct snd_seq_queue *queue; struct snd_seq_timer *tmr;
queue = queueptr(queueid); if (queue == NULL) return -EINVAL;
tmr = queue->timer;
result = snd_seq_timer_open(queue); if (result < 0) {
snd_seq_timer_defaults(tmr);
result = snd_seq_timer_open(queue);
}
queuefree(queue); return result;
}
/* close timer - *q->usemutexshouldbedownbeforecallingthisfunction
*/ int snd_seq_queue_timer_close(int queueid)
{ struct snd_seq_queue *queue; int result = 0;
/* change queue tempo and ppq */ int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info)
{ struct snd_seq_queue *q = queueptr(queueid); int result;
if (q == NULL) return -EINVAL; if (! queue_access_lock(q, client)) {
queuefree(q); return -EPERM;
}
result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq,
info->tempo_base); if (result >= 0 && info->skew_base > 0)
result = snd_seq_timer_set_skew(q->timer, info->skew_value,
info->skew_base);
queue_access_unlock(q);
queuefree(q); return result;
}
/* use or unuse this queue */ staticvoid queue_use(struct snd_seq_queue *queue, int client, int use)
{ if (use) { if (!test_and_set_bit(client, queue->clients_bitmap))
queue->clients++;
} else { if (test_and_clear_bit(client, queue->clients_bitmap))
queue->clients--;
} if (queue->clients) { if (use && queue->clients == 1)
snd_seq_timer_defaults(queue->timer);
snd_seq_timer_open(queue);
} else {
snd_seq_timer_close(queue);
}
}
/* use or unuse this queue - *ifitisthefirstclient,startsthetimer. *ifitisnotlongerusedbyanyclients,stopthetimer.
*/ int snd_seq_queue_use(int queueid, int client, int use)
{ struct snd_seq_queue *queue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.