kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / sound / isa / i386 / midibuf.c
1 /*
2  * sound/midibuf.c
3  * 
4  * Device file manager for /dev/midi#
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  * 
28  * $DragonFly: src/sys/dev/sound/isa/i386/Attic/midibuf.c,v 1.2 2003/08/07 21:17:12 dillon Exp $
29  */
30
31 #include "sound_config.h"
32
33
34 #if defined(CONFIG_MIDI)
35
36 #include <sys/select.h>
37
38 /*
39  * Don't make MAX_QUEUE_SIZE larger than 4000
40  */
41
42 #define MAX_QUEUE_SIZE  4000
43 int
44 MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait);
45
46 static void
47 drain_midi_queue(int dev);
48
49 static int     *midi_sleeper[MAX_MIDI_DEV] = {NULL};
50 static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}};
51 static int     *input_sleeper[MAX_MIDI_DEV] = {NULL};
52 static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { {0}};
53
54 struct midi_buf {
55         int             len, head, tail;
56         u_char   queue[MAX_QUEUE_SIZE];
57 };
58
59 struct midi_parms {
60         int             prech_timeout;  /* Timeout before the first ch */
61 };
62
63 static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
64 static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
65 static struct midi_parms parms[MAX_MIDI_DEV];
66
67 static void     midi_poll(void  *dummy);
68
69 static volatile int open_devs = 0;
70
71 #define DATA_AVAIL(q) (q->len)
72 #define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
73
74 #define QUEUE_BYTE(q, data) \
75         if (SPACE_AVAIL(q)) { \
76           u_long flags; \
77           flags = splhigh(); \
78           q->queue[q->tail] = (data); \
79           q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
80           splx(flags); \
81         }
82
83 #define REMOVE_BYTE(q, data) \
84         if (DATA_AVAIL(q)) { \
85           u_long flags; \
86           flags = splhigh(); \
87           data = q->queue[q->head]; \
88           q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
89           splx(flags); \
90         }
91
92 static void
93 drain_midi_queue(int dev)
94 {
95
96     /*
97      * Give the Midi driver time to drain its output queues
98      */
99
100     if (midi_devs[dev]->buffer_status != NULL)
101         while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
102                    midi_devs[dev]->buffer_status(dev)) {
103             int    chn;
104
105             midi_sleeper[dev] = &chn;
106             DO_SLEEP(chn, midi_sleep_flag[dev], hz / 10);
107
108         };
109 }
110
111 static void
112 midi_input_intr(int dev, u_char data)
113 {
114         if (midi_in_buf[dev] == NULL)
115                 return;
116
117         if (data == 0xfe)       /* Active sensing */
118                 return;         /* Ignore */
119
120         if (SPACE_AVAIL(midi_in_buf[dev])) {
121                 QUEUE_BYTE(midi_in_buf[dev], data);
122                 if ((input_sleep_flag[dev].mode & WK_SLEEP)) {
123                         input_sleep_flag[dev].mode = WK_WAKEUP;
124                         wakeup(input_sleeper[dev]);
125                 };
126         }
127 }
128
129 static void
130 midi_output_intr(int dev)
131 {
132         /*
133          * Currently NOP
134          */
135 }
136
137 static void
138 midi_poll(void *dummy)
139 {
140         u_long   flags;
141         int             dev;
142
143         flags = splhigh();
144         if (open_devs) {
145                 for (dev = 0; dev < num_midis; dev++)
146                         if (midi_out_buf[dev] != NULL) {
147                                 while (DATA_AVAIL(midi_out_buf[dev]) &&
148                                        midi_devs[dev]->putc(dev,
149                                                             midi_out_buf[dev]->queue[midi_out_buf[dev]->head])) {
150                                         midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
151                                         midi_out_buf[dev]->len--;
152                                 }
153
154                                 if (DATA_AVAIL(midi_out_buf[dev]) < 100 &&
155                                     (midi_sleep_flag[dev].mode & WK_SLEEP)) {
156                                         midi_sleep_flag[dev].mode = WK_WAKEUP;
157                                         wakeup(midi_sleeper[dev]);
158                                 };
159                         }
160                 timeout( midi_poll, 0, 1);;     /* Come back later */
161         }
162         splx(flags);
163 }
164
165 int
166 MIDIbuf_open(int dev, struct fileinfo * file)
167 {
168         int             mode, err;
169
170         dev = dev >> 4;
171         mode = file->mode & O_ACCMODE;
172
173         if (num_midis > MAX_MIDI_DEV) {
174                 printf("Sound: FATAL ERROR: Too many midi interfaces\n");
175                 num_midis = MAX_MIDI_DEV;
176         }
177         if (dev < 0 || dev >= num_midis) {
178                 printf("Sound: Nonexistent MIDI interface %d\n", dev);
179                 return -(ENXIO);
180         }
181         /*
182          * Interrupts disabled. Be careful
183          */
184
185         if ((err = midi_devs[dev]->open(dev, mode,
186                                   midi_input_intr, midi_output_intr)) < 0) {
187                 return err;
188         }
189         parms[dev].prech_timeout = 0;
190
191         midi_in_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
192
193         if (midi_in_buf[dev] == NULL) {
194                 printf("midi: Can't allocate buffer\n");
195                 midi_devs[dev]->close(dev);
196                 return -(EIO);
197         }
198         midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
199
200         midi_out_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
201
202         if (midi_out_buf[dev] == NULL) {
203                 printf("midi: Can't allocate buffer\n");
204                 midi_devs[dev]->close(dev);
205                 free(midi_in_buf[dev], M_TEMP);
206                 midi_in_buf[dev] = NULL;
207                 return -(EIO);
208         }
209         midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
210         open_devs++;
211
212         {
213                 midi_sleep_flag[dev].aborting = 0;
214                 midi_sleep_flag[dev].mode = WK_NONE;
215         };
216         {
217                 input_sleep_flag[dev].aborting = 0;
218                 input_sleep_flag[dev].mode = WK_NONE;
219         };
220
221         if (open_devs < 2) {    /* This was first open */
222                 {
223                 };
224
225                 timeout( midi_poll, 0, 1);;     /* Start polling */
226         }
227         return err;
228 }
229
230 void
231 MIDIbuf_release(int dev, struct fileinfo * file)
232 {
233         int             mode;
234         u_long   flags;
235
236         dev = dev >> 4;
237         mode = file->mode & O_ACCMODE;
238
239         if (dev < 0 || dev >= num_midis)
240                 return;
241
242         flags = splhigh();
243
244         /*
245          * Wait until the queue is empty
246          */
247
248         if (mode != OPEN_READ) {
249                 midi_devs[dev]->putc(dev, 0xfe);        /* Active sensing to
250                                                          * shut the devices */
251
252                 while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
253                        DATA_AVAIL(midi_out_buf[dev])) {
254                         int   chn;
255                         midi_sleeper[dev] = &chn;
256                         DO_SLEEP(chn, midi_sleep_flag[dev], 0);
257
258                 };              /* Sync */
259
260                 drain_midi_queue(dev);  /* Ensure the output queues are empty */
261         }
262         splx(flags);
263
264         midi_devs[dev]->close(dev);
265
266         free(midi_in_buf[dev], M_TEMP);
267         free(midi_out_buf[dev], M_TEMP);
268         midi_in_buf[dev] = NULL;
269         midi_out_buf[dev] = NULL;
270         if (open_devs < 2) {
271         };
272         open_devs--;
273 }
274
275 int
276 MIDIbuf_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
277 {
278         u_long   flags;
279         int             c, n, i;
280         u_char   tmp_data;
281
282         dev = dev >> 4;
283
284         if (!count)
285                 return 0;
286
287         flags = splhigh();
288
289         c = 0;
290
291         while (c < count) {
292                 n = SPACE_AVAIL(midi_out_buf[dev]);
293
294                 if (n == 0) {   /* No space just now. We have to sleep */
295
296                         {
297                                 int  chn;
298
299                                 midi_sleeper[dev] = &chn;
300                                 DO_SLEEP(chn, midi_sleep_flag[dev], 0);
301                         };
302
303                         if (PROCESS_ABORTING(midi_sleep_flag[dev])) {
304                                 splx(flags);
305                                 return -(EINTR);
306                         }
307                         n = SPACE_AVAIL(midi_out_buf[dev]);
308                 }
309                 if (n > (count - c))
310                         n = count - c;
311
312                 for (i = 0; i < n; i++) {
313
314                         if (uiomove((char *) &tmp_data, 1, buf)) {
315                                 printf("sb: Bad copyin()!\n");
316                         };
317                         QUEUE_BYTE(midi_out_buf[dev], tmp_data);
318                         c++;
319                 }
320         }
321
322         splx(flags);
323
324         return c;
325 }
326
327
328 int
329 MIDIbuf_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
330 {
331         int             n, c = 0;
332         u_long   flags;
333         u_char   tmp_data;
334
335         dev = dev >> 4;
336
337         flags = splhigh();
338
339         if (!DATA_AVAIL(midi_in_buf[dev])) {    /* No data yet, wait */
340
341                 {
342                         int   chn;
343
344
345                         input_sleeper[dev] = &chn;
346                         DO_SLEEP(chn, input_sleep_flag[dev],  
347                                  parms[dev].prech_timeout);
348
349                 };
350                 if (PROCESS_ABORTING(input_sleep_flag[dev]))
351                         c = -(EINTR);   /* The user is getting restless */
352         }
353         if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) {   /* Got some bytes */
354                 n = DATA_AVAIL(midi_in_buf[dev]);
355                 if (n > count)
356                         n = count;
357                 c = 0;
358
359                 while (c < n) {
360                         REMOVE_BYTE(midi_in_buf[dev], tmp_data);
361
362                         if (uiomove((char *) &tmp_data, 1, buf)) {
363                                 printf("sb: Bad copyout()!\n");
364                         };
365                         c++;
366                 }
367         }
368         splx(flags);
369
370         return c;
371 }
372
373 int
374 MIDIbuf_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
375 {
376         int             val;
377
378         dev = dev >> 4;
379
380         if (((cmd >> 8) & 0xff) == 'C') {
381                 if (midi_devs[dev]->coproc)     /* Coprocessor ioctl */
382                         return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
383                 else
384                         printf("/dev/midi%d: No coprocessor for this device\n", dev);
385
386                 return -(ENXIO);
387         } else
388                 switch (cmd) {
389
390                 case SNDCTL_MIDI_PRETIME:
391                         val = (int) (*(int *) arg);
392                         if (val < 0)
393                                 val = 0;
394
395                         val = (hz * val) / 10;
396                         parms[dev].prech_timeout = val;
397                         return *(int *) arg = val;
398                         break;
399
400                 default:
401                         return midi_devs[dev]->ioctl(dev, cmd, arg);
402                 }
403 }
404
405 #ifdef ALLOW_POLL
406 int
407 MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait)
408 {
409   int revents = 0;
410
411   dev = dev >> 4;
412
413   if (events & (POLLIN | POLLRDNORM))
414     if (!DATA_AVAIL (midi_in_buf[dev]))
415       selrecord(wait, &selinfo[dev]);
416     else
417       revents |= events & (POLLIN | POLLRDNORM);
418
419   if (events & (POLLOUT | POLLWRNORM))
420     if (SPACE_AVAIL (midi_out_buf[dev]))
421       selrecord(wait, &selinfo[dev]);
422     else
423       revents |= events & (POLLOUT | POLLWRNORM);
424
425   return revents;
426 }
427
428 #endif /* ALLOW_SELECT */
429
430
431
432 #endif