diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch')
-rw-r--r-- | extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch b/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch new file mode 100644 index 00000000..f2120201 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch | |||
@@ -0,0 +1,297 @@ | |||
1 | From d71c2e533be956a95e4ddde8b87f657ada3c9de3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
3 | Date: Mon, 12 Jul 2010 16:09:41 +0200 | ||
4 | Subject: [PATCH 01/43] v4l: Share code between video_usercopy and video_ioctl2 | ||
5 | |||
6 | The two functions are mostly identical. They handle the copy_from_user | ||
7 | and copy_to_user operations related with V4L2 ioctls and call the real | ||
8 | ioctl handler. | ||
9 | |||
10 | Create a __video_usercopy function that implements the core of | ||
11 | video_usercopy and video_ioctl2, and call that function from both. | ||
12 | |||
13 | Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
14 | --- | ||
15 | drivers/media/video/v4l2-ioctl.c | 218 ++++++++++++------------------------- | ||
16 | 1 files changed, 71 insertions(+), 147 deletions(-) | ||
17 | |||
18 | diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c | ||
19 | index dd9283f..1e01554 100644 | ||
20 | --- a/drivers/media/video/v4l2-ioctl.c | ||
21 | +++ b/drivers/media/video/v4l2-ioctl.c | ||
22 | @@ -374,35 +374,62 @@ video_fix_command(unsigned int cmd) | ||
23 | } | ||
24 | #endif | ||
25 | |||
26 | -/* | ||
27 | - * Obsolete usercopy function - Should be removed soon | ||
28 | - */ | ||
29 | -long | ||
30 | -video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
31 | +/* In some cases, only a few fields are used as input, i.e. when the app sets | ||
32 | + * "index" and then the driver fills in the rest of the structure for the thing | ||
33 | + * with that index. We only need to copy up the first non-input field. */ | ||
34 | +static unsigned long cmd_input_size(unsigned int cmd) | ||
35 | +{ | ||
36 | + /* Size of structure up to and including 'field' */ | ||
37 | +#define CMDINSIZE(cmd, type, field) \ | ||
38 | + case VIDIOC_##cmd: \ | ||
39 | + return offsetof(struct v4l2_##type, field) + \ | ||
40 | + sizeof(((struct v4l2_##type *)0)->field); | ||
41 | + | ||
42 | + switch (cmd) { | ||
43 | + CMDINSIZE(ENUM_FMT, fmtdesc, type); | ||
44 | + CMDINSIZE(G_FMT, format, type); | ||
45 | + CMDINSIZE(QUERYBUF, buffer, type); | ||
46 | + CMDINSIZE(G_PARM, streamparm, type); | ||
47 | + CMDINSIZE(ENUMSTD, standard, index); | ||
48 | + CMDINSIZE(ENUMINPUT, input, index); | ||
49 | + CMDINSIZE(G_CTRL, control, id); | ||
50 | + CMDINSIZE(G_TUNER, tuner, index); | ||
51 | + CMDINSIZE(QUERYCTRL, queryctrl, id); | ||
52 | + CMDINSIZE(QUERYMENU, querymenu, index); | ||
53 | + CMDINSIZE(ENUMOUTPUT, output, index); | ||
54 | + CMDINSIZE(G_MODULATOR, modulator, index); | ||
55 | + CMDINSIZE(G_FREQUENCY, frequency, tuner); | ||
56 | + CMDINSIZE(CROPCAP, cropcap, type); | ||
57 | + CMDINSIZE(G_CROP, crop, type); | ||
58 | + CMDINSIZE(ENUMAUDIO, audio, index); | ||
59 | + CMDINSIZE(ENUMAUDOUT, audioout, index); | ||
60 | + CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); | ||
61 | + CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); | ||
62 | + CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); | ||
63 | + CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); | ||
64 | + CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); | ||
65 | + default: | ||
66 | + return _IOC_SIZE(cmd); | ||
67 | + } | ||
68 | +} | ||
69 | + | ||
70 | +static long | ||
71 | +__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
72 | v4l2_kioctl func) | ||
73 | { | ||
74 | char sbuf[128]; | ||
75 | void *mbuf = NULL; | ||
76 | - void *parg = NULL; | ||
77 | + void *parg = (void *)arg; | ||
78 | long err = -EINVAL; | ||
79 | int is_ext_ctrl; | ||
80 | size_t ctrls_size = 0; | ||
81 | void __user *user_ptr = NULL; | ||
82 | |||
83 | -#ifdef __OLD_VIDIOC_ | ||
84 | - cmd = video_fix_command(cmd); | ||
85 | -#endif | ||
86 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
87 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
88 | |||
89 | /* Copy arguments into temp kernel buffer */ | ||
90 | - switch (_IOC_DIR(cmd)) { | ||
91 | - case _IOC_NONE: | ||
92 | - parg = NULL; | ||
93 | - break; | ||
94 | - case _IOC_READ: | ||
95 | - case _IOC_WRITE: | ||
96 | - case (_IOC_WRITE | _IOC_READ): | ||
97 | + if (_IOC_DIR(cmd) != _IOC_NONE) { | ||
98 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
99 | parg = sbuf; | ||
100 | } else { | ||
101 | @@ -414,11 +441,21 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
102 | } | ||
103 | |||
104 | err = -EFAULT; | ||
105 | - if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
106 | - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
107 | + if (_IOC_DIR(cmd) & _IOC_WRITE) { | ||
108 | + unsigned long n = cmd_input_size(cmd); | ||
109 | + | ||
110 | + if (copy_from_user(parg, (void __user *)arg, n)) | ||
111 | goto out; | ||
112 | - break; | ||
113 | + | ||
114 | + /* zero out anything we don't copy from userspace */ | ||
115 | + if (n < _IOC_SIZE(cmd)) | ||
116 | + memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); | ||
117 | + } else { | ||
118 | + /* read-only ioctl */ | ||
119 | + memset(parg, 0, _IOC_SIZE(cmd)); | ||
120 | + } | ||
121 | } | ||
122 | + | ||
123 | if (is_ext_ctrl) { | ||
124 | struct v4l2_ext_controls *p = parg; | ||
125 | |||
126 | @@ -440,7 +477,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
127 | } | ||
128 | } | ||
129 | |||
130 | - /* call driver */ | ||
131 | + /* Handles IOCTL */ | ||
132 | err = func(file, cmd, parg); | ||
133 | if (err == -ENOIOCTLCMD) | ||
134 | err = -EINVAL; | ||
135 | @@ -469,6 +506,19 @@ out: | ||
136 | kfree(mbuf); | ||
137 | return err; | ||
138 | } | ||
139 | + | ||
140 | +/* | ||
141 | + * Obsolete usercopy function - Should be removed soon | ||
142 | + */ | ||
143 | +long | ||
144 | +video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
145 | + v4l2_kioctl func) | ||
146 | +{ | ||
147 | +#ifdef __OLD_VIDIOC_ | ||
148 | + cmd = video_fix_command(cmd); | ||
149 | +#endif | ||
150 | + return __video_usercopy(file, cmd, arg, func); | ||
151 | +} | ||
152 | EXPORT_SYMBOL(video_usercopy); | ||
153 | |||
154 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, | ||
155 | @@ -2041,138 +2091,12 @@ static long __video_do_ioctl(struct file *file, | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | -/* In some cases, only a few fields are used as input, i.e. when the app sets | ||
160 | - * "index" and then the driver fills in the rest of the structure for the thing | ||
161 | - * with that index. We only need to copy up the first non-input field. */ | ||
162 | -static unsigned long cmd_input_size(unsigned int cmd) | ||
163 | -{ | ||
164 | - /* Size of structure up to and including 'field' */ | ||
165 | -#define CMDINSIZE(cmd, type, field) \ | ||
166 | - case VIDIOC_##cmd: \ | ||
167 | - return offsetof(struct v4l2_##type, field) + \ | ||
168 | - sizeof(((struct v4l2_##type *)0)->field); | ||
169 | - | ||
170 | - switch (cmd) { | ||
171 | - CMDINSIZE(ENUM_FMT, fmtdesc, type); | ||
172 | - CMDINSIZE(G_FMT, format, type); | ||
173 | - CMDINSIZE(QUERYBUF, buffer, type); | ||
174 | - CMDINSIZE(G_PARM, streamparm, type); | ||
175 | - CMDINSIZE(ENUMSTD, standard, index); | ||
176 | - CMDINSIZE(ENUMINPUT, input, index); | ||
177 | - CMDINSIZE(G_CTRL, control, id); | ||
178 | - CMDINSIZE(G_TUNER, tuner, index); | ||
179 | - CMDINSIZE(QUERYCTRL, queryctrl, id); | ||
180 | - CMDINSIZE(QUERYMENU, querymenu, index); | ||
181 | - CMDINSIZE(ENUMOUTPUT, output, index); | ||
182 | - CMDINSIZE(G_MODULATOR, modulator, index); | ||
183 | - CMDINSIZE(G_FREQUENCY, frequency, tuner); | ||
184 | - CMDINSIZE(CROPCAP, cropcap, type); | ||
185 | - CMDINSIZE(G_CROP, crop, type); | ||
186 | - CMDINSIZE(ENUMAUDIO, audio, index); | ||
187 | - CMDINSIZE(ENUMAUDOUT, audioout, index); | ||
188 | - CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); | ||
189 | - CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); | ||
190 | - CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); | ||
191 | - CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); | ||
192 | - CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); | ||
193 | - default: | ||
194 | - return _IOC_SIZE(cmd); | ||
195 | - } | ||
196 | -} | ||
197 | - | ||
198 | long video_ioctl2(struct file *file, | ||
199 | unsigned int cmd, unsigned long arg) | ||
200 | { | ||
201 | - char sbuf[128]; | ||
202 | - void *mbuf = NULL; | ||
203 | - void *parg = (void *)arg; | ||
204 | - long err = -EINVAL; | ||
205 | - int is_ext_ctrl; | ||
206 | - size_t ctrls_size = 0; | ||
207 | - void __user *user_ptr = NULL; | ||
208 | - | ||
209 | #ifdef __OLD_VIDIOC_ | ||
210 | cmd = video_fix_command(cmd); | ||
211 | #endif | ||
212 | - is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
213 | - cmd == VIDIOC_TRY_EXT_CTRLS); | ||
214 | - | ||
215 | - /* Copy arguments into temp kernel buffer */ | ||
216 | - if (_IOC_DIR(cmd) != _IOC_NONE) { | ||
217 | - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
218 | - parg = sbuf; | ||
219 | - } else { | ||
220 | - /* too big to allocate from stack */ | ||
221 | - mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); | ||
222 | - if (NULL == mbuf) | ||
223 | - return -ENOMEM; | ||
224 | - parg = mbuf; | ||
225 | - } | ||
226 | - | ||
227 | - err = -EFAULT; | ||
228 | - if (_IOC_DIR(cmd) & _IOC_WRITE) { | ||
229 | - unsigned long n = cmd_input_size(cmd); | ||
230 | - | ||
231 | - if (copy_from_user(parg, (void __user *)arg, n)) | ||
232 | - goto out; | ||
233 | - | ||
234 | - /* zero out anything we don't copy from userspace */ | ||
235 | - if (n < _IOC_SIZE(cmd)) | ||
236 | - memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); | ||
237 | - } else { | ||
238 | - /* read-only ioctl */ | ||
239 | - memset(parg, 0, _IOC_SIZE(cmd)); | ||
240 | - } | ||
241 | - } | ||
242 | - | ||
243 | - if (is_ext_ctrl) { | ||
244 | - struct v4l2_ext_controls *p = parg; | ||
245 | - | ||
246 | - /* In case of an error, tell the caller that it wasn't | ||
247 | - a specific control that caused it. */ | ||
248 | - p->error_idx = p->count; | ||
249 | - user_ptr = (void __user *)p->controls; | ||
250 | - if (p->count) { | ||
251 | - ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
252 | - /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
253 | - mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
254 | - err = -ENOMEM; | ||
255 | - if (NULL == mbuf) | ||
256 | - goto out_ext_ctrl; | ||
257 | - err = -EFAULT; | ||
258 | - if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
259 | - goto out_ext_ctrl; | ||
260 | - p->controls = mbuf; | ||
261 | - } | ||
262 | - } | ||
263 | - | ||
264 | - /* Handles IOCTL */ | ||
265 | - err = __video_do_ioctl(file, cmd, parg); | ||
266 | - if (err == -ENOIOCTLCMD) | ||
267 | - err = -EINVAL; | ||
268 | - if (is_ext_ctrl) { | ||
269 | - struct v4l2_ext_controls *p = parg; | ||
270 | - | ||
271 | - p->controls = (void *)user_ptr; | ||
272 | - if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
273 | - err = -EFAULT; | ||
274 | - goto out_ext_ctrl; | ||
275 | - } | ||
276 | - if (err < 0) | ||
277 | - goto out; | ||
278 | - | ||
279 | -out_ext_ctrl: | ||
280 | - /* Copy results into user buffer */ | ||
281 | - switch (_IOC_DIR(cmd)) { | ||
282 | - case _IOC_READ: | ||
283 | - case (_IOC_WRITE | _IOC_READ): | ||
284 | - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
285 | - err = -EFAULT; | ||
286 | - break; | ||
287 | - } | ||
288 | - | ||
289 | -out: | ||
290 | - kfree(mbuf); | ||
291 | - return err; | ||
292 | + return __video_usercopy(file, cmd, arg, __video_do_ioctl); | ||
293 | } | ||
294 | EXPORT_SYMBOL(video_ioctl2); | ||
295 | -- | ||
296 | 1.6.6.1 | ||
297 | |||