V4L (926_2): Moves compat32 functions from fs to v4l subsystem
[safe/jmp/linux-2.6] / drivers / media / video / compat_ioctl32.c
1 #include <linux/config.h>
2 #include <linux/compat.h>
3 #include <linux/videodev.h>
4
5 #ifdef CONFIG_COMPAT
6 struct video_tuner32 {
7         compat_int_t tuner;
8         char name[32];
9         compat_ulong_t rangelow, rangehigh;
10         u32 flags;      /* It is really u32 in videodev.h */
11         u16 mode, signal;
12 };
13
14 static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
15 {
16         int i;
17
18         if(get_user(kp->tuner, &up->tuner))
19                 return -EFAULT;
20         for(i = 0; i < 32; i++)
21                 __get_user(kp->name[i], &up->name[i]);
22         __get_user(kp->rangelow, &up->rangelow);
23         __get_user(kp->rangehigh, &up->rangehigh);
24         __get_user(kp->flags, &up->flags);
25         __get_user(kp->mode, &up->mode);
26         __get_user(kp->signal, &up->signal);
27         return 0;
28 }
29
30 static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
31 {
32         int i;
33
34         if(put_user(kp->tuner, &up->tuner))
35                 return -EFAULT;
36         for(i = 0; i < 32; i++)
37                 __put_user(kp->name[i], &up->name[i]);
38         __put_user(kp->rangelow, &up->rangelow);
39         __put_user(kp->rangehigh, &up->rangehigh);
40         __put_user(kp->flags, &up->flags);
41         __put_user(kp->mode, &up->mode);
42         __put_user(kp->signal, &up->signal);
43         return 0;
44 }
45
46 struct video_buffer32 {
47         compat_caddr_t base;
48         compat_int_t height, width, depth, bytesperline;
49 };
50
51 static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
52 {
53         u32 tmp;
54
55         if (get_user(tmp, &up->base))
56                 return -EFAULT;
57
58         /* This is actually a physical address stored
59          * as a void pointer.
60          */
61         kp->base = (void *)(unsigned long) tmp;
62
63         __get_user(kp->height, &up->height);
64         __get_user(kp->width, &up->width);
65         __get_user(kp->depth, &up->depth);
66         __get_user(kp->bytesperline, &up->bytesperline);
67         return 0;
68 }
69
70 static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
71 {
72         u32 tmp = (u32)((unsigned long)kp->base);
73
74         if(put_user(tmp, &up->base))
75                 return -EFAULT;
76         __put_user(kp->height, &up->height);
77         __put_user(kp->width, &up->width);
78         __put_user(kp->depth, &up->depth);
79         __put_user(kp->bytesperline, &up->bytesperline);
80         return 0;
81 }
82
83 struct video_clip32 {
84         s32 x, y, width, height;        /* Its really s32 in videodev.h */
85         compat_caddr_t next;
86 };
87
88 struct video_window32 {
89         u32 x, y, width, height, chromakey, flags;
90         compat_caddr_t clips;
91         compat_int_t clipcount;
92 };
93
94 static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
95 {
96         int ret = -ENOIOCTLCMD;
97
98         if (file->f_ops->unlocked_ioctl)
99                 ret = file->f_ops->unlocked_ioctl(file, cmd, arg);
100         else if (file->f_ops->ioctl) {
101                 lock_kernel();
102                 ret = file->f_ops->ioctl(file->f_dentry->d_inode, file, cmd, arg);
103                 unlock_kernel();
104         }
105
106         return ret;
107 }
108
109
110 /* You get back everything except the clips... */
111 static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
112 {
113         if(put_user(kp->x, &up->x))
114                 return -EFAULT;
115         __put_user(kp->y, &up->y);
116         __put_user(kp->width, &up->width);
117         __put_user(kp->height, &up->height);
118         __put_user(kp->chromakey, &up->chromakey);
119         __put_user(kp->flags, &up->flags);
120         __put_user(kp->clipcount, &up->clipcount);
121         return 0;
122 }
123
124 #define VIDIOCGTUNER32          _IOWR('v',4, struct video_tuner32)
125 #define VIDIOCSTUNER32          _IOW('v',5, struct video_tuner32)
126 #define VIDIOCGWIN32            _IOR('v',9, struct video_window32)
127 #define VIDIOCSWIN32            _IOW('v',10, struct video_window32)
128 #define VIDIOCGFBUF32           _IOR('v',11, struct video_buffer32)
129 #define VIDIOCSFBUF32           _IOW('v',12, struct video_buffer32)
130 #define VIDIOCGFREQ32           _IOR('v',14, u32)
131 #define VIDIOCSFREQ32           _IOW('v',15, u32)
132
133 enum {
134         MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
135 };
136
137 static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
138 {
139         struct video_window32 __user *up = compat_ptr(arg);
140         struct video_window __user *vw;
141         struct video_clip __user *p;
142         int nclips;
143         u32 n;
144
145         if (get_user(nclips, &up->clipcount))
146                 return -EFAULT;
147
148         /* Peculiar interface... */
149         if (nclips < 0)
150                 nclips = VIDEO_CLIPMAP_SIZE;
151
152         if (nclips > MaxClips)
153                 return -ENOMEM;
154
155         vw = compat_alloc_user_space(sizeof(struct video_window) +
156                                     nclips * sizeof(struct video_clip));
157
158         p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
159
160         if (get_user(n, &up->x) || put_user(n, &vw->x) ||
161             get_user(n, &up->y) || put_user(n, &vw->y) ||
162             get_user(n, &up->width) || put_user(n, &vw->width) ||
163             get_user(n, &up->height) || put_user(n, &vw->height) ||
164             get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
165             get_user(n, &up->flags) || put_user(n, &vw->flags) ||
166             get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
167             get_user(n, &up->clips) || put_user(p, &vw->clips))
168                 return -EFAULT;
169
170         if (nclips) {
171                 struct video_clip32 __user *u = compat_ptr(n);
172                 int i;
173                 if (!u)
174                         return -EINVAL;
175                 for (i = 0; i < nclips; i++, u++, p++) {
176                         s32 v;
177                         if (get_user(v, &u->x) ||
178                             put_user(v, &p->x) ||
179                             get_user(v, &u->y) ||
180                             put_user(v, &p->y) ||
181                             get_user(v, &u->width) ||
182                             put_user(v, &p->width) ||
183                             get_user(v, &u->height) ||
184                             put_user(v, &p->height) ||
185                             put_user(NULL, &p->next))
186                                 return -EFAULT;
187                 }
188         }
189
190         return native_ioctl(file, VIDIOCSWIN, (unsigned long)p);
191 }
192
193 static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
194 {
195         union {
196                 struct video_tuner vt;
197                 struct video_buffer vb;
198                 struct video_window vw;
199                 unsigned long vx;
200         } karg;
201         mm_segment_t old_fs = get_fs();
202         void __user *up = compat_ptr(arg);
203         int err = 0;
204
205         /* First, convert the command. */
206         switch(cmd) {
207         case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
208         case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
209         case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
210         case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
211         case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
212         case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
213         case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
214         };
215
216         switch(cmd) {
217         case VIDIOCSTUNER:
218         case VIDIOCGTUNER:
219                 err = get_video_tuner32(&karg.vt, up);
220                 break;
221
222         case VIDIOCSFBUF:
223                 err = get_video_buffer32(&karg.vb, up);
224                 break;
225
226         case VIDIOCSFREQ:
227                 err = get_user(karg.vx, (u32 __user *)up);
228                 break;
229         };
230         if(err)
231                 goto out;
232
233         set_fs(KERNEL_DS);
234         err = native_ioctl(file, cmd, (unsigned long)&karg);
235         set_fs(old_fs);
236
237         if(err == 0) {
238                 switch(cmd) {
239                 case VIDIOCGTUNER:
240                         err = put_video_tuner32(&karg.vt, up);
241                         break;
242
243                 case VIDIOCGWIN:
244                         err = put_video_window32(&karg.vw, up);
245                         break;
246
247                 case VIDIOCGFBUF:
248                         err = put_video_buffer32(&karg.vb, up);
249                         break;
250
251                 case VIDIOCGFREQ:
252                         err = put_user(((u32)karg.vx), (u32 __user *)up);
253                         break;
254                 };
255         }
256 out:
257         return err;
258 }
259
260 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
261 {
262         int ret = -ENOIOCTLCMD;
263
264         if (!file->f_ops->ioctl)
265                 return ret;
266
267         switch (cmd) {
268         case VIDIOCSWIN32:
269                 ret = do_set_window(file, cmd, arg);
270                 break;
271         case VIDIOCGTUNER32:
272         case VIDIOCSTUNER32:
273         case VIDIOCGWIN32:
274         case VIDIOCGFBUF32:
275         case VIDIOCSFBUF32:
276         case VIDIOCGFREQ32:
277         case VIDIOCSFREQ32
278                 ret = do_video_ioctl(file, cmd, arg);
279                 break;
280
281         /* Little v, the video4linux ioctls (conflict?) */
282         case VIDIOCGCAP:
283         case VIDIOCGCHAN:
284         case VIDIOCSCHAN:
285         case VIDIOCGPICT:
286         case VIDIOCSPICT:
287         case VIDIOCCAPTURE:
288         case VIDIOCKEY:
289         case VIDIOCGAUDIO:
290         case VIDIOCSAUDIO:
291         case VIDIOCSYNC:
292         case VIDIOCMCAPTURE:
293         case VIDIOCGMBUF:
294         case VIDIOCGUNIT:
295         case VIDIOCGCAPTURE:
296         case VIDIOCSCAPTURE:
297
298         /* BTTV specific... */
299         case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
300         case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
301         case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
302         case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
303         case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
304         case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
305         case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
306         case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
307                 ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
308                 break;
309
310         return ret;
311 }
312 #else
313 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
314 {
315         return -ENOIOCTLCMD;
316 }
317 #endif
318 EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);