1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * ALSA sequencer Priority Queue
41da177e4SLinus Torvalds * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include <linux/time.h>
81da177e4SLinus Torvalds #include <linux/slab.h>
91da177e4SLinus Torvalds #include <sound/core.h>
101da177e4SLinus Torvalds #include "seq_timer.h"
111da177e4SLinus Torvalds #include "seq_prioq.h"
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds /* Implementation is a simple linked list for now...
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds This priority queue orders the events on timestamp. For events with an
171da177e4SLinus Torvalds equeal timestamp the queue behaves as a FIFO.
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * +-------+
211da177e4SLinus Torvalds * Head --> | first |
221da177e4SLinus Torvalds * +-------+
231da177e4SLinus Torvalds * |next
241da177e4SLinus Torvalds * +-----v-+
251da177e4SLinus Torvalds * | |
261da177e4SLinus Torvalds * +-------+
271da177e4SLinus Torvalds * |
281da177e4SLinus Torvalds * +-----v-+
291da177e4SLinus Torvalds * | |
301da177e4SLinus Torvalds * +-------+
311da177e4SLinus Torvalds * |
321da177e4SLinus Torvalds * +-----v-+
331da177e4SLinus Torvalds * Tail --> | last |
341da177e4SLinus Torvalds * +-------+
351da177e4SLinus Torvalds *
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds */
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds /* create new prioq (constructor) */
snd_seq_prioq_new(void)42c7e0b5bfSTakashi Iwai struct snd_seq_prioq *snd_seq_prioq_new(void)
431da177e4SLinus Torvalds {
44c7e0b5bfSTakashi Iwai struct snd_seq_prioq *f;
451da177e4SLinus Torvalds
46ecca82b4STakashi Iwai f = kzalloc(sizeof(*f), GFP_KERNEL);
4724db8bbaSTakashi Iwai if (!f)
481da177e4SLinus Torvalds return NULL;
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds spin_lock_init(&f->lock);
511da177e4SLinus Torvalds f->head = NULL;
521da177e4SLinus Torvalds f->tail = NULL;
531da177e4SLinus Torvalds f->cells = 0;
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds return f;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds /* delete prioq (destructor) */
snd_seq_prioq_delete(struct snd_seq_prioq ** fifo)59c7e0b5bfSTakashi Iwai void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
601da177e4SLinus Torvalds {
61c7e0b5bfSTakashi Iwai struct snd_seq_prioq *f = *fifo;
621da177e4SLinus Torvalds *fifo = NULL;
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds if (f == NULL) {
6504cc79a0STakashi Iwai pr_debug("ALSA: seq: snd_seq_prioq_delete() called with NULL prioq\n");
661da177e4SLinus Torvalds return;
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds /* release resources...*/
701da177e4SLinus Torvalds /*....................*/
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds if (f->cells > 0) {
731da177e4SLinus Torvalds /* drain prioQ */
741da177e4SLinus Torvalds while (f->cells > 0)
75d0f83306STakashi Iwai snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds kfree(f);
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds /* compare timestamp between events */
851da177e4SLinus Torvalds /* return 1 if a >= b; 0 */
compare_timestamp(struct snd_seq_event * a,struct snd_seq_event * b)86c7e0b5bfSTakashi Iwai static inline int compare_timestamp(struct snd_seq_event *a,
87c7e0b5bfSTakashi Iwai struct snd_seq_event *b)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
901da177e4SLinus Torvalds /* compare ticks */
911da177e4SLinus Torvalds return (snd_seq_compare_tick_time(&a->time.tick, &b->time.tick));
921da177e4SLinus Torvalds } else {
931da177e4SLinus Torvalds /* compare real time */
941da177e4SLinus Torvalds return (snd_seq_compare_real_time(&a->time.time, &b->time.time));
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds /* compare timestamp between events */
991da177e4SLinus Torvalds /* return negative if a < b;
1001da177e4SLinus Torvalds * zero if a = b;
1011da177e4SLinus Torvalds * positive if a > b;
1021da177e4SLinus Torvalds */
compare_timestamp_rel(struct snd_seq_event * a,struct snd_seq_event * b)103c7e0b5bfSTakashi Iwai static inline int compare_timestamp_rel(struct snd_seq_event *a,
104c7e0b5bfSTakashi Iwai struct snd_seq_event *b)
1051da177e4SLinus Torvalds {
1061da177e4SLinus Torvalds if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
1071da177e4SLinus Torvalds /* compare ticks */
1081da177e4SLinus Torvalds if (a->time.tick > b->time.tick)
1091da177e4SLinus Torvalds return 1;
1101da177e4SLinus Torvalds else if (a->time.tick == b->time.tick)
1111da177e4SLinus Torvalds return 0;
1121da177e4SLinus Torvalds else
1131da177e4SLinus Torvalds return -1;
1141da177e4SLinus Torvalds } else {
1151da177e4SLinus Torvalds /* compare real time */
1161da177e4SLinus Torvalds if (a->time.time.tv_sec > b->time.time.tv_sec)
1171da177e4SLinus Torvalds return 1;
1181da177e4SLinus Torvalds else if (a->time.time.tv_sec == b->time.time.tv_sec) {
1191da177e4SLinus Torvalds if (a->time.time.tv_nsec > b->time.time.tv_nsec)
1201da177e4SLinus Torvalds return 1;
1211da177e4SLinus Torvalds else if (a->time.time.tv_nsec == b->time.time.tv_nsec)
1221da177e4SLinus Torvalds return 0;
1231da177e4SLinus Torvalds else
1241da177e4SLinus Torvalds return -1;
1251da177e4SLinus Torvalds } else
1261da177e4SLinus Torvalds return -1;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds
1301da177e4SLinus Torvalds /* enqueue cell to prioq */
snd_seq_prioq_cell_in(struct snd_seq_prioq * f,struct snd_seq_event_cell * cell)131c7e0b5bfSTakashi Iwai int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
132c7e0b5bfSTakashi Iwai struct snd_seq_event_cell * cell)
1331da177e4SLinus Torvalds {
134c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *cur, *prev;
1351da177e4SLinus Torvalds unsigned long flags;
1361da177e4SLinus Torvalds int count;
1371da177e4SLinus Torvalds int prior;
1381da177e4SLinus Torvalds
1397eaa943cSTakashi Iwai if (snd_BUG_ON(!f || !cell))
1407eaa943cSTakashi Iwai return -EINVAL;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds /* check flags */
1431da177e4SLinus Torvalds prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
1441da177e4SLinus Torvalds
1451da177e4SLinus Torvalds spin_lock_irqsave(&f->lock, flags);
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds /* check if this element needs to inserted at the end (ie. ordered
1481da177e4SLinus Torvalds data is inserted) This will be very likeley if a sequencer
1491da177e4SLinus Torvalds application or midi file player is feeding us (sequential) data */
1501da177e4SLinus Torvalds if (f->tail && !prior) {
1511da177e4SLinus Torvalds if (compare_timestamp(&cell->event, &f->tail->event)) {
1521da177e4SLinus Torvalds /* add new cell to tail of the fifo */
1531da177e4SLinus Torvalds f->tail->next = cell;
1541da177e4SLinus Torvalds f->tail = cell;
1551da177e4SLinus Torvalds cell->next = NULL;
1561da177e4SLinus Torvalds f->cells++;
1571da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
1581da177e4SLinus Torvalds return 0;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds /* traverse list of elements to find the place where the new cell is
1621da177e4SLinus Torvalds to be inserted... Note that this is a order n process ! */
1631da177e4SLinus Torvalds
1641da177e4SLinus Torvalds prev = NULL; /* previous cell */
1651da177e4SLinus Torvalds cur = f->head; /* cursor */
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds count = 10000; /* FIXME: enough big, isn't it? */
1681da177e4SLinus Torvalds while (cur != NULL) {
1691da177e4SLinus Torvalds /* compare timestamps */
1701da177e4SLinus Torvalds int rel = compare_timestamp_rel(&cell->event, &cur->event);
1711da177e4SLinus Torvalds if (rel < 0)
1721da177e4SLinus Torvalds /* new cell has earlier schedule time, */
1731da177e4SLinus Torvalds break;
1741da177e4SLinus Torvalds else if (rel == 0 && prior)
1751da177e4SLinus Torvalds /* equal schedule time and prior to others */
1761da177e4SLinus Torvalds break;
1771da177e4SLinus Torvalds /* new cell has equal or larger schedule time, */
1781da177e4SLinus Torvalds /* move cursor to next cell */
1791da177e4SLinus Torvalds prev = cur;
1801da177e4SLinus Torvalds cur = cur->next;
1811da177e4SLinus Torvalds if (! --count) {
1821da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
18304cc79a0STakashi Iwai pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
1841da177e4SLinus Torvalds return -EINVAL;
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds /* insert it before cursor */
1891da177e4SLinus Torvalds if (prev != NULL)
1901da177e4SLinus Torvalds prev->next = cell;
1911da177e4SLinus Torvalds cell->next = cur;
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds if (f->head == cur) /* this is the first cell, set head to it */
1941da177e4SLinus Torvalds f->head = cell;
1951da177e4SLinus Torvalds if (cur == NULL) /* reached end of the list */
1961da177e4SLinus Torvalds f->tail = cell;
1971da177e4SLinus Torvalds f->cells++;
1981da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
1991da177e4SLinus Torvalds return 0;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
202d0f83306STakashi Iwai /* return 1 if the current time >= event timestamp */
event_is_ready(struct snd_seq_event * ev,void * current_time)203d0f83306STakashi Iwai static int event_is_ready(struct snd_seq_event *ev, void *current_time)
204d0f83306STakashi Iwai {
205d0f83306STakashi Iwai if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK)
206d0f83306STakashi Iwai return snd_seq_compare_tick_time(current_time, &ev->time.tick);
207d0f83306STakashi Iwai else
208d0f83306STakashi Iwai return snd_seq_compare_real_time(current_time, &ev->time.time);
209d0f83306STakashi Iwai }
210d0f83306STakashi Iwai
2111da177e4SLinus Torvalds /* dequeue cell from prioq */
snd_seq_prioq_cell_out(struct snd_seq_prioq * f,void * current_time)212d0f83306STakashi Iwai struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
213d0f83306STakashi Iwai void *current_time)
2141da177e4SLinus Torvalds {
215c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *cell;
2161da177e4SLinus Torvalds unsigned long flags;
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds if (f == NULL) {
21904cc79a0STakashi Iwai pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
2201da177e4SLinus Torvalds return NULL;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds spin_lock_irqsave(&f->lock, flags);
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds cell = f->head;
225d0f83306STakashi Iwai if (cell && current_time && !event_is_ready(&cell->event, current_time))
226d0f83306STakashi Iwai cell = NULL;
2271da177e4SLinus Torvalds if (cell) {
2281da177e4SLinus Torvalds f->head = cell->next;
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvalds /* reset tail if this was the last element */
2311da177e4SLinus Torvalds if (f->tail == cell)
2321da177e4SLinus Torvalds f->tail = NULL;
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds cell->next = NULL;
2351da177e4SLinus Torvalds f->cells--;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds
2381da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
2391da177e4SLinus Torvalds return cell;
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds /* return number of events available in prioq */
snd_seq_prioq_avail(struct snd_seq_prioq * f)243c7e0b5bfSTakashi Iwai int snd_seq_prioq_avail(struct snd_seq_prioq * f)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds if (f == NULL) {
24604cc79a0STakashi Iwai pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
2471da177e4SLinus Torvalds return 0;
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds return f->cells;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds
prioq_match(struct snd_seq_event_cell * cell,int client,int timestamp)252c7e0b5bfSTakashi Iwai static inline int prioq_match(struct snd_seq_event_cell *cell,
253c7e0b5bfSTakashi Iwai int client, int timestamp)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds if (cell->event.source.client == client ||
2561da177e4SLinus Torvalds cell->event.dest.client == client)
2571da177e4SLinus Torvalds return 1;
2581da177e4SLinus Torvalds if (!timestamp)
2591da177e4SLinus Torvalds return 0;
2601da177e4SLinus Torvalds switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
2611da177e4SLinus Torvalds case SNDRV_SEQ_TIME_STAMP_TICK:
2621da177e4SLinus Torvalds if (cell->event.time.tick)
2631da177e4SLinus Torvalds return 1;
2641da177e4SLinus Torvalds break;
2651da177e4SLinus Torvalds case SNDRV_SEQ_TIME_STAMP_REAL:
2661da177e4SLinus Torvalds if (cell->event.time.time.tv_sec ||
2671da177e4SLinus Torvalds cell->event.time.time.tv_nsec)
2681da177e4SLinus Torvalds return 1;
2691da177e4SLinus Torvalds break;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds return 0;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvalds /* remove cells for left client */
snd_seq_prioq_leave(struct snd_seq_prioq * f,int client,int timestamp)275c7e0b5bfSTakashi Iwai void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
2761da177e4SLinus Torvalds {
277c7e0b5bfSTakashi Iwai register struct snd_seq_event_cell *cell, *next;
2781da177e4SLinus Torvalds unsigned long flags;
279c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *prev = NULL;
280c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds /* collect all removed cells */
2831da177e4SLinus Torvalds spin_lock_irqsave(&f->lock, flags);
2841da177e4SLinus Torvalds cell = f->head;
2851da177e4SLinus Torvalds while (cell) {
2861da177e4SLinus Torvalds next = cell->next;
2871da177e4SLinus Torvalds if (prioq_match(cell, client, timestamp)) {
2881da177e4SLinus Torvalds /* remove cell from prioq */
2891da177e4SLinus Torvalds if (cell == f->head) {
2901da177e4SLinus Torvalds f->head = cell->next;
2911da177e4SLinus Torvalds } else {
2921da177e4SLinus Torvalds prev->next = cell->next;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds if (cell == f->tail)
2951da177e4SLinus Torvalds f->tail = cell->next;
2961da177e4SLinus Torvalds f->cells--;
2971da177e4SLinus Torvalds /* add cell to free list */
2981da177e4SLinus Torvalds cell->next = NULL;
2991da177e4SLinus Torvalds if (freefirst == NULL) {
3001da177e4SLinus Torvalds freefirst = cell;
3011da177e4SLinus Torvalds } else {
3021da177e4SLinus Torvalds freeprev->next = cell;
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds freeprev = cell;
3051da177e4SLinus Torvalds } else {
3061da177e4SLinus Torvalds #if 0
30704cc79a0STakashi Iwai pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
308006de267STakashi Iwai "client = %i\n",
3091da177e4SLinus Torvalds cell->event.type,
3101da177e4SLinus Torvalds cell->event.source.client,
3111da177e4SLinus Torvalds cell->event.dest.client,
3121da177e4SLinus Torvalds client);
3131da177e4SLinus Torvalds #endif
3141da177e4SLinus Torvalds prev = cell;
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds cell = next;
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
3191da177e4SLinus Torvalds
3201da177e4SLinus Torvalds /* remove selected cells */
3211da177e4SLinus Torvalds while (freefirst) {
3221da177e4SLinus Torvalds freenext = freefirst->next;
3231da177e4SLinus Torvalds snd_seq_cell_free(freefirst);
3241da177e4SLinus Torvalds freefirst = freenext;
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds
prioq_remove_match(struct snd_seq_remove_events * info,struct snd_seq_event * ev)328c7e0b5bfSTakashi Iwai static int prioq_remove_match(struct snd_seq_remove_events *info,
329c7e0b5bfSTakashi Iwai struct snd_seq_event *ev)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds int res;
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
3341da177e4SLinus Torvalds if (ev->dest.client != info->dest.client ||
3351da177e4SLinus Torvalds ev->dest.port != info->dest.port)
3361da177e4SLinus Torvalds return 0;
3371da177e4SLinus Torvalds }
3381da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
3391da177e4SLinus Torvalds if (! snd_seq_ev_is_channel_type(ev))
3401da177e4SLinus Torvalds return 0;
3411da177e4SLinus Torvalds /* data.note.channel and data.control.channel are identical */
3421da177e4SLinus Torvalds if (ev->data.note.channel != info->channel)
3431da177e4SLinus Torvalds return 0;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
3461da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
3471da177e4SLinus Torvalds res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick);
3481da177e4SLinus Torvalds else
3491da177e4SLinus Torvalds res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
3501da177e4SLinus Torvalds if (!res)
3511da177e4SLinus Torvalds return 0;
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
3541da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
3551da177e4SLinus Torvalds res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick);
3561da177e4SLinus Torvalds else
3571da177e4SLinus Torvalds res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
3581da177e4SLinus Torvalds if (res)
3591da177e4SLinus Torvalds return 0;
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
3621da177e4SLinus Torvalds if (ev->type != info->type)
3631da177e4SLinus Torvalds return 0;
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
3661da177e4SLinus Torvalds /* Do not remove off events */
3671da177e4SLinus Torvalds switch (ev->type) {
3681da177e4SLinus Torvalds case SNDRV_SEQ_EVENT_NOTEOFF:
3691da177e4SLinus Torvalds /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
3701da177e4SLinus Torvalds return 0;
3711da177e4SLinus Torvalds default:
3721da177e4SLinus Torvalds break;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
3761da177e4SLinus Torvalds if (info->tag != ev->tag)
3771da177e4SLinus Torvalds return 0;
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds return 1;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds /* remove cells matching remove criteria */
snd_seq_prioq_remove_events(struct snd_seq_prioq * f,int client,struct snd_seq_remove_events * info)384c7e0b5bfSTakashi Iwai void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
385c7e0b5bfSTakashi Iwai struct snd_seq_remove_events *info)
3861da177e4SLinus Torvalds {
387c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *cell, *next;
3881da177e4SLinus Torvalds unsigned long flags;
389c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *prev = NULL;
390c7e0b5bfSTakashi Iwai struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds /* collect all removed cells */
3931da177e4SLinus Torvalds spin_lock_irqsave(&f->lock, flags);
3941da177e4SLinus Torvalds cell = f->head;
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds while (cell) {
3971da177e4SLinus Torvalds next = cell->next;
3981da177e4SLinus Torvalds if (cell->event.source.client == client &&
3991da177e4SLinus Torvalds prioq_remove_match(info, &cell->event)) {
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds /* remove cell from prioq */
4021da177e4SLinus Torvalds if (cell == f->head) {
4031da177e4SLinus Torvalds f->head = cell->next;
4041da177e4SLinus Torvalds } else {
4051da177e4SLinus Torvalds prev->next = cell->next;
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds if (cell == f->tail)
4091da177e4SLinus Torvalds f->tail = cell->next;
4101da177e4SLinus Torvalds f->cells--;
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds /* add cell to free list */
4131da177e4SLinus Torvalds cell->next = NULL;
4141da177e4SLinus Torvalds if (freefirst == NULL) {
4151da177e4SLinus Torvalds freefirst = cell;
4161da177e4SLinus Torvalds } else {
4171da177e4SLinus Torvalds freeprev->next = cell;
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds
4201da177e4SLinus Torvalds freeprev = cell;
4211da177e4SLinus Torvalds } else {
4221da177e4SLinus Torvalds prev = cell;
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds cell = next;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds spin_unlock_irqrestore(&f->lock, flags);
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds /* remove selected cells */
4291da177e4SLinus Torvalds while (freefirst) {
4301da177e4SLinus Torvalds freenext = freefirst->next;
4311da177e4SLinus Torvalds snd_seq_cell_free(freefirst);
4321da177e4SLinus Torvalds freefirst = freenext;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds
437