xref: /openbmc/linux/sound/core/seq/seq_prioq.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
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