diff options
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 15 | ||||
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 9 | ||||
-rw-r--r-- | drivers/media/video/soc_camera.c | 99 |
3 files changed, 91 insertions, 32 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 | ||
167 | static 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 | */ | ||
818 | static int pxa_camera_add_device(struct soc_camera_device *icd) | 818 | static 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 | ||
840 | ebusy: | 838 | ebusy: |
841 | mutex_unlock(&camera_lock); | ||
842 | |||
843 | return ret; | 839 | return ret; |
844 | } | 840 | } |
845 | 841 | ||
842 | /* Called with .video_lock held */ | ||
846 | static void pxa_camera_remove_device(struct soc_camera_device *icd) | 843 | static 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 | ||
78 | static DEFINE_MUTEX(camera_lock); | ||
79 | |||
80 | /* per video frame buffer */ | 77 | /* per video frame buffer */ |
81 | struct sh_mobile_ceu_buffer { | 78 | struct 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 */ | ||
295 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | 293 | static 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; |
321 | err: | 317 | err: |
322 | mutex_unlock(&camera_lock); | ||
323 | |||
324 | return ret; | 318 | return ret; |
325 | } | 319 | } |
326 | 320 | ||
321 | /* Called with .video_lock held */ | ||
327 | static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | 322 | static 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 @@ | |||
33 | static LIST_HEAD(hosts); | 33 | static LIST_HEAD(hosts); |
34 | static LIST_HEAD(devices); | 34 | static LIST_HEAD(devices); |
35 | static DEFINE_MUTEX(list_lock); | 35 | static DEFINE_MUTEX(list_lock); |
36 | static DEFINE_MUTEX(video_lock); | ||
37 | 36 | ||
38 | const struct soc_camera_data_format *soc_camera_format_by_fourcc( | 37 | const 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 */ |
317 | eiciadd: | 321 | eiciadd: |
318 | soc_camera_free_user_formats(icd); | 322 | soc_camera_free_user_formats(icd); |
319 | eiufmt: | 323 | eiufmt: |
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); |
322 | emgi: | 327 | emgi: |
323 | module_put(icd->ops->owner); | 328 | module_put(icd->ops->owner); |
324 | emgd: | 329 | emgd: |
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 | |||
468 | unlock: | ||
469 | mutex_unlock(&icf->vb_vidq.vb_lock); | ||
470 | |||
471 | return ret; | ||
453 | } | 472 | } |
454 | 473 | ||
455 | static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, | 474 | static 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 | ||
527 | static int soc_camera_streamoff(struct file *file, void *priv, | 553 | static 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 | ||
852 | eiadd: | ||
853 | mutex_unlock(&icd->video_lock); | ||
854 | module_put(ici->ops->owner); | ||
855 | emgi: | ||
856 | module_put(icd->ops->owner); | ||
857 | emgd: | ||
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 | */ | ||
1015 | int soc_camera_video_start(struct soc_camera_device *icd) | 1082 | int 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 | } |
1069 | EXPORT_SYMBOL(soc_camera_video_stop); | 1136 | EXPORT_SYMBOL(soc_camera_video_stop); |
1070 | 1137 | ||