aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/soc_camera.c52
-rw-r--r--include/media/soc_camera.h2
2 files changed, 41 insertions, 13 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index c947525c3f2f..322f837bcfea 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -179,11 +179,9 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
179 179
180static int soc_camera_open(struct inode *inode, struct file *file) 180static int soc_camera_open(struct inode *inode, struct file *file)
181{ 181{
182 struct video_device *vdev = video_devdata(file); 182 struct video_device *vdev;
183 struct soc_camera_device *icd = container_of(vdev->dev, 183 struct soc_camera_device *icd;
184 struct soc_camera_device, dev); 184 struct soc_camera_host *ici;
185 struct soc_camera_host *ici =
186 to_soc_camera_host(icd->dev.parent);
187 struct soc_camera_file *icf; 185 struct soc_camera_file *icf;
188 int ret; 186 int ret;
189 187
@@ -191,7 +189,12 @@ static int soc_camera_open(struct inode *inode, struct file *file)
191 if (!icf) 189 if (!icf)
192 return -ENOMEM; 190 return -ENOMEM;
193 191
194 icf->icd = icd; 192 /* Protect against icd->remove() until we module_get() both drivers. */
193 mutex_lock(&video_lock);
194
195 vdev = video_devdata(file);
196 icd = container_of(vdev->dev, struct soc_camera_device, dev);
197 ici = to_soc_camera_host(icd->dev.parent);
195 198
196 if (!try_module_get(icd->ops->owner)) { 199 if (!try_module_get(icd->ops->owner)) {
197 dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); 200 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
@@ -205,6 +208,22 @@ static int soc_camera_open(struct inode *inode, struct file *file)
205 goto emgi; 208 goto emgi;
206 } 209 }
207 210
211 icd->use_count++;
212
213 icf->icd = icd;
214
215 /* Now we really have to activate the camera */
216 if (icd->use_count == 1) {
217 ret = ici->add(icd);
218 if (ret < 0) {
219 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
220 icd->use_count--;
221 goto eiciadd;
222 }
223 }
224
225 mutex_unlock(&video_lock);
226
208 file->private_data = icf; 227 file->private_data = icf;
209 dev_dbg(&icd->dev, "camera device open\n"); 228 dev_dbg(&icd->dev, "camera device open\n");
210 229
@@ -216,9 +235,13 @@ static int soc_camera_open(struct inode *inode, struct file *file)
216 235
217 return 0; 236 return 0;
218 237
238 /* All errors are entered with the video_lock held */
239eiciadd:
240 module_put(ici->owner);
219emgi: 241emgi:
220 module_put(icd->ops->owner); 242 module_put(icd->ops->owner);
221emgd: 243emgd:
244 mutex_unlock(&video_lock);
222 vfree(icf); 245 vfree(icf);
223 return ret; 246 return ret;
224} 247}
@@ -230,8 +253,14 @@ static int soc_camera_close(struct inode *inode, struct file *file)
230 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 253 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
231 struct video_device *vdev = icd->vdev; 254 struct video_device *vdev = icd->vdev;
232 255
256 mutex_lock(&video_lock);
257 icd->use_count--;
258 if (!icd->use_count)
259 ici->remove(icd);
233 module_put(icd->ops->owner); 260 module_put(icd->ops->owner);
234 module_put(ici->owner); 261 module_put(ici->owner);
262 mutex_unlock(&video_lock);
263
235 vfree(file->private_data); 264 vfree(file->private_data);
236 265
237 dev_dbg(vdev->dev, "camera device close\n"); 266 dev_dbg(vdev->dev, "camera device close\n");
@@ -673,14 +702,14 @@ static int soc_camera_probe(struct device *dev)
673 if (!icd->probe) 702 if (!icd->probe)
674 return -ENODEV; 703 return -ENODEV;
675 704
705 /* We only call ->add() here to activate and probe the camera.
706 * We shall ->remove() and deactivate it immediately afterwards. */
676 ret = ici->add(icd); 707 ret = ici->add(icd);
677 if (ret < 0) 708 if (ret < 0)
678 return ret; 709 return ret;
679 710
680 ret = icd->probe(icd); 711 ret = icd->probe(icd);
681 if (ret < 0) 712 if (ret >= 0) {
682 ici->remove(icd);
683 else {
684 const struct v4l2_queryctrl *qctrl; 713 const struct v4l2_queryctrl *qctrl;
685 714
686 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN); 715 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
@@ -689,6 +718,7 @@ static int soc_camera_probe(struct device *dev)
689 icd->exposure = qctrl ? qctrl->default_value : 718 icd->exposure = qctrl ? qctrl->default_value :
690 (unsigned short)~0; 719 (unsigned short)~0;
691 } 720 }
721 ici->remove(icd);
692 722
693 return ret; 723 return ret;
694} 724}
@@ -698,14 +728,10 @@ static int soc_camera_probe(struct device *dev)
698static int soc_camera_remove(struct device *dev) 728static int soc_camera_remove(struct device *dev)
699{ 729{
700 struct soc_camera_device *icd = to_soc_camera_dev(dev); 730 struct soc_camera_device *icd = to_soc_camera_dev(dev);
701 struct soc_camera_host *ici =
702 to_soc_camera_host(icd->dev.parent);
703 731
704 if (icd->remove) 732 if (icd->remove)
705 icd->remove(icd); 733 icd->remove(icd);
706 734
707 ici->remove(icd);
708
709 return 0; 735 return 0;
710} 736}
711 737
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 69aba7188e44..c886b1e64872 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -41,6 +41,8 @@ struct soc_camera_device {
41 int (*probe)(struct soc_camera_device *icd); 41 int (*probe)(struct soc_camera_device *icd);
42 void (*remove)(struct soc_camera_device *icd); 42 void (*remove)(struct soc_camera_device *icd);
43 struct module *owner; 43 struct module *owner;
44 /* soc_camera.c private count. Only accessed with video_lock held */
45 int use_count;
44}; 46};
45 47
46struct soc_camera_file { 48struct soc_camera_file {