1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ALSA sequencer FIFO 4 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> 5 */ 6 7 #include <sound/core.h> 8 #include <linux/slab.h> 9 #include <linux/sched/signal.h> 10 11 #include "seq_fifo.h" 12 #include "seq_lock.h" 13 14 15 /* FIFO */ 16 17 /* create new fifo */ 18 struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) 19 { 20 struct snd_seq_fifo *f; 21 22 f = kzalloc_obj(*f); 23 if (!f) 24 return NULL; 25 26 f->pool = snd_seq_pool_new(poolsize); 27 if (f->pool == NULL) { 28 kfree(f); 29 return NULL; 30 } 31 if (snd_seq_pool_init(f->pool) < 0) { 32 snd_seq_pool_delete(&f->pool); 33 kfree(f); 34 return NULL; 35 } 36 37 spin_lock_init(&f->lock); 38 snd_use_lock_init(&f->use_lock); 39 init_waitqueue_head(&f->input_sleep); 40 atomic_set(&f->overflow, 0); 41 42 f->head = NULL; 43 f->tail = NULL; 44 f->cells = 0; 45 46 return f; 47 } 48 49 void snd_seq_fifo_delete(struct snd_seq_fifo **fifo) 50 { 51 struct snd_seq_fifo *f; 52 53 if (snd_BUG_ON(!fifo)) 54 return; 55 f = *fifo; 56 if (snd_BUG_ON(!f)) 57 return; 58 *fifo = NULL; 59 60 if (f->pool) 61 snd_seq_pool_mark_closing(f->pool); 62 63 snd_seq_fifo_clear(f); 64 65 /* wake up clients if any */ 66 if (waitqueue_active(&f->input_sleep)) 67 wake_up(&f->input_sleep); 68 69 /* release resources...*/ 70 /*....................*/ 71 72 if (f->pool) { 73 snd_seq_pool_done(f->pool); 74 snd_seq_pool_delete(&f->pool); 75 } 76 77 kfree(f); 78 } 79 80 static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f); 81 82 /* clear queue */ 83 void snd_seq_fifo_clear(struct snd_seq_fifo *f) 84 { 85 struct snd_seq_event_cell *cell; 86 87 /* clear overflow flag */ 88 atomic_set(&f->overflow, 0); 89 90 snd_use_lock_sync(&f->use_lock); 91 guard(spinlock_irq)(&f->lock); 92 /* drain the fifo */ 93 while ((cell = fifo_cell_out(f)) != NULL) { 94 snd_seq_cell_free(cell); 95 } 96 } 97 98 99 /* enqueue event to fifo */ 100 int snd_seq_fifo_event_in(struct snd_seq_fifo *f, 101 struct snd_seq_event *event) 102 { 103 struct snd_seq_event_cell *cell; 104 struct snd_seq_pool *pool; 105 bool linked; 106 int err; 107 108 if (snd_BUG_ON(!f)) 109 return -EINVAL; 110 111 guard(snd_seq_fifo)(f); 112 retry: 113 pool = READ_ONCE(f->pool); 114 err = snd_seq_event_dup(pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ 115 if (err < 0) { 116 if ((err == -ENOMEM) || (err == -EAGAIN)) 117 atomic_inc(&f->overflow); 118 return err; 119 } 120 121 /* append new cells to fifo */ 122 linked = false; 123 scoped_guard(spinlock_irqsave, &f->lock) { 124 if (cell->pool == f->pool) { 125 if (f->tail) 126 f->tail->next = cell; 127 f->tail = cell; 128 if (!f->head) 129 f->head = cell; 130 cell->next = NULL; 131 f->cells++; 132 linked = true; 133 } 134 } 135 136 if (!linked) { 137 /* Retry against the replacement pool after resize publishes it. */ 138 snd_seq_cell_free(cell); 139 goto retry; 140 } 141 142 /* wakeup client */ 143 if (waitqueue_active(&f->input_sleep)) 144 wake_up(&f->input_sleep); 145 146 return 0; /* success */ 147 148 } 149 150 /* dequeue cell from fifo */ 151 static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f) 152 { 153 struct snd_seq_event_cell *cell; 154 155 cell = f->head; 156 if (cell) { 157 f->head = cell->next; 158 159 /* reset tail if this was the last element */ 160 if (f->tail == cell) 161 f->tail = NULL; 162 163 cell->next = NULL; 164 f->cells--; 165 } 166 167 return cell; 168 } 169 170 /* dequeue cell from fifo and copy on user space */ 171 int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, 172 struct snd_seq_event_cell **cellp, int nonblock) 173 { 174 struct snd_seq_event_cell *cell; 175 unsigned long flags; 176 wait_queue_entry_t wait; 177 178 if (snd_BUG_ON(!f)) 179 return -EINVAL; 180 181 *cellp = NULL; 182 init_waitqueue_entry(&wait, current); 183 spin_lock_irqsave(&f->lock, flags); 184 while ((cell = fifo_cell_out(f)) == NULL) { 185 if (nonblock) { 186 /* non-blocking - return immediately */ 187 spin_unlock_irqrestore(&f->lock, flags); 188 return -EAGAIN; 189 } 190 set_current_state(TASK_INTERRUPTIBLE); 191 add_wait_queue(&f->input_sleep, &wait); 192 spin_unlock_irqrestore(&f->lock, flags); 193 schedule(); 194 spin_lock_irqsave(&f->lock, flags); 195 remove_wait_queue(&f->input_sleep, &wait); 196 if (signal_pending(current)) { 197 spin_unlock_irqrestore(&f->lock, flags); 198 return -ERESTARTSYS; 199 } 200 } 201 spin_unlock_irqrestore(&f->lock, flags); 202 *cellp = cell; 203 204 return 0; 205 } 206 207 208 void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, 209 struct snd_seq_event_cell *cell) 210 { 211 bool linked = false; 212 213 if (cell) { 214 scoped_guard(spinlock_irqsave, &f->lock) { 215 if (cell->pool == f->pool) { 216 cell->next = f->head; 217 f->head = cell; 218 if (!f->tail) 219 f->tail = cell; 220 f->cells++; 221 linked = true; 222 } 223 } 224 if (!linked) 225 snd_seq_cell_free(cell); 226 } 227 } 228 229 230 /* polling; return non-zero if queue is available */ 231 int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file, 232 poll_table *wait) 233 { 234 poll_wait(file, &f->input_sleep, wait); 235 guard(spinlock_irq)(&f->lock); 236 return (f->cells > 0); 237 } 238 239 /* change the size of pool; all old events are removed */ 240 int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) 241 { 242 struct snd_seq_pool *newpool, *oldpool; 243 struct snd_seq_event_cell *cell, *next, *oldhead; 244 245 if (snd_BUG_ON(!f || !f->pool)) 246 return -EINVAL; 247 248 /* allocate new pool */ 249 newpool = snd_seq_pool_new(poolsize); 250 if (newpool == NULL) 251 return -ENOMEM; 252 if (snd_seq_pool_init(newpool) < 0) { 253 snd_seq_pool_delete(&newpool); 254 return -ENOMEM; 255 } 256 257 scoped_guard(spinlock_irq, &f->lock) { 258 /* remember old pool */ 259 oldpool = f->pool; 260 oldhead = f->head; 261 /* exchange pools */ 262 WRITE_ONCE(f->pool, newpool); 263 f->head = NULL; 264 f->tail = NULL; 265 f->cells = 0; 266 /* NOTE: overflow flag is not cleared */ 267 } 268 269 /* close the old pool and wait until all users are gone */ 270 snd_seq_pool_mark_closing(oldpool); 271 snd_use_lock_sync(&f->use_lock); 272 273 /* release cells in old pool */ 274 for (cell = oldhead; cell; cell = next) { 275 next = cell->next; 276 snd_seq_cell_free(cell); 277 } 278 snd_seq_pool_delete(&oldpool); 279 280 return 0; 281 } 282 283 /* get the number of unused cells safely */ 284 int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f) 285 { 286 if (!f) 287 return 0; 288 289 guard(snd_seq_fifo)(f); 290 guard(spinlock_irqsave)(&f->lock); 291 return snd_seq_unused_cells(f->pool); 292 } 293