Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / sound / core / seq / oss / seq_oss_ioctl.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * OSS compatible sequencer driver
4  *
5  * OSS compatible i/o control
6  *
7  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
8  */
9
10 #include "seq_oss_device.h"
11 #include "seq_oss_readq.h"
12 #include "seq_oss_writeq.h"
13 #include "seq_oss_timer.h"
14 #include "seq_oss_synth.h"
15 #include "seq_oss_midi.h"
16 #include "seq_oss_event.h"
17
18 static int snd_seq_oss_synth_info_user(struct seq_oss_devinfo *dp, void __user *arg)
19 {
20         struct synth_info info;
21
22         if (copy_from_user(&info, arg, sizeof(info)))
23                 return -EFAULT;
24         if (snd_seq_oss_synth_make_info(dp, info.device, &info) < 0)
25                 return -EINVAL;
26         if (copy_to_user(arg, &info, sizeof(info)))
27                 return -EFAULT;
28         return 0;
29 }
30
31 static int snd_seq_oss_midi_info_user(struct seq_oss_devinfo *dp, void __user *arg)
32 {
33         struct midi_info info;
34
35         if (copy_from_user(&info, arg, sizeof(info)))
36                 return -EFAULT;
37         if (snd_seq_oss_midi_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_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
45 {
46         unsigned char ev[8];
47         struct snd_seq_event tmpev;
48
49         if (copy_from_user(ev, arg, 8))
50                 return -EFAULT;
51         memset(&tmpev, 0, sizeof(tmpev));
52         snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
53         tmpev.time.tick = 0;
54         if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
55                 snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
56         }
57         return 0;
58 }
59
60 int
61 snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg)
62 {
63         int dev, val;
64         void __user *arg = (void __user *)carg;
65         int __user *p = arg;
66
67         switch (cmd) {
68         case SNDCTL_TMR_TIMEBASE:
69         case SNDCTL_TMR_TEMPO:
70         case SNDCTL_TMR_START:
71         case SNDCTL_TMR_STOP:
72         case SNDCTL_TMR_CONTINUE:
73         case SNDCTL_TMR_METRONOME:
74         case SNDCTL_TMR_SOURCE:
75         case SNDCTL_TMR_SELECT:
76         case SNDCTL_SEQ_CTRLRATE:
77                 return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
78
79         case SNDCTL_SEQ_PANIC:
80                 snd_seq_oss_reset(dp);
81                 return -EINVAL;
82
83         case SNDCTL_SEQ_SYNC:
84                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
85                         return 0;
86                 while (snd_seq_oss_writeq_sync(dp->writeq))
87                         ;
88                 if (signal_pending(current))
89                         return -ERESTARTSYS;
90                 return 0;
91
92         case SNDCTL_SEQ_RESET:
93                 snd_seq_oss_reset(dp);
94                 return 0;
95
96         case SNDCTL_SEQ_TESTMIDI:
97                 if (get_user(dev, p))
98                         return -EFAULT;
99                 return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
100
101         case SNDCTL_SEQ_GETINCOUNT:
102                 if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
103                         return 0;
104                 return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
105
106         case SNDCTL_SEQ_GETOUTCOUNT:
107                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
108                         return 0;
109                 return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
110
111         case SNDCTL_SEQ_GETTIME:
112                 return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
113
114         case SNDCTL_SEQ_RESETSAMPLES:
115                 if (get_user(dev, p))
116                         return -EFAULT;
117                 return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
118
119         case SNDCTL_SEQ_NRSYNTHS:
120                 return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
121
122         case SNDCTL_SEQ_NRMIDIS:
123                 return put_user(dp->max_mididev, p) ? -EFAULT : 0;
124
125         case SNDCTL_SYNTH_MEMAVL:
126                 if (get_user(dev, p))
127                         return -EFAULT;
128                 val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
129                 return put_user(val, p) ? -EFAULT : 0;
130
131         case SNDCTL_FM_4OP_ENABLE:
132                 if (get_user(dev, p))
133                         return -EFAULT;
134                 snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
135                 return 0;
136
137         case SNDCTL_SYNTH_INFO:
138         case SNDCTL_SYNTH_ID:
139                 return snd_seq_oss_synth_info_user(dp, arg);
140
141         case SNDCTL_SEQ_OUTOFBAND:
142                 return snd_seq_oss_oob_user(dp, arg);
143
144         case SNDCTL_MIDI_INFO:
145                 return snd_seq_oss_midi_info_user(dp, arg);
146
147         case SNDCTL_SEQ_THRESHOLD:
148                 if (! is_write_mode(dp->file_mode))
149                         return 0;
150                 if (get_user(val, p))
151                         return -EFAULT;
152                 if (val < 1)
153                         val = 1;
154                 if (val >= dp->writeq->maxlen)
155                         val = dp->writeq->maxlen - 1;
156                 snd_seq_oss_writeq_set_output(dp->writeq, val);
157                 return 0;
158
159         case SNDCTL_MIDI_PRETIME:
160                 if (dp->readq == NULL || !is_read_mode(dp->file_mode))
161                         return 0;
162                 if (get_user(val, p))
163                         return -EFAULT;
164                 if (val <= 0)
165                         val = -1;
166                 else
167                         val = (HZ * val) / 10;
168                 dp->readq->pre_event_timeout = val;
169                 return put_user(val, p) ? -EFAULT : 0;
170
171         default:
172                 if (! is_write_mode(dp->file_mode))
173                         return -EIO;
174                 return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
175         }
176         return 0;
177 }
178