blob: e869670dbae56923c4238af843c4892776a90755 [file] [log] [blame]
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001/*
2 * camera image capture (abstract) bus driver
3 *
4 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
5 *
6 * This driver provides an interface between platform-specific camera
7 * busses and camera devices. It should be used if the camera is
8 * connected not over a "proper" bus like PCI or USB, but over a
9 * special bus, like, for example, the Quick Capture interface on PXA270
10 * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
11 * It can handle multiple cameras and / or multiple busses, which can
12 * be used, e.g., in stereo-vision applications.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/device.h>
22#include <linux/list.h>
23#include <linux/err.h>
24#include <linux/mutex.h>
25#include <linux/vmalloc.h>
26
27#include <media/v4l2-common.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030028#include <media/v4l2-ioctl.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030029#include <media/v4l2-dev.h>
Paulius Zaleckas092d3922008-07-11 20:50:31 -030030#include <media/videobuf-core.h>
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030031#include <media/soc_camera.h>
32
33static LIST_HEAD(hosts);
34static LIST_HEAD(devices);
35static DEFINE_MUTEX(list_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030036
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -030037const struct soc_camera_data_format *soc_camera_format_by_fourcc(
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -030038 struct soc_camera_device *icd, unsigned int fourcc)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030039{
40 unsigned int i;
41
Guennadi Liakhovetski26f1b942008-03-24 12:18:36 -030042 for (i = 0; i < icd->num_formats; i++)
43 if (icd->formats[i].fourcc == fourcc)
44 return icd->formats + i;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030045 return NULL;
46}
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -030047EXPORT_SYMBOL(soc_camera_format_by_fourcc);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030048
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -030049const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
50 struct soc_camera_device *icd, unsigned int fourcc)
51{
52 unsigned int i;
53
54 for (i = 0; i < icd->num_user_formats; i++)
55 if (icd->user_formats[i].host_fmt->fourcc == fourcc)
56 return icd->user_formats + i;
57 return NULL;
58}
59EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
60
Guennadi Liakhovetskibd73b362008-12-23 05:54:45 -030061/**
62 * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
63 * @icl: camera platform parameters
64 * @flags: flags to be inverted according to platform configuration
65 * @return: resulting flags
66 */
67unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
68 unsigned long flags)
69{
70 unsigned long f;
71
72 /* If only one of the two polarities is supported, switch to the opposite */
73 if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
74 f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
75 if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW)
76 flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW;
77 }
78
79 if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
80 f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
81 if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW)
82 flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW;
83 }
84
85 if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
86 f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
87 if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING)
88 flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING;
89 }
90
91 return flags;
92}
93EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
94
Hans Verkuil72937892008-06-01 10:35:18 -030095static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -030096 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -030097{
98 struct soc_camera_file *icf = file->private_data;
99 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300100 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300101 enum v4l2_field field;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300102 int ret;
103
104 WARN_ON(priv != file->private_data);
105
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300106 /*
107 * TODO: this might also have to migrate to host-drivers, if anyone
108 * wishes to support other fields
109 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300110 field = f->fmt.pix.field;
111
112 if (field == V4L2_FIELD_ANY) {
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300113 f->fmt.pix.field = V4L2_FIELD_NONE;
114 } else if (field != V4L2_FIELD_NONE) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300115 dev_err(&icd->dev, "Field type invalid.\n");
116 return -EINVAL;
117 }
118
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300119 /* limit format to hardware capabilities */
Guennadi Liakhovetskid8fac212008-12-01 09:45:21 -0300120 ret = ici->ops->try_fmt(icd, f);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300121
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300122 return ret;
123}
124
125static int soc_camera_enum_input(struct file *file, void *priv,
126 struct v4l2_input *inp)
127{
128 if (inp->index != 0)
129 return -EINVAL;
130
131 inp->type = V4L2_INPUT_TYPE_CAMERA;
132 inp->std = V4L2_STD_UNKNOWN;
133 strcpy(inp->name, "Camera");
134
135 return 0;
136}
137
138static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
139{
140 *i = 0;
141
142 return 0;
143}
144
145static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
146{
147 if (i > 0)
148 return -EINVAL;
149
150 return 0;
151}
152
153static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
154{
155 return 0;
156}
157
158static int soc_camera_reqbufs(struct file *file, void *priv,
159 struct v4l2_requestbuffers *p)
160{
161 int ret;
162 struct soc_camera_file *icf = file->private_data;
163 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300164 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300165
166 WARN_ON(priv != file->private_data);
167
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300168 dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300169
170 ret = videobuf_reqbufs(&icf->vb_vidq, p);
171 if (ret < 0)
172 return ret;
173
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300174 return ici->ops->reqbufs(icf, p);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300175}
176
177static int soc_camera_querybuf(struct file *file, void *priv,
178 struct v4l2_buffer *p)
179{
180 struct soc_camera_file *icf = file->private_data;
181
182 WARN_ON(priv != file->private_data);
183
184 return videobuf_querybuf(&icf->vb_vidq, p);
185}
186
187static int soc_camera_qbuf(struct file *file, void *priv,
188 struct v4l2_buffer *p)
189{
190 struct soc_camera_file *icf = file->private_data;
191
192 WARN_ON(priv != file->private_data);
193
194 return videobuf_qbuf(&icf->vb_vidq, p);
195}
196
197static int soc_camera_dqbuf(struct file *file, void *priv,
198 struct v4l2_buffer *p)
199{
200 struct soc_camera_file *icf = file->private_data;
201
202 WARN_ON(priv != file->private_data);
203
204 return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
205}
206
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300207static int soc_camera_init_user_formats(struct soc_camera_device *icd)
208{
209 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
210 int i, fmts = 0;
211
212 if (!ici->ops->get_formats)
213 /*
214 * Fallback mode - the host will have to serve all
215 * sensor-provided formats one-to-one to the user
216 */
217 fmts = icd->num_formats;
218 else
219 /*
220 * First pass - only count formats this host-sensor
221 * configuration can provide
222 */
223 for (i = 0; i < icd->num_formats; i++)
224 fmts += ici->ops->get_formats(icd, i, NULL);
225
226 if (!fmts)
227 return -ENXIO;
228
229 icd->user_formats =
230 vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
231 if (!icd->user_formats)
232 return -ENOMEM;
233
234 icd->num_user_formats = fmts;
235 fmts = 0;
236
237 dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
238
239 /* Second pass - actually fill data formats */
240 for (i = 0; i < icd->num_formats; i++)
241 if (!ici->ops->get_formats) {
242 icd->user_formats[i].host_fmt = icd->formats + i;
243 icd->user_formats[i].cam_fmt = icd->formats + i;
244 icd->user_formats[i].buswidth = icd->formats[i].depth;
245 } else {
246 fmts += ici->ops->get_formats(icd, i,
247 &icd->user_formats[fmts]);
248 }
249
250 icd->current_fmt = icd->user_formats[0].host_fmt;
251
252 return 0;
253}
254
255static void soc_camera_free_user_formats(struct soc_camera_device *icd)
256{
257 vfree(icd->user_formats);
258}
259
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300260static int soc_camera_open(struct inode *inode, struct file *file)
261{
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300262 struct video_device *vdev;
263 struct soc_camera_device *icd;
264 struct soc_camera_host *ici;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300265 struct soc_camera_file *icf;
266 int ret;
267
268 icf = vmalloc(sizeof(*icf));
269 if (!icf)
270 return -ENOMEM;
271
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300272 /*
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 */
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300276
277 vdev = video_devdata(file);
Hans Verkuil5e85e732008-07-20 06:31:39 -0300278 icd = container_of(vdev->parent, struct soc_camera_device, dev);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300279 ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300280
281 if (!try_module_get(icd->ops->owner)) {
282 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
283 ret = -EINVAL;
284 goto emgd;
285 }
286
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300287 if (!try_module_get(ici->ops->owner)) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300288 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
289 ret = -EINVAL;
290 goto emgi;
291 }
292
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300293 /* Protect against icd->remove() until we module_get() both drivers. */
294 mutex_lock(&icd->video_lock);
295
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300296 icf->icd = icd;
Guennadi Liakhovetski1a0063a2008-04-04 13:46:34 -0300297 icd->use_count++;
298
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300299 /* Now we really have to activate the camera */
300 if (icd->use_count == 1) {
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300301 ret = soc_camera_init_user_formats(icd);
302 if (ret < 0)
303 goto eiufmt;
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300304 ret = ici->ops->add(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300305 if (ret < 0) {
306 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300307 goto eiciadd;
308 }
309 }
310
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300311 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300312
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300313 file->private_data = icf;
314 dev_dbg(&icd->dev, "camera device open\n");
315
Magnus Damma034d1b2008-07-11 20:59:34 -0300316 ici->ops->init_videobuf(&icf->vb_vidq, icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300317
318 return 0;
319
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300320 /* First two errors are entered with the .video_lock held */
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300321eiciadd:
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300322 soc_camera_free_user_formats(icd);
323eiufmt:
324 icd->use_count--;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300325 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300326 module_put(ici->ops->owner);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300327emgi:
328 module_put(icd->ops->owner);
329emgd:
330 vfree(icf);
331 return ret;
332}
333
334static int soc_camera_close(struct inode *inode, struct file *file)
335{
336 struct soc_camera_file *icf = file->private_data;
337 struct soc_camera_device *icd = icf->icd;
338 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
339 struct video_device *vdev = icd->vdev;
340
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300341 mutex_lock(&icd->video_lock);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300342 icd->use_count--;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300343 if (!icd->use_count) {
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300344 ici->ops->remove(icd);
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300345 soc_camera_free_user_formats(icd);
346 }
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300347 mutex_unlock(&icd->video_lock);
348
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300349 module_put(icd->ops->owner);
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300350 module_put(ici->ops->owner);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300351
Guennadi Liakhovetski1a0063a2008-04-04 13:46:34 -0300352 vfree(icf);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300353
Hans Verkuil5e85e732008-07-20 06:31:39 -0300354 dev_dbg(vdev->parent, "camera device close\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300355
356 return 0;
357}
358
Andrew Mortonaba360d2008-04-22 14:45:59 -0300359static ssize_t soc_camera_read(struct file *file, char __user *buf,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300360 size_t count, loff_t *ppos)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300361{
362 struct soc_camera_file *icf = file->private_data;
363 struct soc_camera_device *icd = icf->icd;
364 struct video_device *vdev = icd->vdev;
365 int err = -EINVAL;
366
Hans Verkuil5e85e732008-07-20 06:31:39 -0300367 dev_err(vdev->parent, "camera device read not implemented\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300368
369 return err;
370}
371
372static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
373{
374 struct soc_camera_file *icf = file->private_data;
375 struct soc_camera_device *icd = icf->icd;
376 int err;
377
378 dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
379
380 err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
381
382 dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
383 (unsigned long)vma->vm_start,
384 (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
385 err);
386
387 return err;
388}
389
390static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
391{
392 struct soc_camera_file *icf = file->private_data;
393 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300394 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300395
396 if (list_empty(&icf->vb_vidq.stream)) {
397 dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
398 return POLLERR;
399 }
400
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300401 return ici->ops->poll(file, pt);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300402}
403
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300404static struct file_operations soc_camera_fops = {
405 .owner = THIS_MODULE,
406 .open = soc_camera_open,
407 .release = soc_camera_close,
408 .ioctl = video_ioctl2,
409 .read = soc_camera_read,
410 .mmap = soc_camera_mmap,
411 .poll = soc_camera_poll,
412 .llseek = no_llseek,
413};
414
Hans Verkuil72937892008-06-01 10:35:18 -0300415static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300416 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300417{
418 struct soc_camera_file *icf = file->private_data;
419 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300420 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
421 struct v4l2_pix_format *pix = &f->fmt.pix;
422 __u32 pixfmt = pix->pixelformat;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300423 int ret;
424 struct v4l2_rect rect;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300425
426 WARN_ON(priv != file->private_data);
427
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300428 ret = soc_camera_try_fmt_vid_cap(file, priv, f);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300429 if (ret < 0)
430 return ret;
431
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300432 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
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300440 rect.left = icd->x_current;
441 rect.top = icd->y_current;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300442 rect.width = pix->width;
443 rect.height = pix->height;
444 ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300445 if (ret < 0) {
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300446 goto unlock;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300447 } else if (!icd->current_fmt ||
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300448 icd->current_fmt->fourcc != pixfmt) {
449 dev_err(&ici->dev,
450 "Host driver hasn't set up current format correctly!\n");
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300451 ret = -EINVAL;
452 goto unlock;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300453 }
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300454
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300455 icd->width = rect.width;
456 icd->height = rect.height;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300457 icf->vb_vidq.field = pix->field;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300458 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300459 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
460 f->type);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300461
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300462 dev_dbg(&icd->dev, "set width: %d height: %d\n",
463 icd->width, icd->height);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300464
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300465 /* set physical bus parameters */
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300466 ret = ici->ops->set_bus_param(icd, pixfmt);
467
468unlock:
469 mutex_unlock(&icf->vb_vidq.vb_lock);
470
471 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300472}
473
Hans Verkuil72937892008-06-01 10:35:18 -0300474static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300475 struct v4l2_fmtdesc *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300476{
477 struct soc_camera_file *icf = file->private_data;
478 struct soc_camera_device *icd = icf->icd;
479 const struct soc_camera_data_format *format;
480
481 WARN_ON(priv != file->private_data);
482
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300483 if (f->index >= icd->num_user_formats)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300484 return -EINVAL;
485
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300486 format = icd->user_formats[f->index].host_fmt;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300487
488 strlcpy(f->description, format->name, sizeof(f->description));
489 f->pixelformat = format->fourcc;
490 return 0;
491}
492
Hans Verkuil72937892008-06-01 10:35:18 -0300493static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300494 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300495{
496 struct soc_camera_file *icf = file->private_data;
497 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300498 struct v4l2_pix_format *pix = &f->fmt.pix;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300499
500 WARN_ON(priv != file->private_data);
501
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300502 pix->width = icd->width;
503 pix->height = icd->height;
504 pix->field = icf->vb_vidq.field;
505 pix->pixelformat = icd->current_fmt->fourcc;
506 pix->bytesperline = pix->width *
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300507 DIV_ROUND_UP(icd->current_fmt->depth, 8);
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300508 pix->sizeimage = pix->height * pix->bytesperline;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300509 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
510 icd->current_fmt->fourcc);
511 return 0;
512}
513
514static int soc_camera_querycap(struct file *file, void *priv,
515 struct v4l2_capability *cap)
516{
517 struct soc_camera_file *icf = file->private_data;
518 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300519 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300520
521 WARN_ON(priv != file->private_data);
522
523 strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300524 return ici->ops->querycap(ici, cap);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300525}
526
527static int soc_camera_streamon(struct file *file, void *priv,
528 enum v4l2_buf_type i)
529{
530 struct soc_camera_file *icf = file->private_data;
531 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300532 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300533
534 WARN_ON(priv != file->private_data);
535
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300536 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300537
538 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
539 return -EINVAL;
540
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300541 mutex_lock(&icd->video_lock);
542
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300543 icd->ops->start_capture(icd);
544
545 /* This calls buf_queue from host driver's videobuf_queue_ops */
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300546 ret = videobuf_streamon(&icf->vb_vidq);
547
548 mutex_unlock(&icd->video_lock);
549
550 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300551}
552
553static int soc_camera_streamoff(struct file *file, void *priv,
554 enum v4l2_buf_type i)
555{
556 struct soc_camera_file *icf = file->private_data;
557 struct soc_camera_device *icd = icf->icd;
558
559 WARN_ON(priv != file->private_data);
560
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300561 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300562
563 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
564 return -EINVAL;
565
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300566 mutex_lock(&icd->video_lock);
567
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300568 /* This calls buf_release from host driver's videobuf_queue_ops for all
569 * remaining buffers. When the last buffer is freed, stop capture */
570 videobuf_streamoff(&icf->vb_vidq);
571
572 icd->ops->stop_capture(icd);
573
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300574 mutex_unlock(&icd->video_lock);
575
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300576 return 0;
577}
578
579static int soc_camera_queryctrl(struct file *file, void *priv,
580 struct v4l2_queryctrl *qc)
581{
582 struct soc_camera_file *icf = file->private_data;
583 struct soc_camera_device *icd = icf->icd;
584 int i;
585
586 WARN_ON(priv != file->private_data);
587
588 if (!qc->id)
589 return -EINVAL;
590
591 for (i = 0; i < icd->ops->num_controls; i++)
592 if (qc->id == icd->ops->controls[i].id) {
593 memcpy(qc, &(icd->ops->controls[i]),
594 sizeof(*qc));
595 return 0;
596 }
597
598 return -EINVAL;
599}
600
601static int soc_camera_g_ctrl(struct file *file, void *priv,
602 struct v4l2_control *ctrl)
603{
604 struct soc_camera_file *icf = file->private_data;
605 struct soc_camera_device *icd = icf->icd;
606
607 WARN_ON(priv != file->private_data);
608
609 switch (ctrl->id) {
610 case V4L2_CID_GAIN:
611 if (icd->gain == (unsigned short)~0)
612 return -EINVAL;
613 ctrl->value = icd->gain;
614 return 0;
615 case V4L2_CID_EXPOSURE:
616 if (icd->exposure == (unsigned short)~0)
617 return -EINVAL;
618 ctrl->value = icd->exposure;
619 return 0;
620 }
621
622 if (icd->ops->get_control)
623 return icd->ops->get_control(icd, ctrl);
624 return -EINVAL;
625}
626
627static int soc_camera_s_ctrl(struct file *file, void *priv,
628 struct v4l2_control *ctrl)
629{
630 struct soc_camera_file *icf = file->private_data;
631 struct soc_camera_device *icd = icf->icd;
632
633 WARN_ON(priv != file->private_data);
634
635 if (icd->ops->set_control)
636 return icd->ops->set_control(icd, ctrl);
637 return -EINVAL;
638}
639
640static int soc_camera_cropcap(struct file *file, void *fh,
641 struct v4l2_cropcap *a)
642{
643 struct soc_camera_file *icf = file->private_data;
644 struct soc_camera_device *icd = icf->icd;
645
646 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
647 a->bounds.left = icd->x_min;
648 a->bounds.top = icd->y_min;
649 a->bounds.width = icd->width_max;
650 a->bounds.height = icd->height_max;
651 a->defrect.left = icd->x_min;
652 a->defrect.top = icd->y_min;
653 a->defrect.width = 640;
654 a->defrect.height = 480;
655 a->pixelaspect.numerator = 1;
656 a->pixelaspect.denominator = 1;
657
658 return 0;
659}
660
661static int soc_camera_g_crop(struct file *file, void *fh,
662 struct v4l2_crop *a)
663{
664 struct soc_camera_file *icf = file->private_data;
665 struct soc_camera_device *icd = icf->icd;
666
667 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
668 a->c.left = icd->x_current;
669 a->c.top = icd->y_current;
670 a->c.width = icd->width;
671 a->c.height = icd->height;
672
673 return 0;
674}
675
676static int soc_camera_s_crop(struct file *file, void *fh,
677 struct v4l2_crop *a)
678{
679 struct soc_camera_file *icf = file->private_data;
680 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300681 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300682 int ret;
683
684 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
685 return -EINVAL;
686
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300687 /* Cropping is allowed during a running capture, guard consistency */
688 mutex_lock(&icf->vb_vidq.vb_lock);
689
Guennadi Liakhovetskid8fac212008-12-01 09:45:21 -0300690 ret = ici->ops->set_fmt(icd, 0, &a->c);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300691 if (!ret) {
692 icd->width = a->c.width;
693 icd->height = a->c.height;
694 icd->x_current = a->c.left;
695 icd->y_current = a->c.top;
696 }
697
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300698 mutex_unlock(&icf->vb_vidq.vb_lock);
699
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300700 return ret;
701}
702
703static int soc_camera_g_chip_ident(struct file *file, void *fh,
704 struct v4l2_chip_ident *id)
705{
706 struct soc_camera_file *icf = file->private_data;
707 struct soc_camera_device *icd = icf->icd;
708
709 if (!icd->ops->get_chip_id)
710 return -EINVAL;
711
712 return icd->ops->get_chip_id(icd, id);
713}
714
715#ifdef CONFIG_VIDEO_ADV_DEBUG
716static int soc_camera_g_register(struct file *file, void *fh,
717 struct v4l2_register *reg)
718{
719 struct soc_camera_file *icf = file->private_data;
720 struct soc_camera_device *icd = icf->icd;
721
722 if (!icd->ops->get_register)
723 return -EINVAL;
724
725 return icd->ops->get_register(icd, reg);
726}
727
728static int soc_camera_s_register(struct file *file, void *fh,
729 struct v4l2_register *reg)
730{
731 struct soc_camera_file *icf = file->private_data;
732 struct soc_camera_device *icd = icf->icd;
733
734 if (!icd->ops->set_register)
735 return -EINVAL;
736
737 return icd->ops->set_register(icd, reg);
738}
739#endif
740
741static int device_register_link(struct soc_camera_device *icd)
742{
743 int ret = device_register(&icd->dev);
744
745 if (ret < 0) {
746 /* Prevent calling device_unregister() */
747 icd->dev.parent = NULL;
748 dev_err(&icd->dev, "Cannot register device: %d\n", ret);
749 /* Even if probe() was unsuccessful for all registered drivers,
750 * device_register() returns 0, and we add the link, just to
751 * document this camera's control device */
752 } else if (icd->control)
753 /* Have to sysfs_remove_link() before device_unregister()? */
754 if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
755 "control"))
756 dev_warn(&icd->dev,
757 "Failed creating the control symlink\n");
758 return ret;
759}
760
761/* So far this function cannot fail */
762static void scan_add_host(struct soc_camera_host *ici)
763{
764 struct soc_camera_device *icd;
765
766 mutex_lock(&list_lock);
767
768 list_for_each_entry(icd, &devices, list) {
769 if (icd->iface == ici->nr) {
770 icd->dev.parent = &ici->dev;
771 device_register_link(icd);
772 }
773 }
774
775 mutex_unlock(&list_lock);
776}
777
778/* return: 0 if no match found or a match found and
779 * device_register() successful, error code otherwise */
780static int scan_add_device(struct soc_camera_device *icd)
781{
782 struct soc_camera_host *ici;
783 int ret = 0;
784
785 mutex_lock(&list_lock);
786
787 list_add_tail(&icd->list, &devices);
788
789 /* Watch out for class_for_each_device / class_find_device API by
790 * Dave Young <hidave.darkstar@gmail.com> */
791 list_for_each_entry(ici, &hosts, list) {
792 if (icd->iface == ici->nr) {
793 ret = 1;
794 icd->dev.parent = &ici->dev;
795 break;
796 }
797 }
798
799 mutex_unlock(&list_lock);
800
801 if (ret)
802 ret = device_register_link(icd);
803
804 return ret;
805}
806
807static int soc_camera_probe(struct device *dev)
808{
809 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300810 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300811 int ret;
812
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300813 /*
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
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300834 /* We only call ->add() here to activate and probe the camera.
835 * We shall ->remove() and deactivate it immediately afterwards. */
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300836 ret = ici->ops->add(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300837 if (ret < 0)
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300838 goto eiadd;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300839
Guennadi Liakhovetski26f1b942008-03-24 12:18:36 -0300840 ret = icd->ops->probe(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300841 if (ret >= 0) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300842 const struct v4l2_queryctrl *qctrl;
843
844 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
845 icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
846 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
847 icd->exposure = qctrl ? qctrl->default_value :
848 (unsigned short)~0;
849 }
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300850 ici->ops->remove(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300851
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300852eiadd:
853 mutex_unlock(&icd->video_lock);
854 module_put(ici->ops->owner);
855emgi:
856 module_put(icd->ops->owner);
857emgd:
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300858 return ret;
859}
860
861/* This is called on device_unregister, which only means we have to disconnect
862 * from the host, but not remove ourselves from the device list */
863static int soc_camera_remove(struct device *dev)
864{
865 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300866
Guennadi Liakhovetski26f1b942008-03-24 12:18:36 -0300867 if (icd->ops->remove)
868 icd->ops->remove(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300869
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300870 return 0;
871}
872
Robert Jarzmik2e521062008-08-01 20:14:50 -0300873static int soc_camera_suspend(struct device *dev, pm_message_t state)
874{
875 struct soc_camera_device *icd = to_soc_camera_dev(dev);
876 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
877 int ret = 0;
878
879 if (ici->ops->suspend)
880 ret = ici->ops->suspend(icd, state);
881
882 return ret;
883}
884
885static int soc_camera_resume(struct device *dev)
886{
887 struct soc_camera_device *icd = to_soc_camera_dev(dev);
888 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
889 int ret = 0;
890
891 if (ici->ops->resume)
892 ret = ici->ops->resume(icd);
893
894 return ret;
895}
896
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300897static struct bus_type soc_camera_bus_type = {
898 .name = "soc-camera",
899 .probe = soc_camera_probe,
900 .remove = soc_camera_remove,
Robert Jarzmik2e521062008-08-01 20:14:50 -0300901 .suspend = soc_camera_suspend,
902 .resume = soc_camera_resume,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300903};
904
905static struct device_driver ic_drv = {
906 .name = "camera",
907 .bus = &soc_camera_bus_type,
908 .owner = THIS_MODULE,
909};
910
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300911static void dummy_release(struct device *dev)
912{
913}
914
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300915int soc_camera_host_register(struct soc_camera_host *ici)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300916{
917 int ret;
918 struct soc_camera_host *ix;
919
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300920 if (!ici || !ici->ops ||
921 !ici->ops->try_fmt ||
922 !ici->ops->set_fmt ||
923 !ici->ops->set_bus_param ||
924 !ici->ops->querycap ||
925 !ici->ops->init_videobuf ||
926 !ici->ops->reqbufs ||
927 !ici->ops->add ||
928 !ici->ops->remove ||
929 !ici->ops->poll)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300930 return -EINVAL;
931
932 /* Number might be equal to the platform device ID */
Kay Sieversaf128a12008-10-30 00:51:46 -0300933 dev_set_name(&ici->dev, "camera_host%d", ici->nr);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300934
935 mutex_lock(&list_lock);
936 list_for_each_entry(ix, &hosts, list) {
937 if (ix->nr == ici->nr) {
938 mutex_unlock(&list_lock);
939 return -EBUSY;
940 }
941 }
942
943 list_add_tail(&ici->list, &hosts);
944 mutex_unlock(&list_lock);
945
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300946 ici->dev.release = dummy_release;
947
948 ret = device_register(&ici->dev);
949
950 if (ret)
951 goto edevr;
952
953 scan_add_host(ici);
954
955 return 0;
956
957edevr:
958 mutex_lock(&list_lock);
959 list_del(&ici->list);
960 mutex_unlock(&list_lock);
961
962 return ret;
963}
964EXPORT_SYMBOL(soc_camera_host_register);
965
966/* Unregister all clients! */
967void soc_camera_host_unregister(struct soc_camera_host *ici)
968{
969 struct soc_camera_device *icd;
970
971 mutex_lock(&list_lock);
972
973 list_del(&ici->list);
974
975 list_for_each_entry(icd, &devices, list) {
976 if (icd->dev.parent == &ici->dev) {
977 device_unregister(&icd->dev);
978 /* Not before device_unregister(), .remove
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300979 * needs parent to call ici->ops->remove() */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300980 icd->dev.parent = NULL;
981 memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
982 }
983 }
984
985 mutex_unlock(&list_lock);
986
987 device_unregister(&ici->dev);
988}
989EXPORT_SYMBOL(soc_camera_host_unregister);
990
991/* Image capture device */
992int soc_camera_device_register(struct soc_camera_device *icd)
993{
994 struct soc_camera_device *ix;
995 int num = -1, i;
996
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300997 if (!icd || !icd->ops ||
998 !icd->ops->probe ||
999 !icd->ops->init ||
1000 !icd->ops->release ||
1001 !icd->ops->start_capture ||
1002 !icd->ops->stop_capture ||
1003 !icd->ops->set_fmt ||
1004 !icd->ops->try_fmt ||
1005 !icd->ops->query_bus_param ||
1006 !icd->ops->set_bus_param)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001007 return -EINVAL;
1008
1009 for (i = 0; i < 256 && num < 0; i++) {
1010 num = i;
1011 list_for_each_entry(ix, &devices, list) {
1012 if (ix->iface == icd->iface && ix->devnum == i) {
1013 num = -1;
1014 break;
1015 }
1016 }
1017 }
1018
1019 if (num < 0)
1020 /* ok, we have 256 cameras on this host...
1021 * man, stay reasonable... */
1022 return -ENOMEM;
1023
1024 icd->devnum = num;
1025 icd->dev.bus = &soc_camera_bus_type;
Kay Sieversaf128a12008-10-30 00:51:46 -03001026 dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001027
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001028 icd->dev.release = dummy_release;
1029 icd->use_count = 0;
1030 icd->host_priv = NULL;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001031 mutex_init(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001032
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001033 return scan_add_device(icd);
1034}
1035EXPORT_SYMBOL(soc_camera_device_register);
1036
1037void soc_camera_device_unregister(struct soc_camera_device *icd)
1038{
1039 mutex_lock(&list_lock);
1040 list_del(&icd->list);
1041
1042 /* The bus->remove will be eventually called */
1043 if (icd->dev.parent)
1044 device_unregister(&icd->dev);
1045 mutex_unlock(&list_lock);
1046}
1047EXPORT_SYMBOL(soc_camera_device_unregister);
1048
Hans Verkuila3998102008-07-21 02:57:38 -03001049static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
1050 .vidioc_querycap = soc_camera_querycap,
1051 .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
1052 .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
1053 .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
1054 .vidioc_enum_input = soc_camera_enum_input,
1055 .vidioc_g_input = soc_camera_g_input,
1056 .vidioc_s_input = soc_camera_s_input,
1057 .vidioc_s_std = soc_camera_s_std,
1058 .vidioc_reqbufs = soc_camera_reqbufs,
1059 .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
1060 .vidioc_querybuf = soc_camera_querybuf,
1061 .vidioc_qbuf = soc_camera_qbuf,
1062 .vidioc_dqbuf = soc_camera_dqbuf,
1063 .vidioc_streamon = soc_camera_streamon,
1064 .vidioc_streamoff = soc_camera_streamoff,
1065 .vidioc_queryctrl = soc_camera_queryctrl,
1066 .vidioc_g_ctrl = soc_camera_g_ctrl,
1067 .vidioc_s_ctrl = soc_camera_s_ctrl,
1068 .vidioc_cropcap = soc_camera_cropcap,
1069 .vidioc_g_crop = soc_camera_g_crop,
1070 .vidioc_s_crop = soc_camera_s_crop,
1071 .vidioc_g_chip_ident = soc_camera_g_chip_ident,
1072#ifdef CONFIG_VIDEO_ADV_DEBUG
1073 .vidioc_g_register = soc_camera_g_register,
1074 .vidioc_s_register = soc_camera_s_register,
1075#endif
1076};
1077
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001078/*
1079 * Usually called from the struct soc_camera_ops .probe() method, i.e., from
1080 * soc_camera_probe() above with .video_lock held
1081 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001082int soc_camera_video_start(struct soc_camera_device *icd)
1083{
1084 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1085 int err = -ENOMEM;
1086 struct video_device *vdev;
1087
1088 if (!icd->dev.parent)
1089 return -ENODEV;
1090
1091 vdev = video_device_alloc();
1092 if (!vdev)
1093 goto evidallocd;
1094 dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
1095
1096 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001097
Hans Verkuil5e85e732008-07-20 06:31:39 -03001098 vdev->parent = &icd->dev;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001099 vdev->current_norm = V4L2_STD_UNKNOWN;
1100 vdev->fops = &soc_camera_fops;
Hans Verkuila3998102008-07-21 02:57:38 -03001101 vdev->ioctl_ops = &soc_camera_ioctl_ops;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001102 vdev->release = video_device_release;
1103 vdev->minor = -1;
1104 vdev->tvnorms = V4L2_STD_UNKNOWN,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001105
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001106 err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
1107 if (err < 0) {
Hans Verkuil5e85e732008-07-20 06:31:39 -03001108 dev_err(vdev->parent, "video_register_device failed\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001109 goto evidregd;
1110 }
1111 icd->vdev = vdev;
1112
1113 return 0;
1114
1115evidregd:
1116 video_device_release(vdev);
1117evidallocd:
1118 return err;
1119}
1120EXPORT_SYMBOL(soc_camera_video_start);
1121
1122void soc_camera_video_stop(struct soc_camera_device *icd)
1123{
1124 struct video_device *vdev = icd->vdev;
1125
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001126 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001127
1128 if (!icd->dev.parent || !vdev)
1129 return;
1130
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001131 mutex_lock(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001132 video_unregister_device(vdev);
1133 icd->vdev = NULL;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001134 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001135}
1136EXPORT_SYMBOL(soc_camera_video_stop);
1137
1138static int __init soc_camera_init(void)
1139{
1140 int ret = bus_register(&soc_camera_bus_type);
1141 if (ret)
1142 return ret;
1143 ret = driver_register(&ic_drv);
1144 if (ret)
1145 goto edrvr;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001146
1147 return 0;
1148
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001149edrvr:
1150 bus_unregister(&soc_camera_bus_type);
1151 return ret;
1152}
1153
1154static void __exit soc_camera_exit(void)
1155{
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001156 driver_unregister(&ic_drv);
1157 bus_unregister(&soc_camera_bus_type);
1158}
1159
1160module_init(soc_camera_init);
1161module_exit(soc_camera_exit);
1162
1163MODULE_DESCRIPTION("Image capture bus driver");
1164MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
1165MODULE_LICENSE("GPL");