1 /* 2 * OSS compatible sequencer driver 3 * 4 * OSS compatible i/o control 5 * 6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 #include "seq_oss_device.h" 24 #include "seq_oss_readq.h" 25 #include "seq_oss_writeq.h" 26 #include "seq_oss_timer.h" 27 #include "seq_oss_synth.h" 28 #include "seq_oss_midi.h" 29 #include "seq_oss_event.h" 30 31 static int snd_seq_oss_synth_info_user(struct seq_oss_devinfo *dp, void __user *arg) 32 { 33 struct synth_info info; 34 35 if (copy_from_user(&info, arg, sizeof(info))) 36 return -EFAULT; 37 if (snd_seq_oss_synth_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_midi_info_user(struct seq_oss_devinfo *dp, void __user *arg) 45 { 46 struct midi_info info; 47 48 if (copy_from_user(&info, arg, sizeof(info))) 49 return -EFAULT; 50 if (snd_seq_oss_midi_make_info(dp, info.device, &info) < 0) 51 return -EINVAL; 52 if (copy_to_user(arg, &info, sizeof(info))) 53 return -EFAULT; 54 return 0; 55 } 56 57 static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg) 58 { 59 unsigned char ev[8]; 60 struct snd_seq_event tmpev; 61 62 if (copy_from_user(ev, arg, 8)) 63 return -EFAULT; 64 memset(&tmpev, 0, sizeof(tmpev)); 65 snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client); 66 tmpev.time.tick = 0; 67 if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) { 68 snd_seq_oss_dispatch(dp, &tmpev, 0, 0); 69 } 70 return 0; 71 } 72 73 int 74 snd_seq_oss_ioctl(struct seq_oss_devinfo *dp, unsigned int cmd, unsigned long carg) 75 { 76 int dev, val; 77 void __user *arg = (void __user *)carg; 78 int __user *p = arg; 79 80 switch (cmd) { 81 case SNDCTL_TMR_TIMEBASE: 82 case SNDCTL_TMR_TEMPO: 83 case SNDCTL_TMR_START: 84 case SNDCTL_TMR_STOP: 85 case SNDCTL_TMR_CONTINUE: 86 case SNDCTL_TMR_METRONOME: 87 case SNDCTL_TMR_SOURCE: 88 case SNDCTL_TMR_SELECT: 89 case SNDCTL_SEQ_CTRLRATE: 90 return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg); 91 92 case SNDCTL_SEQ_PANIC: 93 debug_printk(("panic\n")); 94 snd_seq_oss_reset(dp); 95 return -EINVAL; 96 97 case SNDCTL_SEQ_SYNC: 98 debug_printk(("sync\n")); 99 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL) 100 return 0; 101 while (snd_seq_oss_writeq_sync(dp->writeq)) 102 ; 103 if (signal_pending(current)) 104 return -ERESTARTSYS; 105 return 0; 106 107 case SNDCTL_SEQ_RESET: 108 debug_printk(("reset\n")); 109 snd_seq_oss_reset(dp); 110 return 0; 111 112 case SNDCTL_SEQ_TESTMIDI: 113 debug_printk(("test midi\n")); 114 if (get_user(dev, p)) 115 return -EFAULT; 116 return snd_seq_oss_midi_open(dp, dev, dp->file_mode); 117 118 case SNDCTL_SEQ_GETINCOUNT: 119 debug_printk(("get in count\n")); 120 if (dp->readq == NULL || ! is_read_mode(dp->file_mode)) 121 return 0; 122 return put_user(dp->readq->qlen, p) ? -EFAULT : 0; 123 124 case SNDCTL_SEQ_GETOUTCOUNT: 125 debug_printk(("get out count\n")); 126 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL) 127 return 0; 128 return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0; 129 130 case SNDCTL_SEQ_GETTIME: 131 debug_printk(("get time\n")); 132 return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0; 133 134 case SNDCTL_SEQ_RESETSAMPLES: 135 debug_printk(("reset samples\n")); 136 if (get_user(dev, p)) 137 return -EFAULT; 138 return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg); 139 140 case SNDCTL_SEQ_NRSYNTHS: 141 debug_printk(("nr synths\n")); 142 return put_user(dp->max_synthdev, p) ? -EFAULT : 0; 143 144 case SNDCTL_SEQ_NRMIDIS: 145 debug_printk(("nr midis\n")); 146 return put_user(dp->max_mididev, p) ? -EFAULT : 0; 147 148 case SNDCTL_SYNTH_MEMAVL: 149 debug_printk(("mem avail\n")); 150 if (get_user(dev, p)) 151 return -EFAULT; 152 val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg); 153 return put_user(val, p) ? -EFAULT : 0; 154 155 case SNDCTL_FM_4OP_ENABLE: 156 debug_printk(("4op\n")); 157 if (get_user(dev, p)) 158 return -EFAULT; 159 snd_seq_oss_synth_ioctl(dp, dev, cmd, carg); 160 return 0; 161 162 case SNDCTL_SYNTH_INFO: 163 case SNDCTL_SYNTH_ID: 164 debug_printk(("synth info\n")); 165 return snd_seq_oss_synth_info_user(dp, arg); 166 167 case SNDCTL_SEQ_OUTOFBAND: 168 debug_printk(("out of band\n")); 169 return snd_seq_oss_oob_user(dp, arg); 170 171 case SNDCTL_MIDI_INFO: 172 debug_printk(("midi info\n")); 173 return snd_seq_oss_midi_info_user(dp, arg); 174 175 case SNDCTL_SEQ_THRESHOLD: 176 debug_printk(("threshold\n")); 177 if (! is_write_mode(dp->file_mode)) 178 return 0; 179 if (get_user(val, p)) 180 return -EFAULT; 181 if (val < 1) 182 val = 1; 183 if (val >= dp->writeq->maxlen) 184 val = dp->writeq->maxlen - 1; 185 snd_seq_oss_writeq_set_output(dp->writeq, val); 186 return 0; 187 188 case SNDCTL_MIDI_PRETIME: 189 debug_printk(("pretime\n")); 190 if (dp->readq == NULL || !is_read_mode(dp->file_mode)) 191 return 0; 192 if (get_user(val, p)) 193 return -EFAULT; 194 if (val <= 0) 195 val = -1; 196 else 197 val = (HZ * val) / 10; 198 dp->readq->pre_event_timeout = val; 199 return put_user(val, p) ? -EFAULT : 0; 200 201 default: 202 debug_printk(("others\n")); 203 if (! is_write_mode(dp->file_mode)) 204 return -EIO; 205 return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg); 206 } 207 return 0; 208 } 209 210