Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * OSS compatible sequencer driver | |
3 | * | |
4 | * seq_oss_readq.c - MIDI input queue | |
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_readq.h" | |
24 | #include "seq_oss_event.h" | |
25 | #include <sound/seq_oss_legacy.h> | |
26 | #include "../seq_lock.h" | |
27 | #include <linux/wait.h> | |
5a0e3ad6 | 28 | #include <linux/slab.h> |
1da177e4 LT |
29 | |
30 | /* | |
31 | * constants | |
32 | */ | |
33 | //#define SNDRV_SEQ_OSS_MAX_TIMEOUT (unsigned long)(-1) | |
34 | #define SNDRV_SEQ_OSS_MAX_TIMEOUT (HZ * 3600) | |
35 | ||
36 | ||
37 | /* | |
38 | * prototypes | |
39 | */ | |
40 | ||
41 | ||
42 | /* | |
43 | * create a read queue | |
44 | */ | |
080dece3 TI |
45 | struct seq_oss_readq * |
46 | snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen) | |
1da177e4 | 47 | { |
080dece3 | 48 | struct seq_oss_readq *q; |
1da177e4 | 49 | |
ecca82b4 | 50 | if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) { |
1da177e4 LT |
51 | snd_printk(KERN_ERR "can't malloc read queue\n"); |
52 | return NULL; | |
53 | } | |
54 | ||
080dece3 | 55 | if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) { |
1da177e4 LT |
56 | snd_printk(KERN_ERR "can't malloc read queue buffer\n"); |
57 | kfree(q); | |
58 | return NULL; | |
59 | } | |
60 | ||
61 | q->maxlen = maxlen; | |
62 | q->qlen = 0; | |
63 | q->head = q->tail = 0; | |
64 | init_waitqueue_head(&q->midi_sleep); | |
65 | spin_lock_init(&q->lock); | |
66 | q->pre_event_timeout = SNDRV_SEQ_OSS_MAX_TIMEOUT; | |
67 | q->input_time = (unsigned long)-1; | |
68 | ||
69 | return q; | |
70 | } | |
71 | ||
72 | /* | |
73 | * delete the read queue | |
74 | */ | |
75 | void | |
080dece3 | 76 | snd_seq_oss_readq_delete(struct seq_oss_readq *q) |
1da177e4 LT |
77 | { |
78 | if (q) { | |
79 | kfree(q->q); | |
80 | kfree(q); | |
81 | } | |
82 | } | |
83 | ||
84 | /* | |
85 | * reset the read queue | |
86 | */ | |
87 | void | |
080dece3 | 88 | snd_seq_oss_readq_clear(struct seq_oss_readq *q) |
1da177e4 LT |
89 | { |
90 | if (q->qlen) { | |
91 | q->qlen = 0; | |
92 | q->head = q->tail = 0; | |
93 | } | |
94 | /* if someone sleeping, wake'em up */ | |
95 | if (waitqueue_active(&q->midi_sleep)) | |
96 | wake_up(&q->midi_sleep); | |
97 | q->input_time = (unsigned long)-1; | |
98 | } | |
99 | ||
100 | /* | |
101 | * put a midi byte | |
102 | */ | |
103 | int | |
080dece3 | 104 | snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, int len) |
1da177e4 | 105 | { |
080dece3 | 106 | union evrec rec; |
1da177e4 LT |
107 | int result; |
108 | ||
109 | memset(&rec, 0, sizeof(rec)); | |
110 | rec.c[0] = SEQ_MIDIPUTC; | |
111 | rec.c[2] = dev; | |
112 | ||
113 | while (len-- > 0) { | |
114 | rec.c[1] = *data++; | |
115 | result = snd_seq_oss_readq_put_event(q, &rec); | |
116 | if (result < 0) | |
117 | return result; | |
118 | } | |
119 | return 0; | |
120 | } | |
121 | ||
122 | /* | |
123 | * copy an event to input queue: | |
124 | * return zero if enqueued | |
125 | */ | |
126 | int | |
080dece3 | 127 | snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev) |
1da177e4 LT |
128 | { |
129 | unsigned long flags; | |
130 | ||
131 | spin_lock_irqsave(&q->lock, flags); | |
132 | if (q->qlen >= q->maxlen - 1) { | |
133 | spin_unlock_irqrestore(&q->lock, flags); | |
134 | return -ENOMEM; | |
135 | } | |
136 | ||
137 | memcpy(&q->q[q->tail], ev, sizeof(*ev)); | |
138 | q->tail = (q->tail + 1) % q->maxlen; | |
139 | q->qlen++; | |
140 | ||
141 | /* wake up sleeper */ | |
142 | if (waitqueue_active(&q->midi_sleep)) | |
143 | wake_up(&q->midi_sleep); | |
144 | ||
145 | spin_unlock_irqrestore(&q->lock, flags); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | ||
151 | /* | |
152 | * pop queue | |
153 | * caller must hold lock | |
154 | */ | |
155 | int | |
080dece3 | 156 | snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec) |
1da177e4 LT |
157 | { |
158 | if (q->qlen == 0) | |
159 | return -EAGAIN; | |
160 | memcpy(rec, &q->q[q->head], sizeof(*rec)); | |
161 | return 0; | |
162 | } | |
163 | ||
164 | /* | |
165 | * sleep until ready | |
166 | */ | |
167 | void | |
080dece3 | 168 | snd_seq_oss_readq_wait(struct seq_oss_readq *q) |
1da177e4 LT |
169 | { |
170 | wait_event_interruptible_timeout(q->midi_sleep, | |
171 | (q->qlen > 0 || q->head == q->tail), | |
172 | q->pre_event_timeout); | |
173 | } | |
174 | ||
175 | /* | |
176 | * drain one record | |
177 | * caller must hold lock | |
178 | */ | |
179 | void | |
080dece3 | 180 | snd_seq_oss_readq_free(struct seq_oss_readq *q) |
1da177e4 LT |
181 | { |
182 | if (q->qlen > 0) { | |
183 | q->head = (q->head + 1) % q->maxlen; | |
184 | q->qlen--; | |
185 | } | |
186 | } | |
187 | ||
188 | /* | |
189 | * polling/select: | |
190 | * return non-zero if readq is not empty. | |
191 | */ | |
192 | unsigned int | |
080dece3 | 193 | snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wait) |
1da177e4 LT |
194 | { |
195 | poll_wait(file, &q->midi_sleep, wait); | |
196 | return q->qlen; | |
197 | } | |
198 | ||
199 | /* | |
200 | * put a timestamp | |
201 | */ | |
202 | int | |
080dece3 | 203 | snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode) |
1da177e4 LT |
204 | { |
205 | if (curt != q->input_time) { | |
080dece3 | 206 | union evrec rec; |
1da177e4 LT |
207 | memset(&rec, 0, sizeof(rec)); |
208 | switch (seq_mode) { | |
209 | case SNDRV_SEQ_OSS_MODE_SYNTH: | |
210 | rec.echo = (curt << 8) | SEQ_WAIT; | |
211 | snd_seq_oss_readq_put_event(q, &rec); | |
212 | break; | |
213 | case SNDRV_SEQ_OSS_MODE_MUSIC: | |
214 | rec.t.code = EV_TIMING; | |
215 | rec.t.cmd = TMR_WAIT_ABS; | |
216 | rec.t.time = curt; | |
217 | snd_seq_oss_readq_put_event(q, &rec); | |
218 | break; | |
219 | } | |
220 | q->input_time = curt; | |
221 | } | |
222 | return 0; | |
223 | } | |
224 | ||
225 | ||
04f141a8 | 226 | #ifdef CONFIG_PROC_FS |
1da177e4 LT |
227 | /* |
228 | * proc interface | |
229 | */ | |
230 | void | |
080dece3 | 231 | snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf) |
1da177e4 LT |
232 | { |
233 | snd_iprintf(buf, " read queue [%s] length = %d : tick = %ld\n", | |
234 | (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"), | |
235 | q->qlen, q->input_time); | |
236 | } | |
04f141a8 | 237 | #endif /* CONFIG_PROC_FS */ |