1 /*
2 * Copyright (C) 1999 Seigo Tanimura
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the following
7 * conditions are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
16 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: releng/5.0/sys/dev/sound/midi/midibuf.c 92252 2002-03-14 01:32:30Z alfred $
29 *
30 */
31
32 /*
33 * This file implements a midi event/message queue. A midi
34 * event/message queue holds midi events and messages to
35 * transmit to or received from a midi interface.
36 */
37
38 #include <dev/sound/midi/midi.h>
39
40 /* Some macros to handle the queue. */
41 #define DATA_AVAIL(dbuf) ((dbuf)->rl)
42 #define SPACE_AVAIL(dbuf) ((dbuf)->fl)
43
44 static void queuerawdata(midi_dbuf *dbuf, char *data, int len);
45 static void dequeuerawdata(midi_dbuf *dbuf, char *data, int len);
46 static void copyrawdata(midi_dbuf *dbuf, int offset, char *data, int len);
47 static void deleterawdata(midi_dbuf *dbuf, int len);
48
49 /*
50 * Here are the functions to interact to the midi device drivers.
51 * These are called from midi device driver functions under sys/i386/isa/snd.
52 */
53
54 int
55 midibuf_init(midi_dbuf *dbuf)
56 {
57 if (dbuf->buf == NULL) {
58 dbuf->buf = malloc(MIDI_BUFFSIZE, M_DEVBUF, M_WAITOK | M_ZERO);
59 cv_init(&dbuf->cv_in, "midi queue in");
60 cv_init(&dbuf->cv_out, "midi queue out");
61 }
62
63 return (midibuf_clear(dbuf));
64 }
65
66 int
67 midibuf_destroy(midi_dbuf *dbuf)
68 {
69 if (dbuf->buf != NULL) {
70 free(dbuf->buf, M_DEVBUF);
71 cv_destroy(&dbuf->cv_in);
72 cv_destroy(&dbuf->cv_out);
73 }
74
75 return (0);
76 }
77
78 int
79 midibuf_clear(midi_dbuf *dbuf)
80 {
81 bzero(dbuf->buf, MIDI_BUFFSIZE);
82 dbuf->bufsize = MIDI_BUFFSIZE;
83 dbuf->rp = dbuf->fp = 0;
84 dbuf->dl = 0;
85 dbuf->rl = 0;
86 dbuf->fl = dbuf->bufsize;
87 dbuf->int_count = 0;
88 dbuf->chan = 0;
89 /*dbuf->unit_size = 1;*/ /* The drivers are responsible. */
90 bzero(&dbuf->sel, sizeof(dbuf->sel));
91 dbuf->total = 0;
92 dbuf->prev_total = 0;
93 dbuf->blocksize = dbuf->bufsize / 4;
94
95 return (0);
96 }
97
98 /* The sequencer calls this function to queue data. */
99 int
100 midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len, int *lenw, midi_callback_t *cb, void *d, int reason, struct mtx *m)
101 {
102 int i, lwrt;
103
104 if (m != NULL)
105 mtx_assert(m, MA_OWNED);
106
107 if (lenw == NULL)
108 return (EINVAL);
109 *lenw = 0;
110
111 /* Is this a real queue? */
112 if (dbuf == (midi_dbuf *)NULL)
113 return (EINVAL);
114
115 /* Write down every single byte. */
116 while (len > 0) {
117 /* Find out the number of bytes to write. */
118 lwrt = SPACE_AVAIL(dbuf);
119 if (lwrt > len)
120 lwrt = len;
121 if (lwrt > 0) {
122 /* We can write some now. Queue the data. */
123 queuerawdata(dbuf, data, lwrt);
124
125 *lenw += lwrt;
126 len -= lwrt;
127 data += lwrt;
128 }
129
130 if (cb != NULL)
131 (*cb)(d, reason);
132
133 /* Have we got still more data to write? */
134 if (len > 0) {
135 /* Sleep until we have enough space. */
136 i = cv_wait_sig(&dbuf->cv_out, m);
137 if (i == EINTR || i == ERESTART)
138 return (i);
139 }
140 }
141
142 return (0);
143 }
144
145 int
146 midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len, int *leno)
147 {
148 if (leno == NULL)
149 return (EINVAL);
150 *leno = 0;
151
152 /* Is this a real queue? */
153 if (dbuf == (midi_dbuf *)NULL)
154 return (EINVAL);
155
156 /* Have we got any data in the queue? */
157 *leno = DATA_AVAIL(dbuf);
158 if (*leno == 0)
159 return (EAGAIN);
160
161 /* Dequeue the data. */
162 if (*leno > len)
163 *leno = len;
164 dequeuerawdata(dbuf, data, *leno);
165
166 return (0);
167 }
168
169 int
170 midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len, int *leni)
171 {
172 if (leni == NULL)
173 return (EINVAL);
174 *leni = 0;
175
176 /* Is this a real queue? */
177 if (dbuf == (midi_dbuf *)NULL)
178 return (EINVAL);
179
180 /* Have we got any data to write? */
181 if (len == 0)
182 return (0);
183 /* Can we write now? */
184 if (SPACE_AVAIL(dbuf) < len)
185 return (EAGAIN);
186
187 /* We can write some now. Queue the data. */
188 queuerawdata(dbuf, data, len);
189 *leni = len;
190
191 return (0);
192 }
193
194 /* The sequencer calls this function to dequeue data. */
195 int
196 midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len, int *lenr, midi_callback_t *cb, void *d, int reason, struct mtx *m)
197 {
198 int i, lrd;
199
200 if (m != NULL)
201 mtx_assert(m, MA_OWNED);
202
203 if (lenr == NULL)
204 return (EINVAL);
205 *lenr = 0;
206
207 /* Is this a real queue? */
208 if (dbuf == (midi_dbuf *)NULL)
209 return (EINVAL);
210
211 /* Write down every single byte. */
212 while (len > 0) {
213 if (cb != NULL)
214 (*cb)(d, reason);
215
216 /* Have we got data to read? */
217 if ((lrd = DATA_AVAIL(dbuf)) == 0) {
218 /* Sleep until we have data ready to read. */
219 i = cv_wait_sig(&dbuf->cv_in, m);
220 if (i == EINTR || i == ERESTART)
221 return (i);
222 /* Find out the number of bytes to read. */
223 lrd = DATA_AVAIL(dbuf);
224 }
225
226 if (lrd > len)
227 lrd = len;
228 if (lrd > 0) {
229 /* We can read some data now. Dequeue the data. */
230 dequeuerawdata(dbuf, data, lrd);
231
232 *lenr += lrd;
233 len -= lrd;
234 data += lrd;
235 }
236 }
237
238 return (0);
239 }
240
241 /* The sequencer calls this function to copy data without dequeueing. */
242 int
243 midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len, int *lenc, midi_callback_t *cb, void *d, int reason, struct mtx *m)
244 {
245 int i, lrd;
246
247 if (m != NULL)
248 mtx_assert(m, MA_OWNED);
249
250 if (lenc == NULL)
251 return (EINVAL);
252 *lenc = 0;
253
254 /* Is this a real queue? */
255 if (dbuf == (midi_dbuf *)NULL)
256 return (EINVAL);
257
258 /* Write down every single byte. */
259 while (len > 0) {
260 if (cb != NULL)
261 (*cb)(d, reason);
262
263 /* Have we got data to read? */
264 if ((lrd = DATA_AVAIL(dbuf)) == 0) {
265 /* Sleep until we have data ready to read. */
266 i = cv_wait_sig(&dbuf->cv_in, m);
267 if (i == EINTR || i == ERESTART)
268 return (i);
269 /* Find out the number of bytes to read. */
270 lrd = DATA_AVAIL(dbuf);
271 }
272
273 if (lrd > len)
274 lrd = len;
275 if (lrd > 0) {
276 /* We can read some data now. Copy the data. */
277 copyrawdata(dbuf, *lenc, data, lrd);
278
279 *lenc += lrd;
280 len -= lrd;
281 data += lrd;
282 }
283 }
284
285 return (0);
286 }
287
288 /*
289 * The sequencer calls this function to delete the data
290 * that the sequencer has already read.
291 */
292 int
293 midibuf_seqdelete(midi_dbuf *dbuf, int len, int *lenr, midi_callback_t *cb, void *d, int reason, struct mtx *m)
294 {
295 int i, lrd;
296
297 if (m != NULL)
298 mtx_assert(m, MA_OWNED);
299
300 if (lenr == NULL)
301 return (EINVAL);
302 *lenr = 0;
303
304 /* Is this a real queue? */
305 if (dbuf == (midi_dbuf *)NULL)
306 return (EINVAL);
307
308 /* Write down every single byte. */
309 while (len > 0) {
310 if (cb != NULL)
311 (*cb)(d, reason);
312
313 /* Have we got data to read? */
314 if ((lrd = DATA_AVAIL(dbuf)) == 0) {
315 /* Sleep until we have data ready to read. */
316 i = cv_wait_sig(&dbuf->cv_in, m);
317 if (i == EINTR || i == ERESTART)
318 return (i);
319 /* Find out the number of bytes to read. */
320 lrd = DATA_AVAIL(dbuf);
321 }
322
323 if (lrd > len)
324 lrd = len;
325 if (lrd > 0) {
326 /* We can read some data now. Delete the data. */
327 deleterawdata(dbuf, lrd);
328
329 *lenr += lrd;
330 len -= lrd;
331 }
332 }
333
334 return (0);
335 }
336
337 /*
338 * The functions below here are the libraries for the above ones.
339 */
340
341 static void
342 queuerawdata(midi_dbuf *dbuf, char *data, int len)
343 {
344 /* dbuf->fp might wrap around dbuf->bufsize. */
345 if (dbuf->bufsize - dbuf->fp < len) {
346 /* The new data wraps, copy them twice. */
347 bcopy(data, dbuf->buf + dbuf->fp, dbuf->bufsize - dbuf->fp);
348 bcopy(data + dbuf->bufsize - dbuf->fp, dbuf->buf, len - (dbuf->bufsize - dbuf->fp));
349 } else
350 /* The new data do not wrap, once is enough. */
351 bcopy(data, dbuf->buf + dbuf->fp, len);
352
353 /* Adjust the pointer and the length counters. */
354 dbuf->fp = (dbuf->fp + len) % dbuf->bufsize;
355 dbuf->fl -= len;
356 dbuf->rl += len;
357
358 /* Wake up the processes sleeping on input data. */
359 cv_broadcast(&dbuf->cv_in);
360 if (SEL_WAITING(&dbuf->sel) && dbuf->rl >= dbuf->blocksize)
361 selwakeup(&dbuf->sel);
362 }
363
364 static void
365 dequeuerawdata(midi_dbuf *dbuf, char *data, int len)
366 {
367 /* Copy the data. */
368 copyrawdata(dbuf, 0, data, len);
369
370 /* Delete the data. */
371 deleterawdata(dbuf, len);
372 }
373
374 static void
375 copyrawdata(midi_dbuf *dbuf, int offset, char *data, int len)
376 {
377 int rp;
378
379 rp = (dbuf->rp + offset) % dbuf->bufsize;
380
381 /* dbuf->rp might wrap around dbuf->bufsize. */
382 if (dbuf->bufsize - rp < len) {
383 /* The data to be read wraps, copy them twice. */
384 bcopy(dbuf->buf + rp, data, dbuf->bufsize - rp);
385 bcopy(dbuf->buf, data + dbuf->bufsize - rp, len - (dbuf->bufsize - rp));
386 } else
387 /* The new data do not wrap, once is enough. */
388 bcopy(dbuf->buf + rp, data, len);
389 }
390
391 static void
392 deleterawdata(midi_dbuf *dbuf, int len)
393 {
394 /* Adjust the pointer and the length counters. */
395 dbuf->rp = (dbuf->rp + len) % dbuf->bufsize;
396 dbuf->rl -= len;
397 dbuf->fl += len;
398
399 /* Wake up the processes sleeping on queueing. */
400 cv_broadcast(&dbuf->cv_out);
401 if (SEL_WAITING(&dbuf->sel) && dbuf->fl >= dbuf->blocksize)
402 selwakeup(&dbuf->sel);
403 }
Cache object: 3d25eb101d239ba91254b08e092a92b8
|