seq_fifo.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * ALSA sequencer FIFO
  3. * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
  4. *
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. */
  21. #include <sound/driver.h>
  22. #include <sound/core.h>
  23. #include <linux/slab.h>
  24. #include "seq_fifo.h"
  25. #include "seq_lock.h"
  26. /* FIFO */
  27. /* create new fifo */
  28. fifo_t *snd_seq_fifo_new(int poolsize)
  29. {
  30. fifo_t *f;
  31. f = kcalloc(1, sizeof(*f), GFP_KERNEL);
  32. if (f == NULL) {
  33. snd_printd("malloc failed for snd_seq_fifo_new() \n");
  34. return NULL;
  35. }
  36. f->pool = snd_seq_pool_new(poolsize);
  37. if (f->pool == NULL) {
  38. kfree(f);
  39. return NULL;
  40. }
  41. if (snd_seq_pool_init(f->pool) < 0) {
  42. snd_seq_pool_delete(&f->pool);
  43. kfree(f);
  44. return NULL;
  45. }
  46. spin_lock_init(&f->lock);
  47. snd_use_lock_init(&f->use_lock);
  48. init_waitqueue_head(&f->input_sleep);
  49. atomic_set(&f->overflow, 0);
  50. f->head = NULL;
  51. f->tail = NULL;
  52. f->cells = 0;
  53. return f;
  54. }
  55. void snd_seq_fifo_delete(fifo_t **fifo)
  56. {
  57. fifo_t *f;
  58. snd_assert(fifo != NULL, return);
  59. f = *fifo;
  60. snd_assert(f != NULL, return);
  61. *fifo = NULL;
  62. snd_seq_fifo_clear(f);
  63. /* wake up clients if any */
  64. if (waitqueue_active(&f->input_sleep))
  65. wake_up(&f->input_sleep);
  66. /* release resources...*/
  67. /*....................*/
  68. if (f->pool) {
  69. snd_seq_pool_done(f->pool);
  70. snd_seq_pool_delete(&f->pool);
  71. }
  72. kfree(f);
  73. }
  74. static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f);
  75. /* clear queue */
  76. void snd_seq_fifo_clear(fifo_t *f)
  77. {
  78. snd_seq_event_cell_t *cell;
  79. unsigned long flags;
  80. /* clear overflow flag */
  81. atomic_set(&f->overflow, 0);
  82. snd_use_lock_sync(&f->use_lock);
  83. spin_lock_irqsave(&f->lock, flags);
  84. /* drain the fifo */
  85. while ((cell = fifo_cell_out(f)) != NULL) {
  86. snd_seq_cell_free(cell);
  87. }
  88. spin_unlock_irqrestore(&f->lock, flags);
  89. }
  90. /* enqueue event to fifo */
  91. int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event)
  92. {
  93. snd_seq_event_cell_t *cell;
  94. unsigned long flags;
  95. int err;
  96. snd_assert(f != NULL, return -EINVAL);
  97. snd_use_lock_use(&f->use_lock);
  98. err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
  99. if (err < 0) {
  100. if (err == -ENOMEM)
  101. atomic_inc(&f->overflow);
  102. snd_use_lock_free(&f->use_lock);
  103. return err;
  104. }
  105. /* append new cells to fifo */
  106. spin_lock_irqsave(&f->lock, flags);
  107. if (f->tail != NULL)
  108. f->tail->next = cell;
  109. f->tail = cell;
  110. if (f->head == NULL)
  111. f->head = cell;
  112. f->cells++;
  113. spin_unlock_irqrestore(&f->lock, flags);
  114. /* wakeup client */
  115. if (waitqueue_active(&f->input_sleep))
  116. wake_up(&f->input_sleep);
  117. snd_use_lock_free(&f->use_lock);
  118. return 0; /* success */
  119. }
  120. /* dequeue cell from fifo */
  121. static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f)
  122. {
  123. snd_seq_event_cell_t *cell;
  124. if ((cell = f->head) != NULL) {
  125. f->head = cell->next;
  126. /* reset tail if this was the last element */
  127. if (f->tail == cell)
  128. f->tail = NULL;
  129. cell->next = NULL;
  130. f->cells--;
  131. }
  132. return cell;
  133. }
  134. /* dequeue cell from fifo and copy on user space */
  135. int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
  136. {
  137. snd_seq_event_cell_t *cell;
  138. unsigned long flags;
  139. wait_queue_t wait;
  140. snd_assert(f != NULL, return -EINVAL);
  141. *cellp = NULL;
  142. init_waitqueue_entry(&wait, current);
  143. spin_lock_irqsave(&f->lock, flags);
  144. while ((cell = fifo_cell_out(f)) == NULL) {
  145. if (nonblock) {
  146. /* non-blocking - return immediately */
  147. spin_unlock_irqrestore(&f->lock, flags);
  148. return -EAGAIN;
  149. }
  150. set_current_state(TASK_INTERRUPTIBLE);
  151. add_wait_queue(&f->input_sleep, &wait);
  152. spin_unlock_irq(&f->lock);
  153. schedule();
  154. spin_lock_irq(&f->lock);
  155. remove_wait_queue(&f->input_sleep, &wait);
  156. if (signal_pending(current)) {
  157. spin_unlock_irqrestore(&f->lock, flags);
  158. return -ERESTARTSYS;
  159. }
  160. }
  161. spin_unlock_irqrestore(&f->lock, flags);
  162. *cellp = cell;
  163. return 0;
  164. }
  165. void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell)
  166. {
  167. unsigned long flags;
  168. if (cell) {
  169. spin_lock_irqsave(&f->lock, flags);
  170. cell->next = f->head;
  171. f->head = cell;
  172. f->cells++;
  173. spin_unlock_irqrestore(&f->lock, flags);
  174. }
  175. }
  176. /* polling; return non-zero if queue is available */
  177. int snd_seq_fifo_poll_wait(fifo_t *f, struct file *file, poll_table *wait)
  178. {
  179. poll_wait(file, &f->input_sleep, wait);
  180. return (f->cells > 0);
  181. }
  182. /* change the size of pool; all old events are removed */
  183. int snd_seq_fifo_resize(fifo_t *f, int poolsize)
  184. {
  185. unsigned long flags;
  186. pool_t *newpool, *oldpool;
  187. snd_seq_event_cell_t *cell, *next, *oldhead;
  188. snd_assert(f != NULL && f->pool != NULL, return -EINVAL);
  189. /* allocate new pool */
  190. newpool = snd_seq_pool_new(poolsize);
  191. if (newpool == NULL)
  192. return -ENOMEM;
  193. if (snd_seq_pool_init(newpool) < 0) {
  194. snd_seq_pool_delete(&newpool);
  195. return -ENOMEM;
  196. }
  197. spin_lock_irqsave(&f->lock, flags);
  198. /* remember old pool */
  199. oldpool = f->pool;
  200. oldhead = f->head;
  201. /* exchange pools */
  202. f->pool = newpool;
  203. f->head = NULL;
  204. f->tail = NULL;
  205. f->cells = 0;
  206. /* NOTE: overflow flag is not cleared */
  207. spin_unlock_irqrestore(&f->lock, flags);
  208. /* release cells in old pool */
  209. for (cell = oldhead; cell; cell = next) {
  210. next = cell->next;
  211. snd_seq_cell_free(cell);
  212. }
  213. snd_seq_pool_delete(&oldpool);
  214. return 0;
  215. }