aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-04-22 13:45:32 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:46 -0400
commit9dc4e48fbea5412127ce2eb30d688c4fc55f5565 (patch)
tree8b0912f884f3613922f2bba2198d6b8fc3f95691
parent6f2896756c4f1d4df5bd30599e6444c9513cfe8d (diff)
V4L/DVB (7276): soc-camera: deactivate cameras when not used
Only attach cameras to the host interface for probing, then detach until open. This allows platforms with several cameras on an interface, physically supporting only one camera, to handle multiple cameras and activate them selectively after initial probing. The first attach during probe is needed to activate the host interface to be able to physically communicate with cameras. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-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 {