diff options
author | Jean-Francois Moine <moinejf@free.fr> | 2008-07-12 08:28:04 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:26:09 -0400 |
commit | 5b77ae7776183d733ec86727bcc34c52a336afd6 (patch) | |
tree | f7b71b30108e5397ad4e6277e7bb414c95e13df7 /drivers/media | |
parent | 51fc8e3bc03aeddc557d3084d08425eb4cb8ed41 (diff) |
V4L/DVB (8350): gspca: Conform to v4l2 spec and mutex unlock fix.
gspca: Empty the application queues on streamoff ioctl.
streamon/off and qbuf ioctls may be done by any application.
Don't handle MJPEG pixel format as JPEG.
(thanks to Hans de Goede)
Authorize reqbufs ioctl when streaming.
Bad mutex unlock in poll() when streaming problem.
(thanks to Mauro Carvalho Chehab)
Don't handle 'webcam disconnected' in stream off.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 146 |
1 files changed, 74 insertions, 72 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 2ffb00ab0811..a566fd394895 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -42,8 +42,8 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); | |||
42 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); | 42 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); |
43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
44 | 44 | ||
45 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 6) | 45 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7) |
46 | static const char version[] = "2.1.6"; | 46 | static const char version[] = "2.1.7"; |
47 | 47 | ||
48 | static int video_nr = -1; | 48 | static int video_nr = -1; |
49 | 49 | ||
@@ -558,11 +558,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) | |||
558 | gspca_set_alt0(gspca_dev); | 558 | gspca_set_alt0(gspca_dev); |
559 | gspca_dev->sd_desc->stop0(gspca_dev); | 559 | gspca_dev->sd_desc->stop0(gspca_dev); |
560 | PDEBUG(D_STREAM, "stream off OK"); | 560 | PDEBUG(D_STREAM, "stream off OK"); |
561 | } else { | ||
562 | destroy_urbs(gspca_dev); | ||
563 | atomic_inc(&gspca_dev->nevent); | ||
564 | wake_up_interruptible(&gspca_dev->wq); | ||
565 | PDEBUG(D_ERR|D_STREAM, "stream off no device ??"); | ||
566 | } | 561 | } |
567 | } | 562 | } |
568 | 563 | ||
@@ -680,9 +675,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, | |||
680 | w = fmt->fmt.pix.width; | 675 | w = fmt->fmt.pix.width; |
681 | h = fmt->fmt.pix.height; | 676 | h = fmt->fmt.pix.height; |
682 | 677 | ||
683 | /* (luvcview problem) */ | ||
684 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) | ||
685 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; | ||
686 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 678 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
687 | if (gspca_debug & D_CONF) | 679 | if (gspca_debug & D_CONF) |
688 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); | 680 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); |
@@ -816,7 +808,7 @@ static int dev_close(struct inode *inode, struct file *file) | |||
816 | return -ERESTARTSYS; | 808 | return -ERESTARTSYS; |
817 | gspca_dev->users--; | 809 | gspca_dev->users--; |
818 | 810 | ||
819 | /* if the file did capture, free the streaming resources */ | 811 | /* if the file did the capture, free the streaming resources */ |
820 | if (gspca_dev->capt_file == file) { | 812 | if (gspca_dev->capt_file == file) { |
821 | mutex_lock(&gspca_dev->usb_lock); | 813 | mutex_lock(&gspca_dev->usb_lock); |
822 | if (gspca_dev->streaming) | 814 | if (gspca_dev->streaming) |
@@ -981,7 +973,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
981 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 973 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
982 | return -EINVAL; | 974 | return -EINVAL; |
983 | switch (rb->memory) { | 975 | switch (rb->memory) { |
984 | case GSPCA_MEMORY_READ: | 976 | case GSPCA_MEMORY_READ: /* (internal call) */ |
985 | case V4L2_MEMORY_MMAP: | 977 | case V4L2_MEMORY_MMAP: |
986 | case V4L2_MEMORY_USERPTR: | 978 | case V4L2_MEMORY_USERPTR: |
987 | break; | 979 | break; |
@@ -991,33 +983,46 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
991 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 983 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
992 | return -ERESTARTSYS; | 984 | return -ERESTARTSYS; |
993 | 985 | ||
994 | /* only one file may do capture */ | 986 | if (gspca_dev->memory != GSPCA_MEMORY_NO |
995 | if ((gspca_dev->capt_file != NULL && gspca_dev->capt_file != file) | 987 | && gspca_dev->memory != rb->memory) { |
996 | || gspca_dev->streaming) { | ||
997 | ret = -EBUSY; | 988 | ret = -EBUSY; |
998 | goto out; | 989 | goto out; |
999 | } | 990 | } |
1000 | 991 | ||
1001 | if (rb->count == 0) { /* unrequest */ | 992 | /* only one file may do the capture */ |
1002 | for (i = 0; i < gspca_dev->nframes; i++) { | 993 | if (gspca_dev->capt_file != NULL |
1003 | if (gspca_dev->frame[i].vma_use_count) { | 994 | && gspca_dev->capt_file != file) { |
1004 | ret = -EBUSY; | 995 | ret = -EBUSY; |
1005 | goto out; | 996 | goto out; |
1006 | } | 997 | } |
1007 | } | 998 | |
1008 | frame_free(gspca_dev); | 999 | /* if allocated, the buffers must not be mapped */ |
1009 | gspca_dev->capt_file = NULL; | 1000 | for (i = 0; i < gspca_dev->nframes; i++) { |
1010 | } else { | 1001 | if (gspca_dev->frame[i].vma_use_count) { |
1011 | if (gspca_dev->nframes != 0) { | ||
1012 | ret = -EBUSY; | 1002 | ret = -EBUSY; |
1013 | goto out; | 1003 | goto out; |
1014 | } | 1004 | } |
1015 | gspca_dev->memory = rb->memory; | 1005 | } |
1016 | ret = frame_alloc(gspca_dev, rb->count); | 1006 | |
1017 | if (ret == 0) { | 1007 | /* stop streaming */ |
1018 | rb->count = gspca_dev->nframes; | 1008 | if (gspca_dev->streaming) { |
1019 | gspca_dev->capt_file = file; | 1009 | mutex_lock(&gspca_dev->usb_lock); |
1020 | } | 1010 | gspca_stream_off(gspca_dev); |
1011 | mutex_unlock(&gspca_dev->usb_lock); | ||
1012 | } | ||
1013 | |||
1014 | /* free the previous allocated buffers, if any */ | ||
1015 | if (gspca_dev->nframes != 0) { | ||
1016 | frame_free(gspca_dev); | ||
1017 | gspca_dev->capt_file = NULL; | ||
1018 | } | ||
1019 | if (rb->count == 0) /* unrequest */ | ||
1020 | goto out; | ||
1021 | gspca_dev->memory = rb->memory; | ||
1022 | ret = frame_alloc(gspca_dev, rb->count); | ||
1023 | if (ret == 0) { | ||
1024 | rb->count = gspca_dev->nframes; | ||
1025 | gspca_dev->capt_file = file; | ||
1021 | } | 1026 | } |
1022 | out: | 1027 | out: |
1023 | mutex_unlock(&gspca_dev->queue_lock); | 1028 | mutex_unlock(&gspca_dev->queue_lock); |
@@ -1059,10 +1064,6 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1059 | ret = -EINVAL; | 1064 | ret = -EINVAL; |
1060 | goto out; | 1065 | goto out; |
1061 | } | 1066 | } |
1062 | if (gspca_dev->capt_file != file) { | ||
1063 | ret = -EINVAL; | ||
1064 | goto out; | ||
1065 | } | ||
1066 | if (!gspca_dev->streaming) { | 1067 | if (!gspca_dev->streaming) { |
1067 | ret = gspca_init_transfer(gspca_dev); | 1068 | ret = gspca_init_transfer(gspca_dev); |
1068 | if (ret < 0) | 1069 | if (ret < 0) |
@@ -1086,7 +1087,7 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1086 | enum v4l2_buf_type buf_type) | 1087 | enum v4l2_buf_type buf_type) |
1087 | { | 1088 | { |
1088 | struct gspca_dev *gspca_dev = priv; | 1089 | struct gspca_dev *gspca_dev = priv; |
1089 | int ret; | 1090 | int i, ret; |
1090 | 1091 | ||
1091 | if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1092 | if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1092 | return -EINVAL; | 1093 | return -EINVAL; |
@@ -1094,18 +1095,23 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1094 | return 0; | 1095 | return 0; |
1095 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | 1096 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) |
1096 | return -ERESTARTSYS; | 1097 | return -ERESTARTSYS; |
1098 | |||
1099 | /* stop streaming */ | ||
1097 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { | 1100 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { |
1098 | ret = -ERESTARTSYS; | 1101 | ret = -ERESTARTSYS; |
1099 | goto out; | 1102 | goto out; |
1100 | } | 1103 | } |
1101 | if (gspca_dev->capt_file != file) { | ||
1102 | ret = -EINVAL; | ||
1103 | goto out2; | ||
1104 | } | ||
1105 | gspca_stream_off(gspca_dev); | 1104 | gspca_stream_off(gspca_dev); |
1106 | ret = 0; | ||
1107 | out2: | ||
1108 | mutex_unlock(&gspca_dev->usb_lock); | 1105 | mutex_unlock(&gspca_dev->usb_lock); |
1106 | |||
1107 | /* empty the application queues */ | ||
1108 | for (i = 0; i < gspca_dev->nframes; i++) | ||
1109 | gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS; | ||
1110 | gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; | ||
1111 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
1112 | gspca_dev->sequence = 0; | ||
1113 | atomic_set(&gspca_dev->nevent, 0); | ||
1114 | ret = 0; | ||
1109 | out: | 1115 | out: |
1110 | mutex_unlock(&gspca_dev->queue_lock); | 1116 | mutex_unlock(&gspca_dev->queue_lock); |
1111 | return ret; | 1117 | return ret; |
@@ -1364,14 +1370,17 @@ static int vidioc_dqbuf(struct file *file, void *priv, | |||
1364 | return -EINVAL; | 1370 | return -EINVAL; |
1365 | if (v4l2_buf->memory != gspca_dev->memory) | 1371 | if (v4l2_buf->memory != gspca_dev->memory) |
1366 | return -EINVAL; | 1372 | return -EINVAL; |
1367 | if (!gspca_dev->streaming) | 1373 | |
1374 | /* if not streaming, be sure the application will not loop forever */ | ||
1375 | if (!(file->f_flags & O_NONBLOCK) | ||
1376 | && !gspca_dev->streaming && gspca_dev->users == 1) | ||
1368 | return -EINVAL; | 1377 | return -EINVAL; |
1369 | if (gspca_dev->capt_file != file) { | ||
1370 | ret = -EINVAL; | ||
1371 | goto out; | ||
1372 | } | ||
1373 | 1378 | ||
1374 | /* only one read */ | 1379 | /* only the capturing file may dequeue */ |
1380 | if (gspca_dev->capt_file != file) | ||
1381 | return -EINVAL; | ||
1382 | |||
1383 | /* only one dequeue / read at a time */ | ||
1375 | if (mutex_lock_interruptible(&gspca_dev->read_lock)) | 1384 | if (mutex_lock_interruptible(&gspca_dev->read_lock)) |
1376 | return -ERESTARTSYS; | 1385 | return -ERESTARTSYS; |
1377 | 1386 | ||
@@ -1416,24 +1425,23 @@ static int vidioc_qbuf(struct file *file, void *priv, | |||
1416 | if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1425 | if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1417 | return -EINVAL; | 1426 | return -EINVAL; |
1418 | 1427 | ||
1428 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | ||
1429 | return -ERESTARTSYS; | ||
1430 | |||
1419 | index = v4l2_buf->index; | 1431 | index = v4l2_buf->index; |
1420 | if ((unsigned) index >= gspca_dev->nframes) { | 1432 | if ((unsigned) index >= gspca_dev->nframes) { |
1421 | PDEBUG(D_FRAM, | 1433 | PDEBUG(D_FRAM, |
1422 | "qbuf idx %d >= %d", index, gspca_dev->nframes); | 1434 | "qbuf idx %d >= %d", index, gspca_dev->nframes); |
1423 | return -EINVAL; | 1435 | ret = -EINVAL; |
1436 | goto out; | ||
1424 | } | 1437 | } |
1425 | frame = &gspca_dev->frame[index]; | 1438 | if (v4l2_buf->memory != gspca_dev->memory) { |
1426 | |||
1427 | if (v4l2_buf->memory != frame->v4l2_buf.memory) { | ||
1428 | PDEBUG(D_FRAM, "qbuf bad memory type"); | 1439 | PDEBUG(D_FRAM, "qbuf bad memory type"); |
1429 | return -EINVAL; | 1440 | ret = -EINVAL; |
1441 | goto out; | ||
1430 | } | 1442 | } |
1431 | if (gspca_dev->capt_file != file) | ||
1432 | return -EINVAL; | ||
1433 | |||
1434 | if (mutex_lock_interruptible(&gspca_dev->queue_lock)) | ||
1435 | return -ERESTARTSYS; | ||
1436 | 1443 | ||
1444 | frame = &gspca_dev->frame[index]; | ||
1437 | if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) { | 1445 | if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) { |
1438 | PDEBUG(D_FRAM, "qbuf bad state"); | 1446 | PDEBUG(D_FRAM, "qbuf bad state"); |
1439 | ret = -EINVAL; | 1447 | ret = -EINVAL; |
@@ -1492,9 +1500,6 @@ static int read_alloc(struct gspca_dev *gspca_dev, | |||
1492 | v4l2_buf.memory = GSPCA_MEMORY_READ; | 1500 | v4l2_buf.memory = GSPCA_MEMORY_READ; |
1493 | for (i = 0; i < gspca_dev->nbufread; i++) { | 1501 | for (i = 0; i < gspca_dev->nbufread; i++) { |
1494 | v4l2_buf.index = i; | 1502 | v4l2_buf.index = i; |
1495 | /*fixme: ugly!*/ | ||
1496 | gspca_dev->frame[i].v4l2_buf.flags |= | ||
1497 | V4L2_BUF_FLAG_MAPPED; | ||
1498 | ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); | 1503 | ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); |
1499 | if (ret != 0) { | 1504 | if (ret != 0) { |
1500 | PDEBUG(D_STREAM, "read qbuf err: %d", ret); | 1505 | PDEBUG(D_STREAM, "read qbuf err: %d", ret); |
@@ -1522,17 +1527,13 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) | |||
1522 | if (!gspca_dev->present) | 1527 | if (!gspca_dev->present) |
1523 | return POLLERR; | 1528 | return POLLERR; |
1524 | 1529 | ||
1525 | /* if not streaming, the user would use read() */ | 1530 | /* if reqbufs is not done, the user would use read() */ |
1526 | if (!gspca_dev->streaming) { | 1531 | if (gspca_dev->nframes == 0) { |
1527 | if (gspca_dev->memory != GSPCA_MEMORY_NO) { | 1532 | if (gspca_dev->memory != GSPCA_MEMORY_NO) |
1528 | ret = POLLERR; /* not the 1st time */ | 1533 | return POLLERR; /* not the 1st time */ |
1529 | goto out; | ||
1530 | } | ||
1531 | ret = read_alloc(gspca_dev, file); | 1534 | ret = read_alloc(gspca_dev, file); |
1532 | if (ret != 0) { | 1535 | if (ret != 0) |
1533 | ret = POLLERR; | 1536 | return POLLERR; |
1534 | goto out; | ||
1535 | } | ||
1536 | } | 1537 | } |
1537 | 1538 | ||
1538 | if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) | 1539 | if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) |
@@ -1542,6 +1543,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) | |||
1542 | goto out; | 1543 | goto out; |
1543 | } | 1544 | } |
1544 | 1545 | ||
1546 | /* check the next incoming buffer */ | ||
1545 | i = gspca_dev->fr_o; | 1547 | i = gspca_dev->fr_o; |
1546 | i = gspca_dev->fr_queue[i]; | 1548 | i = gspca_dev->fr_queue[i]; |
1547 | if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE) | 1549 | if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE) |