aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/gspca.c
diff options
context:
space:
mode:
authorJean-Francois Moine <moinejf@free.fr>2008-05-04 05:46:21 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-07-20 06:14:40 -0400
commit4aa0d037a6c8e6b37ecfd986a444f83190c32a21 (patch)
tree37ec7366de97498236b82048e7c10e0d6ebe22e2 /drivers/media/video/gspca/gspca.c
parente2997a72ddfafc25bd0c8f1f52bcf41979d5a559 (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.c163
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>");
39MODULE_DESCRIPTION("GSPCA USB Camera Driver"); 39MODULE_DESCRIPTION("GSPCA USB Camera Driver");
40MODULE_LICENSE("GPL"); 40MODULE_LICENSE("GPL");
41 41
42#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 30) 42#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 1)
43static const char version[] = "0.0.30"; 43static const char version[] = "0.1.1";
44 44
45static int video_nr = -1; 45static 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
735static int try_fmt_cap(struct file *file, 729static 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 }
1066out:
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;
1154out2:
1155 mutex_unlock(&gspca_dev->usb_lock);
1156out:
1157 mutex_unlock(&gspca_dev->queue_lock);
1158 return ret;
1141} 1159}
1142 1160
1143static int vidioc_g_jpegcomp(struct file *file, void *priv, 1161static 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;
1307done: 1326out:
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;
1419done: 1446out:
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 */
1720void gspca_disconnect(struct usb_interface *intf) 1751void 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;