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

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

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

~ [ 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