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
18static 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(to: &info, from: arg, n: sizeof(info)))
23 return -EFAULT;
24 if (snd_seq_oss_synth_make_info(dp, dev: info.device, inf: &info) < 0)
25 return -EINVAL;
26 if (copy_to_user(to: arg, from: &info, n: sizeof(info)))
27 return -EFAULT;
28 return 0;
29}
30
31static 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(to: &info, from: arg, n: sizeof(info)))
36 return -EFAULT;
37 if (snd_seq_oss_midi_make_info(dp, dev: info.device, inf: &info) < 0)
38 return -EINVAL;
39 if (copy_to_user(to: arg, from: &info, n: sizeof(info)))
40 return -EFAULT;
41 return 0;
42}
43
44static 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(to: ev, from: arg, n: 8))
50 return -EFAULT;
51 memset(&tmpev, 0, sizeof(tmpev));
52 snd_seq_oss_fill_addr(dp, ev: &tmpev, dest_client: dp->addr.client, dest_port: dp->addr.port);
53 tmpev.time.tick = 0;
54 if (! snd_seq_oss_process_event(dp, q: (union evrec *)ev, ev: &tmpev)) {
55 snd_seq_oss_dispatch(dp, ev: &tmpev, atomic: 0, hop: 0);
56 }
57 return 0;
58}
59
60int
61snd_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(timer: 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(q: 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, file_mode: 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, addr: 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, addr: 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, addr: 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(q: dp->writeq, size: 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, dev: 0, cmd, addr: carg);
175 }
176 return 0;
177}
178
179

source code of linux/sound/core/seq/oss/seq_oss_ioctl.c