1 /* 2 * ALSA sequencer Memory Manager 3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> 4 * Jaroslav Kysela <perex@perex.cz> 5 * 2000 by Takashi Iwai <tiwai@suse.de> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23 #include <linux/init.h> 24 #include <linux/export.h> 25 #include <linux/slab.h> 26 #include <linux/sched/signal.h> 27 #include <linux/vmalloc.h> 28 #include <sound/core.h> 29 30 #include <sound/seq_kernel.h> 31 #include "seq_memory.h" 32 #include "seq_queue.h" 33 #include "seq_info.h" 34 #include "seq_lock.h" 35 36 static inline int snd_seq_pool_available(struct snd_seq_pool *pool) 37 { 38 return pool->total_elements - atomic_read(&pool->counter); 39 } 40 41 static inline int snd_seq_output_ok(struct snd_seq_pool *pool) 42 { 43 return snd_seq_pool_available(pool) >= pool->room; 44 } 45 46 /* 47 * Variable length event: 48 * The event like sysex uses variable length type. 49 * The external data may be stored in three different formats. 50 * 1) kernel space 51 * This is the normal case. 52 * ext.data.len = length 53 * ext.data.ptr = buffer pointer 54 * 2) user space 55 * When an event is generated via read(), the external data is 56 * kept in user space until expanded. 57 * ext.data.len = length | SNDRV_SEQ_EXT_USRPTR 58 * ext.data.ptr = userspace pointer 59 * 3) chained cells 60 * When the variable length event is enqueued (in prioq or fifo), 61 * the external data is decomposed to several cells. 62 * ext.data.len = length | SNDRV_SEQ_EXT_CHAINED 63 * ext.data.ptr = the additiona cell head 64 * -> cell.next -> cell.next -> .. 65 */ 66 67 /* 68 * exported: 69 * call dump function to expand external data. 70 */ 71 72 static int get_var_len(const struct snd_seq_event *event) 73 { 74 if ((event->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) 75 return -EINVAL; 76 77 return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; 78 } 79 80 int snd_seq_dump_var_event(const struct snd_seq_event *event, 81 snd_seq_dump_func_t func, void *private_data) 82 { 83 int len, err; 84 struct snd_seq_event_cell *cell; 85 86 if ((len = get_var_len(event)) <= 0) 87 return len; 88 89 if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { 90 char buf[32]; 91 char __user *curptr = (char __force __user *)event->data.ext.ptr; 92 while (len > 0) { 93 int size = sizeof(buf); 94 if (len < size) 95 size = len; 96 if (copy_from_user(buf, curptr, size)) 97 return -EFAULT; 98 err = func(private_data, buf, size); 99 if (err < 0) 100 return err; 101 curptr += size; 102 len -= size; 103 } 104 return 0; 105 } 106 if (!(event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) 107 return func(private_data, event->data.ext.ptr, len); 108 109 cell = (struct snd_seq_event_cell *)event->data.ext.ptr; 110 for (; len > 0 && cell; cell = cell->next) { 111 int size = sizeof(struct snd_seq_event); 112 if (len < size) 113 size = len; 114 err = func(private_data, &cell->event, size); 115 if (err < 0) 116 return err; 117 len -= size; 118 } 119 return 0; 120 } 121 EXPORT_SYMBOL(snd_seq_dump_var_event); 122 123 124 /* 125 * exported: 126 * expand the variable length event to linear buffer space. 127 */ 128 129 static int seq_copy_in_kernel(char **bufptr, const void *src, int size) 130 { 131 memcpy(*bufptr, src, size); 132 *bufptr += size; 133 return 0; 134 } 135 136 static int seq_copy_in_user(char __user **bufptr, const void *src, int size) 137 { 138 if (copy_to_user(*bufptr, src, size)) 139 return -EFAULT; 140 *bufptr += size; 141 return 0; 142 } 143 144 int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char *buf, 145 int in_kernel, int size_aligned) 146 { 147 int len, newlen; 148 int err; 149 150 if ((len = get_var_len(event)) < 0) 151 return len; 152 newlen = len; 153 if (size_aligned > 0) 154 newlen = roundup(len, size_aligned); 155 if (count < newlen) 156 return -EAGAIN; 157 158 if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) { 159 if (! in_kernel) 160 return -EINVAL; 161 if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len)) 162 return -EFAULT; 163 return newlen; 164 } 165 err = snd_seq_dump_var_event(event, 166 in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel : 167 (snd_seq_dump_func_t)seq_copy_in_user, 168 &buf); 169 return err < 0 ? err : newlen; 170 } 171 EXPORT_SYMBOL(snd_seq_expand_var_event); 172 173 /* 174 * release this cell, free extended data if available 175 */ 176 177 static inline void free_cell(struct snd_seq_pool *pool, 178 struct snd_seq_event_cell *cell) 179 { 180 cell->next = pool->free; 181 pool->free = cell; 182 atomic_dec(&pool->counter); 183 } 184 185 void snd_seq_cell_free(struct snd_seq_event_cell * cell) 186 { 187 unsigned long flags; 188 struct snd_seq_pool *pool; 189 190 if (snd_BUG_ON(!cell)) 191 return; 192 pool = cell->pool; 193 if (snd_BUG_ON(!pool)) 194 return; 195 196 spin_lock_irqsave(&pool->lock, flags); 197 free_cell(pool, cell); 198 if (snd_seq_ev_is_variable(&cell->event)) { 199 if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) { 200 struct snd_seq_event_cell *curp, *nextptr; 201 curp = cell->event.data.ext.ptr; 202 for (; curp; curp = nextptr) { 203 nextptr = curp->next; 204 curp->next = pool->free; 205 free_cell(pool, curp); 206 } 207 } 208 } 209 if (waitqueue_active(&pool->output_sleep)) { 210 /* has enough space now? */ 211 if (snd_seq_output_ok(pool)) 212 wake_up(&pool->output_sleep); 213 } 214 spin_unlock_irqrestore(&pool->lock, flags); 215 } 216 217 218 /* 219 * allocate an event cell. 220 */ 221 static int snd_seq_cell_alloc(struct snd_seq_pool *pool, 222 struct snd_seq_event_cell **cellp, 223 int nonblock, struct file *file) 224 { 225 struct snd_seq_event_cell *cell; 226 unsigned long flags; 227 int err = -EAGAIN; 228 wait_queue_entry_t wait; 229 230 if (pool == NULL) 231 return -EINVAL; 232 233 *cellp = NULL; 234 235 init_waitqueue_entry(&wait, current); 236 spin_lock_irqsave(&pool->lock, flags); 237 if (pool->ptr == NULL) { /* not initialized */ 238 pr_debug("ALSA: seq: pool is not initialized\n"); 239 err = -EINVAL; 240 goto __error; 241 } 242 while (pool->free == NULL && ! nonblock && ! pool->closing) { 243 244 set_current_state(TASK_INTERRUPTIBLE); 245 add_wait_queue(&pool->output_sleep, &wait); 246 spin_unlock_irq(&pool->lock); 247 schedule(); 248 spin_lock_irq(&pool->lock); 249 remove_wait_queue(&pool->output_sleep, &wait); 250 /* interrupted? */ 251 if (signal_pending(current)) { 252 err = -ERESTARTSYS; 253 goto __error; 254 } 255 } 256 if (pool->closing) { /* closing.. */ 257 err = -ENOMEM; 258 goto __error; 259 } 260 261 cell = pool->free; 262 if (cell) { 263 int used; 264 pool->free = cell->next; 265 atomic_inc(&pool->counter); 266 used = atomic_read(&pool->counter); 267 if (pool->max_used < used) 268 pool->max_used = used; 269 pool->event_alloc_success++; 270 /* clear cell pointers */ 271 cell->next = NULL; 272 err = 0; 273 } else 274 pool->event_alloc_failures++; 275 *cellp = cell; 276 277 __error: 278 spin_unlock_irqrestore(&pool->lock, flags); 279 return err; 280 } 281 282 283 /* 284 * duplicate the event to a cell. 285 * if the event has external data, the data is decomposed to additional 286 * cells. 287 */ 288 int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, 289 struct snd_seq_event_cell **cellp, int nonblock, 290 struct file *file) 291 { 292 int ncells, err; 293 unsigned int extlen; 294 struct snd_seq_event_cell *cell; 295 296 *cellp = NULL; 297 298 ncells = 0; 299 extlen = 0; 300 if (snd_seq_ev_is_variable(event)) { 301 extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK; 302 ncells = (extlen + sizeof(struct snd_seq_event) - 1) / sizeof(struct snd_seq_event); 303 } 304 if (ncells >= pool->total_elements) 305 return -ENOMEM; 306 307 err = snd_seq_cell_alloc(pool, &cell, nonblock, file); 308 if (err < 0) 309 return err; 310 311 /* copy the event */ 312 cell->event = *event; 313 314 /* decompose */ 315 if (snd_seq_ev_is_variable(event)) { 316 int len = extlen; 317 int is_chained = event->data.ext.len & SNDRV_SEQ_EXT_CHAINED; 318 int is_usrptr = event->data.ext.len & SNDRV_SEQ_EXT_USRPTR; 319 struct snd_seq_event_cell *src, *tmp, *tail; 320 char *buf; 321 322 cell->event.data.ext.len = extlen | SNDRV_SEQ_EXT_CHAINED; 323 cell->event.data.ext.ptr = NULL; 324 325 src = (struct snd_seq_event_cell *)event->data.ext.ptr; 326 buf = (char *)event->data.ext.ptr; 327 tail = NULL; 328 329 while (ncells-- > 0) { 330 int size = sizeof(struct snd_seq_event); 331 if (len < size) 332 size = len; 333 err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); 334 if (err < 0) 335 goto __error; 336 if (cell->event.data.ext.ptr == NULL) 337 cell->event.data.ext.ptr = tmp; 338 if (tail) 339 tail->next = tmp; 340 tail = tmp; 341 /* copy chunk */ 342 if (is_chained && src) { 343 tmp->event = src->event; 344 src = src->next; 345 } else if (is_usrptr) { 346 if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) { 347 err = -EFAULT; 348 goto __error; 349 } 350 } else { 351 memcpy(&tmp->event, buf, size); 352 } 353 buf += size; 354 len -= size; 355 } 356 } 357 358 *cellp = cell; 359 return 0; 360 361 __error: 362 snd_seq_cell_free(cell); 363 return err; 364 } 365 366 367 /* poll wait */ 368 int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, 369 poll_table *wait) 370 { 371 poll_wait(file, &pool->output_sleep, wait); 372 return snd_seq_output_ok(pool); 373 } 374 375 376 /* allocate room specified number of events */ 377 int snd_seq_pool_init(struct snd_seq_pool *pool) 378 { 379 int cell; 380 struct snd_seq_event_cell *cellptr; 381 unsigned long flags; 382 383 if (snd_BUG_ON(!pool)) 384 return -EINVAL; 385 386 cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); 387 if (!cellptr) 388 return -ENOMEM; 389 390 /* add new cells to the free cell list */ 391 spin_lock_irqsave(&pool->lock, flags); 392 if (pool->ptr) { 393 spin_unlock_irqrestore(&pool->lock, flags); 394 vfree(cellptr); 395 return 0; 396 } 397 398 pool->ptr = cellptr; 399 pool->free = NULL; 400 401 for (cell = 0; cell < pool->size; cell++) { 402 cellptr = pool->ptr + cell; 403 cellptr->pool = pool; 404 cellptr->next = pool->free; 405 pool->free = cellptr; 406 } 407 pool->room = (pool->size + 1) / 2; 408 409 /* init statistics */ 410 pool->max_used = 0; 411 pool->total_elements = pool->size; 412 spin_unlock_irqrestore(&pool->lock, flags); 413 return 0; 414 } 415 416 /* refuse the further insertion to the pool */ 417 void snd_seq_pool_mark_closing(struct snd_seq_pool *pool) 418 { 419 unsigned long flags; 420 421 if (snd_BUG_ON(!pool)) 422 return; 423 spin_lock_irqsave(&pool->lock, flags); 424 pool->closing = 1; 425 spin_unlock_irqrestore(&pool->lock, flags); 426 } 427 428 /* remove events */ 429 int snd_seq_pool_done(struct snd_seq_pool *pool) 430 { 431 unsigned long flags; 432 struct snd_seq_event_cell *ptr; 433 434 if (snd_BUG_ON(!pool)) 435 return -EINVAL; 436 437 /* wait for closing all threads */ 438 if (waitqueue_active(&pool->output_sleep)) 439 wake_up(&pool->output_sleep); 440 441 while (atomic_read(&pool->counter) > 0) 442 schedule_timeout_uninterruptible(1); 443 444 /* release all resources */ 445 spin_lock_irqsave(&pool->lock, flags); 446 ptr = pool->ptr; 447 pool->ptr = NULL; 448 pool->free = NULL; 449 pool->total_elements = 0; 450 spin_unlock_irqrestore(&pool->lock, flags); 451 452 vfree(ptr); 453 454 spin_lock_irqsave(&pool->lock, flags); 455 pool->closing = 0; 456 spin_unlock_irqrestore(&pool->lock, flags); 457 458 return 0; 459 } 460 461 462 /* init new memory pool */ 463 struct snd_seq_pool *snd_seq_pool_new(int poolsize) 464 { 465 struct snd_seq_pool *pool; 466 467 /* create pool block */ 468 pool = kzalloc(sizeof(*pool), GFP_KERNEL); 469 if (!pool) 470 return NULL; 471 spin_lock_init(&pool->lock); 472 pool->ptr = NULL; 473 pool->free = NULL; 474 pool->total_elements = 0; 475 atomic_set(&pool->counter, 0); 476 pool->closing = 0; 477 init_waitqueue_head(&pool->output_sleep); 478 479 pool->size = poolsize; 480 481 /* init statistics */ 482 pool->max_used = 0; 483 return pool; 484 } 485 486 /* remove memory pool */ 487 int snd_seq_pool_delete(struct snd_seq_pool **ppool) 488 { 489 struct snd_seq_pool *pool = *ppool; 490 491 *ppool = NULL; 492 if (pool == NULL) 493 return 0; 494 snd_seq_pool_mark_closing(pool); 495 snd_seq_pool_done(pool); 496 kfree(pool); 497 return 0; 498 } 499 500 /* initialize sequencer memory */ 501 int __init snd_sequencer_memory_init(void) 502 { 503 return 0; 504 } 505 506 /* release sequencer memory */ 507 void __exit snd_sequencer_memory_done(void) 508 { 509 } 510 511 512 /* exported to seq_clientmgr.c */ 513 void snd_seq_info_pool(struct snd_info_buffer *buffer, 514 struct snd_seq_pool *pool, char *space) 515 { 516 if (pool == NULL) 517 return; 518 snd_iprintf(buffer, "%sPool size : %d\n", space, pool->total_elements); 519 snd_iprintf(buffer, "%sCells in use : %d\n", space, atomic_read(&pool->counter)); 520 snd_iprintf(buffer, "%sPeak cells in use : %d\n", space, pool->max_used); 521 snd_iprintf(buffer, "%sAlloc success : %d\n", space, pool->event_alloc_success); 522 snd_iprintf(buffer, "%sAlloc failures : %d\n", space, pool->event_alloc_failures); 523 } 524