diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2010-11-21 11:36:34 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-01 17:10:24 -0500 |
commit | 6947756dfcecc493062a46e77f6bf51dddb5be75 (patch) | |
tree | 9ef949c2b95d43ce0389ea6d54b5b469322aaf0b /drivers/media/video | |
parent | 4aa275975beee41fd542a0f6df8cd0fee06089bf (diff) |
[media] uvcvideo: Lock stream mutex when accessing format-related information
The stream mutex protects access to the struct uvc_streaming ctrl,
cur_format and cur_frame fields as well as to the hardware probe
control. Lock it appropriately.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 78 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 3 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 4 |
3 files changed, 58 insertions, 27 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 07dd2357fbb9..2f6dc6b97348 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -226,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, | |||
226 | * developers test their webcams with the Linux driver as well as with | 226 | * developers test their webcams with the Linux driver as well as with |
227 | * the Windows driver). | 227 | * the Windows driver). |
228 | */ | 228 | */ |
229 | mutex_lock(&stream->mutex); | ||
229 | if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) | 230 | if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) |
230 | probe->dwMaxVideoFrameSize = | 231 | probe->dwMaxVideoFrameSize = |
231 | stream->ctrl.dwMaxVideoFrameSize; | 232 | stream->ctrl.dwMaxVideoFrameSize; |
232 | 233 | ||
233 | /* Probe the device. */ | 234 | /* Probe the device. */ |
234 | ret = uvc_probe_video(stream, probe); | 235 | ret = uvc_probe_video(stream, probe); |
236 | mutex_unlock(&stream->mutex); | ||
235 | if (ret < 0) | 237 | if (ret < 0) |
236 | goto done; | 238 | goto done; |
237 | 239 | ||
@@ -255,14 +257,21 @@ done: | |||
255 | static int uvc_v4l2_get_format(struct uvc_streaming *stream, | 257 | static int uvc_v4l2_get_format(struct uvc_streaming *stream, |
256 | struct v4l2_format *fmt) | 258 | struct v4l2_format *fmt) |
257 | { | 259 | { |
258 | struct uvc_format *format = stream->cur_format; | 260 | struct uvc_format *format; |
259 | struct uvc_frame *frame = stream->cur_frame; | 261 | struct uvc_frame *frame; |
262 | int ret = 0; | ||
260 | 263 | ||
261 | if (fmt->type != stream->type) | 264 | if (fmt->type != stream->type) |
262 | return -EINVAL; | 265 | return -EINVAL; |
263 | 266 | ||
264 | if (format == NULL || frame == NULL) | 267 | mutex_lock(&stream->mutex); |
265 | return -EINVAL; | 268 | format = stream->cur_format; |
269 | frame = stream->cur_frame; | ||
270 | |||
271 | if (format == NULL || frame == NULL) { | ||
272 | ret = -EINVAL; | ||
273 | goto done; | ||
274 | } | ||
266 | 275 | ||
267 | fmt->fmt.pix.pixelformat = format->fcc; | 276 | fmt->fmt.pix.pixelformat = format->fcc; |
268 | fmt->fmt.pix.width = frame->wWidth; | 277 | fmt->fmt.pix.width = frame->wWidth; |
@@ -273,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, | |||
273 | fmt->fmt.pix.colorspace = format->colorspace; | 282 | fmt->fmt.pix.colorspace = format->colorspace; |
274 | fmt->fmt.pix.priv = 0; | 283 | fmt->fmt.pix.priv = 0; |
275 | 284 | ||
276 | return 0; | 285 | done: |
286 | mutex_unlock(&stream->mutex); | ||
287 | return ret; | ||
277 | } | 288 | } |
278 | 289 | ||
279 | static int uvc_v4l2_set_format(struct uvc_streaming *stream, | 290 | static int uvc_v4l2_set_format(struct uvc_streaming *stream, |
@@ -287,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, | |||
287 | if (fmt->type != stream->type) | 298 | if (fmt->type != stream->type) |
288 | return -EINVAL; | 299 | return -EINVAL; |
289 | 300 | ||
290 | if (uvc_queue_allocated(&stream->queue)) | ||
291 | return -EBUSY; | ||
292 | |||
293 | ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); | 301 | ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); |
294 | if (ret < 0) | 302 | if (ret < 0) |
295 | return ret; | 303 | return ret; |
296 | 304 | ||
305 | mutex_lock(&stream->mutex); | ||
306 | |||
307 | if (uvc_queue_allocated(&stream->queue)) { | ||
308 | ret = -EBUSY; | ||
309 | goto done; | ||
310 | } | ||
311 | |||
297 | memcpy(&stream->ctrl, &probe, sizeof probe); | 312 | memcpy(&stream->ctrl, &probe, sizeof probe); |
298 | stream->cur_format = format; | 313 | stream->cur_format = format; |
299 | stream->cur_frame = frame; | 314 | stream->cur_frame = frame; |
300 | 315 | ||
301 | return 0; | 316 | done: |
317 | mutex_unlock(&stream->mutex); | ||
318 | return ret; | ||
302 | } | 319 | } |
303 | 320 | ||
304 | static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | 321 | static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, |
@@ -309,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | |||
309 | if (parm->type != stream->type) | 326 | if (parm->type != stream->type) |
310 | return -EINVAL; | 327 | return -EINVAL; |
311 | 328 | ||
329 | mutex_lock(&stream->mutex); | ||
312 | numerator = stream->ctrl.dwFrameInterval; | 330 | numerator = stream->ctrl.dwFrameInterval; |
331 | mutex_unlock(&stream->mutex); | ||
332 | |||
313 | denominator = 10000000; | 333 | denominator = 10000000; |
314 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); | 334 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); |
315 | 335 | ||
@@ -336,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | |||
336 | static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, | 356 | static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, |
337 | struct v4l2_streamparm *parm) | 357 | struct v4l2_streamparm *parm) |
338 | { | 358 | { |
339 | struct uvc_frame *frame = stream->cur_frame; | ||
340 | struct uvc_streaming_control probe; | 359 | struct uvc_streaming_control probe; |
341 | struct v4l2_fract timeperframe; | 360 | struct v4l2_fract timeperframe; |
342 | uint32_t interval; | 361 | uint32_t interval; |
@@ -345,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, | |||
345 | if (parm->type != stream->type) | 364 | if (parm->type != stream->type) |
346 | return -EINVAL; | 365 | return -EINVAL; |
347 | 366 | ||
348 | if (uvc_queue_streaming(&stream->queue)) | ||
349 | return -EBUSY; | ||
350 | |||
351 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 367 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
352 | timeperframe = parm->parm.capture.timeperframe; | 368 | timeperframe = parm->parm.capture.timeperframe; |
353 | else | 369 | else |
354 | timeperframe = parm->parm.output.timeperframe; | 370 | timeperframe = parm->parm.output.timeperframe; |
355 | 371 | ||
356 | memcpy(&probe, &stream->ctrl, sizeof probe); | ||
357 | interval = uvc_fraction_to_interval(timeperframe.numerator, | 372 | interval = uvc_fraction_to_interval(timeperframe.numerator, |
358 | timeperframe.denominator); | 373 | timeperframe.denominator); |
359 | |||
360 | uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", | 374 | uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", |
361 | timeperframe.numerator, timeperframe.denominator, interval); | 375 | timeperframe.numerator, timeperframe.denominator, interval); |
362 | probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); | 376 | |
377 | mutex_lock(&stream->mutex); | ||
378 | |||
379 | if (uvc_queue_streaming(&stream->queue)) { | ||
380 | mutex_unlock(&stream->mutex); | ||
381 | return -EBUSY; | ||
382 | } | ||
383 | |||
384 | memcpy(&probe, &stream->ctrl, sizeof probe); | ||
385 | probe.dwFrameInterval = | ||
386 | uvc_try_frame_interval(stream->cur_frame, interval); | ||
363 | 387 | ||
364 | /* Probe the device with the new settings. */ | 388 | /* Probe the device with the new settings. */ |
365 | ret = uvc_probe_video(stream, &probe); | 389 | ret = uvc_probe_video(stream, &probe); |
366 | if (ret < 0) | 390 | if (ret < 0) { |
391 | mutex_unlock(&stream->mutex); | ||
367 | return ret; | 392 | return ret; |
393 | } | ||
368 | 394 | ||
369 | memcpy(&stream->ctrl, &probe, sizeof probe); | 395 | memcpy(&stream->ctrl, &probe, sizeof probe); |
396 | mutex_unlock(&stream->mutex); | ||
370 | 397 | ||
371 | /* Return the actual frame period. */ | 398 | /* Return the actual frame period. */ |
372 | timeperframe.numerator = probe.dwFrameInterval; | 399 | timeperframe.numerator = probe.dwFrameInterval; |
@@ -869,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
869 | case VIDIOC_CROPCAP: | 896 | case VIDIOC_CROPCAP: |
870 | { | 897 | { |
871 | struct v4l2_cropcap *ccap = arg; | 898 | struct v4l2_cropcap *ccap = arg; |
872 | struct uvc_frame *frame = stream->cur_frame; | ||
873 | 899 | ||
874 | if (ccap->type != stream->type) | 900 | if (ccap->type != stream->type) |
875 | return -EINVAL; | 901 | return -EINVAL; |
876 | 902 | ||
877 | ccap->bounds.left = 0; | 903 | ccap->bounds.left = 0; |
878 | ccap->bounds.top = 0; | 904 | ccap->bounds.top = 0; |
879 | ccap->bounds.width = frame->wWidth; | 905 | |
880 | ccap->bounds.height = frame->wHeight; | 906 | mutex_lock(&stream->mutex); |
907 | ccap->bounds.width = stream->cur_frame->wWidth; | ||
908 | ccap->bounds.height = stream->cur_frame->wHeight; | ||
909 | mutex_unlock(&stream->mutex); | ||
881 | 910 | ||
882 | ccap->defrect = ccap->bounds; | 911 | ccap->defrect = ccap->bounds; |
883 | 912 | ||
@@ -894,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
894 | case VIDIOC_REQBUFS: | 923 | case VIDIOC_REQBUFS: |
895 | { | 924 | { |
896 | struct v4l2_requestbuffers *rb = arg; | 925 | struct v4l2_requestbuffers *rb = arg; |
897 | unsigned int bufsize = | ||
898 | stream->ctrl.dwMaxVideoFrameSize; | ||
899 | 926 | ||
900 | if (rb->type != stream->type || | 927 | if (rb->type != stream->type || |
901 | rb->memory != V4L2_MEMORY_MMAP) | 928 | rb->memory != V4L2_MEMORY_MMAP) |
@@ -904,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
904 | if ((ret = uvc_acquire_privileges(handle)) < 0) | 931 | if ((ret = uvc_acquire_privileges(handle)) < 0) |
905 | return ret; | 932 | return ret; |
906 | 933 | ||
907 | ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize); | 934 | mutex_lock(&stream->mutex); |
935 | ret = uvc_alloc_buffers(&stream->queue, rb->count, | ||
936 | stream->ctrl.dwMaxVideoFrameSize); | ||
937 | mutex_unlock(&stream->mutex); | ||
908 | if (ret < 0) | 938 | if (ret < 0) |
909 | return ret; | 939 | return ret; |
910 | 940 | ||
@@ -952,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
952 | if (!uvc_has_privileges(handle)) | 982 | if (!uvc_has_privileges(handle)) |
953 | return -EBUSY; | 983 | return -EBUSY; |
954 | 984 | ||
985 | mutex_lock(&stream->mutex); | ||
955 | ret = uvc_video_enable(stream, 1); | 986 | ret = uvc_video_enable(stream, 1); |
987 | mutex_unlock(&stream->mutex); | ||
956 | if (ret < 0) | 988 | if (ret < 0) |
957 | return ret; | 989 | return ret; |
958 | break; | 990 | break; |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 5555f0102838..5673d673504b 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream, | |||
293 | unsigned int i; | 293 | unsigned int i; |
294 | int ret; | 294 | int ret; |
295 | 295 | ||
296 | mutex_lock(&stream->mutex); | ||
297 | |||
298 | /* Perform probing. The device should adjust the requested values | 296 | /* Perform probing. The device should adjust the requested values |
299 | * according to its capabilities. However, some devices, namely the | 297 | * according to its capabilities. However, some devices, namely the |
300 | * first generation UVC Logitech webcams, don't implement the Video | 298 | * first generation UVC Logitech webcams, don't implement the Video |
@@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream, | |||
346 | } | 344 | } |
347 | 345 | ||
348 | done: | 346 | done: |
349 | mutex_unlock(&stream->mutex); | ||
350 | return ret; | 347 | return ret; |
351 | } | 348 | } |
352 | 349 | ||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index ea893bc0df07..45f01e7e13d2 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -436,7 +436,9 @@ struct uvc_streaming { | |||
436 | struct uvc_streaming_control ctrl; | 436 | struct uvc_streaming_control ctrl; |
437 | struct uvc_format *cur_format; | 437 | struct uvc_format *cur_format; |
438 | struct uvc_frame *cur_frame; | 438 | struct uvc_frame *cur_frame; |
439 | 439 | /* Protect access to ctrl, cur_format, cur_frame and hardware video | |
440 | * probe control. | ||
441 | */ | ||
440 | struct mutex mutex; | 442 | struct mutex mutex; |
441 | 443 | ||
442 | unsigned int frozen : 1; | 444 | unsigned int frozen : 1; |