diff options
| -rw-r--r-- | drivers/media/video/uvc/uvc_queue.c | 76 | ||||
| -rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 67 | ||||
| -rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 2 |
3 files changed, 79 insertions, 66 deletions
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 32c18229863b..f14581bd707f 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c | |||
| @@ -380,6 +380,82 @@ done: | |||
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | /* | 382 | /* |
| 383 | * VMA operations. | ||
| 384 | */ | ||
| 385 | static void uvc_vm_open(struct vm_area_struct *vma) | ||
| 386 | { | ||
| 387 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
| 388 | buffer->vma_use_count++; | ||
| 389 | } | ||
| 390 | |||
| 391 | static void uvc_vm_close(struct vm_area_struct *vma) | ||
| 392 | { | ||
| 393 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
| 394 | buffer->vma_use_count--; | ||
| 395 | } | ||
| 396 | |||
| 397 | static const struct vm_operations_struct uvc_vm_ops = { | ||
| 398 | .open = uvc_vm_open, | ||
| 399 | .close = uvc_vm_close, | ||
| 400 | }; | ||
| 401 | |||
| 402 | /* | ||
| 403 | * Memory-map a video buffer. | ||
| 404 | * | ||
| 405 | * This function implements video buffers memory mapping and is intended to be | ||
| 406 | * used by the device mmap handler. | ||
| 407 | */ | ||
| 408 | int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) | ||
| 409 | { | ||
| 410 | struct uvc_buffer *uninitialized_var(buffer); | ||
| 411 | struct page *page; | ||
| 412 | unsigned long addr, start, size; | ||
| 413 | unsigned int i; | ||
| 414 | int ret = 0; | ||
| 415 | |||
| 416 | start = vma->vm_start; | ||
| 417 | size = vma->vm_end - vma->vm_start; | ||
| 418 | |||
| 419 | mutex_lock(&queue->mutex); | ||
| 420 | |||
| 421 | for (i = 0; i < queue->count; ++i) { | ||
| 422 | buffer = &queue->buffer[i]; | ||
| 423 | if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) | ||
| 424 | break; | ||
| 425 | } | ||
| 426 | |||
| 427 | if (i == queue->count || size != queue->buf_size) { | ||
| 428 | ret = -EINVAL; | ||
| 429 | goto done; | ||
| 430 | } | ||
| 431 | |||
| 432 | /* | ||
| 433 | * VM_IO marks the area as being an mmaped region for I/O to a | ||
| 434 | * device. It also prevents the region from being core dumped. | ||
| 435 | */ | ||
| 436 | vma->vm_flags |= VM_IO; | ||
| 437 | |||
| 438 | addr = (unsigned long)queue->mem + buffer->buf.m.offset; | ||
| 439 | while (size > 0) { | ||
| 440 | page = vmalloc_to_page((void *)addr); | ||
| 441 | if ((ret = vm_insert_page(vma, start, page)) < 0) | ||
| 442 | goto done; | ||
| 443 | |||
| 444 | start += PAGE_SIZE; | ||
| 445 | addr += PAGE_SIZE; | ||
| 446 | size -= PAGE_SIZE; | ||
| 447 | } | ||
| 448 | |||
| 449 | vma->vm_ops = &uvc_vm_ops; | ||
| 450 | vma->vm_private_data = buffer; | ||
| 451 | uvc_vm_open(vma); | ||
| 452 | |||
| 453 | done: | ||
| 454 | mutex_unlock(&queue->mutex); | ||
| 455 | return ret; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* | ||
| 383 | * Poll the video queue. | 459 | * Poll the video queue. |
| 384 | * | 460 | * |
| 385 | * This function implements video queue polling and is intended to be used by | 461 | * This function implements video queue polling and is intended to be used by |
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 0fd9848bd9d7..07dd2357fbb9 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
| @@ -1032,79 +1032,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, | |||
| 1032 | return -EINVAL; | 1032 | return -EINVAL; |
| 1033 | } | 1033 | } |
| 1034 | 1034 | ||
| 1035 | /* | ||
| 1036 | * VMA operations. | ||
| 1037 | */ | ||
| 1038 | static void uvc_vm_open(struct vm_area_struct *vma) | ||
| 1039 | { | ||
| 1040 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
| 1041 | buffer->vma_use_count++; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static void uvc_vm_close(struct vm_area_struct *vma) | ||
| 1045 | { | ||
| 1046 | struct uvc_buffer *buffer = vma->vm_private_data; | ||
| 1047 | buffer->vma_use_count--; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static const struct vm_operations_struct uvc_vm_ops = { | ||
| 1051 | .open = uvc_vm_open, | ||
| 1052 | .close = uvc_vm_close, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | 1035 | static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) |
| 1056 | { | 1036 | { |
| 1057 | struct uvc_fh *handle = file->private_data; | 1037 | struct uvc_fh *handle = file->private_data; |
| 1058 | struct uvc_streaming *stream = handle->stream; | 1038 | struct uvc_streaming *stream = handle->stream; |
| 1059 | struct uvc_video_queue *queue = &stream->queue; | ||
| 1060 | struct uvc_buffer *uninitialized_var(buffer); | ||
| 1061 | struct page *page; | ||
| 1062 | unsigned long addr, start, size; | ||
| 1063 | unsigned int i; | ||
| 1064 | int ret = 0; | ||
| 1065 | 1039 | ||
| 1066 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); | 1040 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); |
| 1067 | 1041 | ||
| 1068 | start = vma->vm_start; | 1042 | return uvc_queue_mmap(&stream->queue, vma); |
| 1069 | size = vma->vm_end - vma->vm_start; | ||
| 1070 | |||
| 1071 | mutex_lock(&queue->mutex); | ||
| 1072 | |||
| 1073 | for (i = 0; i < queue->count; ++i) { | ||
| 1074 | buffer = &queue->buffer[i]; | ||
| 1075 | if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) | ||
| 1076 | break; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | if (i == queue->count || size != queue->buf_size) { | ||
| 1080 | ret = -EINVAL; | ||
| 1081 | goto done; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | /* | ||
| 1085 | * VM_IO marks the area as being an mmaped region for I/O to a | ||
| 1086 | * device. It also prevents the region from being core dumped. | ||
| 1087 | */ | ||
| 1088 | vma->vm_flags |= VM_IO; | ||
| 1089 | |||
| 1090 | addr = (unsigned long)queue->mem + buffer->buf.m.offset; | ||
| 1091 | while (size > 0) { | ||
| 1092 | page = vmalloc_to_page((void *)addr); | ||
| 1093 | if ((ret = vm_insert_page(vma, start, page)) < 0) | ||
| 1094 | goto done; | ||
| 1095 | |||
| 1096 | start += PAGE_SIZE; | ||
| 1097 | addr += PAGE_SIZE; | ||
| 1098 | size -= PAGE_SIZE; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | vma->vm_ops = &uvc_vm_ops; | ||
| 1102 | vma->vm_private_data = buffer; | ||
| 1103 | uvc_vm_open(vma); | ||
| 1104 | |||
| 1105 | done: | ||
| 1106 | mutex_unlock(&queue->mutex); | ||
| 1107 | return ret; | ||
| 1108 | } | 1043 | } |
| 1109 | 1044 | ||
| 1110 | static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) | 1045 | static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 45209245244b..ea893bc0df07 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
| @@ -574,6 +574,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); | |||
| 574 | extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); | 574 | extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); |
| 575 | extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, | 575 | extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, |
| 576 | struct uvc_buffer *buf); | 576 | struct uvc_buffer *buf); |
| 577 | extern int uvc_queue_mmap(struct uvc_video_queue *queue, | ||
| 578 | struct vm_area_struct *vma); | ||
| 577 | extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, | 579 | extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, |
| 578 | struct file *file, poll_table *wait); | 580 | struct file *file, poll_table *wait); |
| 579 | extern int uvc_queue_allocated(struct uvc_video_queue *queue); | 581 | extern int uvc_queue_allocated(struct uvc_video_queue *queue); |
