seq_oss_writeq.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * OSS compatible sequencer driver
  3. *
  4. * seq_oss_writeq.c - write queue and sync
  5. *
  6. * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. #include "seq_oss_writeq.h"
  23. #include "seq_oss_event.h"
  24. #include "seq_oss_timer.h"
  25. #include <sound/seq_oss_legacy.h>
  26. #include "../seq_lock.h"
  27. #include "../seq_clientmgr.h"
  28. #include <linux/wait.h>
  29. #include <linux/slab.h>
  30. /*
  31. * create a write queue record
  32. */
  33. struct seq_oss_writeq *
  34. snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
  35. {
  36. struct seq_oss_writeq *q;
  37. struct snd_seq_client_pool pool;
  38. if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
  39. return NULL;
  40. q->dp = dp;
  41. q->maxlen = maxlen;
  42. spin_lock_init(&q->sync_lock);
  43. q->sync_event_put = 0;
  44. q->sync_time = 0;
  45. init_waitqueue_head(&q->sync_sleep);
  46. memset(&pool, 0, sizeof(pool));
  47. pool.client = dp->cseq;
  48. pool.output_pool = maxlen;
  49. pool.output_room = maxlen / 2;
  50. snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
  51. return q;
  52. }
  53. /*
  54. * delete the write queue
  55. */
  56. void
  57. snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
  58. {
  59. if (q) {
  60. snd_seq_oss_writeq_clear(q); /* to be sure */
  61. kfree(q);
  62. }
  63. }
  64. /*
  65. * reset the write queue
  66. */
  67. void
  68. snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
  69. {
  70. struct snd_seq_remove_events reset;
  71. memset(&reset, 0, sizeof(reset));
  72. reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
  73. snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
  74. /* wake up sleepers if any */
  75. snd_seq_oss_writeq_wakeup(q, 0);
  76. }
  77. /*
  78. * wait until the write buffer has enough room
  79. */
  80. int
  81. snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
  82. {
  83. struct seq_oss_devinfo *dp = q->dp;
  84. abstime_t time;
  85. time = snd_seq_oss_timer_cur_tick(dp->timer);
  86. if (q->sync_time >= time)
  87. return 0; /* already finished */
  88. if (! q->sync_event_put) {
  89. struct snd_seq_event ev;
  90. union evrec *rec;
  91. /* put echoback event */
  92. memset(&ev, 0, sizeof(ev));
  93. ev.flags = 0;
  94. ev.type = SNDRV_SEQ_EVENT_ECHO;
  95. ev.time.tick = time;
  96. /* echo back to itself */
  97. snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
  98. rec = (union evrec *)&ev.data;
  99. rec->t.code = SEQ_SYNCTIMER;
  100. rec->t.time = time;
  101. q->sync_event_put = 1;
  102. snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
  103. }
  104. wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
  105. if (signal_pending(current))
  106. /* interrupted - return 0 to finish sync */
  107. q->sync_event_put = 0;
  108. if (! q->sync_event_put || q->sync_time >= time)
  109. return 0;
  110. return 1;
  111. }
  112. /*
  113. * wake up sync - echo event was catched
  114. */
  115. void
  116. snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
  117. {
  118. unsigned long flags;
  119. spin_lock_irqsave(&q->sync_lock, flags);
  120. q->sync_time = time;
  121. q->sync_event_put = 0;
  122. wake_up(&q->sync_sleep);
  123. spin_unlock_irqrestore(&q->sync_lock, flags);
  124. }
  125. /*
  126. * return the unused pool size
  127. */
  128. int
  129. snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
  130. {
  131. struct snd_seq_client_pool pool;
  132. pool.client = q->dp->cseq;
  133. snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
  134. return pool.output_free;
  135. }
  136. /*
  137. * set output threshold size from ioctl
  138. */
  139. void
  140. snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
  141. {
  142. struct snd_seq_client_pool pool;
  143. pool.client = q->dp->cseq;
  144. snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
  145. pool.output_room = val;
  146. snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
  147. }