diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2008-05-04 05:46:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:14:40 -0400 |
commit | 4aa0d037a6c8e6b37ecfd986a444f83190c32a21 (patch) | |
tree | 37ec7366de97498236b82048e7c10e0d6ebe22e2 /drivers/media/video/gspca/gspca.c | |
parent | e2997a72ddfafc25bd0c8f1f52bcf41979d5a559 (diff) |
V4L/DVB (8154): Fix protection problems in the main driver.
- Protect format change when streaming active.
- Protect USB exchanges on close.
- Set a timeout in frame wait.
- Have only one capture file and free the resources when closing this file.
- Simplify the URB buffer.
- Don't reset the control values at open time in pac207.
- Fix compilation warnings of stk014.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 163 |
1 files changed, 97 insertions, 66 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index c4735e133611..04dbaba4b78f 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -39,8 +39,8 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); | |||
39 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); | 39 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | 41 | ||
42 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 30) | 42 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 1) |
43 | static const char version[] = "0.0.30"; | 43 | static const char version[] = "0.1.1"; |
44 | 44 | ||
45 | static int video_nr = -1; | 45 | static int video_nr = -1; |
46 | 46 | ||
@@ -346,22 +346,17 @@ static int gspca_kill_transfer(struct gspca_dev *gspca_dev) | |||
346 | 346 | ||
347 | PDEBUG(D_STREAM, "kill transfer"); | 347 | PDEBUG(D_STREAM, "kill transfer"); |
348 | for (i = 0; i < NURBS; ++i) { | 348 | for (i = 0; i < NURBS; ++i) { |
349 | urb = gspca_dev->pktbuf[i].urb; | 349 | urb = gspca_dev->urb[i]; |
350 | if (urb == NULL) | 350 | if (urb == NULL) |
351 | continue; | 351 | continue; |
352 | 352 | ||
353 | gspca_dev->pktbuf[i].urb = NULL; | 353 | gspca_dev->urb[i] = NULL; |
354 | usb_kill_urb(urb); | 354 | usb_kill_urb(urb); |
355 | 355 | if (urb->transfer_buffer != 0) | |
356 | /* urb->transfer_buffer_length is not touched by USB core, | ||
357 | * so we can use it here as the buffer length */ | ||
358 | if (gspca_dev->pktbuf[i].data) { | ||
359 | usb_buffer_free(gspca_dev->dev, | 356 | usb_buffer_free(gspca_dev->dev, |
360 | urb->transfer_buffer_length, | 357 | urb->transfer_buffer_length, |
361 | gspca_dev->pktbuf[i].data, | 358 | urb->transfer_buffer, |
362 | urb->transfer_dma); | 359 | urb->transfer_dma); |
363 | gspca_dev->pktbuf[i].data = NULL; | ||
364 | } | ||
365 | usb_free_urb(urb); | 360 | usb_free_urb(urb); |
366 | } | 361 | } |
367 | return 0; | 362 | return 0; |
@@ -460,25 +455,25 @@ static int create_urbs(struct gspca_dev *gspca_dev, | |||
460 | err("usb_alloc_urb failed"); | 455 | err("usb_alloc_urb failed"); |
461 | return -ENOMEM; | 456 | return -ENOMEM; |
462 | } | 457 | } |
463 | gspca_dev->pktbuf[n].data = usb_buffer_alloc(gspca_dev->dev, | 458 | urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev, |
464 | bsize, | 459 | bsize, |
465 | GFP_KERNEL, | 460 | GFP_KERNEL, |
466 | &urb->transfer_dma); | 461 | &urb->transfer_dma); |
467 | 462 | ||
468 | if (gspca_dev->pktbuf[n].data == NULL) { | 463 | if (urb->transfer_buffer == NULL) { |
469 | usb_free_urb(urb); | 464 | usb_free_urb(urb); |
470 | gspca_kill_transfer(gspca_dev); | 465 | gspca_kill_transfer(gspca_dev); |
471 | err("usb_buffer_urb failed"); | 466 | err("usb_buffer_urb failed"); |
472 | return -ENOMEM; | 467 | return -ENOMEM; |
473 | } | 468 | } |
474 | gspca_dev->pktbuf[n].urb = urb; | 469 | gspca_dev->urb[n] = urb; |
475 | urb->dev = gspca_dev->dev; | 470 | urb->dev = gspca_dev->dev; |
476 | urb->context = gspca_dev; | 471 | urb->context = gspca_dev; |
477 | urb->pipe = usb_rcvisocpipe(gspca_dev->dev, | 472 | urb->pipe = usb_rcvisocpipe(gspca_dev->dev, |
478 | ep->desc.bEndpointAddress); | 473 | ep->desc.bEndpointAddress); |
479 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 474 | urb->transfer_flags = URB_ISO_ASAP |
475 | | URB_NO_TRANSFER_DMA_MAP; | ||
480 | urb->interval = ep->desc.bInterval; | 476 | urb->interval = ep->desc.bInterval; |
481 | urb->transfer_buffer = gspca_dev->pktbuf[n].data; | ||
482 | urb->complete = isoc_irq; | 477 | urb->complete = isoc_irq; |
483 | urb->number_of_packets = npkt; | 478 | urb->number_of_packets = npkt; |
484 | urb->transfer_buffer_length = bsize; | 479 | urb->transfer_buffer_length = bsize; |
@@ -523,8 +518,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) | |||
523 | 518 | ||
524 | /* submit the URBs */ | 519 | /* submit the URBs */ |
525 | for (n = 0; n < NURBS; n++) { | 520 | for (n = 0; n < NURBS; n++) { |
526 | ret = usb_submit_urb(gspca_dev->pktbuf[n].urb, | 521 | ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL); |
527 | GFP_KERNEL); | ||
528 | if (ret < 0) { | 522 | if (ret < 0) { |
529 | PDEBUG(D_ERR|D_STREAM, | 523 | PDEBUG(D_ERR|D_STREAM, |
530 | "usb_submit_urb [%d] err %d", n, ret); | 524 | "usb_submit_urb [%d] err %d", n, ret); |
@@ -732,15 +726,13 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, | |||
732 | return 0; | 726 | return 0; |
733 | } | 727 | } |
734 | 728 | ||
735 | static int try_fmt_cap(struct file *file, | 729 | static int try_fmt_cap(struct gspca_dev *gspca_dev, |
736 | void *priv, | ||
737 | struct v4l2_format *fmt) | 730 | struct v4l2_format *fmt) |
738 | { | 731 | { |
739 | struct gspca_dev *gspca_dev = priv; | ||
740 | int w, h, mode, mode2, frsz; | 732 | int w, h, mode, mode2, frsz; |
741 | 733 | ||
742 | w = (int) fmt->fmt.pix.width; | 734 | w = fmt->fmt.pix.width; |
743 | h = (int) fmt->fmt.pix.height; | 735 | h = fmt->fmt.pix.height; |
744 | #ifdef GSPCA_DEBUG | 736 | #ifdef GSPCA_DEBUG |
745 | if (gspca_debug & D_CONF) | 737 | if (gspca_debug & D_CONF) |
746 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); | 738 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); |
@@ -786,9 +778,10 @@ static int vidioc_try_fmt_cap(struct file *file, | |||
786 | void *priv, | 778 | void *priv, |
787 | struct v4l2_format *fmt) | 779 | struct v4l2_format *fmt) |
788 | { | 780 | { |
781 | struct gspca_dev *gspca_dev = priv; | ||
789 | int ret; | 782 | int ret; |
790 | 783 | ||
791 | ret = try_fmt_cap(file, priv, fmt); | 784 | ret = try_fmt_cap(gspca_dev, fmt); |
792 | if (ret < 0) | 785 | if (ret < 0) |
793 | return ret; | 786 | return ret; |
794 | return 0; | 787 | return 0; |
@@ -809,14 +802,19 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, | |||
809 | #endif | 802 | #endif |
810 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 803 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
811 | return -ERESTARTSYS; | 804 | return -ERESTARTSYS; |
812 | ret = try_fmt_cap(file, priv, fmt); | 805 | ret = try_fmt_cap(gspca_dev, fmt); |
813 | if (ret < 0) | 806 | if (ret < 0) |
814 | goto out; | 807 | goto out; |
815 | 808 | ||
816 | if (ret == gspca_dev->curr_mode) | 809 | if (ret == gspca_dev->curr_mode) |
817 | goto out; /* same mode */ | 810 | goto out; /* same mode */ |
818 | was_streaming = gspca_dev->streaming; | 811 | was_streaming = gspca_dev->streaming; |
819 | if (was_streaming != 0) { | 812 | if (was_streaming) { |
813 | if (gspca_dev->capt_file != 0 | ||
814 | && gspca_dev->capt_file != file) { | ||
815 | ret = -EBUSY; | ||
816 | goto out; | ||
817 | } | ||
820 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { | 818 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { |
821 | ret = -ERESTARTSYS; | 819 | ret = -ERESTARTSYS; |
822 | goto out; | 820 | goto out; |
@@ -824,8 +822,8 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, | |||
824 | gspca_stream_off(gspca_dev); | 822 | gspca_stream_off(gspca_dev); |
825 | mutex_unlock(&gspca_dev->usb_lock); | 823 | mutex_unlock(&gspca_dev->usb_lock); |
826 | } | 824 | } |
827 | gspca_dev->width = (int) fmt->fmt.pix.width; | 825 | gspca_dev->width = fmt->fmt.pix.width; |
828 | gspca_dev->height = (int) fmt->fmt.pix.height; | 826 | gspca_dev->height = fmt->fmt.pix.height; |
829 | gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; | 827 | gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; |
830 | gspca_dev->curr_mode = ret; | 828 | gspca_dev->curr_mode = ret; |
831 | if (was_streaming) | 829 | if (was_streaming) |
@@ -891,17 +889,18 @@ static int dev_close(struct inode *inode, struct file *file) | |||
891 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 889 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
892 | return -ERESTARTSYS; | 890 | return -ERESTARTSYS; |
893 | gspca_dev->users--; | 891 | gspca_dev->users--; |
894 | if (gspca_dev->users > 0) { | ||
895 | mutex_unlock(&gspca_dev->queue_lock); | ||
896 | return 0; | ||
897 | } | ||
898 | 892 | ||
899 | if (gspca_dev->streaming) | 893 | /* if the file did capture, free the streaming resources */ |
900 | gspca_stream_off(gspca_dev); | 894 | if (gspca_dev->capt_file == file) { |
901 | gspca_dev->sd_desc->close(gspca_dev); | 895 | mutex_lock(&gspca_dev->usb_lock); |
902 | 896 | if (gspca_dev->streaming) | |
903 | frame_free(gspca_dev); | 897 | gspca_stream_off(gspca_dev); |
904 | file->private_data = NULL; | 898 | gspca_dev->sd_desc->close(gspca_dev); |
899 | mutex_unlock(&gspca_dev->usb_lock); | ||
900 | frame_free(gspca_dev); | ||
901 | file->private_data = NULL; | ||
902 | gspca_dev->capt_file = 0; | ||
903 | } | ||
905 | mutex_unlock(&gspca_dev->queue_lock); | 904 | mutex_unlock(&gspca_dev->queue_lock); |
906 | PDEBUG(D_STREAM, "closed"); | 905 | PDEBUG(D_STREAM, "closed"); |
907 | return 0; | 906 | return 0; |
@@ -1052,12 +1051,19 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
1052 | return frsz; | 1051 | return frsz; |
1053 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 1052 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
1054 | return -ERESTARTSYS; | 1053 | return -ERESTARTSYS; |
1054 | if (gspca_dev->capt_file != 0) { /* only one file may do capture */ | ||
1055 | ret = -EBUSY; | ||
1056 | goto out; | ||
1057 | } | ||
1055 | ret = frame_alloc(gspca_dev, | 1058 | ret = frame_alloc(gspca_dev, |
1056 | rb->count, | 1059 | rb->count, |
1057 | (unsigned int) frsz, | 1060 | (unsigned int) frsz, |
1058 | rb->memory); | 1061 | rb->memory); |
1059 | if (ret == 0) | 1062 | if (ret == 0) { |
1060 | rb->count = gspca_dev->nframes; | 1063 | rb->count = gspca_dev->nframes; |
1064 | gspca_dev->capt_file = file; | ||
1065 | } | ||
1066 | out: | ||
1061 | mutex_unlock(&gspca_dev->queue_lock); | 1067 | mutex_unlock(&gspca_dev->queue_lock); |
1062 | PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count); | 1068 | PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count); |
1063 | return ret; | 1069 | return ret; |
@@ -1099,6 +1105,10 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1099 | ret = -EINVAL; | 1105 | ret = -EINVAL; |
1100 | goto out; | 1106 | goto out; |
1101 | } | 1107 | } |
1108 | if (gspca_dev->capt_file != file) { | ||
1109 | ret = -EINVAL; | ||
1110 | goto out; | ||
1111 | } | ||
1102 | if (!gspca_dev->streaming) { | 1112 | if (!gspca_dev->streaming) { |
1103 | ret = gspca_init_transfer(gspca_dev); | 1113 | ret = gspca_init_transfer(gspca_dev); |
1104 | if (ret < 0) | 1114 | if (ret < 0) |
@@ -1122,22 +1132,30 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1122 | enum v4l2_buf_type buf_type) | 1132 | enum v4l2_buf_type buf_type) |
1123 | { | 1133 | { |
1124 | struct gspca_dev *gspca_dev = priv; | 1134 | struct gspca_dev *gspca_dev = priv; |
1135 | int ret; | ||
1125 | 1136 | ||
1126 | PDEBUG(D_STREAM, "stream off"); | 1137 | PDEBUG(D_STREAM, "stream off"); |
1127 | if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1138 | if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1128 | return -EINVAL; | 1139 | return -EINVAL; |
1129 | if (gspca_dev->streaming) { | 1140 | if (!gspca_dev->streaming) |
1130 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 1141 | return 0; |
1131 | return -ERESTARTSYS; | 1142 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
1132 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { | 1143 | return -ERESTARTSYS; |
1133 | mutex_unlock(&gspca_dev->queue_lock); | 1144 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { |
1134 | return -ERESTARTSYS; | 1145 | ret = -ERESTARTSYS; |
1135 | } | 1146 | goto out; |
1136 | gspca_stream_off(gspca_dev); | ||
1137 | mutex_unlock(&gspca_dev->usb_lock); | ||
1138 | mutex_unlock(&gspca_dev->queue_lock); | ||
1139 | } | 1147 | } |
1140 | return 0; | 1148 | if (gspca_dev->capt_file != file) { |
1149 | ret = -EINVAL; | ||
1150 | goto out2; | ||
1151 | } | ||
1152 | gspca_stream_off(gspca_dev); | ||
1153 | ret = 0; | ||
1154 | out2: | ||
1155 | mutex_unlock(&gspca_dev->usb_lock); | ||
1156 | out: | ||
1157 | mutex_unlock(&gspca_dev->queue_lock); | ||
1158 | return ret; | ||
1141 | } | 1159 | } |
1142 | 1160 | ||
1143 | static int vidioc_g_jpegcomp(struct file *file, void *priv, | 1161 | static int vidioc_g_jpegcomp(struct file *file, void *priv, |
@@ -1187,14 +1205,11 @@ static int vidioc_s_parm(struct file *filp, void *priv, | |||
1187 | struct gspca_dev *gspca_dev = priv; | 1205 | struct gspca_dev *gspca_dev = priv; |
1188 | int n; | 1206 | int n; |
1189 | 1207 | ||
1190 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | ||
1191 | return -ERESTARTSYS; | ||
1192 | n = parm->parm.capture.readbuffers; | 1208 | n = parm->parm.capture.readbuffers; |
1193 | if (n == 0 || n > GSPCA_MAX_FRAMES) | 1209 | if (n == 0 || n > GSPCA_MAX_FRAMES) |
1194 | parm->parm.capture.readbuffers = gspca_dev->nbufread; | 1210 | parm->parm.capture.readbuffers = gspca_dev->nbufread; |
1195 | else | 1211 | else |
1196 | gspca_dev->nbufread = n; | 1212 | gspca_dev->nbufread = n; |
1197 | mutex_unlock(&gspca_dev->usb_lock); | ||
1198 | return 0; | 1213 | return 0; |
1199 | } | 1214 | } |
1200 | 1215 | ||
@@ -1245,7 +1260,11 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1245 | return -ERESTARTSYS; | 1260 | return -ERESTARTSYS; |
1246 | if (!gspca_dev->present) { | 1261 | if (!gspca_dev->present) { |
1247 | ret = -ENODEV; | 1262 | ret = -ENODEV; |
1248 | goto done; | 1263 | goto out; |
1264 | } | ||
1265 | if (gspca_dev->capt_file != file) { | ||
1266 | ret = -EINVAL; | ||
1267 | goto out; | ||
1249 | } | 1268 | } |
1250 | 1269 | ||
1251 | for (i = 0; i < gspca_dev->nframes; ++i) { | 1270 | for (i = 0; i < gspca_dev->nframes; ++i) { |
@@ -1262,7 +1281,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1262 | if (frame == 0) { | 1281 | if (frame == 0) { |
1263 | PDEBUG(D_STREAM, "mmap no frame buffer found"); | 1282 | PDEBUG(D_STREAM, "mmap no frame buffer found"); |
1264 | ret = -EINVAL; | 1283 | ret = -EINVAL; |
1265 | goto done; | 1284 | goto out; |
1266 | } | 1285 | } |
1267 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1286 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1268 | if (i == 0 && size == frame->v4l2_buf.length * gspca_dev->nframes) | 1287 | if (i == 0 && size == frame->v4l2_buf.length * gspca_dev->nframes) |
@@ -1272,7 +1291,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1272 | if (size != frame->v4l2_buf.length) { | 1291 | if (size != frame->v4l2_buf.length) { |
1273 | PDEBUG(D_STREAM, "mmap bad size"); | 1292 | PDEBUG(D_STREAM, "mmap bad size"); |
1274 | ret = -EINVAL; | 1293 | ret = -EINVAL; |
1275 | goto done; | 1294 | goto out; |
1276 | } | 1295 | } |
1277 | 1296 | ||
1278 | /* | 1297 | /* |
@@ -1286,7 +1305,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1286 | page = vmalloc_to_page((void *) addr); | 1305 | page = vmalloc_to_page((void *) addr); |
1287 | ret = vm_insert_page(vma, start, page); | 1306 | ret = vm_insert_page(vma, start, page); |
1288 | if (ret < 0) | 1307 | if (ret < 0) |
1289 | goto done; | 1308 | goto out; |
1290 | start += PAGE_SIZE; | 1309 | start += PAGE_SIZE; |
1291 | addr += PAGE_SIZE; | 1310 | addr += PAGE_SIZE; |
1292 | size -= PAGE_SIZE; | 1311 | size -= PAGE_SIZE; |
@@ -1304,7 +1323,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) | |||
1304 | } | 1323 | } |
1305 | #endif | 1324 | #endif |
1306 | ret = 0; | 1325 | ret = 0; |
1307 | done: | 1326 | out: |
1308 | mutex_unlock(&gspca_dev->queue_lock); | 1327 | mutex_unlock(&gspca_dev->queue_lock); |
1309 | return ret; | 1328 | return ret; |
1310 | } | 1329 | } |
@@ -1356,10 +1375,14 @@ static int gspca_frame_wait(struct gspca_dev *gspca_dev, | |||
1356 | 1375 | ||
1357 | /* wait till a frame is ready */ | 1376 | /* wait till a frame is ready */ |
1358 | for (;;) { | 1377 | for (;;) { |
1359 | ret = wait_event_interruptible(gspca_dev->wq, | 1378 | ret = wait_event_interruptible_timeout(gspca_dev->wq, |
1360 | atomic_read(&gspca_dev->nevent) > 0); | 1379 | atomic_read(&gspca_dev->nevent) > 0, |
1361 | if (ret != 0) | 1380 | msecs_to_jiffies(3000)); |
1362 | return ret; | 1381 | if (ret <= 0) { |
1382 | if (ret < 0) | ||
1383 | return ret; | ||
1384 | return -EIO; | ||
1385 | } | ||
1363 | if (!gspca_dev->streaming || !gspca_dev->present) | 1386 | if (!gspca_dev->streaming || !gspca_dev->present) |
1364 | return -EIO; | 1387 | return -EIO; |
1365 | i = gspca_dev->fr_o; | 1388 | i = gspca_dev->fr_o; |
@@ -1402,6 +1425,10 @@ static int vidioc_dqbuf(struct file *file, void *priv, | |||
1402 | return -EINVAL; | 1425 | return -EINVAL; |
1403 | if (!gspca_dev->streaming) | 1426 | if (!gspca_dev->streaming) |
1404 | return -EINVAL; | 1427 | return -EINVAL; |
1428 | if (gspca_dev->capt_file != file) { | ||
1429 | ret = -EINVAL; | ||
1430 | goto out; | ||
1431 | } | ||
1405 | 1432 | ||
1406 | /* only one read */ | 1433 | /* only one read */ |
1407 | if (mutex_lock_interruptible(&gspca_dev->read_lock)) | 1434 | if (mutex_lock_interruptible(&gspca_dev->read_lock)) |
@@ -1409,14 +1436,14 @@ static int vidioc_dqbuf(struct file *file, void *priv, | |||
1409 | 1436 | ||
1410 | ret = gspca_frame_wait(gspca_dev, file->f_flags & O_NONBLOCK); | 1437 | ret = gspca_frame_wait(gspca_dev, file->f_flags & O_NONBLOCK); |
1411 | if (ret < 0) | 1438 | if (ret < 0) |
1412 | goto done; | 1439 | goto out; |
1413 | i = ret; /* frame index */ | 1440 | i = ret; /* frame index */ |
1414 | frame = &gspca_dev->frame[i]; | 1441 | frame = &gspca_dev->frame[i]; |
1415 | frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; | 1442 | frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; |
1416 | memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); | 1443 | memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); |
1417 | PDEBUG(D_FRAM, "dqbuf %d", i); | 1444 | PDEBUG(D_FRAM, "dqbuf %d", i); |
1418 | ret = 0; | 1445 | ret = 0; |
1419 | done: | 1446 | out: |
1420 | mutex_unlock(&gspca_dev->read_lock); | 1447 | mutex_unlock(&gspca_dev->read_lock); |
1421 | return ret; | 1448 | return ret; |
1422 | } | 1449 | } |
@@ -1450,6 +1477,8 @@ static int vidioc_qbuf(struct file *file, void *priv, | |||
1450 | PDEBUG(D_STREAM, "qbuf bad memory type"); | 1477 | PDEBUG(D_STREAM, "qbuf bad memory type"); |
1451 | return -EINVAL; | 1478 | return -EINVAL; |
1452 | } | 1479 | } |
1480 | if (gspca_dev->capt_file != file) | ||
1481 | return -EINVAL; | ||
1453 | 1482 | ||
1454 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 1483 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
1455 | return -ERESTARTSYS; | 1484 | return -ERESTARTSYS; |
@@ -1524,7 +1553,9 @@ static ssize_t dev_read(struct file *file, char __user *data, | |||
1524 | return ret; | 1553 | return ret; |
1525 | } | 1554 | } |
1526 | } | 1555 | } |
1527 | } | 1556 | } else if (gspca_dev->capt_file != file) |
1557 | return -EINVAL; | ||
1558 | |||
1528 | if (!gspca_dev->streaming) { | 1559 | if (!gspca_dev->streaming) { |
1529 | ret = vidioc_streamon(file, gspca_dev, | 1560 | ret = vidioc_streamon(file, gspca_dev, |
1530 | V4L2_BUF_TYPE_VIDEO_CAPTURE); | 1561 | V4L2_BUF_TYPE_VIDEO_CAPTURE); |
@@ -1719,7 +1750,7 @@ EXPORT_SYMBOL(gspca_dev_probe); | |||
1719 | */ | 1750 | */ |
1720 | void gspca_disconnect(struct usb_interface *intf) | 1751 | void gspca_disconnect(struct usb_interface *intf) |
1721 | { | 1752 | { |
1722 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); | 1753 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); |
1723 | 1754 | ||
1724 | if (!gspca_dev) | 1755 | if (!gspca_dev) |
1725 | return; | 1756 | return; |