179 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * OSS compatible sequencer driver4 *5 * OSS compatible i/o control6 *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(&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 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(&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 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(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 60int61snd_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 else167 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 179