aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/em28xx
diff options
context:
space:
mode:
authorDevin Heitmueller <dheitmueller@kernellabs.com>2009-09-02 23:23:27 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 22:47:42 -0400
commit8c873d31af868b4e340defc7053945636c8bd0e1 (patch)
treef25bc046a8354eaaa40b65b8b775010592657985 /drivers/media/video/em28xx
parent91f6dcec929b37a4568ddf55ef84e007d8fccc34 (diff)
V4L/DVB (12744): em28xx: restructure fh/dev locking to handle both video and vbi
The current locking infrastructure didn't support having multiple fds accessing the device (such as video and vbi). Rework the locking infrastructure, borrowing the design from cx88. This work was sponsored by EyeMagnet Limited. Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/em28xx')
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c182
-rw-r--r--drivers/media/video/em28xx/em28xx.h10
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 */
836static int res_get(struct em28xx_fh *fh) 836static 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; 859static 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
853static int res_check(struct em28xx_fh *fh) 864static 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
858static void res_free(struct em28xx_fh *fh) 869static 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
882static 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
447struct em28xx_audio { 451struct 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
465struct em28xx_fh { 469struct 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 */