~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/oss/midibuf.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * sound/oss/midibuf.c
  3  *
  4  * Device file manager for /dev/midi#
  5  */
  6 /*
  7  * Copyright (C) by Hannu Savolainen 1993-1997
  8  *
  9  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 10  * Version 2 (June 1991). See the "COPYING" file distributed with this software
 11  * for more info.
 12  */
 13 /*
 14  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
 15  */
 16 #include <linux/stddef.h>
 17 #include <linux/kmod.h>
 18 #include <linux/spinlock.h>
 19 #define MIDIBUF_C
 20 
 21 #include "sound_config.h"
 22 
 23 
 24 /*
 25  * Don't make MAX_QUEUE_SIZE larger than 4000
 26  */
 27 
 28 #define MAX_QUEUE_SIZE  4000
 29 
 30 static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
 31 static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];
 32 
 33 struct midi_buf
 34 {
 35         int len, head, tail;
 36         unsigned char queue[MAX_QUEUE_SIZE];
 37 };
 38 
 39 struct midi_parms
 40 {
 41         long prech_timeout;     /*
 42                                  * Timeout before the first ch
 43                                  */
 44 };
 45 
 46 static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
 47 static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
 48 static struct midi_parms parms[MAX_MIDI_DEV];
 49 
 50 static void midi_poll(unsigned long dummy);
 51 
 52 
 53 static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
 54 
 55 static volatile int open_devs;
 56 static DEFINE_SPINLOCK(lock);
 57 
 58 #define DATA_AVAIL(q) (q->len)
 59 #define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
 60 
 61 #define QUEUE_BYTE(q, data) \
 62         if (SPACE_AVAIL(q)) \
 63         { \
 64           unsigned long flags; \
 65           spin_lock_irqsave(&lock, flags); \
 66           q->queue[q->tail] = (data); \
 67           q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
 68           spin_unlock_irqrestore(&lock, flags); \
 69         }
 70 
 71 #define REMOVE_BYTE(q, data) \
 72         if (DATA_AVAIL(q)) \
 73         { \
 74           unsigned long flags; \
 75           spin_lock_irqsave(&lock, flags); \
 76           data = q->queue[q->head]; \
 77           q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
 78           spin_unlock_irqrestore(&lock, flags); \
 79         }
 80 
 81 static void drain_midi_queue(int dev)
 82 {
 83 
 84         /*
 85          * Give the Midi driver time to drain its output queues
 86          */
 87 
 88         if (midi_devs[dev]->buffer_status != NULL)
 89                 wait_event_interruptible_timeout(midi_sleeper[dev],
 90                                 !midi_devs[dev]->buffer_status(dev), HZ/10);
 91 }
 92 
 93 static void midi_input_intr(int dev, unsigned char data)
 94 {
 95         if (midi_in_buf[dev] == NULL)
 96                 return;
 97 
 98         if (data == 0xfe)       /*
 99                                  * Active sensing
100                                  */
101                 return;         /*
102                                  * Ignore
103                                  */
104 
105         if (SPACE_AVAIL(midi_in_buf[dev])) {
106                 QUEUE_BYTE(midi_in_buf[dev], data);
107                 wake_up(&input_sleeper[dev]);
108         }
109 }
110 
111 static void midi_output_intr(int dev)
112 {
113         /*
114          * Currently NOP
115          */
116 }
117 
118 static void midi_poll(unsigned long dummy)
119 {
120         unsigned long   flags;
121         int             dev;
122 
123         spin_lock_irqsave(&lock, flags);
124         if (open_devs)
125         {
126                 for (dev = 0; dev < num_midis; dev++)
127                         if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
128                         {
129                                 while (DATA_AVAIL(midi_out_buf[dev]))
130                                 {
131                                         int ok;
132                                         int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
133 
134                                         spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
135                                         ok = midi_devs[dev]->outputc(dev, c);
136                                         spin_lock_irqsave(&lock, flags);
137                                         if (!ok)
138                                                 break;
139                                         midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
140                                         midi_out_buf[dev]->len--;
141                                 }
142 
143                                 if (DATA_AVAIL(midi_out_buf[dev]) < 100)
144                                         wake_up(&midi_sleeper[dev]);
145                         }
146                 poll_timer.expires = (1) + jiffies;
147                 add_timer(&poll_timer);
148                 /*
149                  * Come back later
150                  */
151         }
152         spin_unlock_irqrestore(&lock, flags);
153 }
154 
155 int MIDIbuf_open(int dev, struct file *file)
156 {
157         int mode, err;
158 
159         dev = dev >> 4;
160         mode = translate_mode(file);
161 
162         if (num_midis > MAX_MIDI_DEV)
163         {
164                 printk(KERN_ERR "midi: Too many midi interfaces\n");
165                 num_midis = MAX_MIDI_DEV;
166         }
167         if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
168                   return -ENXIO;
169         /*
170          *    Interrupts disabled. Be careful
171          */
172 
173         module_put(midi_devs[dev]->owner);
174 
175         if ((err = midi_devs[dev]->open(dev, mode,
176                                  midi_input_intr, midi_output_intr)) < 0)
177                 return err;
178 
179         parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
180         midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
181 
182         if (midi_in_buf[dev] == NULL)
183         {
184                 printk(KERN_WARNING "midi: Can't allocate buffer\n");
185                 midi_devs[dev]->close(dev);
186                 return -EIO;
187         }
188         midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
189 
190         midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
191 
192         if (midi_out_buf[dev] == NULL)
193         {
194                 printk(KERN_WARNING "midi: Can't allocate buffer\n");
195                 midi_devs[dev]->close(dev);
196                 vfree(midi_in_buf[dev]);
197                 midi_in_buf[dev] = NULL;
198                 return -EIO;
199         }
200         midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
201         open_devs++;
202 
203         init_waitqueue_head(&midi_sleeper[dev]);
204         init_waitqueue_head(&input_sleeper[dev]);
205 
206         if (open_devs < 2)      /* This was first open */
207         {
208                 poll_timer.expires = 1 + jiffies;
209                 add_timer(&poll_timer); /* Start polling */
210         }
211         return err;
212 }
213 
214 void MIDIbuf_release(int dev, struct file *file)
215 {
216         int mode;
217 
218         dev = dev >> 4;
219         mode = translate_mode(file);
220 
221         if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
222                 return;
223 
224         /*
225          * Wait until the queue is empty
226          */
227 
228         if (mode != OPEN_READ)
229         {
230                 midi_devs[dev]->outputc(dev, 0xfe);     /*
231                                                            * Active sensing to shut the
232                                                            * devices
233                                                          */
234 
235                 wait_event_interruptible(midi_sleeper[dev],
236                                          !DATA_AVAIL(midi_out_buf[dev]));
237                 /*
238                  *      Sync
239                  */
240 
241                 drain_midi_queue(dev);  /*
242                                          * Ensure the output queues are empty
243                                          */
244         }
245 
246         midi_devs[dev]->close(dev);
247 
248         open_devs--;
249         if (open_devs == 0)
250                 del_timer_sync(&poll_timer);
251         vfree(midi_in_buf[dev]);
252         vfree(midi_out_buf[dev]);
253         midi_in_buf[dev] = NULL;
254         midi_out_buf[dev] = NULL;
255 
256         module_put(midi_devs[dev]->owner);
257 }
258 
259 int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
260 {
261         int c, n, i;
262         unsigned char tmp_data;
263 
264         dev = dev >> 4;
265 
266         if (!count)
267                 return 0;
268 
269         c = 0;
270 
271         while (c < count)
272         {
273                 n = SPACE_AVAIL(midi_out_buf[dev]);
274 
275                 if (n == 0) {   /*
276                                  * No space just now.
277                                  */
278 
279                         if (file->f_flags & O_NONBLOCK) {
280                                 c = -EAGAIN;
281                                 goto out;
282                         }
283 
284                         if (wait_event_interruptible(midi_sleeper[dev],
285                                                 SPACE_AVAIL(midi_out_buf[dev])))
286                         {
287                                 c = -EINTR;
288                                 goto out;
289                         }
290                         n = SPACE_AVAIL(midi_out_buf[dev]);
291                 }
292                 if (n > (count - c))
293                         n = count - c;
294 
295                 for (i = 0; i < n; i++)
296                 {
297                         /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */
298                         /* yes, think the same, so I removed the cli() brackets 
299                                 QUEUE_BYTE is protected against interrupts */
300                         if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
301                                 c = -EFAULT;
302                                 goto out;
303                         }
304                         QUEUE_BYTE(midi_out_buf[dev], tmp_data);
305                         c++;
306                 }
307         }
308 out:
309         return c;
310 }
311 
312 
313 int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
314 {
315         int n, c = 0;
316         unsigned char tmp_data;
317 
318         dev = dev >> 4;
319 
320         if (!DATA_AVAIL(midi_in_buf[dev])) {    /*
321                                                  * No data yet, wait
322                                                  */
323                 if (file->f_flags & O_NONBLOCK) {
324                         c = -EAGAIN;
325                         goto out;
326                 }
327                 wait_event_interruptible_timeout(input_sleeper[dev],
328                                                  DATA_AVAIL(midi_in_buf[dev]),
329                                                  parms[dev].prech_timeout);
330 
331                 if (signal_pending(current))
332                         c = -EINTR;     /* The user is getting restless */
333         }
334         if (c == 0 && DATA_AVAIL(midi_in_buf[dev]))     /*
335                                                          * Got some bytes
336                                                          */
337         {
338                 n = DATA_AVAIL(midi_in_buf[dev]);
339                 if (n > count)
340                         n = count;
341                 c = 0;
342 
343                 while (c < n)
344                 {
345                         char *fixit;
346                         REMOVE_BYTE(midi_in_buf[dev], tmp_data);
347                         fixit = (char *) &tmp_data;
348                         /* BROKE BROKE BROKE */
349                         /* yes removed the cli() brackets again
350                          should q->len,tail&head be atomic_t? */
351                         if (copy_to_user(&(buf)[c], fixit, 1)) {
352                                 c = -EFAULT;
353                                 goto out;
354                         }
355                         c++;
356                 }
357         }
358 out:
359         return c;
360 }
361 
362 int MIDIbuf_ioctl(int dev, struct file *file,
363                   unsigned int cmd, void __user *arg)
364 {
365         int val;
366 
367         dev = dev >> 4;
368         
369         if (((cmd >> 8) & 0xff) == 'C') 
370         {
371                 if (midi_devs[dev]->coproc)     /* Coprocessor ioctl */
372                         return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
373 /*              printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
374                 return -ENXIO;
375         }
376         else
377         {
378                 switch (cmd) 
379                 {
380                         case SNDCTL_MIDI_PRETIME:
381                                 if (get_user(val, (int __user *)arg))
382                                         return -EFAULT;
383                                 if (val < 0)
384                                         val = 0;
385                                 val = (HZ * val) / 10;
386                                 parms[dev].prech_timeout = val;
387                                 return put_user(val, (int __user *)arg);
388                         
389                         default:
390                                 if (!midi_devs[dev]->ioctl)
391                                         return -EINVAL;
392                                 return midi_devs[dev]->ioctl(dev, cmd, arg);
393                 }
394         }
395 }
396 
397 /* No kernel lock - fine */
398 unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
399 {
400         unsigned int mask = 0;
401 
402         dev = dev >> 4;
403 
404         /* input */
405         poll_wait(file, &input_sleeper[dev], wait);
406         if (DATA_AVAIL(midi_in_buf[dev]))
407                 mask |= POLLIN | POLLRDNORM;
408 
409         /* output */
410         poll_wait(file, &midi_sleeper[dev], wait);
411         if (!SPACE_AVAIL(midi_out_buf[dev]))
412                 mask |= POLLOUT | POLLWRNORM;
413         
414         return mask;
415 }
416 
417 
418 int MIDIbuf_avail(int dev)
419 {
420         if (midi_in_buf[dev])
421                 return DATA_AVAIL (midi_in_buf[dev]);
422         return 0;
423 }
424 EXPORT_SYMBOL(MIDIbuf_avail);
425 
426 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp