1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include "seq_oss_writeq.h"
24#include "seq_oss_event.h"
25#include "seq_oss_timer.h"
26#include <sound/seq_oss_legacy.h>
27#include "../seq_lock.h"
28#include "../seq_clientmgr.h"
29#include <linux/wait.h>
30#include <linux/slab.h>
31
32
33
34
35
36struct seq_oss_writeq *
37snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
38{
39 struct seq_oss_writeq *q;
40 struct snd_seq_client_pool pool;
41
42 if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
43 return NULL;
44 q->dp = dp;
45 q->maxlen = maxlen;
46 spin_lock_init(&q->sync_lock);
47 q->sync_event_put = 0;
48 q->sync_time = 0;
49 init_waitqueue_head(&q->sync_sleep);
50
51 memset(&pool, 0, sizeof(pool));
52 pool.client = dp->cseq;
53 pool.output_pool = maxlen;
54 pool.output_room = maxlen / 2;
55
56 snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
57
58 return q;
59}
60
61
62
63
64void
65snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
66{
67 if (q) {
68 snd_seq_oss_writeq_clear(q);
69 kfree(q);
70 }
71}
72
73
74
75
76
77void
78snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
79{
80 struct snd_seq_remove_events reset;
81
82 memset(&reset, 0, sizeof(reset));
83 reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT;
84 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
85
86
87 snd_seq_oss_writeq_wakeup(q, 0);
88}
89
90
91
92
93int
94snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
95{
96 struct seq_oss_devinfo *dp = q->dp;
97 abstime_t time;
98
99 time = snd_seq_oss_timer_cur_tick(dp->timer);
100 if (q->sync_time >= time)
101 return 0;
102
103 if (! q->sync_event_put) {
104 struct snd_seq_event ev;
105 union evrec *rec;
106
107
108 memset(&ev, 0, sizeof(ev));
109 ev.flags = 0;
110 ev.type = SNDRV_SEQ_EVENT_ECHO;
111 ev.time.tick = time;
112
113 snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
114 rec = (union evrec *)&ev.data;
115 rec->t.code = SEQ_SYNCTIMER;
116 rec->t.time = time;
117 q->sync_event_put = 1;
118 snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
119 }
120
121 wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
122 if (signal_pending(current))
123
124 q->sync_event_put = 0;
125 if (! q->sync_event_put || q->sync_time >= time)
126 return 0;
127 return 1;
128}
129
130
131
132
133void
134snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
135{
136 unsigned long flags;
137
138 spin_lock_irqsave(&q->sync_lock, flags);
139 q->sync_time = time;
140 q->sync_event_put = 0;
141 wake_up(&q->sync_sleep);
142 spin_unlock_irqrestore(&q->sync_lock, flags);
143}
144
145
146
147
148
149int
150snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
151{
152 struct snd_seq_client_pool pool;
153 pool.client = q->dp->cseq;
154 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
155 return pool.output_free;
156}
157
158
159
160
161
162void
163snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
164{
165 struct snd_seq_client_pool pool;
166 pool.client = q->dp->cseq;
167 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
168 pool.output_room = val;
169 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
170}
171
172