blob: b12d11f213bd3dcfee630bdc4ce645d9fd210c88 [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{
Kuninori Morimoto513791a2008-12-18 12:46:45 -0300155 struct soc_camera_file *icf = file->private_data;
156 struct soc_camera_device *icd = icf->icd;
157 int ret = 0;
158
159 if (icd->ops->set_std)
160 ret = icd->ops->set_std(icd, a);
161
162 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300163}
164
165static int soc_camera_reqbufs(struct file *file, void *priv,
166 struct v4l2_requestbuffers *p)
167{
168 int ret;
169 struct soc_camera_file *icf = file->private_data;
170 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300171 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300172
173 WARN_ON(priv != file->private_data);
174
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300175 dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300176
177 ret = videobuf_reqbufs(&icf->vb_vidq, p);
178 if (ret < 0)
179 return ret;
180
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300181 return ici->ops->reqbufs(icf, p);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300182}
183
184static int soc_camera_querybuf(struct file *file, void *priv,
185 struct v4l2_buffer *p)
186{
187 struct soc_camera_file *icf = file->private_data;
188
189 WARN_ON(priv != file->private_data);
190
191 return videobuf_querybuf(&icf->vb_vidq, p);
192}
193
194static int soc_camera_qbuf(struct file *file, void *priv,
195 struct v4l2_buffer *p)
196{
197 struct soc_camera_file *icf = file->private_data;
198
199 WARN_ON(priv != file->private_data);
200
201 return videobuf_qbuf(&icf->vb_vidq, p);
202}
203
204static int soc_camera_dqbuf(struct file *file, void *priv,
205 struct v4l2_buffer *p)
206{
207 struct soc_camera_file *icf = file->private_data;
208
209 WARN_ON(priv != file->private_data);
210
211 return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
212}
213
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300214static int soc_camera_init_user_formats(struct soc_camera_device *icd)
215{
216 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
217 int i, fmts = 0;
218
219 if (!ici->ops->get_formats)
220 /*
221 * Fallback mode - the host will have to serve all
222 * sensor-provided formats one-to-one to the user
223 */
224 fmts = icd->num_formats;
225 else
226 /*
227 * First pass - only count formats this host-sensor
228 * configuration can provide
229 */
230 for (i = 0; i < icd->num_formats; i++)
231 fmts += ici->ops->get_formats(icd, i, NULL);
232
233 if (!fmts)
234 return -ENXIO;
235
236 icd->user_formats =
237 vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
238 if (!icd->user_formats)
239 return -ENOMEM;
240
241 icd->num_user_formats = fmts;
242 fmts = 0;
243
244 dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
245
246 /* Second pass - actually fill data formats */
247 for (i = 0; i < icd->num_formats; i++)
248 if (!ici->ops->get_formats) {
249 icd->user_formats[i].host_fmt = icd->formats + i;
250 icd->user_formats[i].cam_fmt = icd->formats + i;
251 icd->user_formats[i].buswidth = icd->formats[i].depth;
252 } else {
253 fmts += ici->ops->get_formats(icd, i,
254 &icd->user_formats[fmts]);
255 }
256
257 icd->current_fmt = icd->user_formats[0].host_fmt;
258
259 return 0;
260}
261
262static void soc_camera_free_user_formats(struct soc_camera_device *icd)
263{
264 vfree(icd->user_formats);
265}
266
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300267static int soc_camera_open(struct inode *inode, struct file *file)
268{
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300269 struct video_device *vdev;
270 struct soc_camera_device *icd;
271 struct soc_camera_host *ici;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300272 struct soc_camera_file *icf;
273 int ret;
274
275 icf = vmalloc(sizeof(*icf));
276 if (!icf)
277 return -ENOMEM;
278
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300279 /*
280 * It is safe to dereference these pointers now as long as a user has
281 * the video device open - we are protected by the held cdev reference.
282 */
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300283
284 vdev = video_devdata(file);
Hans Verkuil5e85e732008-07-20 06:31:39 -0300285 icd = container_of(vdev->parent, struct soc_camera_device, dev);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300286 ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300287
288 if (!try_module_get(icd->ops->owner)) {
289 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
290 ret = -EINVAL;
291 goto emgd;
292 }
293
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300294 if (!try_module_get(ici->ops->owner)) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300295 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
296 ret = -EINVAL;
297 goto emgi;
298 }
299
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300300 /* Protect against icd->remove() until we module_get() both drivers. */
301 mutex_lock(&icd->video_lock);
302
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300303 icf->icd = icd;
Guennadi Liakhovetski1a0063a2008-04-04 13:46:34 -0300304 icd->use_count++;
305
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300306 /* Now we really have to activate the camera */
307 if (icd->use_count == 1) {
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300308 ret = soc_camera_init_user_formats(icd);
309 if (ret < 0)
310 goto eiufmt;
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300311 ret = ici->ops->add(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300312 if (ret < 0) {
313 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300314 goto eiciadd;
315 }
316 }
317
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300318 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300319
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300320 file->private_data = icf;
321 dev_dbg(&icd->dev, "camera device open\n");
322
Magnus Damma034d1b2008-07-11 20:59:34 -0300323 ici->ops->init_videobuf(&icf->vb_vidq, icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300324
325 return 0;
326
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300327 /* First two errors are entered with the .video_lock held */
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300328eiciadd:
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300329 soc_camera_free_user_formats(icd);
330eiufmt:
331 icd->use_count--;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300332 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300333 module_put(ici->ops->owner);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300334emgi:
335 module_put(icd->ops->owner);
336emgd:
337 vfree(icf);
338 return ret;
339}
340
341static int soc_camera_close(struct inode *inode, struct file *file)
342{
343 struct soc_camera_file *icf = file->private_data;
344 struct soc_camera_device *icd = icf->icd;
345 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
346 struct video_device *vdev = icd->vdev;
347
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300348 mutex_lock(&icd->video_lock);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300349 icd->use_count--;
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300350 if (!icd->use_count) {
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300351 ici->ops->remove(icd);
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300352 soc_camera_free_user_formats(icd);
353 }
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300354 mutex_unlock(&icd->video_lock);
355
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300356 module_put(icd->ops->owner);
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300357 module_put(ici->ops->owner);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300358
Guennadi Liakhovetski1a0063a2008-04-04 13:46:34 -0300359 vfree(icf);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300360
Hans Verkuil5e85e732008-07-20 06:31:39 -0300361 dev_dbg(vdev->parent, "camera device close\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300362
363 return 0;
364}
365
Andrew Mortonaba360d2008-04-22 14:45:59 -0300366static ssize_t soc_camera_read(struct file *file, char __user *buf,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300367 size_t count, loff_t *ppos)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300368{
369 struct soc_camera_file *icf = file->private_data;
370 struct soc_camera_device *icd = icf->icd;
371 struct video_device *vdev = icd->vdev;
372 int err = -EINVAL;
373
Hans Verkuil5e85e732008-07-20 06:31:39 -0300374 dev_err(vdev->parent, "camera device read not implemented\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300375
376 return err;
377}
378
379static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
380{
381 struct soc_camera_file *icf = file->private_data;
382 struct soc_camera_device *icd = icf->icd;
383 int err;
384
385 dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
386
387 err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
388
389 dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
390 (unsigned long)vma->vm_start,
391 (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
392 err);
393
394 return err;
395}
396
397static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
398{
399 struct soc_camera_file *icf = file->private_data;
400 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300401 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300402
403 if (list_empty(&icf->vb_vidq.stream)) {
404 dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
405 return POLLERR;
406 }
407
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300408 return ici->ops->poll(file, pt);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300409}
410
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300411static struct file_operations soc_camera_fops = {
412 .owner = THIS_MODULE,
413 .open = soc_camera_open,
414 .release = soc_camera_close,
415 .ioctl = video_ioctl2,
416 .read = soc_camera_read,
417 .mmap = soc_camera_mmap,
418 .poll = soc_camera_poll,
419 .llseek = no_llseek,
420};
421
Hans Verkuil72937892008-06-01 10:35:18 -0300422static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300423 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300424{
425 struct soc_camera_file *icf = file->private_data;
426 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300427 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
428 struct v4l2_pix_format *pix = &f->fmt.pix;
429 __u32 pixfmt = pix->pixelformat;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300430 int ret;
431 struct v4l2_rect rect;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300432
433 WARN_ON(priv != file->private_data);
434
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300435 ret = soc_camera_try_fmt_vid_cap(file, priv, f);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300436 if (ret < 0)
437 return ret;
438
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300439 mutex_lock(&icf->vb_vidq.vb_lock);
440
441 if (videobuf_queue_is_busy(&icf->vb_vidq)) {
442 dev_err(&icd->dev, "S_FMT denied: queue busy\n");
443 ret = -EBUSY;
444 goto unlock;
445 }
446
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300447 rect.left = icd->x_current;
448 rect.top = icd->y_current;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300449 rect.width = pix->width;
450 rect.height = pix->height;
451 ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300452 if (ret < 0) {
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300453 goto unlock;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300454 } else if (!icd->current_fmt ||
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300455 icd->current_fmt->fourcc != pixfmt) {
456 dev_err(&ici->dev,
457 "Host driver hasn't set up current format correctly!\n");
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300458 ret = -EINVAL;
459 goto unlock;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300460 }
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300461
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300462 icd->width = rect.width;
463 icd->height = rect.height;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300464 icf->vb_vidq.field = pix->field;
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300465 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300466 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
467 f->type);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300468
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300469 dev_dbg(&icd->dev, "set width: %d height: %d\n",
470 icd->width, icd->height);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300471
Guennadi Liakhovetskiad5f2e82008-03-07 21:57:18 -0300472 /* set physical bus parameters */
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300473 ret = ici->ops->set_bus_param(icd, pixfmt);
474
475unlock:
476 mutex_unlock(&icf->vb_vidq.vb_lock);
477
478 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300479}
480
Hans Verkuil72937892008-06-01 10:35:18 -0300481static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300482 struct v4l2_fmtdesc *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300483{
484 struct soc_camera_file *icf = file->private_data;
485 struct soc_camera_device *icd = icf->icd;
486 const struct soc_camera_data_format *format;
487
488 WARN_ON(priv != file->private_data);
489
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300490 if (f->index >= icd->num_user_formats)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300491 return -EINVAL;
492
Guennadi Liakhovetskic2786ad2008-12-01 09:45:27 -0300493 format = icd->user_formats[f->index].host_fmt;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300494
495 strlcpy(f->description, format->name, sizeof(f->description));
496 f->pixelformat = format->fourcc;
497 return 0;
498}
499
Hans Verkuil72937892008-06-01 10:35:18 -0300500static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
Guennadi Liakhovetskiabe4c472008-12-01 09:44:56 -0300501 struct v4l2_format *f)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300502{
503 struct soc_camera_file *icf = file->private_data;
504 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300505 struct v4l2_pix_format *pix = &f->fmt.pix;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300506
507 WARN_ON(priv != file->private_data);
508
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300509 pix->width = icd->width;
510 pix->height = icd->height;
511 pix->field = icf->vb_vidq.field;
512 pix->pixelformat = icd->current_fmt->fourcc;
513 pix->bytesperline = pix->width *
Guennadi Liakhovetski25c4d742008-12-01 09:44:59 -0300514 DIV_ROUND_UP(icd->current_fmt->depth, 8);
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300515 pix->sizeimage = pix->height * pix->bytesperline;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300516 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
517 icd->current_fmt->fourcc);
518 return 0;
519}
520
521static int soc_camera_querycap(struct file *file, void *priv,
522 struct v4l2_capability *cap)
523{
524 struct soc_camera_file *icf = file->private_data;
525 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300526 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300527
528 WARN_ON(priv != file->private_data);
529
530 strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300531 return ici->ops->querycap(ici, cap);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300532}
533
534static int soc_camera_streamon(struct file *file, void *priv,
535 enum v4l2_buf_type i)
536{
537 struct soc_camera_file *icf = file->private_data;
538 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300539 int ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300540
541 WARN_ON(priv != file->private_data);
542
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300543 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300544
545 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
546 return -EINVAL;
547
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300548 mutex_lock(&icd->video_lock);
549
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300550 icd->ops->start_capture(icd);
551
552 /* This calls buf_queue from host driver's videobuf_queue_ops */
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300553 ret = videobuf_streamon(&icf->vb_vidq);
554
555 mutex_unlock(&icd->video_lock);
556
557 return ret;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300558}
559
560static int soc_camera_streamoff(struct file *file, void *priv,
561 enum v4l2_buf_type i)
562{
563 struct soc_camera_file *icf = file->private_data;
564 struct soc_camera_device *icd = icf->icd;
565
566 WARN_ON(priv != file->private_data);
567
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300568 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300569
570 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
571 return -EINVAL;
572
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300573 mutex_lock(&icd->video_lock);
574
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300575 /* This calls buf_release from host driver's videobuf_queue_ops for all
576 * remaining buffers. When the last buffer is freed, stop capture */
577 videobuf_streamoff(&icf->vb_vidq);
578
579 icd->ops->stop_capture(icd);
580
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300581 mutex_unlock(&icd->video_lock);
582
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300583 return 0;
584}
585
586static int soc_camera_queryctrl(struct file *file, void *priv,
587 struct v4l2_queryctrl *qc)
588{
589 struct soc_camera_file *icf = file->private_data;
590 struct soc_camera_device *icd = icf->icd;
591 int i;
592
593 WARN_ON(priv != file->private_data);
594
595 if (!qc->id)
596 return -EINVAL;
597
598 for (i = 0; i < icd->ops->num_controls; i++)
599 if (qc->id == icd->ops->controls[i].id) {
600 memcpy(qc, &(icd->ops->controls[i]),
601 sizeof(*qc));
602 return 0;
603 }
604
605 return -EINVAL;
606}
607
608static int soc_camera_g_ctrl(struct file *file, void *priv,
609 struct v4l2_control *ctrl)
610{
611 struct soc_camera_file *icf = file->private_data;
612 struct soc_camera_device *icd = icf->icd;
613
614 WARN_ON(priv != file->private_data);
615
616 switch (ctrl->id) {
617 case V4L2_CID_GAIN:
618 if (icd->gain == (unsigned short)~0)
619 return -EINVAL;
620 ctrl->value = icd->gain;
621 return 0;
622 case V4L2_CID_EXPOSURE:
623 if (icd->exposure == (unsigned short)~0)
624 return -EINVAL;
625 ctrl->value = icd->exposure;
626 return 0;
627 }
628
629 if (icd->ops->get_control)
630 return icd->ops->get_control(icd, ctrl);
631 return -EINVAL;
632}
633
634static int soc_camera_s_ctrl(struct file *file, void *priv,
635 struct v4l2_control *ctrl)
636{
637 struct soc_camera_file *icf = file->private_data;
638 struct soc_camera_device *icd = icf->icd;
639
640 WARN_ON(priv != file->private_data);
641
642 if (icd->ops->set_control)
643 return icd->ops->set_control(icd, ctrl);
644 return -EINVAL;
645}
646
647static int soc_camera_cropcap(struct file *file, void *fh,
648 struct v4l2_cropcap *a)
649{
650 struct soc_camera_file *icf = file->private_data;
651 struct soc_camera_device *icd = icf->icd;
652
653 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
654 a->bounds.left = icd->x_min;
655 a->bounds.top = icd->y_min;
656 a->bounds.width = icd->width_max;
657 a->bounds.height = icd->height_max;
658 a->defrect.left = icd->x_min;
659 a->defrect.top = icd->y_min;
660 a->defrect.width = 640;
661 a->defrect.height = 480;
662 a->pixelaspect.numerator = 1;
663 a->pixelaspect.denominator = 1;
664
665 return 0;
666}
667
668static int soc_camera_g_crop(struct file *file, void *fh,
669 struct v4l2_crop *a)
670{
671 struct soc_camera_file *icf = file->private_data;
672 struct soc_camera_device *icd = icf->icd;
673
674 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
675 a->c.left = icd->x_current;
676 a->c.top = icd->y_current;
677 a->c.width = icd->width;
678 a->c.height = icd->height;
679
680 return 0;
681}
682
683static int soc_camera_s_crop(struct file *file, void *fh,
684 struct v4l2_crop *a)
685{
686 struct soc_camera_file *icf = file->private_data;
687 struct soc_camera_device *icd = icf->icd;
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300688 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300689 int ret;
690
691 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
692 return -EINVAL;
693
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300694 /* Cropping is allowed during a running capture, guard consistency */
695 mutex_lock(&icf->vb_vidq.vb_lock);
696
Guennadi Liakhovetskid8fac212008-12-01 09:45:21 -0300697 ret = ici->ops->set_fmt(icd, 0, &a->c);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300698 if (!ret) {
699 icd->width = a->c.width;
700 icd->height = a->c.height;
701 icd->x_current = a->c.left;
702 icd->y_current = a->c.top;
703 }
704
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300705 mutex_unlock(&icf->vb_vidq.vb_lock);
706
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300707 return ret;
708}
709
710static int soc_camera_g_chip_ident(struct file *file, void *fh,
711 struct v4l2_chip_ident *id)
712{
713 struct soc_camera_file *icf = file->private_data;
714 struct soc_camera_device *icd = icf->icd;
715
716 if (!icd->ops->get_chip_id)
717 return -EINVAL;
718
719 return icd->ops->get_chip_id(icd, id);
720}
721
722#ifdef CONFIG_VIDEO_ADV_DEBUG
723static int soc_camera_g_register(struct file *file, void *fh,
724 struct v4l2_register *reg)
725{
726 struct soc_camera_file *icf = file->private_data;
727 struct soc_camera_device *icd = icf->icd;
728
729 if (!icd->ops->get_register)
730 return -EINVAL;
731
732 return icd->ops->get_register(icd, reg);
733}
734
735static int soc_camera_s_register(struct file *file, void *fh,
736 struct v4l2_register *reg)
737{
738 struct soc_camera_file *icf = file->private_data;
739 struct soc_camera_device *icd = icf->icd;
740
741 if (!icd->ops->set_register)
742 return -EINVAL;
743
744 return icd->ops->set_register(icd, reg);
745}
746#endif
747
748static int device_register_link(struct soc_camera_device *icd)
749{
750 int ret = device_register(&icd->dev);
751
752 if (ret < 0) {
753 /* Prevent calling device_unregister() */
754 icd->dev.parent = NULL;
755 dev_err(&icd->dev, "Cannot register device: %d\n", ret);
756 /* Even if probe() was unsuccessful for all registered drivers,
757 * device_register() returns 0, and we add the link, just to
758 * document this camera's control device */
759 } else if (icd->control)
760 /* Have to sysfs_remove_link() before device_unregister()? */
761 if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
762 "control"))
763 dev_warn(&icd->dev,
764 "Failed creating the control symlink\n");
765 return ret;
766}
767
768/* So far this function cannot fail */
769static void scan_add_host(struct soc_camera_host *ici)
770{
771 struct soc_camera_device *icd;
772
773 mutex_lock(&list_lock);
774
775 list_for_each_entry(icd, &devices, list) {
776 if (icd->iface == ici->nr) {
777 icd->dev.parent = &ici->dev;
778 device_register_link(icd);
779 }
780 }
781
782 mutex_unlock(&list_lock);
783}
784
785/* return: 0 if no match found or a match found and
786 * device_register() successful, error code otherwise */
787static int scan_add_device(struct soc_camera_device *icd)
788{
789 struct soc_camera_host *ici;
790 int ret = 0;
791
792 mutex_lock(&list_lock);
793
794 list_add_tail(&icd->list, &devices);
795
796 /* Watch out for class_for_each_device / class_find_device API by
797 * Dave Young <hidave.darkstar@gmail.com> */
798 list_for_each_entry(ici, &hosts, list) {
799 if (icd->iface == ici->nr) {
800 ret = 1;
801 icd->dev.parent = &ici->dev;
802 break;
803 }
804 }
805
806 mutex_unlock(&list_lock);
807
808 if (ret)
809 ret = device_register_link(icd);
810
811 return ret;
812}
813
814static int soc_camera_probe(struct device *dev)
815{
816 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300817 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300818 int ret;
819
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300820 /*
821 * Possible race scenario:
822 * modprobe <camera-host-driver> triggers __func__
823 * at this moment respective <camera-sensor-driver> gets rmmod'ed
824 * to protect take module references.
825 */
826
827 if (!try_module_get(icd->ops->owner)) {
828 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
829 ret = -EINVAL;
830 goto emgd;
831 }
832
833 if (!try_module_get(ici->ops->owner)) {
834 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
835 ret = -EINVAL;
836 goto emgi;
837 }
838
839 mutex_lock(&icd->video_lock);
840
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300841 /* We only call ->add() here to activate and probe the camera.
842 * We shall ->remove() and deactivate it immediately afterwards. */
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300843 ret = ici->ops->add(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300844 if (ret < 0)
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300845 goto eiadd;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300846
Guennadi Liakhovetski26f1b942008-03-24 12:18:36 -0300847 ret = icd->ops->probe(icd);
Guennadi Liakhovetski9dc4e482008-04-22 14:45:32 -0300848 if (ret >= 0) {
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300849 const struct v4l2_queryctrl *qctrl;
850
851 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
852 icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
853 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
854 icd->exposure = qctrl ? qctrl->default_value :
855 (unsigned short)~0;
856 }
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300857 ici->ops->remove(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300858
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -0300859eiadd:
860 mutex_unlock(&icd->video_lock);
861 module_put(ici->ops->owner);
862emgi:
863 module_put(icd->ops->owner);
864emgd:
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300865 return ret;
866}
867
868/* This is called on device_unregister, which only means we have to disconnect
869 * from the host, but not remove ourselves from the device list */
870static int soc_camera_remove(struct device *dev)
871{
872 struct soc_camera_device *icd = to_soc_camera_dev(dev);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300873
Guennadi Liakhovetski26f1b942008-03-24 12:18:36 -0300874 if (icd->ops->remove)
875 icd->ops->remove(icd);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300876
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300877 return 0;
878}
879
Robert Jarzmik2e521062008-08-01 20:14:50 -0300880static int soc_camera_suspend(struct device *dev, pm_message_t state)
881{
882 struct soc_camera_device *icd = to_soc_camera_dev(dev);
883 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
884 int ret = 0;
885
886 if (ici->ops->suspend)
887 ret = ici->ops->suspend(icd, state);
888
889 return ret;
890}
891
892static int soc_camera_resume(struct device *dev)
893{
894 struct soc_camera_device *icd = to_soc_camera_dev(dev);
895 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
896 int ret = 0;
897
898 if (ici->ops->resume)
899 ret = ici->ops->resume(icd);
900
901 return ret;
902}
903
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300904static struct bus_type soc_camera_bus_type = {
905 .name = "soc-camera",
906 .probe = soc_camera_probe,
907 .remove = soc_camera_remove,
Robert Jarzmik2e521062008-08-01 20:14:50 -0300908 .suspend = soc_camera_suspend,
909 .resume = soc_camera_resume,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300910};
911
912static struct device_driver ic_drv = {
913 .name = "camera",
914 .bus = &soc_camera_bus_type,
915 .owner = THIS_MODULE,
916};
917
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300918static void dummy_release(struct device *dev)
919{
920}
921
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300922int soc_camera_host_register(struct soc_camera_host *ici)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300923{
924 int ret;
925 struct soc_camera_host *ix;
926
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -0300927 if (!ici || !ici->ops ||
928 !ici->ops->try_fmt ||
929 !ici->ops->set_fmt ||
930 !ici->ops->set_bus_param ||
931 !ici->ops->querycap ||
932 !ici->ops->init_videobuf ||
933 !ici->ops->reqbufs ||
934 !ici->ops->add ||
935 !ici->ops->remove ||
936 !ici->ops->poll)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300937 return -EINVAL;
938
939 /* Number might be equal to the platform device ID */
Kay Sieversaf128a12008-10-30 00:51:46 -0300940 dev_set_name(&ici->dev, "camera_host%d", ici->nr);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300941
942 mutex_lock(&list_lock);
943 list_for_each_entry(ix, &hosts, list) {
944 if (ix->nr == ici->nr) {
945 mutex_unlock(&list_lock);
946 return -EBUSY;
947 }
948 }
949
950 list_add_tail(&ici->list, &hosts);
951 mutex_unlock(&list_lock);
952
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300953 ici->dev.release = dummy_release;
954
955 ret = device_register(&ici->dev);
956
957 if (ret)
958 goto edevr;
959
960 scan_add_host(ici);
961
962 return 0;
963
964edevr:
965 mutex_lock(&list_lock);
966 list_del(&ici->list);
967 mutex_unlock(&list_lock);
968
969 return ret;
970}
971EXPORT_SYMBOL(soc_camera_host_register);
972
973/* Unregister all clients! */
974void soc_camera_host_unregister(struct soc_camera_host *ici)
975{
976 struct soc_camera_device *icd;
977
978 mutex_lock(&list_lock);
979
980 list_del(&ici->list);
981
982 list_for_each_entry(icd, &devices, list) {
983 if (icd->dev.parent == &ici->dev) {
984 device_unregister(&icd->dev);
985 /* Not before device_unregister(), .remove
Guennadi Liakhovetskib8d99042008-04-04 13:41:25 -0300986 * needs parent to call ici->ops->remove() */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -0300987 icd->dev.parent = NULL;
988 memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
989 }
990 }
991
992 mutex_unlock(&list_lock);
993
994 device_unregister(&ici->dev);
995}
996EXPORT_SYMBOL(soc_camera_host_unregister);
997
998/* Image capture device */
999int soc_camera_device_register(struct soc_camera_device *icd)
1000{
1001 struct soc_camera_device *ix;
1002 int num = -1, i;
1003
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001004 if (!icd || !icd->ops ||
1005 !icd->ops->probe ||
1006 !icd->ops->init ||
1007 !icd->ops->release ||
1008 !icd->ops->start_capture ||
1009 !icd->ops->stop_capture ||
1010 !icd->ops->set_fmt ||
1011 !icd->ops->try_fmt ||
1012 !icd->ops->query_bus_param ||
1013 !icd->ops->set_bus_param)
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001014 return -EINVAL;
1015
1016 for (i = 0; i < 256 && num < 0; i++) {
1017 num = i;
1018 list_for_each_entry(ix, &devices, list) {
1019 if (ix->iface == icd->iface && ix->devnum == i) {
1020 num = -1;
1021 break;
1022 }
1023 }
1024 }
1025
1026 if (num < 0)
1027 /* ok, we have 256 cameras on this host...
1028 * man, stay reasonable... */
1029 return -ENOMEM;
1030
1031 icd->devnum = num;
1032 icd->dev.bus = &soc_camera_bus_type;
Kay Sieversaf128a12008-10-30 00:51:46 -03001033 dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001034
Guennadi Liakhovetski64f59052008-12-18 11:51:55 -03001035 icd->dev.release = dummy_release;
1036 icd->use_count = 0;
1037 icd->host_priv = NULL;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001038 mutex_init(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001039
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001040 return scan_add_device(icd);
1041}
1042EXPORT_SYMBOL(soc_camera_device_register);
1043
1044void soc_camera_device_unregister(struct soc_camera_device *icd)
1045{
1046 mutex_lock(&list_lock);
1047 list_del(&icd->list);
1048
1049 /* The bus->remove will be eventually called */
1050 if (icd->dev.parent)
1051 device_unregister(&icd->dev);
1052 mutex_unlock(&list_lock);
1053}
1054EXPORT_SYMBOL(soc_camera_device_unregister);
1055
Hans Verkuila3998102008-07-21 02:57:38 -03001056static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
1057 .vidioc_querycap = soc_camera_querycap,
1058 .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
1059 .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
1060 .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
1061 .vidioc_enum_input = soc_camera_enum_input,
1062 .vidioc_g_input = soc_camera_g_input,
1063 .vidioc_s_input = soc_camera_s_input,
1064 .vidioc_s_std = soc_camera_s_std,
1065 .vidioc_reqbufs = soc_camera_reqbufs,
1066 .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
1067 .vidioc_querybuf = soc_camera_querybuf,
1068 .vidioc_qbuf = soc_camera_qbuf,
1069 .vidioc_dqbuf = soc_camera_dqbuf,
1070 .vidioc_streamon = soc_camera_streamon,
1071 .vidioc_streamoff = soc_camera_streamoff,
1072 .vidioc_queryctrl = soc_camera_queryctrl,
1073 .vidioc_g_ctrl = soc_camera_g_ctrl,
1074 .vidioc_s_ctrl = soc_camera_s_ctrl,
1075 .vidioc_cropcap = soc_camera_cropcap,
1076 .vidioc_g_crop = soc_camera_g_crop,
1077 .vidioc_s_crop = soc_camera_s_crop,
1078 .vidioc_g_chip_ident = soc_camera_g_chip_ident,
1079#ifdef CONFIG_VIDEO_ADV_DEBUG
1080 .vidioc_g_register = soc_camera_g_register,
1081 .vidioc_s_register = soc_camera_s_register,
1082#endif
1083};
1084
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001085/*
1086 * Usually called from the struct soc_camera_ops .probe() method, i.e., from
1087 * soc_camera_probe() above with .video_lock held
1088 */
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001089int soc_camera_video_start(struct soc_camera_device *icd)
1090{
1091 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1092 int err = -ENOMEM;
1093 struct video_device *vdev;
1094
1095 if (!icd->dev.parent)
1096 return -ENODEV;
1097
1098 vdev = video_device_alloc();
1099 if (!vdev)
1100 goto evidallocd;
1101 dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
1102
1103 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001104
Hans Verkuil5e85e732008-07-20 06:31:39 -03001105 vdev->parent = &icd->dev;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001106 vdev->current_norm = V4L2_STD_UNKNOWN;
1107 vdev->fops = &soc_camera_fops;
Hans Verkuila3998102008-07-21 02:57:38 -03001108 vdev->ioctl_ops = &soc_camera_ioctl_ops;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001109 vdev->release = video_device_release;
1110 vdev->minor = -1;
1111 vdev->tvnorms = V4L2_STD_UNKNOWN,
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001112
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001113 err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
1114 if (err < 0) {
Hans Verkuil5e85e732008-07-20 06:31:39 -03001115 dev_err(vdev->parent, "video_register_device failed\n");
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001116 goto evidregd;
1117 }
1118 icd->vdev = vdev;
1119
1120 return 0;
1121
1122evidregd:
1123 video_device_release(vdev);
1124evidallocd:
1125 return err;
1126}
1127EXPORT_SYMBOL(soc_camera_video_start);
1128
1129void soc_camera_video_stop(struct soc_camera_device *icd)
1130{
1131 struct video_device *vdev = icd->vdev;
1132
Harvey Harrison7e28adb2008-04-08 23:20:00 -03001133 dev_dbg(&icd->dev, "%s\n", __func__);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001134
1135 if (!icd->dev.parent || !vdev)
1136 return;
1137
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001138 mutex_lock(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001139 video_unregister_device(vdev);
1140 icd->vdev = NULL;
Guennadi Liakhovetski1c3bb742008-12-18 12:28:54 -03001141 mutex_unlock(&icd->video_lock);
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001142}
1143EXPORT_SYMBOL(soc_camera_video_stop);
1144
1145static int __init soc_camera_init(void)
1146{
1147 int ret = bus_register(&soc_camera_bus_type);
1148 if (ret)
1149 return ret;
1150 ret = driver_register(&ic_drv);
1151 if (ret)
1152 goto edrvr;
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001153
1154 return 0;
1155
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001156edrvr:
1157 bus_unregister(&soc_camera_bus_type);
1158 return ret;
1159}
1160
1161static void __exit soc_camera_exit(void)
1162{
Guennadi Liakhovetskie55222e2008-04-22 14:42:03 -03001163 driver_unregister(&ic_drv);
1164 bus_unregister(&soc_camera_bus_type);
1165}
1166
1167module_init(soc_camera_init);
1168module_exit(soc_camera_exit);
1169
1170MODULE_DESCRIPTION("Image capture bus driver");
1171MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
1172MODULE_LICENSE("GPL");