aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/soc_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-04-22 13:42:03 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:42 -0400
commite55222ef27a2390d8abce27a3ce2d4c719ad5f1b (patch)
treeedf00fea5b924b53c08a69f702520523dc734a16 /drivers/media/video/soc_camera.c
parenta7c7402f68cf97c9a021466c04029f039f9f4f27 (diff)
V4L/DVB (7170): soc_camera V4L2 driver for directly-connected SoC-based cameras
This driver provides an interface between platform-specific camera busses and camera devices. It should be used if the camera is connected not over a "proper" bus like PCI or USB, but over a special bus, like, for example, the Quick Capture interface on PXA270 SoCs. Later it should also be used for i.MX31 SoCs from Freescale. It can handle multiple cameras and / or multiple busses, which can be used, e.g., in stereo-vision applications. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r--drivers/media/video/soc_camera.c973
1 files changed, 973 insertions, 0 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
new file mode 100644
index 000000000000..904e9dfc1a89
--- /dev/null
+++ b/drivers/media/video/soc_camera.c
@@ -0,0 +1,973 @@
1/*
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>
28#include <media/v4l2-dev.h>
29#include <media/soc_camera.h>
30
31static LIST_HEAD(hosts);
32static LIST_HEAD(devices);
33static DEFINE_MUTEX(list_lock);
34static DEFINE_MUTEX(video_lock);
35
36const static struct soc_camera_data_format*
37format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
38{
39 unsigned int i;
40
41 for (i = 0; i < icd->ops->num_formats; i++)
42 if (icd->ops->formats[i].fourcc == fourcc)
43 return icd->ops->formats + i;
44 return NULL;
45}
46
47static int soc_camera_try_fmt_cap(struct file *file, void *priv,
48 struct v4l2_format *f)
49{
50 struct soc_camera_file *icf = file->private_data;
51 struct soc_camera_device *icd = icf->icd;
52 struct soc_camera_host *ici =
53 to_soc_camera_host(icd->dev.parent);
54 enum v4l2_field field;
55 const struct soc_camera_data_format *fmt;
56 int ret;
57
58 WARN_ON(priv != file->private_data);
59
60 fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
61 if (!fmt) {
62 dev_dbg(&icd->dev, "invalid format 0x%08x\n",
63 f->fmt.pix.pixelformat);
64 return -EINVAL;
65 }
66
67 dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
68
69 field = f->fmt.pix.field;
70
71 if (field == V4L2_FIELD_ANY) {
72 field = V4L2_FIELD_NONE;
73 } else if (V4L2_FIELD_NONE != field) {
74 dev_err(&icd->dev, "Field type invalid.\n");
75 return -EINVAL;
76 }
77
78 /* limit to host capabilities */
79 ret = ici->try_fmt_cap(ici, f);
80
81 /* limit to sensor capabilities */
82 if (!ret)
83 ret = icd->ops->try_fmt_cap(icd, f);
84
85 /* calculate missing fields */
86 f->fmt.pix.field = field;
87 f->fmt.pix.bytesperline =
88 (f->fmt.pix.width * fmt->depth) >> 3;
89 f->fmt.pix.sizeimage =
90 f->fmt.pix.height * f->fmt.pix.bytesperline;
91
92 return ret;
93}
94
95static int soc_camera_enum_input(struct file *file, void *priv,
96 struct v4l2_input *inp)
97{
98 if (inp->index != 0)
99 return -EINVAL;
100
101 inp->type = V4L2_INPUT_TYPE_CAMERA;
102 inp->std = V4L2_STD_UNKNOWN;
103 strcpy(inp->name, "Camera");
104
105 return 0;
106}
107
108static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
109{
110 *i = 0;
111
112 return 0;
113}
114
115static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
116{
117 if (i > 0)
118 return -EINVAL;
119
120 return 0;
121}
122
123static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
124{
125 return 0;
126}
127
128static int soc_camera_reqbufs(struct file *file, void *priv,
129 struct v4l2_requestbuffers *p)
130{
131 int ret;
132 struct soc_camera_file *icf = file->private_data;
133 struct soc_camera_device *icd = icf->icd;
134 struct soc_camera_host *ici =
135 to_soc_camera_host(icd->dev.parent);
136
137 WARN_ON(priv != file->private_data);
138
139 dev_dbg(&icd->dev, "%s: %d\n", __FUNCTION__, p->memory);
140
141 ret = videobuf_reqbufs(&icf->vb_vidq, p);
142 if (ret < 0)
143 return ret;
144
145 return ici->reqbufs(icf, p);
146
147 return ret;
148}
149
150static int soc_camera_querybuf(struct file *file, void *priv,
151 struct v4l2_buffer *p)
152{
153 struct soc_camera_file *icf = file->private_data;
154
155 WARN_ON(priv != file->private_data);
156
157 return videobuf_querybuf(&icf->vb_vidq, p);
158}
159
160static int soc_camera_qbuf(struct file *file, void *priv,
161 struct v4l2_buffer *p)
162{
163 struct soc_camera_file *icf = file->private_data;
164
165 WARN_ON(priv != file->private_data);
166
167 return videobuf_qbuf(&icf->vb_vidq, p);
168}
169
170static int soc_camera_dqbuf(struct file *file, void *priv,
171 struct v4l2_buffer *p)
172{
173 struct soc_camera_file *icf = file->private_data;
174
175 WARN_ON(priv != file->private_data);
176
177 return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
178}
179
180static int soc_camera_open(struct inode *inode, struct file *file)
181{
182 struct video_device *vdev = video_devdata(file);
183 struct soc_camera_device *icd = container_of(vdev->dev,
184 struct soc_camera_device, dev);
185 struct soc_camera_host *ici =
186 to_soc_camera_host(icd->dev.parent);
187 struct soc_camera_file *icf;
188 int ret;
189
190 icf = vmalloc(sizeof(*icf));
191 if (!icf)
192 return -ENOMEM;
193
194 icf->icd = icd;
195
196 if (!try_module_get(icd->ops->owner)) {
197 dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
198 ret = -EINVAL;
199 goto emgd;
200 }
201
202 if (!try_module_get(ici->owner)) {
203 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
204 ret = -EINVAL;
205 goto emgi;
206 }
207
208 file->private_data = icf;
209 dev_dbg(&icd->dev, "camera device open\n");
210
211 /* We must pass NULL as dev pointer, then all pci_* dma operations
212 * transform to normal dma_* ones. Do we need an irqlock? */
213 videobuf_queue_pci_init(&icf->vb_vidq, ici->vbq_ops, NULL, NULL,
214 V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
215 ici->msize, icd);
216
217 return 0;
218
219emgi:
220 module_put(icd->ops->owner);
221emgd:
222 vfree(icf);
223 return ret;
224}
225
226static int soc_camera_close(struct inode *inode, struct file *file)
227{
228 struct soc_camera_file *icf = file->private_data;
229 struct soc_camera_device *icd = icf->icd;
230 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
231 struct video_device *vdev = icd->vdev;
232
233 module_put(icd->ops->owner);
234 module_put(ici->owner);
235 vfree(file->private_data);
236
237 dev_dbg(vdev->dev, "camera device close\n");
238
239 return 0;
240}
241
242static int soc_camera_read(struct file *file, char __user *buf,
243 size_t count, loff_t *ppos)
244{
245 struct soc_camera_file *icf = file->private_data;
246 struct soc_camera_device *icd = icf->icd;
247 struct video_device *vdev = icd->vdev;
248 int err = -EINVAL;
249
250 dev_err(vdev->dev, "camera device read not implemented\n");
251
252 return err;
253}
254
255static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
256{
257 struct soc_camera_file *icf = file->private_data;
258 struct soc_camera_device *icd = icf->icd;
259 int err;
260
261 dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
262
263 err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
264
265 dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
266 (unsigned long)vma->vm_start,
267 (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
268 err);
269
270 return err;
271}
272
273static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
274{
275 struct soc_camera_file *icf = file->private_data;
276 struct soc_camera_device *icd = icf->icd;
277 struct soc_camera_host *ici =
278 to_soc_camera_host(icd->dev.parent);
279
280 if (list_empty(&icf->vb_vidq.stream)) {
281 dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
282 return POLLERR;
283 }
284
285 return ici->poll(file, pt);
286}
287
288
289static struct file_operations soc_camera_fops = {
290 .owner = THIS_MODULE,
291 .open = soc_camera_open,
292 .release = soc_camera_close,
293 .ioctl = video_ioctl2,
294 .read = soc_camera_read,
295 .mmap = soc_camera_mmap,
296 .poll = soc_camera_poll,
297 .llseek = no_llseek,
298};
299
300
301static int soc_camera_s_fmt_cap(struct file *file, void *priv,
302 struct v4l2_format *f)
303{
304 struct soc_camera_file *icf = file->private_data;
305 struct soc_camera_device *icd = icf->icd;
306 struct soc_camera_host *ici =
307 to_soc_camera_host(icd->dev.parent);
308 int ret;
309 struct v4l2_rect rect;
310 const static struct soc_camera_data_format *data_fmt;
311
312 WARN_ON(priv != file->private_data);
313
314 data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
315 if (!data_fmt)
316 return -EINVAL;
317
318 /* cached_datawidth may be further adjusted by the ici */
319 icd->cached_datawidth = data_fmt->depth;
320
321 ret = soc_camera_try_fmt_cap(file, icf, f);
322 if (ret < 0)
323 return ret;
324
325 rect.left = icd->x_current;
326 rect.top = icd->y_current;
327 rect.width = f->fmt.pix.width;
328 rect.height = f->fmt.pix.height;
329 ret = ici->set_capture_format(icd, f->fmt.pix.pixelformat, &rect);
330
331 if (!ret) {
332 icd->current_fmt = data_fmt;
333 icd->width = rect.width;
334 icd->height = rect.height;
335 icf->vb_vidq.field = f->fmt.pix.field;
336 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
337 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
338 f->type);
339
340 dev_dbg(&icd->dev, "set width: %d height: %d\n",
341 icd->width, icd->height);
342 }
343
344 return ret;
345}
346
347static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
348 struct v4l2_fmtdesc *f)
349{
350 struct soc_camera_file *icf = file->private_data;
351 struct soc_camera_device *icd = icf->icd;
352 const struct soc_camera_data_format *format;
353
354 WARN_ON(priv != file->private_data);
355
356 if (f->index >= icd->ops->num_formats)
357 return -EINVAL;
358
359 format = &icd->ops->formats[f->index];
360
361 strlcpy(f->description, format->name, sizeof(f->description));
362 f->pixelformat = format->fourcc;
363 return 0;
364}
365
366static int soc_camera_g_fmt_cap(struct file *file, void *priv,
367 struct v4l2_format *f)
368{
369 struct soc_camera_file *icf = file->private_data;
370 struct soc_camera_device *icd = icf->icd;
371
372 WARN_ON(priv != file->private_data);
373
374 f->fmt.pix.width = icd->width;
375 f->fmt.pix.height = icd->height;
376 f->fmt.pix.field = icf->vb_vidq.field;
377 f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
378 f->fmt.pix.bytesperline =
379 (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
380 f->fmt.pix.sizeimage =
381 f->fmt.pix.height * f->fmt.pix.bytesperline;
382 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
383 icd->current_fmt->fourcc);
384 return 0;
385}
386
387static int soc_camera_querycap(struct file *file, void *priv,
388 struct v4l2_capability *cap)
389{
390 struct soc_camera_file *icf = file->private_data;
391 struct soc_camera_device *icd = icf->icd;
392 struct soc_camera_host *ici =
393 to_soc_camera_host(icd->dev.parent);
394
395 WARN_ON(priv != file->private_data);
396
397 strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
398 return ici->querycap(ici, cap);
399}
400
401static int soc_camera_streamon(struct file *file, void *priv,
402 enum v4l2_buf_type i)
403{
404 struct soc_camera_file *icf = file->private_data;
405 struct soc_camera_device *icd = icf->icd;
406
407 WARN_ON(priv != file->private_data);
408
409 dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
410
411 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
412 return -EINVAL;
413
414 icd->ops->start_capture(icd);
415
416 /* This calls buf_queue from host driver's videobuf_queue_ops */
417 return videobuf_streamon(&icf->vb_vidq);
418}
419
420static int soc_camera_streamoff(struct file *file, void *priv,
421 enum v4l2_buf_type i)
422{
423 struct soc_camera_file *icf = file->private_data;
424 struct soc_camera_device *icd = icf->icd;
425
426 WARN_ON(priv != file->private_data);
427
428 dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
429
430 if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
431 return -EINVAL;
432
433 /* This calls buf_release from host driver's videobuf_queue_ops for all
434 * remaining buffers. When the last buffer is freed, stop capture */
435 videobuf_streamoff(&icf->vb_vidq);
436
437 icd->ops->stop_capture(icd);
438
439 return 0;
440}
441
442static int soc_camera_queryctrl(struct file *file, void *priv,
443 struct v4l2_queryctrl *qc)
444{
445 struct soc_camera_file *icf = file->private_data;
446 struct soc_camera_device *icd = icf->icd;
447 int i;
448
449 WARN_ON(priv != file->private_data);
450
451 if (!qc->id)
452 return -EINVAL;
453
454 for (i = 0; i < icd->ops->num_controls; i++)
455 if (qc->id == icd->ops->controls[i].id) {
456 memcpy(qc, &(icd->ops->controls[i]),
457 sizeof(*qc));
458 return 0;
459 }
460
461 return -EINVAL;
462}
463
464static int soc_camera_g_ctrl(struct file *file, void *priv,
465 struct v4l2_control *ctrl)
466{
467 struct soc_camera_file *icf = file->private_data;
468 struct soc_camera_device *icd = icf->icd;
469
470 WARN_ON(priv != file->private_data);
471
472 switch (ctrl->id) {
473 case V4L2_CID_GAIN:
474 if (icd->gain == (unsigned short)~0)
475 return -EINVAL;
476 ctrl->value = icd->gain;
477 return 0;
478 case V4L2_CID_EXPOSURE:
479 if (icd->exposure == (unsigned short)~0)
480 return -EINVAL;
481 ctrl->value = icd->exposure;
482 return 0;
483 }
484
485 if (icd->ops->get_control)
486 return icd->ops->get_control(icd, ctrl);
487 return -EINVAL;
488}
489
490static int soc_camera_s_ctrl(struct file *file, void *priv,
491 struct v4l2_control *ctrl)
492{
493 struct soc_camera_file *icf = file->private_data;
494 struct soc_camera_device *icd = icf->icd;
495
496 WARN_ON(priv != file->private_data);
497
498 if (icd->ops->set_control)
499 return icd->ops->set_control(icd, ctrl);
500 return -EINVAL;
501}
502
503static int soc_camera_cropcap(struct file *file, void *fh,
504 struct v4l2_cropcap *a)
505{
506 struct soc_camera_file *icf = file->private_data;
507 struct soc_camera_device *icd = icf->icd;
508
509 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
510 a->bounds.left = icd->x_min;
511 a->bounds.top = icd->y_min;
512 a->bounds.width = icd->width_max;
513 a->bounds.height = icd->height_max;
514 a->defrect.left = icd->x_min;
515 a->defrect.top = icd->y_min;
516 a->defrect.width = 640;
517 a->defrect.height = 480;
518 a->pixelaspect.numerator = 1;
519 a->pixelaspect.denominator = 1;
520
521 return 0;
522}
523
524static int soc_camera_g_crop(struct file *file, void *fh,
525 struct v4l2_crop *a)
526{
527 struct soc_camera_file *icf = file->private_data;
528 struct soc_camera_device *icd = icf->icd;
529
530 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
531 a->c.left = icd->x_current;
532 a->c.top = icd->y_current;
533 a->c.width = icd->width;
534 a->c.height = icd->height;
535
536 return 0;
537}
538
539static int soc_camera_s_crop(struct file *file, void *fh,
540 struct v4l2_crop *a)
541{
542 struct soc_camera_file *icf = file->private_data;
543 struct soc_camera_device *icd = icf->icd;
544 struct soc_camera_host *ici =
545 to_soc_camera_host(icd->dev.parent);
546 int ret;
547
548 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
549 return -EINVAL;
550
551 ret = ici->set_capture_format(icd, 0, &a->c);
552 if (!ret) {
553 icd->width = a->c.width;
554 icd->height = a->c.height;
555 icd->x_current = a->c.left;
556 icd->y_current = a->c.top;
557 }
558
559 return ret;
560}
561
562static int soc_camera_g_chip_ident(struct file *file, void *fh,
563 struct v4l2_chip_ident *id)
564{
565 struct soc_camera_file *icf = file->private_data;
566 struct soc_camera_device *icd = icf->icd;
567
568 if (!icd->ops->get_chip_id)
569 return -EINVAL;
570
571 return icd->ops->get_chip_id(icd, id);
572}
573
574#ifdef CONFIG_VIDEO_ADV_DEBUG
575static int soc_camera_g_register(struct file *file, void *fh,
576 struct v4l2_register *reg)
577{
578 struct soc_camera_file *icf = file->private_data;
579 struct soc_camera_device *icd = icf->icd;
580
581 if (!icd->ops->get_register)
582 return -EINVAL;
583
584 return icd->ops->get_register(icd, reg);
585}
586
587static int soc_camera_s_register(struct file *file, void *fh,
588 struct v4l2_register *reg)
589{
590 struct soc_camera_file *icf = file->private_data;
591 struct soc_camera_device *icd = icf->icd;
592
593 if (!icd->ops->set_register)
594 return -EINVAL;
595
596 return icd->ops->set_register(icd, reg);
597}
598#endif
599
600static int device_register_link(struct soc_camera_device *icd)
601{
602 int ret = device_register(&icd->dev);
603
604 if (ret < 0) {
605 /* Prevent calling device_unregister() */
606 icd->dev.parent = NULL;
607 dev_err(&icd->dev, "Cannot register device: %d\n", ret);
608 /* Even if probe() was unsuccessful for all registered drivers,
609 * device_register() returns 0, and we add the link, just to
610 * document this camera's control device */
611 } else if (icd->control)
612 /* Have to sysfs_remove_link() before device_unregister()? */
613 if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
614 "control"))
615 dev_warn(&icd->dev,
616 "Failed creating the control symlink\n");
617 return ret;
618}
619
620/* So far this function cannot fail */
621static void scan_add_host(struct soc_camera_host *ici)
622{
623 struct soc_camera_device *icd;
624
625 mutex_lock(&list_lock);
626
627 list_for_each_entry(icd, &devices, list) {
628 if (icd->iface == ici->nr) {
629 icd->dev.parent = &ici->dev;
630 device_register_link(icd);
631 }
632 }
633
634 mutex_unlock(&list_lock);
635}
636
637/* return: 0 if no match found or a match found and
638 * device_register() successful, error code otherwise */
639static int scan_add_device(struct soc_camera_device *icd)
640{
641 struct soc_camera_host *ici;
642 int ret = 0;
643
644 mutex_lock(&list_lock);
645
646 list_add_tail(&icd->list, &devices);
647
648 /* Watch out for class_for_each_device / class_find_device API by
649 * Dave Young <hidave.darkstar@gmail.com> */
650 list_for_each_entry(ici, &hosts, list) {
651 if (icd->iface == ici->nr) {
652 ret = 1;
653 icd->dev.parent = &ici->dev;
654 break;
655 }
656 }
657
658 mutex_unlock(&list_lock);
659
660 if (ret)
661 ret = device_register_link(icd);
662
663 return ret;
664}
665
666static int soc_camera_probe(struct device *dev)
667{
668 struct soc_camera_device *icd = to_soc_camera_dev(dev);
669 struct soc_camera_host *ici =
670 to_soc_camera_host(icd->dev.parent);
671 int ret;
672
673 if (!icd->probe)
674 return -ENODEV;
675
676 ret = ici->add(icd);
677 if (ret < 0)
678 return ret;
679
680 ret = icd->probe(icd);
681 if (ret < 0)
682 ici->remove(icd);
683 else {
684 const struct v4l2_queryctrl *qctrl;
685
686 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
687 icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
688 qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
689 icd->exposure = qctrl ? qctrl->default_value :
690 (unsigned short)~0;
691 }
692
693 return ret;
694}
695
696/* This is called on device_unregister, which only means we have to disconnect
697 * from the host, but not remove ourselves from the device list */
698static int soc_camera_remove(struct device *dev)
699{
700 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
704 if (icd->remove)
705 icd->remove(icd);
706
707 ici->remove(icd);
708
709 return 0;
710}
711
712static struct bus_type soc_camera_bus_type = {
713 .name = "soc-camera",
714 .probe = soc_camera_probe,
715 .remove = soc_camera_remove,
716};
717
718static struct device_driver ic_drv = {
719 .name = "camera",
720 .bus = &soc_camera_bus_type,
721 .owner = THIS_MODULE,
722};
723
724/*
725 * Image capture host - this is a host device, not a bus device, so,
726 * no bus reference, no probing.
727 */
728static struct class soc_camera_host_class = {
729 .owner = THIS_MODULE,
730 .name = "camera_host",
731};
732
733static void dummy_release(struct device *dev)
734{
735}
736
737int soc_camera_host_register(struct soc_camera_host *ici, struct module *owner)
738{
739 int ret;
740 struct soc_camera_host *ix;
741
742 if (!ici->vbq_ops || !ici->add || !ici->remove || !owner)
743 return -EINVAL;
744
745 /* Number might be equal to the platform device ID */
746 sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
747 ici->dev.class = &soc_camera_host_class;
748
749 mutex_lock(&list_lock);
750 list_for_each_entry(ix, &hosts, list) {
751 if (ix->nr == ici->nr) {
752 mutex_unlock(&list_lock);
753 return -EBUSY;
754 }
755 }
756
757 list_add_tail(&ici->list, &hosts);
758 mutex_unlock(&list_lock);
759
760 ici->owner = owner;
761 ici->dev.release = dummy_release;
762
763 ret = device_register(&ici->dev);
764
765 if (ret)
766 goto edevr;
767
768 scan_add_host(ici);
769
770 return 0;
771
772edevr:
773 mutex_lock(&list_lock);
774 list_del(&ici->list);
775 mutex_unlock(&list_lock);
776
777 return ret;
778}
779EXPORT_SYMBOL(soc_camera_host_register);
780
781/* Unregister all clients! */
782void soc_camera_host_unregister(struct soc_camera_host *ici)
783{
784 struct soc_camera_device *icd;
785
786 mutex_lock(&list_lock);
787
788 list_del(&ici->list);
789
790 list_for_each_entry(icd, &devices, list) {
791 if (icd->dev.parent == &ici->dev) {
792 device_unregister(&icd->dev);
793 /* Not before device_unregister(), .remove
794 * needs parent to call ici->remove() */
795 icd->dev.parent = NULL;
796 memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
797 }
798 }
799
800 mutex_unlock(&list_lock);
801
802 device_unregister(&ici->dev);
803}
804EXPORT_SYMBOL(soc_camera_host_unregister);
805
806/* Image capture device */
807int soc_camera_device_register(struct soc_camera_device *icd)
808{
809 struct soc_camera_device *ix;
810 int num = -1, i;
811
812 if (!icd)
813 return -EINVAL;
814
815 for (i = 0; i < 256 && num < 0; i++) {
816 num = i;
817 list_for_each_entry(ix, &devices, list) {
818 if (ix->iface == icd->iface && ix->devnum == i) {
819 num = -1;
820 break;
821 }
822 }
823 }
824
825 if (num < 0)
826 /* ok, we have 256 cameras on this host...
827 * man, stay reasonable... */
828 return -ENOMEM;
829
830 icd->devnum = num;
831 icd->dev.bus = &soc_camera_bus_type;
832 snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
833 "%u-%u", icd->iface, icd->devnum);
834
835 icd->dev.release = dummy_release;
836
837 if (icd->ops->get_datawidth)
838 icd->cached_datawidth = icd->ops->get_datawidth(icd);
839
840 return scan_add_device(icd);
841}
842EXPORT_SYMBOL(soc_camera_device_register);
843
844void soc_camera_device_unregister(struct soc_camera_device *icd)
845{
846 mutex_lock(&list_lock);
847 list_del(&icd->list);
848
849 /* The bus->remove will be eventually called */
850 if (icd->dev.parent)
851 device_unregister(&icd->dev);
852 mutex_unlock(&list_lock);
853}
854EXPORT_SYMBOL(soc_camera_device_unregister);
855
856int soc_camera_video_start(struct soc_camera_device *icd)
857{
858 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
859 int err = -ENOMEM;
860 struct video_device *vdev;
861
862 if (!icd->dev.parent)
863 return -ENODEV;
864
865 vdev = video_device_alloc();
866 if (!vdev)
867 goto evidallocd;
868 dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
869
870 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
871 /* Maybe better &ici->dev */
872 vdev->dev = &icd->dev;
873 vdev->type = VID_TYPE_CAPTURE;
874 vdev->current_norm = V4L2_STD_UNKNOWN;
875 vdev->fops = &soc_camera_fops;
876 vdev->release = video_device_release;
877 vdev->minor = -1;
878 vdev->tvnorms = V4L2_STD_UNKNOWN,
879 vdev->vidioc_querycap = soc_camera_querycap;
880 vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap;
881 vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
882 vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap;
883 vdev->vidioc_enum_input = soc_camera_enum_input;
884 vdev->vidioc_g_input = soc_camera_g_input;
885 vdev->vidioc_s_input = soc_camera_s_input;
886 vdev->vidioc_s_std = soc_camera_s_std;
887 vdev->vidioc_reqbufs = soc_camera_reqbufs;
888 vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
889 vdev->vidioc_querybuf = soc_camera_querybuf;
890 vdev->vidioc_qbuf = soc_camera_qbuf;
891 vdev->vidioc_dqbuf = soc_camera_dqbuf;
892 vdev->vidioc_streamon = soc_camera_streamon;
893 vdev->vidioc_streamoff = soc_camera_streamoff;
894 vdev->vidioc_queryctrl = soc_camera_queryctrl;
895 vdev->vidioc_g_ctrl = soc_camera_g_ctrl;
896 vdev->vidioc_s_ctrl = soc_camera_s_ctrl;
897 vdev->vidioc_cropcap = soc_camera_cropcap;
898 vdev->vidioc_g_crop = soc_camera_g_crop;
899 vdev->vidioc_s_crop = soc_camera_s_crop;
900 vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident;
901#ifdef CONFIG_VIDEO_ADV_DEBUG
902 vdev->vidioc_g_register = soc_camera_g_register;
903 vdev->vidioc_s_register = soc_camera_s_register;
904#endif
905
906 icd->current_fmt = &icd->ops->formats[0];
907
908 err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
909 if (err < 0) {
910 dev_err(vdev->dev, "video_register_device failed\n");
911 goto evidregd;
912 }
913 icd->vdev = vdev;
914
915 return 0;
916
917evidregd:
918 video_device_release(vdev);
919evidallocd:
920 return err;
921}
922EXPORT_SYMBOL(soc_camera_video_start);
923
924void soc_camera_video_stop(struct soc_camera_device *icd)
925{
926 struct video_device *vdev = icd->vdev;
927
928 dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
929
930 if (!icd->dev.parent || !vdev)
931 return;
932
933 mutex_lock(&video_lock);
934 video_unregister_device(vdev);
935 icd->vdev = NULL;
936 mutex_unlock(&video_lock);
937}
938EXPORT_SYMBOL(soc_camera_video_stop);
939
940static int __init soc_camera_init(void)
941{
942 int ret = bus_register(&soc_camera_bus_type);
943 if (ret)
944 return ret;
945 ret = driver_register(&ic_drv);
946 if (ret)
947 goto edrvr;
948 ret = class_register(&soc_camera_host_class);
949 if (ret)
950 goto eclr;
951
952 return 0;
953
954eclr:
955 driver_unregister(&ic_drv);
956edrvr:
957 bus_unregister(&soc_camera_bus_type);
958 return ret;
959}
960
961static void __exit soc_camera_exit(void)
962{
963 class_unregister(&soc_camera_host_class);
964 driver_unregister(&ic_drv);
965 bus_unregister(&soc_camera_bus_type);
966}
967
968module_init(soc_camera_init);
969module_exit(soc_camera_exit);
970
971MODULE_DESCRIPTION("Image capture bus driver");
972MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
973MODULE_LICENSE("GPL");