Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / sound / core / seq / oss / seq_oss_ioctl.c
1 /*
2  * OSS compatible sequencer driver
3  *
4  * OSS compatible i/o control
5  *
6  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include "seq_oss_device.h"
24 #include "seq_oss_readq.h"
25 #include "seq_oss_writeq.h"
26 #include "seq_oss_timer.h"
27 #include "seq_oss_synth.h"
28 #include "seq_oss_midi.h"
29 #include "seq_oss_event.h"
30
31 static int snd_seq_oss_synth_info_user(struct seq_oss_devinfo *dp, void __user *arg)
32 {
33         struct synth_info info;
34
35         if (copy_from_user(&info, arg, sizeof(info)))
36                 return -EFAULT;
37         if (snd_seq_oss_synth_make_info(dp, info.device, &info) < 0)
38                 return -EINVAL;
39         if (copy_to_user(arg, &info, sizeof(info)))
40                 return -EFAULT;
41         return 0;
42 }
43
44 static int snd_seq_oss_midi_info_user(struct seq_oss_devinfo *dp, void __user *arg)
45 {
46         struct midi_info info;
47
48         if (copy_from_user(&info, arg, sizeof(info)))
49                 return -EFAULT;
50         if (snd_seq_oss_midi_make_info(dp, info.device, &info) < 0)
51                 return -EINVAL;
52         if (copy_to_user(arg, &info, sizeof(info)))
53                 return -EFAULT;
54         return 0;
55 }
56
57 static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
58 {
59         unsigned char ev[8];
60         struct snd_seq_event tmpev;
61
62         if (copy_from_user(ev, arg, 8))
63                 return -EFAULT;
64         memset(&tmpev, 0, sizeof(tmpev));
65         snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
66         tmpev.time.tick = 0;
67         if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
68                 snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
69         }
70         return 0;
71 }
72
73 int
74 snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg)
75 {
76         int dev, val;
77         void __user *arg = (void __user *)carg;
78         int __user *p = arg;
79
80         switch (cmd) {
81         case SNDCTL_TMR_TIMEBASE:
82         case SNDCTL_TMR_TEMPO:
83         case SNDCTL_TMR_START:
84         case SNDCTL_TMR_STOP:
85         case SNDCTL_TMR_CONTINUE:
86         case SNDCTL_TMR_METRONOME:
87         case SNDCTL_TMR_SOURCE:
88         case SNDCTL_TMR_SELECT:
89         case SNDCTL_SEQ_CTRLRATE:
90                 return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
91
92         case SNDCTL_SEQ_PANIC:
93                 snd_seq_oss_reset(dp);
94                 return -EINVAL;
95
96         case SNDCTL_SEQ_SYNC:
97                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
98                         return 0;
99                 while (snd_seq_oss_writeq_sync(dp->writeq))
100                         ;
101                 if (signal_pending(current))
102                         return -ERESTARTSYS;
103                 return 0;
104
105         case SNDCTL_SEQ_RESET:
106                 snd_seq_oss_reset(dp);
107                 return 0;
108
109         case SNDCTL_SEQ_TESTMIDI:
110                 if (get_user(dev, p))
111                         return -EFAULT;
112                 return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
113
114         case SNDCTL_SEQ_GETINCOUNT:
115                 if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
116                         return 0;
117                 return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
118
119         case SNDCTL_SEQ_GETOUTCOUNT:
120                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
121                         return 0;
122                 return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
123
124         case SNDCTL_SEQ_GETTIME:
125                 return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
126
127         case SNDCTL_SEQ_RESETSAMPLES:
128                 if (get_user(dev, p))
129                         return -EFAULT;
130                 return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
131
132         case SNDCTL_SEQ_NRSYNTHS:
133                 return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
134
135         case SNDCTL_SEQ_NRMIDIS:
136                 return put_user(dp->max_mididev, p) ? -EFAULT : 0;
137
138         case SNDCTL_SYNTH_MEMAVL:
139                 if (get_user(dev, p))
140                         return -EFAULT;
141                 val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
142                 return put_user(val, p) ? -EFAULT : 0;
143
144         case SNDCTL_FM_4OP_ENABLE:
145                 if (get_user(dev, p))
146                         return -EFAULT;
147                 snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
148                 return 0;
149
150         case SNDCTL_SYNTH_INFO:
151         case SNDCTL_SYNTH_ID:
152                 return snd_seq_oss_synth_info_user(dp, arg);
153
154         case SNDCTL_SEQ_OUTOFBAND:
155                 return snd_seq_oss_oob_user(dp, arg);
156
157         case SNDCTL_MIDI_INFO:
158                 return snd_seq_oss_midi_info_user(dp, arg);
159
160         case SNDCTL_SEQ_THRESHOLD:
161                 if (! is_write_mode(dp->file_mode))
162                         return 0;
163                 if (get_user(val, p))
164                         return -EFAULT;
165                 if (val < 1)
166                         val = 1;
167                 if (val >= dp->writeq->maxlen)
168                         val = dp->writeq->maxlen - 1;
169                 snd_seq_oss_writeq_set_output(dp->writeq, val);
170                 return 0;
171
172         case SNDCTL_MIDI_PRETIME:
173                 if (dp->readq == NULL || !is_read_mode(dp->file_mode))
174                         return 0;
175                 if (get_user(val, p))
176                         return -EFAULT;
177                 if (val <= 0)
178                         val = -1;
179                 else
180                         val = (HZ * val) / 10;
181                 dp->readq->pre_event_timeout = val;
182                 return put_user(val, p) ? -EFAULT : 0;
183
184         default:
185                 if (! is_write_mode(dp->file_mode))
186                         return -EIO;
187                 return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
188         }
189         return 0;
190 }
191