aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/pxa_camera.c15
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c9
-rw-r--r--drivers/media/video/soc_camera.c99
-rw-r--r--include/media/soc_camera.h8
4 files changed, 96 insertions, 35 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index aa7efc45d364..c3c50de0aa50 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -25,7 +25,6 @@
25#include <linux/version.h> 25#include <linux/version.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/mutex.h>
29#include <linux/clk.h> 28#include <linux/clk.h>
30 29
31#include <media/v4l2-common.h> 30#include <media/v4l2-common.h>
@@ -164,8 +163,6 @@
164 CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ 163 CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
165 CICR0_EOFM | CICR0_FOM) 164 CICR0_EOFM | CICR0_FOM)
166 165
167static DEFINE_MUTEX(camera_lock);
168
169/* 166/*
170 * Structures 167 * Structures
171 */ 168 */
@@ -813,16 +810,17 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
813 return IRQ_HANDLED; 810 return IRQ_HANDLED;
814} 811}
815 812
816/* The following two functions absolutely depend on the fact, that 813/*
817 * there can be only one camera on PXA quick capture interface */ 814 * The following two functions absolutely depend on the fact, that
815 * there can be only one camera on PXA quick capture interface
816 * Called with .video_lock held
817 */
818static int pxa_camera_add_device(struct soc_camera_device *icd) 818static int pxa_camera_add_device(struct soc_camera_device *icd)
819{ 819{
820 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 820 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
821 struct pxa_camera_dev *pcdev = ici->priv; 821 struct pxa_camera_dev *pcdev = ici->priv;
822 int ret; 822 int ret;
823 823
824 mutex_lock(&camera_lock);
825
826 if (pcdev->icd) { 824 if (pcdev->icd) {
827 ret = -EBUSY; 825 ret = -EBUSY;
828 goto ebusy; 826 goto ebusy;
@@ -838,11 +836,10 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
838 pcdev->icd = icd; 836 pcdev->icd = icd;
839 837
840ebusy: 838ebusy:
841 mutex_unlock(&camera_lock);
842
843 return ret; 839 return ret;
844} 840}
845 841
842/* Called with .video_lock held */
846static void pxa_camera_remove_device(struct soc_camera_device *icd) 843static void pxa_camera_remove_device(struct soc_camera_device *icd)
847{ 844{
848 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 845 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index a49bec1509f4..47ffa441c869 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -29,7 +29,6 @@
29#include <linux/version.h> 29#include <linux/version.h>
30#include <linux/device.h> 30#include <linux/device.h>
31#include <linux/platform_device.h> 31#include <linux/platform_device.h>
32#include <linux/mutex.h>
33#include <linux/videodev2.h> 32#include <linux/videodev2.h>
34#include <linux/clk.h> 33#include <linux/clk.h>
35 34
@@ -75,8 +74,6 @@
75#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ 74#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
76#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ 75#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
77 76
78static DEFINE_MUTEX(camera_lock);
79
80/* per video frame buffer */ 77/* per video frame buffer */
81struct sh_mobile_ceu_buffer { 78struct sh_mobile_ceu_buffer {
82 struct videobuf_buffer vb; /* v4l buffer must be first */ 79 struct videobuf_buffer vb; /* v4l buffer must be first */
@@ -292,14 +289,13 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
292 return IRQ_HANDLED; 289 return IRQ_HANDLED;
293} 290}
294 291
292/* Called with .video_lock held */
295static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) 293static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
296{ 294{
297 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 295 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
298 struct sh_mobile_ceu_dev *pcdev = ici->priv; 296 struct sh_mobile_ceu_dev *pcdev = ici->priv;
299 int ret = -EBUSY; 297 int ret = -EBUSY;
300 298
301 mutex_lock(&camera_lock);
302
303 if (pcdev->icd) 299 if (pcdev->icd)
304 goto err; 300 goto err;
305 301
@@ -319,11 +315,10 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
319 315
320 pcdev->icd = icd; 316 pcdev->icd = icd;
321err: 317err:
322 mutex_unlock(&camera_lock);
323
324 return ret; 318 return ret;
325} 319}
326 320
321/* Called with .video_lock held */
327static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) 322static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
328{ 323{
329 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 324 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index d5613cdd93a6..e869670dbae5 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -33,7 +33,6 @@
33static LIST_HEAD(hosts); 33static LIST_HEAD(hosts);
34static LIST_HEAD(devices); 34static LIST_HEAD(devices);
35static DEFINE_MUTEX(list_lock); 35static DEFINE_MUTEX(list_lock);
36static DEFINE_MUTEX(video_lock);
37 36
38const struct soc_camera_data_format *soc_camera_format_by_fourcc( 37const struct soc_camera_data_format *soc_camera_format_by_fourcc(
39 struct soc_camera_device *icd, unsigned int fourcc) 38 struct soc_camera_device *icd, unsigned int fourcc)
@@ -270,8 +269,10 @@ static int soc_camera_open(struct inode *inode, struct file *file)
270 if (!icf) 269 if (!icf)
271 return -ENOMEM; 270 return -ENOMEM;
272 271
273 /* Protect against icd->remove() until we module_get() both drivers. */ 272 /*
274 mutex_lock(&video_lock); 273 * It is safe to dereference these pointers now as long as a user has
274 * the video device open - we are protected by the held cdev reference.
275 */
275 276
276 vdev = video_devdata(file); 277 vdev = video_devdata(file);
277 icd = container_of(vdev->parent, struct soc_camera_device, dev); 278 icd = container_of(vdev->parent, struct soc_camera_device, dev);
@@ -289,6 +290,9 @@ static int soc_camera_open(struct inode *inode, struct file *file)
289 goto emgi; 290 goto emgi;
290 } 291 }
291 292
293 /* Protect against icd->remove() until we module_get() both drivers. */
294 mutex_lock(&icd->video_lock);
295
292 icf->icd = icd; 296 icf->icd = icd;
293 icd->use_count++; 297 icd->use_count++;
294 298
@@ -304,7 +308,7 @@ static int soc_camera_open(struct inode *inode, struct file *file)
304 } 308 }
305 } 309 }
306 310
307 mutex_unlock(&video_lock); 311 mutex_unlock(&icd->video_lock);
308 312
309 file->private_data = icf; 313 file->private_data = icf;
310 dev_dbg(&icd->dev, "camera device open\n"); 314 dev_dbg(&icd->dev, "camera device open\n");
@@ -313,16 +317,16 @@ static int soc_camera_open(struct inode *inode, struct file *file)
313 317
314 return 0; 318 return 0;
315 319
316 /* All errors are entered with the video_lock held */ 320 /* First two errors are entered with the .video_lock held */
317eiciadd: 321eiciadd:
318 soc_camera_free_user_formats(icd); 322 soc_camera_free_user_formats(icd);
319eiufmt: 323eiufmt:
320 icd->use_count--; 324 icd->use_count--;
325 mutex_unlock(&icd->video_lock);
321 module_put(ici->ops->owner); 326 module_put(ici->ops->owner);
322emgi: 327emgi:
323 module_put(icd->ops->owner); 328 module_put(icd->ops->owner);
324emgd: 329emgd:
325 mutex_unlock(&video_lock);
326 vfree(icf); 330 vfree(icf);
327 return ret; 331 return ret;
328} 332}
@@ -334,15 +338,16 @@ static int soc_camera_close(struct inode *inode, struct file *file)
334 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 338 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
335 struct video_device *vdev = icd->vdev; 339 struct video_device *vdev = icd->vdev;
336 340
337 mutex_lock(&video_lock); 341 mutex_lock(&icd->video_lock);
338 icd->use_count--; 342 icd->use_count--;
339 if (!icd->use_count) { 343 if (!icd->use_count) {
340 ici->ops->remove(icd); 344 ici->ops->remove(icd);
341 soc_camera_free_user_formats(icd); 345 soc_camera_free_user_formats(icd);
342 } 346 }
347 mutex_unlock(&icd->video_lock);
348
343 module_put(icd->ops->owner); 349 module_put(icd->ops->owner);
344 module_put(ici->ops->owner); 350 module_put(ici->ops->owner);
345 mutex_unlock(&video_lock);
346 351
347 vfree(icf); 352 vfree(icf);
348 353
@@ -424,18 +429,27 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
424 if (ret < 0) 429 if (ret < 0)
425 return ret; 430 return ret;
426 431
432 mutex_lock(&icf->vb_vidq.vb_lock);
433
434 if (videobuf_queue_is_busy(&icf->vb_vidq)) {
435 dev_err(&icd->dev, "S_FMT denied: queue busy\n");
436 ret = -EBUSY;
437 goto unlock;
438 }
439
427 rect.left = icd->x_current; 440 rect.left = icd->x_current;
428 rect.top = icd->y_current; 441 rect.top = icd->y_current;
429 rect.width = pix->width; 442 rect.width = pix->width;
430 rect.height = pix->height; 443 rect.height = pix->height;
431 ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); 444 ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
432 if (ret < 0) { 445 if (ret < 0) {
433 return ret; 446 goto unlock;
434 } else if (!icd->current_fmt || 447 } else if (!icd->current_fmt ||
435 icd->current_fmt->fourcc != pixfmt) { 448 icd->current_fmt->fourcc != pixfmt) {
436 dev_err(&ici->dev, 449 dev_err(&ici->dev,
437 "Host driver hasn't set up current format correctly!\n"); 450 "Host driver hasn't set up current format correctly!\n");
438 return -EINVAL; 451 ret = -EINVAL;
452 goto unlock;
439 } 453 }
440 454
441 icd->width = rect.width; 455 icd->width = rect.width;
@@ -449,7 +463,12 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
449 icd->width, icd->height); 463 icd->width, icd->height);
450 464
451 /* set physical bus parameters */ 465 /* set physical bus parameters */
452 return ici->ops->set_bus_param(icd, pixfmt); 466 ret = ici->ops->set_bus_param(icd, pixfmt);
467
468unlock:
469 mutex_unlock(&icf->vb_vidq.vb_lock);
470
471 return ret;
453} 472}
454 473
455static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, 474static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
@@ -510,6 +529,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
510{ 529{
511 struct soc_camera_file *icf = file->private_data; 530 struct soc_camera_file *icf = file->private_data;
512 struct soc_camera_device *icd = icf->icd; 531 struct soc_camera_device *icd = icf->icd;
532 int ret;
513 533
514 WARN_ON(priv != file->private_data); 534 WARN_ON(priv != file->private_data);
515 535
@@ -518,10 +538,16 @@ static int soc_camera_streamon(struct file *file, void *priv,
518 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) 538 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
519 return -EINVAL; 539 return -EINVAL;
520 540
541 mutex_lock(&icd->video_lock);
542
521 icd->ops->start_capture(icd); 543 icd->ops->start_capture(icd);
522 544
523 /* This calls buf_queue from host driver's videobuf_queue_ops */ 545 /* This calls buf_queue from host driver's videobuf_queue_ops */
524 return videobuf_streamon(&icf->vb_vidq); 546 ret = videobuf_streamon(&icf->vb_vidq);
547
548 mutex_unlock(&icd->video_lock);
549
550 return ret;
525} 551}
526 552
527static int soc_camera_streamoff(struct file *file, void *priv, 553static int soc_camera_streamoff(struct file *file, void *priv,
@@ -537,12 +563,16 @@ static int soc_camera_streamoff(struct file *file, void *priv,
537 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) 563 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
538 return -EINVAL; 564 return -EINVAL;
539 565
566 mutex_lock(&icd->video_lock);
567
540 /* This calls buf_release from host driver's videobuf_queue_ops for all 568 /* This calls buf_release from host driver's videobuf_queue_ops for all
541 * remaining buffers. When the last buffer is freed, stop capture */ 569 * remaining buffers. When the last buffer is freed, stop capture */
542 videobuf_streamoff(&icf->vb_vidq); 570 videobuf_streamoff(&icf->vb_vidq);
543 571
544 icd->ops->stop_capture(icd); 572 icd->ops->stop_capture(icd);
545 573
574 mutex_unlock(&icd->video_lock);
575
546 return 0; 576 return 0;
547} 577}
548 578
@@ -654,6 +684,9 @@ static int soc_camera_s_crop(struct file *file, void *fh,
654 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 684 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
655 return -EINVAL; 685 return -EINVAL;
656 686
687 /* Cropping is allowed during a running capture, guard consistency */
688 mutex_lock(&icf->vb_vidq.vb_lock);
689
657 ret = ici->ops->set_fmt(icd, 0, &a->c); 690 ret = ici->ops->set_fmt(icd, 0, &a->c);
658 if (!ret) { 691 if (!ret) {
659 icd->width = a->c.width; 692 icd->width = a->c.width;
@@ -662,6 +695,8 @@ static int soc_camera_s_crop(struct file *file, void *fh,
662 icd->y_current = a->c.top; 695 icd->y_current = a->c.top;
663 } 696 }
664 697
698 mutex_unlock(&icf->vb_vidq.vb_lock);
699
665 return ret; 700 return ret;
666} 701}
667 702
@@ -775,11 +810,32 @@ static int soc_camera_probe(struct device *dev)
775 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 810 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
776 int ret; 811 int ret;
777 812
813 /*
814 * Possible race scenario:
815 * modprobe <camera-host-driver> triggers __func__
816 * at this moment respective <camera-sensor-driver> gets rmmod'ed
817 * to protect take module references.
818 */
819
820 if (!try_module_get(icd->ops->owner)) {
821 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
822 ret = -EINVAL;
823 goto emgd;
824 }
825
826 if (!try_module_get(ici->ops->owner)) {
827 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
828 ret = -EINVAL;
829 goto emgi;
830 }
831
832 mutex_lock(&icd->video_lock);
833
778 /* We only call ->add() here to activate and probe the camera. 834 /* We only call ->add() here to activate and probe the camera.
779 * We shall ->remove() and deactivate it immediately afterwards. */ 835 * We shall ->remove() and deactivate it immediately afterwards. */
780 ret = ici->ops->add(icd); 836 ret = ici->ops->add(icd);
781 if (ret < 0) 837 if (ret < 0)
782 return ret; 838 goto eiadd;
783 839
784 ret = icd->ops->probe(icd); 840 ret = icd->ops->probe(icd);
785 if (ret >= 0) { 841 if (ret >= 0) {
@@ -793,6 +849,12 @@ static int soc_camera_probe(struct device *dev)
793 } 849 }
794 ici->ops->remove(icd); 850 ici->ops->remove(icd);
795 851
852eiadd:
853 mutex_unlock(&icd->video_lock);
854 module_put(ici->ops->owner);
855emgi:
856 module_put(icd->ops->owner);
857emgd:
796 return ret; 858 return ret;
797} 859}
798 860
@@ -966,6 +1028,7 @@ int soc_camera_device_register(struct soc_camera_device *icd)
966 icd->dev.release = dummy_release; 1028 icd->dev.release = dummy_release;
967 icd->use_count = 0; 1029 icd->use_count = 0;
968 icd->host_priv = NULL; 1030 icd->host_priv = NULL;
1031 mutex_init(&icd->video_lock);
969 1032
970 return scan_add_device(icd); 1033 return scan_add_device(icd);
971} 1034}
@@ -1012,6 +1075,10 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
1012#endif 1075#endif
1013}; 1076};
1014 1077
1078/*
1079 * Usually called from the struct soc_camera_ops .probe() method, i.e., from
1080 * soc_camera_probe() above with .video_lock held
1081 */
1015int soc_camera_video_start(struct soc_camera_device *icd) 1082int soc_camera_video_start(struct soc_camera_device *icd)
1016{ 1083{
1017 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 1084 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -1027,7 +1094,7 @@ int soc_camera_video_start(struct soc_camera_device *icd)
1027 dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); 1094 dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
1028 1095
1029 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); 1096 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
1030 /* Maybe better &ici->dev */ 1097
1031 vdev->parent = &icd->dev; 1098 vdev->parent = &icd->dev;
1032 vdev->current_norm = V4L2_STD_UNKNOWN; 1099 vdev->current_norm = V4L2_STD_UNKNOWN;
1033 vdev->fops = &soc_camera_fops; 1100 vdev->fops = &soc_camera_fops;
@@ -1061,10 +1128,10 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
1061 if (!icd->dev.parent || !vdev) 1128 if (!icd->dev.parent || !vdev)
1062 return; 1129 return;
1063 1130
1064 mutex_lock(&video_lock); 1131 mutex_lock(&icd->video_lock);
1065 video_unregister_device(vdev); 1132 video_unregister_device(vdev);
1066 icd->vdev = NULL; 1133 icd->vdev = NULL;
1067 mutex_unlock(&video_lock); 1134 mutex_unlock(&icd->video_lock);
1068} 1135}
1069EXPORT_SYMBOL(soc_camera_video_stop); 1136EXPORT_SYMBOL(soc_camera_video_stop);
1070 1137
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 38b826c608be..8bae9a359d93 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -12,9 +12,10 @@
12#ifndef SOC_CAMERA_H 12#ifndef SOC_CAMERA_H
13#define SOC_CAMERA_H 13#define SOC_CAMERA_H
14 14
15#include <linux/mutex.h>
16#include <linux/pm.h>
15#include <linux/videodev2.h> 17#include <linux/videodev2.h>
16#include <media/videobuf-core.h> 18#include <media/videobuf-core.h>
17#include <linux/pm.h>
18 19
19struct soc_camera_device { 20struct soc_camera_device {
20 struct list_head list; 21 struct list_head list;
@@ -45,9 +46,10 @@ struct soc_camera_device {
45 struct soc_camera_format_xlate *user_formats; 46 struct soc_camera_format_xlate *user_formats;
46 int num_user_formats; 47 int num_user_formats;
47 struct module *owner; 48 struct module *owner;
48 void *host_priv; /* per-device host private data */ 49 void *host_priv; /* Per-device host private data */
49 /* soc_camera.c private count. Only accessed with video_lock held */ 50 /* soc_camera.c private count. Only accessed with .video_lock held */
50 int use_count; 51 int use_count;
52 struct mutex video_lock; /* Protects device data */
51}; 53};
52 54
53struct soc_camera_file { 55struct soc_camera_file {