xref: /linux/sound/core/seq/oss/seq_oss_ioctl.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
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 
55 	snd_use_lock_t *lock __free(seq_oss_use_lock) = NULL;
56 
57 	if (!snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev, &lock))
58 		snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
59 	return 0;
60 }
61 
62 int
63 snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg)
64 {
65 	int dev, val;
66 	void __user *arg = (void __user *)carg;
67 	int __user *p = arg;
68 
69 	switch (cmd) {
70 	case SNDCTL_TMR_TIMEBASE:
71 	case SNDCTL_TMR_TEMPO:
72 	case SNDCTL_TMR_START:
73 	case SNDCTL_TMR_STOP:
74 	case SNDCTL_TMR_CONTINUE:
75 	case SNDCTL_TMR_METRONOME:
76 	case SNDCTL_TMR_SOURCE:
77 	case SNDCTL_TMR_SELECT:
78 	case SNDCTL_SEQ_CTRLRATE:
79 		return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
80 
81 	case SNDCTL_SEQ_PANIC:
82 		snd_seq_oss_reset(dp);
83 		return -EINVAL;
84 
85 	case SNDCTL_SEQ_SYNC:
86 		if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
87 			return 0;
88 		while (snd_seq_oss_writeq_sync(dp->writeq))
89 			;
90 		if (signal_pending(current))
91 			return -ERESTARTSYS;
92 		return 0;
93 
94 	case SNDCTL_SEQ_RESET:
95 		snd_seq_oss_reset(dp);
96 		return 0;
97 
98 	case SNDCTL_SEQ_TESTMIDI:
99 		if (get_user(dev, p))
100 			return -EFAULT;
101 		return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
102 
103 	case SNDCTL_SEQ_GETINCOUNT:
104 		if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
105 			return 0;
106 		return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
107 
108 	case SNDCTL_SEQ_GETOUTCOUNT:
109 		if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
110 			return 0;
111 		return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
112 
113 	case SNDCTL_SEQ_GETTIME:
114 		return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
115 
116 	case SNDCTL_SEQ_RESETSAMPLES:
117 		if (get_user(dev, p))
118 			return -EFAULT;
119 		return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
120 
121 	case SNDCTL_SEQ_NRSYNTHS:
122 		return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
123 
124 	case SNDCTL_SEQ_NRMIDIS:
125 		return put_user(dp->max_mididev, p) ? -EFAULT : 0;
126 
127 	case SNDCTL_SYNTH_MEMAVL:
128 		if (get_user(dev, p))
129 			return -EFAULT;
130 		val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
131 		return put_user(val, p) ? -EFAULT : 0;
132 
133 	case SNDCTL_FM_4OP_ENABLE:
134 		if (get_user(dev, p))
135 			return -EFAULT;
136 		snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
137 		return 0;
138 
139 	case SNDCTL_SYNTH_INFO:
140 	case SNDCTL_SYNTH_ID:
141 		return snd_seq_oss_synth_info_user(dp, arg);
142 
143 	case SNDCTL_SEQ_OUTOFBAND:
144 		return snd_seq_oss_oob_user(dp, arg);
145 
146 	case SNDCTL_MIDI_INFO:
147 		return snd_seq_oss_midi_info_user(dp, arg);
148 
149 	case SNDCTL_SEQ_THRESHOLD:
150 		if (! is_write_mode(dp->file_mode))
151 			return 0;
152 		if (get_user(val, p))
153 			return -EFAULT;
154 		if (val < 1)
155 			val = 1;
156 		if (val >= dp->writeq->maxlen)
157 			val = dp->writeq->maxlen - 1;
158 		snd_seq_oss_writeq_set_output(dp->writeq, val);
159 		return 0;
160 
161 	case SNDCTL_MIDI_PRETIME:
162 		if (dp->readq == NULL || !is_read_mode(dp->file_mode))
163 			return 0;
164 		if (get_user(val, p))
165 			return -EFAULT;
166 		if (val <= 0)
167 			val = -1;
168 		else
169 			val = (HZ * val) / 10;
170 		dp->readq->pre_event_timeout = val;
171 		return put_user(val, p) ? -EFAULT : 0;
172 
173 	default:
174 		if (! is_write_mode(dp->file_mode))
175 			return -EIO;
176 		return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
177 	}
178 	return 0;
179 }
180