diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_v4l2.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 185 |
1 files changed, 58 insertions, 127 deletions
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 6d15de9b5204..8cf61e8a634f 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -101,40 +101,6 @@ done: | |||
101 | */ | 101 | */ |
102 | 102 | ||
103 | /* | 103 | /* |
104 | * Mapping V4L2 controls to UVC controls can be straighforward if done well. | ||
105 | * Most of the UVC controls exist in V4L2, and can be mapped directly. Some | ||
106 | * must be grouped (for instance the Red Balance, Blue Balance and Do White | ||
107 | * Balance V4L2 controls use the White Balance Component UVC control) or | ||
108 | * otherwise translated. The approach we take here is to use a translation | ||
109 | * table for the controls that can be mapped directly, and handle the others | ||
110 | * manually. | ||
111 | */ | ||
112 | static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, | ||
113 | struct v4l2_querymenu *query_menu) | ||
114 | { | ||
115 | struct uvc_menu_info *menu_info; | ||
116 | struct uvc_control_mapping *mapping; | ||
117 | struct uvc_control *ctrl; | ||
118 | u32 index = query_menu->index; | ||
119 | u32 id = query_menu->id; | ||
120 | |||
121 | ctrl = uvc_find_control(chain, query_menu->id, &mapping); | ||
122 | if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) | ||
123 | return -EINVAL; | ||
124 | |||
125 | if (query_menu->index >= mapping->menu_count) | ||
126 | return -EINVAL; | ||
127 | |||
128 | memset(query_menu, 0, sizeof(*query_menu)); | ||
129 | query_menu->id = id; | ||
130 | query_menu->index = index; | ||
131 | |||
132 | menu_info = &mapping->menu_info[query_menu->index]; | ||
133 | strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Find the frame interval closest to the requested frame interval for the | 104 | * Find the frame interval closest to the requested frame interval for the |
139 | * given frame format and size. This should be done by the device as part of | 105 | * given frame format and size. This should be done by the device as part of |
140 | * the Video Probe and Commit negotiation, but some hardware don't implement | 106 | * the Video Probe and Commit negotiation, but some hardware don't implement |
@@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, | |||
260 | * 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 |
261 | * the Windows driver). | 227 | * the Windows driver). |
262 | */ | 228 | */ |
229 | mutex_lock(&stream->mutex); | ||
263 | if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) | 230 | if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) |
264 | probe->dwMaxVideoFrameSize = | 231 | probe->dwMaxVideoFrameSize = |
265 | stream->ctrl.dwMaxVideoFrameSize; | 232 | stream->ctrl.dwMaxVideoFrameSize; |
266 | 233 | ||
267 | /* Probe the device. */ | 234 | /* Probe the device. */ |
268 | ret = uvc_probe_video(stream, probe); | 235 | ret = uvc_probe_video(stream, probe); |
236 | mutex_unlock(&stream->mutex); | ||
269 | if (ret < 0) | 237 | if (ret < 0) |
270 | goto done; | 238 | goto done; |
271 | 239 | ||
@@ -289,14 +257,21 @@ done: | |||
289 | static int uvc_v4l2_get_format(struct uvc_streaming *stream, | 257 | static int uvc_v4l2_get_format(struct uvc_streaming *stream, |
290 | struct v4l2_format *fmt) | 258 | struct v4l2_format *fmt) |
291 | { | 259 | { |
292 | struct uvc_format *format = stream->cur_format; | 260 | struct uvc_format *format; |
293 | struct uvc_frame *frame = stream->cur_frame; | 261 | struct uvc_frame *frame; |
262 | int ret = 0; | ||
294 | 263 | ||
295 | if (fmt->type != stream->type) | 264 | if (fmt->type != stream->type) |
296 | return -EINVAL; | 265 | return -EINVAL; |
297 | 266 | ||
298 | if (format == NULL || frame == NULL) | 267 | mutex_lock(&stream->mutex); |
299 | 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 | } | ||
300 | 275 | ||
301 | fmt->fmt.pix.pixelformat = format->fcc; | 276 | fmt->fmt.pix.pixelformat = format->fcc; |
302 | fmt->fmt.pix.width = frame->wWidth; | 277 | fmt->fmt.pix.width = frame->wWidth; |
@@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, | |||
307 | fmt->fmt.pix.colorspace = format->colorspace; | 282 | fmt->fmt.pix.colorspace = format->colorspace; |
308 | fmt->fmt.pix.priv = 0; | 283 | fmt->fmt.pix.priv = 0; |
309 | 284 | ||
310 | return 0; | 285 | done: |
286 | mutex_unlock(&stream->mutex); | ||
287 | return ret; | ||
311 | } | 288 | } |
312 | 289 | ||
313 | static int uvc_v4l2_set_format(struct uvc_streaming *stream, | 290 | static int uvc_v4l2_set_format(struct uvc_streaming *stream, |
@@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, | |||
321 | if (fmt->type != stream->type) | 298 | if (fmt->type != stream->type) |
322 | return -EINVAL; | 299 | return -EINVAL; |
323 | 300 | ||
324 | if (uvc_queue_allocated(&stream->queue)) | ||
325 | return -EBUSY; | ||
326 | |||
327 | ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); | 301 | ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); |
328 | if (ret < 0) | 302 | if (ret < 0) |
329 | return ret; | 303 | return ret; |
330 | 304 | ||
305 | mutex_lock(&stream->mutex); | ||
306 | |||
307 | if (uvc_queue_allocated(&stream->queue)) { | ||
308 | ret = -EBUSY; | ||
309 | goto done; | ||
310 | } | ||
311 | |||
331 | memcpy(&stream->ctrl, &probe, sizeof probe); | 312 | memcpy(&stream->ctrl, &probe, sizeof probe); |
332 | stream->cur_format = format; | 313 | stream->cur_format = format; |
333 | stream->cur_frame = frame; | 314 | stream->cur_frame = frame; |
334 | 315 | ||
335 | return 0; | 316 | done: |
317 | mutex_unlock(&stream->mutex); | ||
318 | return ret; | ||
336 | } | 319 | } |
337 | 320 | ||
338 | static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | 321 | static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, |
@@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | |||
343 | if (parm->type != stream->type) | 326 | if (parm->type != stream->type) |
344 | return -EINVAL; | 327 | return -EINVAL; |
345 | 328 | ||
329 | mutex_lock(&stream->mutex); | ||
346 | numerator = stream->ctrl.dwFrameInterval; | 330 | numerator = stream->ctrl.dwFrameInterval; |
331 | mutex_unlock(&stream->mutex); | ||
332 | |||
347 | denominator = 10000000; | 333 | denominator = 10000000; |
348 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); | 334 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); |
349 | 335 | ||
@@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, | |||
370 | static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, | 356 | static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, |
371 | struct v4l2_streamparm *parm) | 357 | struct v4l2_streamparm *parm) |
372 | { | 358 | { |
373 | struct uvc_frame *frame = stream->cur_frame; | ||
374 | struct uvc_streaming_control probe; | 359 | struct uvc_streaming_control probe; |
375 | struct v4l2_fract timeperframe; | 360 | struct v4l2_fract timeperframe; |
376 | uint32_t interval; | 361 | uint32_t interval; |
@@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, | |||
379 | if (parm->type != stream->type) | 364 | if (parm->type != stream->type) |
380 | return -EINVAL; | 365 | return -EINVAL; |
381 | 366 | ||
382 | if (uvc_queue_streaming(&stream->queue)) | ||
383 | return -EBUSY; | ||
384 | |||
385 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 367 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
386 | timeperframe = parm->parm.capture.timeperframe; | 368 | timeperframe = parm->parm.capture.timeperframe; |
387 | else | 369 | else |
388 | timeperframe = parm->parm.output.timeperframe; | 370 | timeperframe = parm->parm.output.timeperframe; |
389 | 371 | ||
390 | memcpy(&probe, &stream->ctrl, sizeof probe); | ||
391 | interval = uvc_fraction_to_interval(timeperframe.numerator, | 372 | interval = uvc_fraction_to_interval(timeperframe.numerator, |
392 | timeperframe.denominator); | 373 | timeperframe.denominator); |
393 | |||
394 | 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", |
395 | timeperframe.numerator, timeperframe.denominator, interval); | 375 | timeperframe.numerator, timeperframe.denominator, interval); |
396 | 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); | ||
397 | 387 | ||
398 | /* Probe the device with the new settings. */ | 388 | /* Probe the device with the new settings. */ |
399 | ret = uvc_probe_video(stream, &probe); | 389 | ret = uvc_probe_video(stream, &probe); |
400 | if (ret < 0) | 390 | if (ret < 0) { |
391 | mutex_unlock(&stream->mutex); | ||
401 | return ret; | 392 | return ret; |
393 | } | ||
402 | 394 | ||
403 | memcpy(&stream->ctrl, &probe, sizeof probe); | 395 | memcpy(&stream->ctrl, &probe, sizeof probe); |
396 | mutex_unlock(&stream->mutex); | ||
404 | 397 | ||
405 | /* Return the actual frame period. */ | 398 | /* Return the actual frame period. */ |
406 | timeperframe.numerator = probe.dwFrameInterval; | 399 | timeperframe.numerator = probe.dwFrameInterval; |
@@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file) | |||
528 | if (uvc_has_privileges(handle)) { | 521 | if (uvc_has_privileges(handle)) { |
529 | uvc_video_enable(stream, 0); | 522 | uvc_video_enable(stream, 0); |
530 | 523 | ||
531 | mutex_lock(&stream->queue.mutex); | ||
532 | if (uvc_free_buffers(&stream->queue) < 0) | 524 | if (uvc_free_buffers(&stream->queue) < 0) |
533 | uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " | 525 | uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " |
534 | "free buffers.\n"); | 526 | "free buffers.\n"); |
535 | mutex_unlock(&stream->queue.mutex); | ||
536 | } | 527 | } |
537 | 528 | ||
538 | /* Release the file handle. */ | 529 | /* Release the file handle. */ |
@@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
624 | } | 615 | } |
625 | 616 | ||
626 | case VIDIOC_QUERYMENU: | 617 | case VIDIOC_QUERYMENU: |
627 | return uvc_v4l2_query_menu(chain, arg); | 618 | return uvc_query_v4l2_menu(chain, arg); |
628 | 619 | ||
629 | case VIDIOC_G_EXT_CTRLS: | 620 | case VIDIOC_G_EXT_CTRLS: |
630 | { | 621 | { |
@@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
905 | case VIDIOC_CROPCAP: | 896 | case VIDIOC_CROPCAP: |
906 | { | 897 | { |
907 | struct v4l2_cropcap *ccap = arg; | 898 | struct v4l2_cropcap *ccap = arg; |
908 | struct uvc_frame *frame = stream->cur_frame; | ||
909 | 899 | ||
910 | if (ccap->type != stream->type) | 900 | if (ccap->type != stream->type) |
911 | return -EINVAL; | 901 | return -EINVAL; |
912 | 902 | ||
913 | ccap->bounds.left = 0; | 903 | ccap->bounds.left = 0; |
914 | ccap->bounds.top = 0; | 904 | ccap->bounds.top = 0; |
915 | ccap->bounds.width = frame->wWidth; | 905 | |
916 | 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); | ||
917 | 910 | ||
918 | ccap->defrect = ccap->bounds; | 911 | ccap->defrect = ccap->bounds; |
919 | 912 | ||
@@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
930 | case VIDIOC_REQBUFS: | 923 | case VIDIOC_REQBUFS: |
931 | { | 924 | { |
932 | struct v4l2_requestbuffers *rb = arg; | 925 | struct v4l2_requestbuffers *rb = arg; |
933 | unsigned int bufsize = | ||
934 | stream->ctrl.dwMaxVideoFrameSize; | ||
935 | 926 | ||
936 | if (rb->type != stream->type || | 927 | if (rb->type != stream->type || |
937 | rb->memory != V4L2_MEMORY_MMAP) | 928 | rb->memory != V4L2_MEMORY_MMAP) |
@@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
940 | if ((ret = uvc_acquire_privileges(handle)) < 0) | 931 | if ((ret = uvc_acquire_privileges(handle)) < 0) |
941 | return ret; | 932 | return ret; |
942 | 933 | ||
943 | 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); | ||
944 | if (ret < 0) | 938 | if (ret < 0) |
945 | return ret; | 939 | return ret; |
946 | 940 | ||
@@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
988 | if (!uvc_has_privileges(handle)) | 982 | if (!uvc_has_privileges(handle)) |
989 | return -EBUSY; | 983 | return -EBUSY; |
990 | 984 | ||
985 | mutex_lock(&stream->mutex); | ||
991 | ret = uvc_video_enable(stream, 1); | 986 | ret = uvc_video_enable(stream, 1); |
987 | mutex_unlock(&stream->mutex); | ||
992 | if (ret < 0) | 988 | if (ret < 0) |
993 | return ret; | 989 | return ret; |
994 | break; | 990 | break; |
@@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, | |||
1068 | return -EINVAL; | 1064 | return -EINVAL; |
1069 | } | 1065 | } |
1070 | 1066 | ||
1071 | /* | ||
1072 | * VMA operations. | ||
1073 | */ | ||
1074 | static void uvc_vm_open(struct vm_area_struct *vma) | ||
1075 | { | ||
1076 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
1077 | buffer->vma_use_count++; | ||
1078 | } | ||
1079 | |||
1080 | static void uvc_vm_close(struct vm_area_struct *vma) | ||
1081 | { | ||
1082 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
1083 | buffer->vma_use_count--; | ||
1084 | } | ||
1085 | |||
1086 | static const struct vm_operations_struct uvc_vm_ops = { | ||
1087 | .open = uvc_vm_open, | ||
1088 | .close = uvc_vm_close, | ||
1089 | }; | ||
1090 | |||
1091 | static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | 1067 | static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) |
1092 | { | 1068 | { |
1093 | struct uvc_fh *handle = file->private_data; | 1069 | struct uvc_fh *handle = file->private_data; |
1094 | struct uvc_streaming *stream = handle->stream; | 1070 | struct uvc_streaming *stream = handle->stream; |
1095 | struct uvc_video_queue *queue = &stream->queue; | ||
1096 | struct uvc_buffer *uninitialized_var(buffer); | ||
1097 | struct page *page; | ||
1098 | unsigned long addr, start, size; | ||
1099 | unsigned int i; | ||
1100 | int ret = 0; | ||
1101 | 1071 | ||
1102 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); | 1072 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); |
1103 | 1073 | ||
1104 | start = vma->vm_start; | 1074 | return uvc_queue_mmap(&stream->queue, vma); |
1105 | size = vma->vm_end - vma->vm_start; | ||
1106 | |||
1107 | mutex_lock(&queue->mutex); | ||
1108 | |||
1109 | for (i = 0; i < queue->count; ++i) { | ||
1110 | buffer = &queue->buffer[i]; | ||
1111 | if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) | ||
1112 | break; | ||
1113 | } | ||
1114 | |||
1115 | if (i == queue->count || size != queue->buf_size) { | ||
1116 | ret = -EINVAL; | ||
1117 | goto done; | ||
1118 | } | ||
1119 | |||
1120 | /* | ||
1121 | * VM_IO marks the area as being an mmaped region for I/O to a | ||
1122 | * device. It also prevents the region from being core dumped. | ||
1123 | */ | ||
1124 | vma->vm_flags |= VM_IO; | ||
1125 | |||
1126 | addr = (unsigned long)queue->mem + buffer->buf.m.offset; | ||
1127 | while (size > 0) { | ||
1128 | page = vmalloc_to_page((void *)addr); | ||
1129 | if ((ret = vm_insert_page(vma, start, page)) < 0) | ||
1130 | goto done; | ||
1131 | |||
1132 | start += PAGE_SIZE; | ||
1133 | addr += PAGE_SIZE; | ||
1134 | size -= PAGE_SIZE; | ||
1135 | } | ||
1136 | |||
1137 | vma->vm_ops = &uvc_vm_ops; | ||
1138 | vma->vm_private_data = buffer; | ||
1139 | uvc_vm_open(vma); | ||
1140 | |||
1141 | done: | ||
1142 | mutex_unlock(&queue->mutex); | ||
1143 | return ret; | ||
1144 | } | 1075 | } |
1145 | 1076 | ||
1146 | static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) | 1077 | static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) |
@@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = { | |||
1157 | .owner = THIS_MODULE, | 1088 | .owner = THIS_MODULE, |
1158 | .open = uvc_v4l2_open, | 1089 | .open = uvc_v4l2_open, |
1159 | .release = uvc_v4l2_release, | 1090 | .release = uvc_v4l2_release, |
1160 | .ioctl = uvc_v4l2_ioctl, | 1091 | .unlocked_ioctl = uvc_v4l2_ioctl, |
1161 | .read = uvc_v4l2_read, | 1092 | .read = uvc_v4l2_read, |
1162 | .mmap = uvc_v4l2_mmap, | 1093 | .mmap = uvc_v4l2_mmap, |
1163 | .poll = uvc_v4l2_poll, | 1094 | .poll = uvc_v4l2_poll, |