]>
Commit | Line | Data |
---|---|---|
0d0fbf81 AB |
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); | |
925e699f RC |
319 | |
320 | MODULE_LICENSE("GPL"); |