/* remove cells for left client */ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) { register struct snd_seq_event_cell *cell, *next; unsigned long flags; struct snd_seq_event_cell *prev = NULL; struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext; /* collect all removed cells */ spin_lock_irqsave(&f->lock, flags); cell = f->head; while (cell) { next = cell->next; if (prioq_match(cell, client, timestamp)) { /* remove cell from prioq */ if (cell == f->head) { f->head = cell->next; } else { prev->next = cell->next; } if (cell == f->tail) f->tail = cell->next; f->cells--; /* add cell to free list */ cell->next = NULL; if (freefirst == NULL) { freefirst = cell; } else { freeprev->next = cell; } freeprev = cell; } else { #if 0 // printk(KERN_DEBUG "type = %i, source = %i, dest = %i, " // "client = %i\n", // cell->event.type, // cell->event.source.client, // cell->event.dest.client, ; #endif prev = cell; } cell = next; } spin_unlock_irqrestore(&f->lock, flags); /* remove selected cells */ while (freefirst) { freenext = freefirst->next; snd_seq_cell_free(freefirst); freefirst = freenext; } }
/* remove cells matching remove criteria */ void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client, struct snd_seq_remove_events *info) { struct snd_seq_event_cell *cell, *next; unsigned long flags; struct snd_seq_event_cell *prev = NULL; struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext; /* collect all removed cells */ spin_lock_irqsave(&f->lock, flags); cell = f->head; while (cell) { next = cell->next; if (cell->event.source.client == client && prioq_remove_match(info, &cell->event)) { /* remove cell from prioq */ if (cell == f->head) { f->head = cell->next; } else { prev->next = cell->next; } if (cell == f->tail) f->tail = cell->next; f->cells--; /* add cell to free list */ cell->next = NULL; if (freefirst == NULL) { freefirst = cell; } else { freeprev->next = cell; } freeprev = cell; } else { prev = cell; } cell = next; } spin_unlock_irqrestore(&f->lock, flags); /* remove selected cells */ while (freefirst) { freenext = freefirst->next; snd_seq_cell_free(freefirst); freefirst = freenext; } }
/* clear queue */ void snd_seq_fifo_clear(fifo_t *f) { snd_seq_event_cell_t *cell; unsigned long flags; /* clear overflow flag */ atomic_set(&f->overflow, 0); snd_use_lock_sync(&f->use_lock); spin_lock_irqsave(&f->lock, flags); /* drain the fifo */ while ((cell = fifo_cell_out(f)) != NULL) { snd_seq_cell_free(cell); } spin_unlock_irqrestore(&f->lock, flags); }
/* delete prioq (destructor) */ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo) { struct snd_seq_prioq *f = *fifo; *fifo = NULL; if (f == NULL) { snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n"); return; } /* release resources...*/ /*....................*/ if (f->cells > 0) { /* drain prioQ */ while (f->cells > 0) snd_seq_cell_free(snd_seq_prioq_cell_out(f)); } kfree(f); }
/* change the size of pool; all old events are removed */ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) { unsigned long flags; struct snd_seq_pool *newpool, *oldpool; struct snd_seq_event_cell *cell, *next, *oldhead; if (snd_BUG_ON(!f || !f->pool)) return -EINVAL; /* allocate new pool */ newpool = snd_seq_pool_new(poolsize); if (newpool == NULL) return -ENOMEM; if (snd_seq_pool_init(newpool) < 0) { snd_seq_pool_delete(&newpool); return -ENOMEM; } spin_lock_irqsave(&f->lock, flags); /* remember old pool */ oldpool = f->pool; oldhead = f->head; /* exchange pools */ f->pool = newpool; f->head = NULL; f->tail = NULL; f->cells = 0; /* NOTE: overflow flag is not cleared */ spin_unlock_irqrestore(&f->lock, flags); /* release cells in old pool */ for (cell = oldhead; cell; cell = next) { next = cell->next; snd_seq_cell_free(cell); } snd_seq_pool_delete(&oldpool); return 0; }
/* * duplicate the event to a cell. * if the event has external data, the data is decomposed to additional * cells. */ int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t **cellp, int nonblock, struct file *file) { int ncells, err; unsigned int extlen; snd_seq_event_cell_t *cell; *cellp = NULL; ncells = 0; extlen = 0; if (snd_seq_ev_is_variable(event)) { extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; ncells = (extlen + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t); } if (ncells >= pool->total_elements) return -ENOMEM; err = snd_seq_cell_alloc(pool, &cell, nonblock, file); if (err < 0) return err; /* copy the event */ cell->event = *event; /* decompose */ if (snd_seq_ev_is_variable(event)) { int len = extlen; int is_chained = event->data.ext.len & SNDRV_SEQ_EXT_CHAINED; int is_usrptr = event->data.ext.len & SNDRV_SEQ_EXT_USRPTR; snd_seq_event_cell_t *src, *tmp, *tail; char *buf; cell->event.data.ext.len = extlen | SNDRV_SEQ_EXT_CHAINED; cell->event.data.ext.ptr = NULL; src = (snd_seq_event_cell_t*)event->data.ext.ptr; buf = (char *)event->data.ext.ptr; tail = NULL; while (ncells-- > 0) { int size = sizeof(snd_seq_event_t); if (len < size) size = len; err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); if (err < 0) goto __error; if (cell->event.data.ext.ptr == NULL) cell->event.data.ext.ptr = tmp; if (tail) tail->next = tmp; tail = tmp; /* copy chunk */ if (is_chained && src) { tmp->event = src->event; src = src->next; } else if (is_usrptr) { if (copy_from_user(&tmp->event, buf, size)) { err = -EFAULT; goto __error; } } else { memcpy(&tmp->event, buf, size); } buf += size; len -= size; } } *cellp = cell; return 0; __error: snd_seq_cell_free(cell); return err; }