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