Remove the priority part of the priority|flags argument to tsleep(). Only
[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  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32
33 #if defined(CONFIG_MIDI)
34
35 #include <sys/select.h>
36
37 /*
38  * Don't make MAX_QUEUE_SIZE larger than 4000
39  */
40
41 #define MAX_QUEUE_SIZE  4000
42 int
43 MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait);
44
45 static void
46 drain_midi_queue(int dev);
47
48 static int     *midi_sleeper[MAX_MIDI_DEV] = {NULL};
49 static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}};
50 static int     *input_sleeper[MAX_MIDI_DEV] = {NULL};
51 static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { {0}};
52
53 struct midi_buf {
54         int             len, head, tail;
55         u_char   queue[MAX_QUEUE_SIZE];
56 };
57
58 struct midi_parms {
59         int             prech_timeout;  /* Timeout before the first ch */
60 };
61
62 static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
63 static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
64 static struct midi_parms parms[MAX_MIDI_DEV];
65
66 static void     midi_poll(void  *dummy);
67
68 static volatile int open_devs = 0;
69
70 #define DATA_AVAIL(q) (q->len)
71 #define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
72
73 #define QUEUE_BYTE(q, data) \
74         if (SPACE_AVAIL(q)) { \
75           u_long flags; \
76           flags = splhigh(); \
77           q->queue[q->tail] = (data); \
78           q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
79           splx(flags); \
80         }
81
82 #define REMOVE_BYTE(q, data) \
83         if (DATA_AVAIL(q)) { \
84           u_long flags; \
85           flags = splhigh(); \
86           data = q->queue[q->head]; \
87           q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
88           splx(flags); \
89         }
90
91 static void
92 drain_midi_queue(int dev)
93 {
94
95     /*
96      * Give the Midi driver time to drain its output queues
97      */
98
99     if (midi_devs[dev]->buffer_status != NULL)
100         while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
101                    midi_devs[dev]->buffer_status(dev)) {
102             int    chn;
103
104             midi_sleeper[dev] = &chn;
105             DO_SLEEP(chn, midi_sleep_flag[dev], hz / 10);
106
107         };
108 }
109
110 static void
111 midi_input_intr(int dev, u_char data)
112 {
113         if (midi_in_buf[dev] == NULL)
114                 return;
115
116         if (data == 0xfe)       /* Active sensing */
117                 return;         /* Ignore */
118
119         if (SPACE_AVAIL(midi_in_buf[dev])) {
120                 QUEUE_BYTE(midi_in_buf[dev], data);
121                 if ((input_sleep_flag[dev].mode & WK_SLEEP)) {
122                         input_sleep_flag[dev].mode = WK_WAKEUP;
123                         wakeup(input_sleeper[dev]);
124                 };
125         }
126 }
127
128 static void
129 midi_output_intr(int dev)
130 {
131         /*
132          * Currently NOP
133          */
134 }
135
136 static void
137 midi_poll(void *dummy)
138 {
139         u_long   flags;
140         int             dev;
141
142         flags = splhigh();
143         if (open_devs) {
144                 for (dev = 0; dev < num_midis; dev++)
145                         if (midi_out_buf[dev] != NULL) {
146                                 while (DATA_AVAIL(midi_out_buf[dev]) &&
147                                        midi_devs[dev]->putc(dev,
148                                                             midi_out_buf[dev]->queue[midi_out_buf[dev]->head])) {
149                                         midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
150                                         midi_out_buf[dev]->len--;
151                                 }
152
153                                 if (DATA_AVAIL(midi_out_buf[dev]) < 100 &&
154                                     (midi_sleep_flag[dev].mode & WK_SLEEP)) {
155                                         midi_sleep_flag[dev].mode = WK_WAKEUP;
156                                         wakeup(midi_sleeper[dev]);
157                                 };
158                         }
159                 timeout( midi_poll, 0, 1);;     /* Come back later */
160         }
161         splx(flags);
162 }
163
164 int
165 MIDIbuf_open(int dev, struct fileinfo * file)
166 {
167         int             mode, err;
168
169         dev = dev >> 4;
170         mode = file->mode & O_ACCMODE;
171
172         if (num_midis > MAX_MIDI_DEV) {
173                 printf("Sound: FATAL ERROR: Too many midi interfaces\n");
174                 num_midis = MAX_MIDI_DEV;
175         }
176         if (dev < 0 || dev >= num_midis) {
177                 printf("Sound: Nonexistent MIDI interface %d\n", dev);
178                 return -(ENXIO);
179         }
180         /*
181          * Interrupts disabled. Be careful
182          */
183
184         if ((err = midi_devs[dev]->open(dev, mode,
185                                   midi_input_intr, midi_output_intr)) < 0) {
186                 return err;
187         }
188         parms[dev].prech_timeout = 0;
189
190         midi_in_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
191
192         if (midi_in_buf[dev] == NULL) {
193                 printf("midi: Can't allocate buffer\n");
194                 midi_devs[dev]->close(dev);
195                 return -(EIO);
196         }
197         midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
198
199         midi_out_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
200
201         if (midi_out_buf[dev] == NULL) {
202                 printf("midi: Can't allocate buffer\n");
203                 midi_devs[dev]->close(dev);
204                 free(midi_in_buf[dev], M_TEMP);
205                 midi_in_buf[dev] = NULL;
206                 return -(EIO);
207         }
208         midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
209         open_devs++;
210
211         {
212                 midi_sleep_flag[dev].aborting = 0;
213                 midi_sleep_flag[dev].mode = WK_NONE;
214         };
215         {
216                 input_sleep_flag[dev].aborting = 0;
217                 input_sleep_flag[dev].mode = WK_NONE;
218         };
219
220         if (open_devs < 2) {    /* This was first open */
221                 {
222                 };
223
224                 timeout( midi_poll, 0, 1);;     /* Start polling */
225         }
226         return err;
227 }
228
229 void
230 MIDIbuf_release(int dev, struct fileinfo * file)
231 {
232         int             mode;
233         u_long   flags;
234
235         dev = dev >> 4;
236         mode = file->mode & O_ACCMODE;
237
238         if (dev < 0 || dev >= num_midis)
239                 return;
240
241         flags = splhigh();
242
243         /*
244          * Wait until the queue is empty
245          */
246
247         if (mode != OPEN_READ) {
248                 midi_devs[dev]->putc(dev, 0xfe);        /* Active sensing to
249                                                          * shut the devices */
250
251                 while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
252                        DATA_AVAIL(midi_out_buf[dev])) {
253                         int   chn;
254                         midi_sleeper[dev] = &chn;
255                         DO_SLEEP(chn, midi_sleep_flag[dev], 0);
256
257                 };              /* Sync */
258
259                 drain_midi_queue(dev);  /* Ensure the output queues are empty */
260         }
261         splx(flags);
262
263         midi_devs[dev]->close(dev);
264
265         free(midi_in_buf[dev], M_TEMP);
266         free(midi_out_buf[dev], M_TEMP);
267         midi_in_buf[dev] = NULL;
268         midi_out_buf[dev] = NULL;
269         if (open_devs < 2) {
270         };
271         open_devs--;
272 }
273
274 int
275 MIDIbuf_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
276 {
277         u_long   flags;
278         int             c, n, i;
279         u_char   tmp_data;
280
281         dev = dev >> 4;
282
283         if (!count)
284                 return 0;
285
286         flags = splhigh();
287
288         c = 0;
289
290         while (c < count) {
291                 n = SPACE_AVAIL(midi_out_buf[dev]);
292
293                 if (n == 0) {   /* No space just now. We have to sleep */
294
295                         {
296                                 int  chn;
297
298                                 midi_sleeper[dev] = &chn;
299                                 DO_SLEEP(chn, midi_sleep_flag[dev], 0);
300                         };
301
302                         if (PROCESS_ABORTING(midi_sleep_flag[dev])) {
303                                 splx(flags);
304                                 return -(EINTR);
305                         }
306                         n = SPACE_AVAIL(midi_out_buf[dev]);
307                 }
308                 if (n > (count - c))
309                         n = count - c;
310
311                 for (i = 0; i < n; i++) {
312
313                         if (uiomove((char *) &tmp_data, 1, buf)) {
314                                 printf("sb: Bad copyin()!\n");
315                         };
316                         QUEUE_BYTE(midi_out_buf[dev], tmp_data);
317                         c++;
318                 }
319         }
320
321         splx(flags);
322
323         return c;
324 }
325
326
327 int
328 MIDIbuf_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
329 {
330         int             n, c = 0;
331         u_long   flags;
332         u_char   tmp_data;
333
334         dev = dev >> 4;
335
336         flags = splhigh();
337
338         if (!DATA_AVAIL(midi_in_buf[dev])) {    /* No data yet, wait */
339
340                 {
341                         int   chn;
342
343
344                         input_sleeper[dev] = &chn;
345                         DO_SLEEP(chn, input_sleep_flag[dev],  
346                                  parms[dev].prech_timeout);
347
348                 };
349                 if (PROCESS_ABORTING(input_sleep_flag[dev]))
350                         c = -(EINTR);   /* The user is getting restless */
351         }
352         if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) {   /* Got some bytes */
353                 n = DATA_AVAIL(midi_in_buf[dev]);
354                 if (n > count)
355                         n = count;
356                 c = 0;
357
358                 while (c < n) {
359                         REMOVE_BYTE(midi_in_buf[dev], tmp_data);
360
361                         if (uiomove((char *) &tmp_data, 1, buf)) {
362                                 printf("sb: Bad copyout()!\n");
363                         };
364                         c++;
365                 }
366         }
367         splx(flags);
368
369         return c;
370 }
371
372 int
373 MIDIbuf_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
374 {
375         int             val;
376
377         dev = dev >> 4;
378
379         if (((cmd >> 8) & 0xff) == 'C') {
380                 if (midi_devs[dev]->coproc)     /* Coprocessor ioctl */
381                         return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
382                 else
383                         printf("/dev/midi%d: No coprocessor for this device\n", dev);
384
385                 return -(ENXIO);
386         } else
387                 switch (cmd) {
388
389                 case SNDCTL_MIDI_PRETIME:
390                         val = (int) (*(int *) arg);
391                         if (val < 0)
392                                 val = 0;
393
394                         val = (hz * val) / 10;
395                         parms[dev].prech_timeout = val;
396                         return *(int *) arg = val;
397                         break;
398
399                 default:
400                         return midi_devs[dev]->ioctl(dev, cmd, arg);
401                 }
402 }
403
404 #ifdef ALLOW_POLL
405 int
406 MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait)
407 {
408   int revents = 0;
409
410   dev = dev >> 4;
411
412   if (events & (POLLIN | POLLRDNORM))
413     if (!DATA_AVAIL (midi_in_buf[dev]))
414       selrecord(wait, &selinfo[dev]);
415     else
416       revents |= events & (POLLIN | POLLRDNORM);
417
418   if (events & (POLLOUT | POLLWRNORM))
419     if (SPACE_AVAIL (midi_out_buf[dev]))
420       selrecord(wait, &selinfo[dev]);
421     else
422       revents |= events & (POLLOUT | POLLWRNORM);
423
424   return revents;
425 }
426
427 #endif /* ALLOW_SELECT */
428
429
430
431 #endif