diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2009-02-12 06:05:45 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:42:49 -0400 |
commit | 090264e508c20baa0c3eea5a7d8eea4db84a29cc (patch) | |
tree | 4c481782c5b78444f3b50f7507ce7ef9f2722706 /drivers/media/video/gspca/gspca.c | |
parent | 10711d07c109a1b2b3245d68ada6aba5c8c59147 (diff) |
V4L/DVB (10620): gspca - main: More checks of the device disconnection.
- prevent application oops when the device is disconnected
- wake up the application at disconnection time
- check the disconnection in ioctl dqbuf and poll
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 105 |
1 files changed, 74 insertions, 31 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index eac7aec44254..8aac7a1e8f33 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -132,11 +132,13 @@ static void fill_frame(struct gspca_dev *gspca_dev, | |||
132 | cam_pkt_op pkt_scan; | 132 | cam_pkt_op pkt_scan; |
133 | 133 | ||
134 | if (urb->status != 0) { | 134 | if (urb->status != 0) { |
135 | if (urb->status == -ESHUTDOWN) | ||
136 | return; /* disconnection */ | ||
135 | #ifdef CONFIG_PM | 137 | #ifdef CONFIG_PM |
136 | if (!gspca_dev->frozen) | 138 | if (!gspca_dev->frozen) |
137 | #endif | 139 | #endif |
138 | PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); | 140 | PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); |
139 | return; /* disconnection ? */ | 141 | return; |
140 | } | 142 | } |
141 | pkt_scan = gspca_dev->sd_desc->pkt_scan; | 143 | pkt_scan = gspca_dev->sd_desc->pkt_scan; |
142 | for (i = 0; i < urb->number_of_packets; i++) { | 144 | for (i = 0; i < urb->number_of_packets; i++) { |
@@ -208,6 +210,8 @@ static void bulk_irq(struct urb *urb) | |||
208 | switch (urb->status) { | 210 | switch (urb->status) { |
209 | case 0: | 211 | case 0: |
210 | break; | 212 | break; |
213 | case -ESHUTDOWN: | ||
214 | return; /* disconnection */ | ||
211 | case -ECONNRESET: | 215 | case -ECONNRESET: |
212 | urb->status = 0; | 216 | urb->status = 0; |
213 | break; | 217 | break; |
@@ -216,7 +220,7 @@ static void bulk_irq(struct urb *urb) | |||
216 | if (!gspca_dev->frozen) | 220 | if (!gspca_dev->frozen) |
217 | #endif | 221 | #endif |
218 | PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); | 222 | PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); |
219 | return; /* disconnection ? */ | 223 | return; |
220 | } | 224 | } |
221 | 225 | ||
222 | /* check the availability of the frame buffer */ | 226 | /* check the availability of the frame buffer */ |
@@ -422,10 +426,8 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) | |||
422 | if (urb == NULL) | 426 | if (urb == NULL) |
423 | break; | 427 | break; |
424 | 428 | ||
425 | BUG_ON(!gspca_dev->dev); | ||
426 | gspca_dev->urb[i] = NULL; | 429 | gspca_dev->urb[i] = NULL; |
427 | if (!gspca_dev->present) | 430 | usb_kill_urb(urb); |
428 | usb_kill_urb(urb); | ||
429 | if (urb->transfer_buffer != NULL) | 431 | if (urb->transfer_buffer != NULL) |
430 | usb_buffer_free(gspca_dev->dev, | 432 | usb_buffer_free(gspca_dev->dev, |
431 | urb->transfer_buffer_length, | 433 | urb->transfer_buffer_length, |
@@ -593,6 +595,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) | |||
593 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 595 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
594 | return -ERESTARTSYS; | 596 | return -ERESTARTSYS; |
595 | 597 | ||
598 | if (!gspca_dev->present) { | ||
599 | ret = -ENODEV; | ||
600 | goto out; | ||
601 | } | ||
602 | |||
596 | /* set the higher alternate setting and | 603 | /* set the higher alternate setting and |
597 | * loop until urb submit succeeds */ | 604 | * loop until urb submit succeeds */ |
598 | gspca_dev->alt = gspca_dev->nbalt; | 605 | gspca_dev->alt = gspca_dev->nbalt; |
@@ -662,12 +669,14 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) | |||
662 | static void gspca_stream_off(struct gspca_dev *gspca_dev) | 669 | static void gspca_stream_off(struct gspca_dev *gspca_dev) |
663 | { | 670 | { |
664 | gspca_dev->streaming = 0; | 671 | gspca_dev->streaming = 0; |
665 | if (gspca_dev->present | 672 | if (gspca_dev->present) { |
666 | && gspca_dev->sd_desc->stopN) | 673 | if (gspca_dev->sd_desc->stopN) |
667 | gspca_dev->sd_desc->stopN(gspca_dev); | 674 | gspca_dev->sd_desc->stopN(gspca_dev); |
668 | destroy_urbs(gspca_dev); | 675 | destroy_urbs(gspca_dev); |
669 | if (gspca_dev->present) | ||
670 | gspca_set_alt0(gspca_dev); | 676 | gspca_set_alt0(gspca_dev); |
677 | } | ||
678 | |||
679 | /* always call stop0 to free the subdriver's resources */ | ||
671 | if (gspca_dev->sd_desc->stop0) | 680 | if (gspca_dev->sd_desc->stop0) |
672 | gspca_dev->sd_desc->stop0(gspca_dev); | 681 | gspca_dev->sd_desc->stop0(gspca_dev); |
673 | PDEBUG(D_STREAM, "stream off OK"); | 682 | PDEBUG(D_STREAM, "stream off OK"); |
@@ -949,8 +958,17 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
949 | struct v4l2_capability *cap) | 958 | struct v4l2_capability *cap) |
950 | { | 959 | { |
951 | struct gspca_dev *gspca_dev = priv; | 960 | struct gspca_dev *gspca_dev = priv; |
961 | int ret; | ||
952 | 962 | ||
953 | memset(cap, 0, sizeof *cap); | 963 | memset(cap, 0, sizeof *cap); |
964 | |||
965 | /* protect the access to the usb device */ | ||
966 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | ||
967 | return -ERESTARTSYS; | ||
968 | if (!gspca_dev->present) { | ||
969 | ret = -ENODEV; | ||
970 | goto out; | ||
971 | } | ||
954 | strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); | 972 | strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); |
955 | if (gspca_dev->dev->product != NULL) { | 973 | if (gspca_dev->dev->product != NULL) { |
956 | strncpy(cap->card, gspca_dev->dev->product, | 974 | strncpy(cap->card, gspca_dev->dev->product, |
@@ -966,7 +984,10 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
966 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | 984 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
967 | | V4L2_CAP_STREAMING | 985 | | V4L2_CAP_STREAMING |
968 | | V4L2_CAP_READWRITE; | 986 | | V4L2_CAP_READWRITE; |
969 | return 0; | 987 | ret = 0; |
988 | out: | ||
989 | mutex_unlock(&gspca_dev->usb_lock); | ||
990 | return ret; | ||
970 | } | 991 | } |
971 | 992 | ||
972 | static int vidioc_queryctrl(struct file *file, void *priv, | 993 | static int vidioc_queryctrl(struct file *file, void *priv, |
@@ -1029,7 +1050,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
1029 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); | 1050 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); |
1030 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1051 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1031 | return -ERESTARTSYS; | 1052 | return -ERESTARTSYS; |
1032 | ret = ctrls->set(gspca_dev, ctrl->value); | 1053 | if (gspca_dev->present) |
1054 | ret = ctrls->set(gspca_dev, ctrl->value); | ||
1055 | else | ||
1056 | ret = -ENODEV; | ||
1033 | mutex_unlock(&gspca_dev->usb_lock); | 1057 | mutex_unlock(&gspca_dev->usb_lock); |
1034 | return ret; | 1058 | return ret; |
1035 | } | 1059 | } |
@@ -1053,7 +1077,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
1053 | return -EINVAL; | 1077 | return -EINVAL; |
1054 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1078 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1055 | return -ERESTARTSYS; | 1079 | return -ERESTARTSYS; |
1056 | ret = ctrls->get(gspca_dev, &ctrl->value); | 1080 | if (gspca_dev->present) |
1081 | ret = ctrls->get(gspca_dev, &ctrl->value); | ||
1082 | else | ||
1083 | ret = -ENODEV; | ||
1057 | mutex_unlock(&gspca_dev->usb_lock); | 1084 | mutex_unlock(&gspca_dev->usb_lock); |
1058 | return ret; | 1085 | return ret; |
1059 | } | 1086 | } |
@@ -1215,10 +1242,7 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1215 | return -EINVAL; | 1242 | return -EINVAL; |
1216 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 1243 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
1217 | return -ERESTARTSYS; | 1244 | return -ERESTARTSYS; |
1218 | if (!gspca_dev->present) { | 1245 | |
1219 | ret = -ENODEV; | ||
1220 | goto out; | ||
1221 | } | ||
1222 | if (gspca_dev->nframes == 0 | 1246 | if (gspca_dev->nframes == 0 |
1223 | || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) { | 1247 | || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) { |
1224 | ret = -EINVAL; | 1248 | ret = -EINVAL; |
@@ -1286,7 +1310,10 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, | |||
1286 | return -EINVAL; | 1310 | return -EINVAL; |
1287 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1311 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1288 | return -ERESTARTSYS; | 1312 | return -ERESTARTSYS; |
1289 | ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); | 1313 | if (gspca_dev->present) |
1314 | ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); | ||
1315 | else | ||
1316 | ret = -ENODEV; | ||
1290 | mutex_unlock(&gspca_dev->usb_lock); | 1317 | mutex_unlock(&gspca_dev->usb_lock); |
1291 | return ret; | 1318 | return ret; |
1292 | } | 1319 | } |
@@ -1301,7 +1328,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, | |||
1301 | return -EINVAL; | 1328 | return -EINVAL; |
1302 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1329 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1303 | return -ERESTARTSYS; | 1330 | return -ERESTARTSYS; |
1304 | ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); | 1331 | if (gspca_dev->present) |
1332 | ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); | ||
1333 | else | ||
1334 | ret = -ENODEV; | ||
1305 | mutex_unlock(&gspca_dev->usb_lock); | 1335 | mutex_unlock(&gspca_dev->usb_lock); |
1306 | return ret; | 1336 | return ret; |
1307 | } | 1337 | } |
@@ -1320,7 +1350,11 @@ static int vidioc_g_parm(struct file *filp, void *priv, | |||
1320 | 1350 | ||
1321 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1351 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1322 | return -ERESTARTSYS; | 1352 | return -ERESTARTSYS; |
1323 | ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); | 1353 | if (gspca_dev->present) |
1354 | ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, | ||
1355 | parm); | ||
1356 | else | ||
1357 | ret = -ENODEV; | ||
1324 | mutex_unlock(&gspca_dev->usb_lock); | 1358 | mutex_unlock(&gspca_dev->usb_lock); |
1325 | return ret; | 1359 | return ret; |
1326 | } | 1360 | } |
@@ -1345,7 +1379,11 @@ static int vidioc_s_parm(struct file *filp, void *priv, | |||
1345 | 1379 | ||
1346 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 1380 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
1347 | return -ERESTARTSYS; | 1381 | return -ERESTARTSYS; |
1348 | ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); | 1382 | if (gspca_dev->present) |
1383 | ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, | ||
1384 | parm); | ||
1385 | else | ||
1386 | ret = -ENODEV; | ||
1349 | mutex_unlock(&gspca_dev->usb_lock); | 1387 | mutex_unlock(&gspca_dev->usb_lock); |
1350 | return ret; | 1388 | return ret; |
1351 | } | 1389 | } |
@@ -1519,7 +1557,8 @@ static int frame_wait(struct gspca_dev *gspca_dev, | |||
1519 | 1557 | ||
1520 | if (gspca_dev->sd_desc->dq_callback) { | 1558 | if (gspca_dev->sd_desc->dq_callback) { |
1521 | mutex_lock(&gspca_dev->usb_lock); | 1559 | mutex_lock(&gspca_dev->usb_lock); |
1522 | gspca_dev->sd_desc->dq_callback(gspca_dev); | 1560 | if (gspca_dev->present) |
1561 | gspca_dev->sd_desc->dq_callback(gspca_dev); | ||
1523 | mutex_unlock(&gspca_dev->usb_lock); | 1562 | mutex_unlock(&gspca_dev->usb_lock); |
1524 | } | 1563 | } |
1525 | return j; | 1564 | return j; |
@@ -1541,6 +1580,9 @@ static int vidioc_dqbuf(struct file *file, void *priv, | |||
1541 | if (v4l2_buf->memory != gspca_dev->memory) | 1580 | if (v4l2_buf->memory != gspca_dev->memory) |
1542 | return -EINVAL; | 1581 | return -EINVAL; |
1543 | 1582 | ||
1583 | if (!gspca_dev->present) | ||
1584 | return -ENODEV; | ||
1585 | |||
1544 | /* if not streaming, be sure the application will not loop forever */ | 1586 | /* if not streaming, be sure the application will not loop forever */ |
1545 | if (!(file->f_flags & O_NONBLOCK) | 1587 | if (!(file->f_flags & O_NONBLOCK) |
1546 | && !gspca_dev->streaming && gspca_dev->users == 1) | 1588 | && !gspca_dev->streaming && gspca_dev->users == 1) |
@@ -1691,8 +1733,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) | |||
1691 | PDEBUG(D_FRAM, "poll"); | 1733 | PDEBUG(D_FRAM, "poll"); |
1692 | 1734 | ||
1693 | poll_wait(file, &gspca_dev->wq, wait); | 1735 | poll_wait(file, &gspca_dev->wq, wait); |
1694 | if (!gspca_dev->present) | ||
1695 | return POLLERR; | ||
1696 | 1736 | ||
1697 | /* if reqbufs is not done, the user would use read() */ | 1737 | /* if reqbufs is not done, the user would use read() */ |
1698 | if (gspca_dev->nframes == 0) { | 1738 | if (gspca_dev->nframes == 0) { |
@@ -1705,10 +1745,6 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) | |||
1705 | 1745 | ||
1706 | if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) | 1746 | if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) |
1707 | return POLLERR; | 1747 | return POLLERR; |
1708 | if (!gspca_dev->present) { | ||
1709 | ret = POLLERR; | ||
1710 | goto out; | ||
1711 | } | ||
1712 | 1748 | ||
1713 | /* check the next incoming buffer */ | 1749 | /* check the next incoming buffer */ |
1714 | i = gspca_dev->fr_o; | 1750 | i = gspca_dev->fr_o; |
@@ -1717,8 +1753,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) | |||
1717 | ret = POLLIN | POLLRDNORM; /* something to read */ | 1753 | ret = POLLIN | POLLRDNORM; /* something to read */ |
1718 | else | 1754 | else |
1719 | ret = 0; | 1755 | ret = 0; |
1720 | out: | ||
1721 | mutex_unlock(&gspca_dev->queue_lock); | 1756 | mutex_unlock(&gspca_dev->queue_lock); |
1757 | if (!gspca_dev->present) | ||
1758 | return POLLHUP; | ||
1722 | return ret; | 1759 | return ret; |
1723 | } | 1760 | } |
1724 | 1761 | ||
@@ -1944,10 +1981,16 @@ void gspca_disconnect(struct usb_interface *intf) | |||
1944 | 1981 | ||
1945 | mutex_lock(&gspca_dev->usb_lock); | 1982 | mutex_lock(&gspca_dev->usb_lock); |
1946 | gspca_dev->present = 0; | 1983 | gspca_dev->present = 0; |
1947 | mutex_unlock(&gspca_dev->usb_lock); | ||
1948 | 1984 | ||
1949 | destroy_urbs(gspca_dev); | 1985 | if (gspca_dev->streaming) { |
1986 | destroy_urbs(gspca_dev); | ||
1987 | wake_up_interruptible(&gspca_dev->wq); | ||
1988 | } | ||
1989 | |||
1990 | /* the device is freed at exit of this function */ | ||
1950 | gspca_dev->dev = NULL; | 1991 | gspca_dev->dev = NULL; |
1992 | mutex_unlock(&gspca_dev->usb_lock); | ||
1993 | |||
1951 | usb_set_intfdata(intf, NULL); | 1994 | usb_set_intfdata(intf, NULL); |
1952 | 1995 | ||
1953 | /* release the device */ | 1996 | /* release the device */ |