diff options
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 182 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 10 |
2 files changed, 102 insertions, 90 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 55bc8ea56094..dda4a76dcaba 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -833,34 +833,63 @@ static void video_mux(struct em28xx *dev, int index) | |||
833 | } | 833 | } |
834 | 834 | ||
835 | /* Usage lock check functions */ | 835 | /* Usage lock check functions */ |
836 | static int res_get(struct em28xx_fh *fh) | 836 | static int res_get(struct em28xx_fh *fh, unsigned int bit) |
837 | { | 837 | { |
838 | struct em28xx *dev = fh->dev; | 838 | struct em28xx *dev = fh->dev; |
839 | int rc = 0; | ||
840 | 839 | ||
841 | /* This instance already has stream_on */ | 840 | if (fh->resources & bit) |
842 | if (fh->stream_on) | 841 | /* have it already allocated */ |
843 | return rc; | 842 | return 1; |
844 | 843 | ||
845 | if (dev->stream_on) | 844 | /* is it free? */ |
846 | return -EBUSY; | 845 | mutex_lock(&dev->lock); |
846 | if (dev->resources & bit) { | ||
847 | /* no, someone else uses it */ | ||
848 | mutex_unlock(&dev->lock); | ||
849 | return 0; | ||
850 | } | ||
851 | /* it's free, grab it */ | ||
852 | fh->resources |= bit; | ||
853 | dev->resources |= bit; | ||
854 | em28xx_videodbg("res: get %d\n", bit); | ||
855 | mutex_unlock(&dev->lock); | ||
856 | return 1; | ||
857 | } | ||
847 | 858 | ||
848 | dev->stream_on = 1; | 859 | static int res_check(struct em28xx_fh *fh, unsigned int bit) |
849 | fh->stream_on = 1; | 860 | { |
850 | return rc; | 861 | return (fh->resources & bit); |
851 | } | 862 | } |
852 | 863 | ||
853 | static int res_check(struct em28xx_fh *fh) | 864 | static int res_locked(struct em28xx *dev, unsigned int bit) |
854 | { | 865 | { |
855 | return fh->stream_on; | 866 | return (dev->resources & bit); |
856 | } | 867 | } |
857 | 868 | ||
858 | static void res_free(struct em28xx_fh *fh) | 869 | static void res_free(struct em28xx_fh *fh, unsigned int bits) |
859 | { | 870 | { |
860 | struct em28xx *dev = fh->dev; | 871 | struct em28xx *dev = fh->dev; |
861 | 872 | ||
862 | fh->stream_on = 0; | 873 | BUG_ON((fh->resources & bits) != bits); |
863 | dev->stream_on = 0; | 874 | |
875 | mutex_lock(&dev->lock); | ||
876 | fh->resources &= ~bits; | ||
877 | dev->resources &= ~bits; | ||
878 | em28xx_videodbg("res: put %d\n", bits); | ||
879 | mutex_unlock(&dev->lock); | ||
880 | } | ||
881 | |||
882 | static int get_ressource(struct em28xx_fh *fh) | ||
883 | { | ||
884 | switch (fh->type) { | ||
885 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
886 | return EM28XX_RESOURCE_VIDEO; | ||
887 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
888 | return EM28XX_RESOURCE_VBI; | ||
889 | default: | ||
890 | BUG(); | ||
891 | return 0; | ||
892 | } | ||
864 | } | 893 | } |
865 | 894 | ||
866 | /* | 895 | /* |
@@ -1103,12 +1132,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
1103 | goto out; | 1132 | goto out; |
1104 | } | 1133 | } |
1105 | 1134 | ||
1106 | if (dev->stream_on && !fh->stream_on) { | ||
1107 | em28xx_errdev("%s device in use by another fh\n", __func__); | ||
1108 | rc = -EBUSY; | ||
1109 | goto out; | ||
1110 | } | ||
1111 | |||
1112 | rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat, | 1135 | rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat, |
1113 | f->fmt.pix.width, f->fmt.pix.height); | 1136 | f->fmt.pix.width, f->fmt.pix.height); |
1114 | 1137 | ||
@@ -1668,24 +1691,25 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1668 | { | 1691 | { |
1669 | struct em28xx_fh *fh = priv; | 1692 | struct em28xx_fh *fh = priv; |
1670 | struct em28xx *dev = fh->dev; | 1693 | struct em28xx *dev = fh->dev; |
1671 | int rc; | 1694 | int rc = -EINVAL; |
1672 | 1695 | ||
1673 | rc = check_dev(dev); | 1696 | rc = check_dev(dev); |
1674 | if (rc < 0) | 1697 | if (rc < 0) |
1675 | return rc; | 1698 | return rc; |
1676 | 1699 | ||
1700 | if (unlikely(type != fh->type)) | ||
1701 | return -EINVAL; | ||
1677 | 1702 | ||
1678 | mutex_lock(&dev->lock); | 1703 | em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", |
1679 | rc = res_get(fh); | 1704 | fh, type, fh->resources, dev->resources); |
1680 | 1705 | ||
1681 | if (likely(rc >= 0)) { | 1706 | if (unlikely(!res_get(fh,get_ressource(fh)))) |
1682 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1707 | return -EBUSY; |
1683 | rc = videobuf_streamon(&fh->vb_vidq); | ||
1684 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1685 | rc = videobuf_streamon(&fh->vb_vbiq); | ||
1686 | } | ||
1687 | 1708 | ||
1688 | mutex_unlock(&dev->lock); | 1709 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1710 | rc = videobuf_streamon(&fh->vb_vidq); | ||
1711 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1712 | rc = videobuf_streamon(&fh->vb_vbiq); | ||
1689 | 1713 | ||
1690 | return rc; | 1714 | return rc; |
1691 | } | 1715 | } |
@@ -1707,16 +1731,16 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1707 | if (type != fh->type) | 1731 | if (type != fh->type) |
1708 | return -EINVAL; | 1732 | return -EINVAL; |
1709 | 1733 | ||
1710 | mutex_lock(&dev->lock); | 1734 | em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", |
1735 | fh, type, fh->resources, dev->resources); | ||
1711 | 1736 | ||
1712 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1737 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1713 | videobuf_streamoff(&fh->vb_vidq); | 1738 | videobuf_streamoff(&fh->vb_vidq); |
1714 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 1739 | res_free(fh, EM28XX_RESOURCE_VIDEO); |
1740 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
1715 | videobuf_streamoff(&fh->vb_vbiq); | 1741 | videobuf_streamoff(&fh->vb_vbiq); |
1716 | 1742 | res_free(fh, EM28XX_RESOURCE_VBI); | |
1717 | res_free(fh); | 1743 | } |
1718 | |||
1719 | mutex_unlock(&dev->lock); | ||
1720 | 1744 | ||
1721 | return 0; | 1745 | return 0; |
1722 | } | 1746 | } |
@@ -2095,17 +2119,16 @@ static int em28xx_v4l2_open(struct file *filp) | |||
2095 | else | 2119 | else |
2096 | field = V4L2_FIELD_INTERLACED; | 2120 | field = V4L2_FIELD_INTERLACED; |
2097 | 2121 | ||
2098 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2122 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, |
2099 | videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, | 2123 | NULL, &dev->slock, |
2100 | NULL, &dev->slock, fh->type, field, | 2124 | V4L2_BUF_TYPE_VIDEO_CAPTURE, field, |
2101 | sizeof(struct em28xx_buffer), fh); | 2125 | sizeof(struct em28xx_buffer), fh); |
2102 | 2126 | ||
2103 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 2127 | videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops, |
2104 | videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops, | 2128 | NULL, &dev->slock, |
2105 | NULL, &dev->slock, | 2129 | V4L2_BUF_TYPE_VBI_CAPTURE, |
2106 | V4L2_BUF_TYPE_VBI_CAPTURE, | 2130 | V4L2_FIELD_SEQ_TB, |
2107 | V4L2_FIELD_SEQ_TB, | 2131 | sizeof(struct em28xx_buffer), fh); |
2108 | sizeof(struct em28xx_buffer), fh); | ||
2109 | 2132 | ||
2110 | mutex_unlock(&dev->lock); | 2133 | mutex_unlock(&dev->lock); |
2111 | 2134 | ||
@@ -2162,20 +2185,21 @@ static int em28xx_v4l2_close(struct file *filp) | |||
2162 | 2185 | ||
2163 | em28xx_videodbg("users=%d\n", dev->users); | 2186 | em28xx_videodbg("users=%d\n", dev->users); |
2164 | 2187 | ||
2165 | 2188 | if (res_check(fh, EM28XX_RESOURCE_VIDEO)) { | |
2166 | mutex_lock(&dev->lock); | ||
2167 | if (res_check(fh)) | ||
2168 | res_free(fh); | ||
2169 | |||
2170 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 1) { | ||
2171 | videobuf_stop(&fh->vb_vidq); | 2189 | videobuf_stop(&fh->vb_vidq); |
2172 | videobuf_mmap_free(&fh->vb_vidq); | 2190 | res_free(fh, EM28XX_RESOURCE_VIDEO); |
2191 | } | ||
2173 | 2192 | ||
2193 | if (res_check(fh, EM28XX_RESOURCE_VBI)) { | ||
2194 | videobuf_stop(&fh->vb_vbiq); | ||
2195 | res_free(fh, EM28XX_RESOURCE_VBI); | ||
2196 | } | ||
2197 | |||
2198 | if(dev->users == 1) { | ||
2174 | /* the device is already disconnect, | 2199 | /* the device is already disconnect, |
2175 | free the remaining resources */ | 2200 | free the remaining resources */ |
2176 | if (dev->state & DEV_DISCONNECTED) { | 2201 | if (dev->state & DEV_DISCONNECTED) { |
2177 | em28xx_release_resources(dev); | 2202 | em28xx_release_resources(dev); |
2178 | mutex_unlock(&dev->lock); | ||
2179 | kfree(dev); | 2203 | kfree(dev); |
2180 | return 0; | 2204 | return 0; |
2181 | } | 2205 | } |
@@ -2197,15 +2221,11 @@ static int em28xx_v4l2_close(struct file *filp) | |||
2197 | } | 2221 | } |
2198 | } | 2222 | } |
2199 | 2223 | ||
2200 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 2224 | videobuf_mmap_free(&fh->vb_vidq); |
2201 | videobuf_stop(&fh->vb_vbiq); | 2225 | videobuf_mmap_free(&fh->vb_vbiq); |
2202 | videobuf_mmap_free(&fh->vb_vbiq); | ||
2203 | } | ||
2204 | |||
2205 | kfree(fh); | 2226 | kfree(fh); |
2206 | dev->users--; | 2227 | dev->users--; |
2207 | wake_up_interruptible_nr(&dev->open, 1); | 2228 | wake_up_interruptible_nr(&dev->open, 1); |
2208 | mutex_unlock(&dev->lock); | ||
2209 | return 0; | 2229 | return 0; |
2210 | } | 2230 | } |
2211 | 2231 | ||
@@ -2230,12 +2250,8 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
2230 | */ | 2250 | */ |
2231 | 2251 | ||
2232 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 2252 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
2233 | mutex_lock(&dev->lock); | 2253 | if (res_locked(dev, EM28XX_RESOURCE_VIDEO)) |
2234 | rc = res_get(fh); | 2254 | return -EBUSY; |
2235 | mutex_unlock(&dev->lock); | ||
2236 | |||
2237 | if (unlikely(rc < 0)) | ||
2238 | return rc; | ||
2239 | 2255 | ||
2240 | return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, | 2256 | return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, |
2241 | filp->f_flags & O_NONBLOCK); | 2257 | filp->f_flags & O_NONBLOCK); |
@@ -2243,9 +2259,8 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
2243 | 2259 | ||
2244 | 2260 | ||
2245 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 2261 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
2246 | mutex_lock(&dev->lock); | 2262 | if (!res_get(fh, EM28XX_RESOURCE_VBI)) |
2247 | rc = res_get(fh); | 2263 | return -EBUSY; |
2248 | mutex_unlock(&dev->lock); | ||
2249 | 2264 | ||
2250 | return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, | 2265 | return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, |
2251 | filp->f_flags & O_NONBLOCK); | 2266 | filp->f_flags & O_NONBLOCK); |
@@ -2268,19 +2283,17 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait) | |||
2268 | if (rc < 0) | 2283 | if (rc < 0) |
2269 | return rc; | 2284 | return rc; |
2270 | 2285 | ||
2271 | mutex_lock(&dev->lock); | 2286 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
2272 | rc = res_get(fh); | 2287 | if (!res_get(fh, EM28XX_RESOURCE_VIDEO)) |
2273 | mutex_unlock(&dev->lock); | 2288 | return POLLERR; |
2274 | |||
2275 | if (unlikely(rc < 0)) | ||
2276 | return POLLERR; | ||
2277 | |||
2278 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2279 | return videobuf_poll_stream(filp, &fh->vb_vidq, wait); | 2289 | return videobuf_poll_stream(filp, &fh->vb_vidq, wait); |
2280 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 2290 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
2291 | if (!res_get(fh, EM28XX_RESOURCE_VBI)) | ||
2292 | return POLLERR; | ||
2281 | return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); | 2293 | return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); |
2282 | else | 2294 | } else { |
2283 | return POLLERR; | 2295 | return POLLERR; |
2296 | } | ||
2284 | } | 2297 | } |
2285 | 2298 | ||
2286 | /* | 2299 | /* |
@@ -2296,13 +2309,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
2296 | if (rc < 0) | 2309 | if (rc < 0) |
2297 | return rc; | 2310 | return rc; |
2298 | 2311 | ||
2299 | mutex_lock(&dev->lock); | ||
2300 | rc = res_get(fh); | ||
2301 | mutex_unlock(&dev->lock); | ||
2302 | |||
2303 | if (unlikely(rc < 0)) | ||
2304 | return rc; | ||
2305 | |||
2306 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2312 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2307 | rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); | 2313 | rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); |
2308 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 2314 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 8dac50b9c00b..b4a6e07236d3 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -444,6 +444,10 @@ enum em28xx_dev_state { | |||
444 | #define EM28XX_AUDIO 0x10 | 444 | #define EM28XX_AUDIO 0x10 |
445 | #define EM28XX_DVB 0x20 | 445 | #define EM28XX_DVB 0x20 |
446 | 446 | ||
447 | /* em28xx resource types (used for res_get/res_lock etc */ | ||
448 | #define EM28XX_RESOURCE_VIDEO 0x01 | ||
449 | #define EM28XX_RESOURCE_VBI 0x02 | ||
450 | |||
447 | struct em28xx_audio { | 451 | struct em28xx_audio { |
448 | char name[50]; | 452 | char name[50]; |
449 | char *transfer_buffer[EM28XX_AUDIO_BUFS]; | 453 | char *transfer_buffer[EM28XX_AUDIO_BUFS]; |
@@ -464,8 +468,8 @@ struct em28xx; | |||
464 | 468 | ||
465 | struct em28xx_fh { | 469 | struct em28xx_fh { |
466 | struct em28xx *dev; | 470 | struct em28xx *dev; |
467 | unsigned int stream_on:1; /* Locks streams */ | ||
468 | int radio; | 471 | int radio; |
472 | unsigned int resources; | ||
469 | 473 | ||
470 | struct videobuf_queue vb_vidq; | 474 | struct videobuf_queue vb_vidq; |
471 | struct videobuf_queue vb_vbiq; | 475 | struct videobuf_queue vb_vbiq; |
@@ -495,7 +499,6 @@ struct em28xx { | |||
495 | /* Vinmode/Vinctl used at the driver */ | 499 | /* Vinmode/Vinctl used at the driver */ |
496 | int vinmode, vinctl; | 500 | int vinmode, vinctl; |
497 | 501 | ||
498 | unsigned int stream_on:1; /* Locks streams */ | ||
499 | unsigned int has_audio_class:1; | 502 | unsigned int has_audio_class:1; |
500 | unsigned int has_alsa_audio:1; | 503 | unsigned int has_alsa_audio:1; |
501 | 504 | ||
@@ -563,6 +566,9 @@ struct em28xx { | |||
563 | struct video_device *vbi_dev; | 566 | struct video_device *vbi_dev; |
564 | struct video_device *radio_dev; | 567 | struct video_device *radio_dev; |
565 | 568 | ||
569 | /* resources in use */ | ||
570 | unsigned int resources; | ||
571 | |||
566 | unsigned char eedata[256]; | 572 | unsigned char eedata[256]; |
567 | 573 | ||
568 | /* Isoc control struct */ | 574 | /* Isoc control struct */ |