diff options
Diffstat (limited to 'drivers/media/platform/soc_camera/soc_camera.c')
-rw-r--r-- | drivers/media/platform/soc_camera/soc_camera.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 8ec98051ea73..eea832c5fd01 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
@@ -256,12 +256,12 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) | |||
256 | return 0; | 256 | return 0; |
257 | } | 257 | } |
258 | 258 | ||
259 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | 259 | static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a) |
260 | { | 260 | { |
261 | struct soc_camera_device *icd = file->private_data; | 261 | struct soc_camera_device *icd = file->private_data; |
262 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 262 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
263 | 263 | ||
264 | return v4l2_subdev_call(sd, core, s_std, *a); | 264 | return v4l2_subdev_call(sd, core, s_std, a); |
265 | } | 265 | } |
266 | 266 | ||
267 | static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) | 267 | static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) |
@@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, | |||
508 | static int soc_camera_open(struct file *file) | 508 | static int soc_camera_open(struct file *file) |
509 | { | 509 | { |
510 | struct video_device *vdev = video_devdata(file); | 510 | struct video_device *vdev = video_devdata(file); |
511 | struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); | 511 | struct soc_camera_device *icd; |
512 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | ||
513 | struct soc_camera_host *ici; | 512 | struct soc_camera_host *ici; |
514 | int ret; | 513 | int ret; |
515 | 514 | ||
516 | if (!to_soc_camera_control(icd)) | ||
517 | /* No device driver attached */ | ||
518 | return -ENODEV; | ||
519 | |||
520 | /* | 515 | /* |
521 | * Don't mess with the host during probe: wait until the loop in | 516 | * Don't mess with the host during probe: wait until the loop in |
522 | * scan_add_host() completes | 517 | * scan_add_host() completes. Also protect against a race with |
518 | * soc_camera_host_unregister(). | ||
523 | */ | 519 | */ |
524 | if (mutex_lock_interruptible(&list_lock)) | 520 | if (mutex_lock_interruptible(&list_lock)) |
525 | return -ERESTARTSYS; | 521 | return -ERESTARTSYS; |
522 | |||
523 | if (!vdev || !video_is_registered(vdev)) { | ||
524 | mutex_unlock(&list_lock); | ||
525 | return -ENODEV; | ||
526 | } | ||
527 | |||
528 | icd = dev_get_drvdata(vdev->parent); | ||
526 | ici = to_soc_camera_host(icd->parent); | 529 | ici = to_soc_camera_host(icd->parent); |
530 | |||
531 | ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV; | ||
527 | mutex_unlock(&list_lock); | 532 | mutex_unlock(&list_lock); |
528 | 533 | ||
529 | if (mutex_lock_interruptible(&ici->host_lock)) | 534 | if (ret < 0) { |
530 | return -ERESTARTSYS; | ||
531 | if (!try_module_get(ici->ops->owner)) { | ||
532 | dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); | 535 | dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); |
533 | ret = -EINVAL; | 536 | return ret; |
534 | goto emodule; | ||
535 | } | 537 | } |
536 | 538 | ||
539 | if (!to_soc_camera_control(icd)) { | ||
540 | /* No device driver attached */ | ||
541 | ret = -ENODEV; | ||
542 | goto econtrol; | ||
543 | } | ||
544 | |||
545 | if (mutex_lock_interruptible(&ici->host_lock)) { | ||
546 | ret = -ERESTARTSYS; | ||
547 | goto elockhost; | ||
548 | } | ||
537 | icd->use_count++; | 549 | icd->use_count++; |
538 | 550 | ||
539 | /* Now we really have to activate the camera */ | 551 | /* Now we really have to activate the camera */ |
540 | if (icd->use_count == 1) { | 552 | if (icd->use_count == 1) { |
553 | struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); | ||
541 | /* Restore parameters before the last close() per V4L2 API */ | 554 | /* Restore parameters before the last close() per V4L2 API */ |
542 | struct v4l2_format f = { | 555 | struct v4l2_format f = { |
543 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | 556 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, |
@@ -609,9 +622,10 @@ epower: | |||
609 | ici->ops->remove(icd); | 622 | ici->ops->remove(icd); |
610 | eiciadd: | 623 | eiciadd: |
611 | icd->use_count--; | 624 | icd->use_count--; |
612 | module_put(ici->ops->owner); | ||
613 | emodule: | ||
614 | mutex_unlock(&ici->host_lock); | 625 | mutex_unlock(&ici->host_lock); |
626 | elockhost: | ||
627 | econtrol: | ||
628 | module_put(ici->ops->owner); | ||
615 | 629 | ||
616 | return ret; | 630 | return ret; |
617 | } | 631 | } |
@@ -1042,7 +1056,7 @@ static int soc_camera_g_register(struct file *file, void *fh, | |||
1042 | } | 1056 | } |
1043 | 1057 | ||
1044 | static int soc_camera_s_register(struct file *file, void *fh, | 1058 | static int soc_camera_s_register(struct file *file, void *fh, |
1045 | struct v4l2_dbg_register *reg) | 1059 | const struct v4l2_dbg_register *reg) |
1046 | { | 1060 | { |
1047 | struct soc_camera_device *icd = file->private_data; | 1061 | struct soc_camera_device *icd = file->private_data; |
1048 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 1062 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |