ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / core / seq / oss / seq_oss_ioctl.c
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 int
32 snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
33 {
34         int dev, val;
35         struct synth_info inf;
36         struct midi_info minf;
37         unsigned char ev[8];
38         void __user *arg = (void __user *)carg;
39         snd_seq_event_t tmpev;
40
41         switch (cmd) {
42         case SNDCTL_TMR_TIMEBASE:
43         case SNDCTL_TMR_TEMPO:
44         case SNDCTL_TMR_START:
45         case SNDCTL_TMR_STOP:
46         case SNDCTL_TMR_CONTINUE:
47         case SNDCTL_TMR_METRONOME:
48         case SNDCTL_TMR_SOURCE:
49         case SNDCTL_TMR_SELECT:
50         case SNDCTL_SEQ_CTRLRATE:
51                 return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
52
53         case SNDCTL_SEQ_PANIC:
54                 debug_printk(("panic\n"));
55                 snd_seq_oss_reset(dp);
56                 return -EINVAL;
57
58         case SNDCTL_SEQ_SYNC:
59                 debug_printk(("sync\n"));
60                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
61                         return 0;
62                 while (snd_seq_oss_writeq_sync(dp->writeq))
63                         ;
64                 if (signal_pending(current))
65                         return -ERESTARTSYS;
66                 return 0;
67
68         case SNDCTL_SEQ_RESET:
69                 debug_printk(("reset\n"));
70                 snd_seq_oss_reset(dp);
71                 return 0;
72
73         case SNDCTL_SEQ_TESTMIDI:
74                 debug_printk(("test midi\n"));
75                 if (get_user(dev, (int *)arg))
76                         return -EFAULT;
77                 return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
78
79         case SNDCTL_SEQ_GETINCOUNT:
80                 debug_printk(("get in count\n"));
81                 if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
82                         return 0;
83                 return put_user(dp->readq->qlen, (int *)arg) ? -EFAULT : 0;
84
85         case SNDCTL_SEQ_GETOUTCOUNT:
86                 debug_printk(("get out count\n"));
87                 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
88                         return 0;
89                 return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), (int *)arg) ? -EFAULT : 0;
90
91         case SNDCTL_SEQ_GETTIME:
92                 debug_printk(("get time\n"));
93                 return put_user(snd_seq_oss_timer_cur_tick(dp->timer), (int *)arg) ? -EFAULT : 0;
94
95         case SNDCTL_SEQ_RESETSAMPLES:
96                 debug_printk(("reset samples\n"));
97                 if (get_user(dev, (int *)arg))
98                         return -EFAULT;
99                 return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
100
101         case SNDCTL_SEQ_NRSYNTHS:
102                 debug_printk(("nr synths\n"));
103                 return put_user(dp->max_synthdev, (int *)arg) ? -EFAULT : 0;
104
105         case SNDCTL_SEQ_NRMIDIS:
106                 debug_printk(("nr midis\n"));
107                 return put_user(dp->max_mididev, (int *)arg) ? -EFAULT : 0;
108
109         case SNDCTL_SYNTH_MEMAVL:
110                 debug_printk(("mem avail\n"));
111                 if (get_user(dev, (int *)arg))
112                         return -EFAULT;
113                 val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
114                 return put_user(val, (int *)arg) ? -EFAULT : 0;
115
116         case SNDCTL_FM_4OP_ENABLE:
117                 debug_printk(("4op\n"));
118                 if (get_user(dev, (int *)arg))
119                         return -EFAULT;
120                 snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
121                 return 0;
122
123         case SNDCTL_SYNTH_INFO:
124         case SNDCTL_SYNTH_ID:
125                 debug_printk(("synth info\n"));
126                 if (copy_from_user(&inf, arg, sizeof(inf)))
127                         return -EFAULT;
128                 if (snd_seq_oss_synth_make_info(dp, inf.device, &inf) < 0)
129                         return -EINVAL;
130                 if (copy_to_user(arg, &inf, sizeof(inf)))
131                         return -EFAULT;
132                 return 0;
133
134         case SNDCTL_SEQ_OUTOFBAND:
135                 debug_printk(("out of bound\n"));
136                 if (copy_from_user(ev, arg, 8))
137                         return -EFAULT;
138                 memset(&tmpev, 0, sizeof(tmpev));
139                 snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
140                 tmpev.time.tick = 0;
141                 if (! snd_seq_oss_process_event(dp, (evrec_t*)ev, &tmpev)) {
142                         snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
143                 }
144                 return 0;
145
146         case SNDCTL_MIDI_INFO:
147                 debug_printk(("midi info\n"));
148                 if (copy_from_user(&minf, arg, sizeof(minf)))
149                         return -EFAULT;
150                 if (snd_seq_oss_midi_make_info(dp, minf.device, &minf) < 0)
151                         return -EINVAL;
152                 if (copy_to_user(arg, &minf, sizeof(minf)))
153                         return -EFAULT;
154                 return 0;
155
156         case SNDCTL_SEQ_THRESHOLD:
157                 debug_printk(("threshold\n"));
158                 if (! is_write_mode(dp->file_mode))
159                         return 0;
160                 if (get_user(val, (int *)arg))
161                         return -EFAULT;
162                 if (val < 1)
163                         val = 1;
164                 if (val >= dp->writeq->maxlen)
165                         val = dp->writeq->maxlen - 1;
166                 snd_seq_oss_writeq_set_output(dp->writeq, val);
167                 return 0;
168
169         case SNDCTL_MIDI_PRETIME:
170                 debug_printk(("pretime\n"));
171                 if (dp->readq == NULL || !is_read_mode(dp->file_mode))
172                         return 0;
173                 if (get_user(val, (int *)arg))
174                         return -EFAULT;
175                 if (val <= 0)
176                         val = -1;
177                 else
178                         val = (HZ * val) / 10;
179                 dp->readq->pre_event_timeout = val;
180                 return put_user(val, (int *)arg) ? -EFAULT : 0;
181
182         default:
183                 debug_printk(("others\n"));
184                 if (! is_write_mode(dp->file_mode))
185                         return -EIO;
186                 return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
187         }
188         return 0;
189 }
190