]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
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> | |
5a0e3ad6 | 30 | #include <linux/slab.h> |
174cd4b1 | 31 | #include <linux/sched/signal.h> |
1da177e4 LT |
32 | |
33 | ||
34 | /* | |
35 | * create a write queue record | |
36 | */ | |
080dece3 TI |
37 | struct seq_oss_writeq * |
38 | snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) | |
1da177e4 | 39 | { |
080dece3 TI |
40 | struct seq_oss_writeq *q; |
41 | struct snd_seq_client_pool pool; | |
1da177e4 | 42 | |
ecca82b4 | 43 | if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) |
1da177e4 LT |
44 | return NULL; |
45 | q->dp = dp; | |
46 | q->maxlen = maxlen; | |
47 | spin_lock_init(&q->sync_lock); | |
48 | q->sync_event_put = 0; | |
49 | q->sync_time = 0; | |
50 | init_waitqueue_head(&q->sync_sleep); | |
51 | ||
52 | memset(&pool, 0, sizeof(pool)); | |
53 | pool.client = dp->cseq; | |
54 | pool.output_pool = maxlen; | |
55 | pool.output_room = maxlen / 2; | |
56 | ||
57 | snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); | |
58 | ||
59 | return q; | |
60 | } | |
61 | ||
62 | /* | |
63 | * delete the write queue | |
64 | */ | |
65 | void | |
080dece3 | 66 | snd_seq_oss_writeq_delete(struct seq_oss_writeq *q) |
1da177e4 | 67 | { |
7034632d ET |
68 | if (q) { |
69 | snd_seq_oss_writeq_clear(q); /* to be sure */ | |
70 | kfree(q); | |
71 | } | |
1da177e4 LT |
72 | } |
73 | ||
74 | ||
75 | /* | |
76 | * reset the write queue | |
77 | */ | |
78 | void | |
080dece3 | 79 | snd_seq_oss_writeq_clear(struct seq_oss_writeq *q) |
1da177e4 | 80 | { |
080dece3 | 81 | struct snd_seq_remove_events reset; |
1da177e4 LT |
82 | |
83 | memset(&reset, 0, sizeof(reset)); | |
84 | reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */ | |
85 | snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset); | |
86 | ||
87 | /* wake up sleepers if any */ | |
88 | snd_seq_oss_writeq_wakeup(q, 0); | |
89 | } | |
90 | ||
91 | /* | |
92 | * wait until the write buffer has enough room | |
93 | */ | |
94 | int | |
080dece3 | 95 | snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) |
1da177e4 | 96 | { |
080dece3 | 97 | struct seq_oss_devinfo *dp = q->dp; |
1da177e4 LT |
98 | abstime_t time; |
99 | ||
100 | time = snd_seq_oss_timer_cur_tick(dp->timer); | |
101 | if (q->sync_time >= time) | |
102 | return 0; /* already finished */ | |
103 | ||
104 | if (! q->sync_event_put) { | |
080dece3 TI |
105 | struct snd_seq_event ev; |
106 | union evrec *rec; | |
1da177e4 LT |
107 | |
108 | /* put echoback event */ | |
109 | memset(&ev, 0, sizeof(ev)); | |
110 | ev.flags = 0; | |
111 | ev.type = SNDRV_SEQ_EVENT_ECHO; | |
112 | ev.time.tick = time; | |
113 | /* echo back to itself */ | |
114 | snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port); | |
080dece3 | 115 | rec = (union evrec *)&ev.data; |
1da177e4 LT |
116 | rec->t.code = SEQ_SYNCTIMER; |
117 | rec->t.time = time; | |
118 | q->sync_event_put = 1; | |
119 | snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); | |
120 | } | |
121 | ||
122 | wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); | |
123 | if (signal_pending(current)) | |
124 | /* interrupted - return 0 to finish sync */ | |
125 | q->sync_event_put = 0; | |
126 | if (! q->sync_event_put || q->sync_time >= time) | |
127 | return 0; | |
128 | return 1; | |
129 | } | |
130 | ||
131 | /* | |
132 | * wake up sync - echo event was catched | |
133 | */ | |
134 | void | |
080dece3 | 135 | snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time) |
1da177e4 LT |
136 | { |
137 | unsigned long flags; | |
138 | ||
139 | spin_lock_irqsave(&q->sync_lock, flags); | |
140 | q->sync_time = time; | |
141 | q->sync_event_put = 0; | |
69447027 | 142 | wake_up(&q->sync_sleep); |
1da177e4 LT |
143 | spin_unlock_irqrestore(&q->sync_lock, flags); |
144 | } | |
145 | ||
146 | ||
147 | /* | |
148 | * return the unused pool size | |
149 | */ | |
150 | int | |
080dece3 | 151 | snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q) |
1da177e4 | 152 | { |
080dece3 | 153 | struct snd_seq_client_pool pool; |
1da177e4 LT |
154 | pool.client = q->dp->cseq; |
155 | snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool); | |
156 | return pool.output_free; | |
157 | } | |
158 | ||
159 | ||
160 | /* | |
161 | * set output threshold size from ioctl | |
162 | */ | |
163 | void | |
080dece3 | 164 | snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val) |
1da177e4 | 165 | { |
080dece3 | 166 | struct snd_seq_client_pool pool; |
1da177e4 LT |
167 | pool.client = q->dp->cseq; |
168 | snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool); | |
169 | pool.output_room = val; | |
170 | snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool); | |
171 | } | |
172 |