diff options
Diffstat (limited to 'drivers/media/video/compat_ioctl32.c')
-rw-r--r-- | drivers/media/video/compat_ioctl32.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c new file mode 100644 index 000000000000..42dc11c63c0d --- /dev/null +++ b/drivers/media/video/compat_ioctl32.c | |||
@@ -0,0 +1,318 @@ | |||
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); | ||