X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fsoc_camera.c;h=01c33841d1c6fc70feb9272768c42a7dce3b4a4d;hb=25c4d74ea6f07f2aaa3df537619680ba967043f5;hp=4af38d444e0c02a5cffd635464d98df1e2c4d0f7;hpb=26f1b942156766c6ff1a70fb2ac463c6fce31309;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 4af38d4..01c3384 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -25,7 +25,9 @@ #include #include +#include #include +#include #include static LIST_HEAD(hosts); @@ -33,8 +35,8 @@ static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); static DEFINE_MUTEX(video_lock); -const static struct soc_camera_data_format* -format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) +const struct soc_camera_data_format *soc_camera_format_by_fourcc( + struct soc_camera_device *icd, unsigned int fourcc) { unsigned int i; @@ -43,52 +45,35 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) return icd->formats + i; return NULL; } +EXPORT_SYMBOL(soc_camera_format_by_fourcc); -static int soc_camera_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); enum v4l2_field field; - const struct soc_camera_data_format *fmt; int ret; WARN_ON(priv != file->private_data); - fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!fmt) { - dev_dbg(&icd->dev, "invalid format 0x%08x\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc); - + /* + * TODO: this might also have to migrate to host-drivers, if anyone + * wishes to support other fields + */ field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_NONE; - } else if (V4L2_FIELD_NONE != field) { + f->fmt.pix.field = V4L2_FIELD_NONE; + } else if (field != V4L2_FIELD_NONE) { dev_err(&icd->dev, "Field type invalid.\n"); return -EINVAL; } - /* test physical bus parameters */ - ret = ici->try_bus_param(icd, f->fmt.pix.pixelformat); - if (ret) - return ret; - /* limit format to hardware capabilities */ - ret = ici->try_fmt_cap(icd, f); - - /* calculate missing fields */ - f->fmt.pix.field = field; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + ret = ici->ops->try_fmt_cap(icd, f); return ret; } @@ -137,15 +122,13 @@ static int soc_camera_reqbufs(struct file *file, void *priv, WARN_ON(priv != file->private_data); - dev_dbg(&icd->dev, "%s: %d\n", __FUNCTION__, p->memory); + dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory); ret = videobuf_reqbufs(&icf->vb_vidq, p); if (ret < 0) return ret; - return ici->reqbufs(icf, p); - - return ret; + return ici->ops->reqbufs(icf, p); } static int soc_camera_querybuf(struct file *file, void *priv, @@ -194,7 +177,7 @@ static int soc_camera_open(struct inode *inode, struct file *file) mutex_lock(&video_lock); vdev = video_devdata(file); - icd = container_of(vdev->dev, struct soc_camera_device, dev); + icd = container_of(vdev->parent, struct soc_camera_device, dev); ici = to_soc_camera_host(icd->dev.parent); if (!try_module_get(icd->ops->owner)) { @@ -203,19 +186,18 @@ static int soc_camera_open(struct inode *inode, struct file *file) goto emgd; } - if (!try_module_get(ici->owner)) { + if (!try_module_get(ici->ops->owner)) { dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); ret = -EINVAL; goto emgi; } - icd->use_count++; - icf->icd = icd; + icd->use_count++; /* Now we really have to activate the camera */ if (icd->use_count == 1) { - ret = ici->add(icd); + ret = ici->ops->add(icd); if (ret < 0) { dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); icd->use_count--; @@ -228,17 +210,13 @@ static int soc_camera_open(struct inode *inode, struct file *file) file->private_data = icf; dev_dbg(&icd->dev, "camera device open\n"); - /* We must pass NULL as dev pointer, then all pci_* dma operations - * transform to normal dma_* ones. Do we need an irqlock? */ - videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, NULL, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - ici->msize, icd); + ici->ops->init_videobuf(&icf->vb_vidq, icd); return 0; /* All errors are entered with the video_lock held */ eiciadd: - module_put(ici->owner); + module_put(ici->ops->owner); emgi: module_put(icd->ops->owner); emgd: @@ -257,27 +235,27 @@ static int soc_camera_close(struct inode *inode, struct file *file) mutex_lock(&video_lock); icd->use_count--; if (!icd->use_count) - ici->remove(icd); + ici->ops->remove(icd); module_put(icd->ops->owner); - module_put(ici->owner); + module_put(ici->ops->owner); mutex_unlock(&video_lock); - vfree(file->private_data); + vfree(icf); - dev_dbg(vdev->dev, "camera device close\n"); + dev_dbg(vdev->parent, "camera device close\n"); return 0; } static ssize_t soc_camera_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; struct video_device *vdev = icd->vdev; int err = -EINVAL; - dev_err(vdev->dev, "camera device read not implemented\n"); + dev_err(vdev->parent, "camera device read not implemented\n"); return err; } @@ -312,10 +290,9 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) return POLLERR; } - return ici->poll(file, pt); + return ici->ops->poll(file, pt); } - static struct file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, @@ -327,9 +304,8 @@ static struct file_operations soc_camera_fops = { .llseek = no_llseek, }; - -static int soc_camera_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -337,18 +313,10 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, to_soc_camera_host(icd->dev.parent); int ret; struct v4l2_rect rect; - const static struct soc_camera_data_format *data_fmt; WARN_ON(priv != file->private_data); - data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!data_fmt) - return -EINVAL; - - /* buswidth may be further adjusted by the ici */ - icd->buswidth = data_fmt->depth; - - ret = soc_camera_try_fmt_cap(file, icf, f); + ret = soc_camera_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; @@ -356,15 +324,22 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, rect.top = icd->y_current; rect.width = f->fmt.pix.width; rect.height = f->fmt.pix.height; - ret = ici->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); - if (ret < 0) + ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); + if (ret < 0) { return ret; + } else if (!icd->current_fmt || + icd->current_fmt->fourcc != f->fmt.pix.pixelformat) { + dev_err(&ici->dev, "Host driver hasn't set up current " + "format correctly!\n"); + return -EINVAL; + } - icd->current_fmt = data_fmt; + /* buswidth may be further adjusted by the ici */ + icd->buswidth = icd->current_fmt->depth; icd->width = rect.width; icd->height = rect.height; icf->vb_vidq.field = f->fmt.pix.field; - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -372,11 +347,11 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv, icd->width, icd->height); /* set physical bus parameters */ - return ici->set_bus_param(icd, f->fmt.pix.pixelformat); + return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat); } -static int soc_camera_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -394,8 +369,8 @@ static int soc_camera_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int soc_camera_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -406,10 +381,9 @@ static int soc_camera_g_fmt_cap(struct file *file, void *priv, f->fmt.pix.height = icd->height; f->fmt.pix.field = icf->vb_vidq.field; f->fmt.pix.pixelformat = icd->current_fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * icd->current_fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(icd->current_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", icd->current_fmt->fourcc); return 0; @@ -426,7 +400,7 @@ static int soc_camera_querycap(struct file *file, void *priv, WARN_ON(priv != file->private_data); strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver)); - return ici->querycap(ici, cap); + return ici->ops->querycap(ici, cap); } static int soc_camera_streamon(struct file *file, void *priv, @@ -437,7 +411,7 @@ static int soc_camera_streamon(struct file *file, void *priv, WARN_ON(priv != file->private_data); - dev_dbg(&icd->dev, "%s\n", __FUNCTION__); + dev_dbg(&icd->dev, "%s\n", __func__); if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -456,7 +430,7 @@ static int soc_camera_streamoff(struct file *file, void *priv, WARN_ON(priv != file->private_data); - dev_dbg(&icd->dev, "%s\n", __FUNCTION__); + dev_dbg(&icd->dev, "%s\n", __func__); if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -579,7 +553,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = ici->set_fmt_cap(icd, 0, &a->c); + ret = ici->ops->set_fmt_cap(icd, 0, &a->c); if (!ret) { icd->width = a->c.width; icd->height = a->c.height; @@ -706,7 +680,7 @@ static int soc_camera_probe(struct device *dev) /* We only call ->add() here to activate and probe the camera. * We shall ->remove() and deactivate it immediately afterwards. */ - ret = ici->add(icd); + ret = ici->ops->add(icd); if (ret < 0) return ret; @@ -720,7 +694,7 @@ static int soc_camera_probe(struct device *dev) icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0; } - ici->remove(icd); + ici->ops->remove(icd); return ret; } @@ -737,10 +711,36 @@ static int soc_camera_remove(struct device *dev) return 0; } +static int soc_camera_suspend(struct device *dev, pm_message_t state) +{ + struct soc_camera_device *icd = to_soc_camera_dev(dev); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int ret = 0; + + if (ici->ops->suspend) + ret = ici->ops->suspend(icd, state); + + return ret; +} + +static int soc_camera_resume(struct device *dev) +{ + struct soc_camera_device *icd = to_soc_camera_dev(dev); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int ret = 0; + + if (ici->ops->resume) + ret = ici->ops->resume(icd); + + return ret; +} + static struct bus_type soc_camera_bus_type = { .name = "soc-camera", .probe = soc_camera_probe, .remove = soc_camera_remove, + .suspend = soc_camera_suspend, + .resume = soc_camera_resume, }; static struct device_driver ic_drv = { @@ -749,30 +749,20 @@ static struct device_driver ic_drv = { .owner = THIS_MODULE, }; -/* - * Image capture host - this is a host device, not a bus device, so, - * no bus reference, no probing. - */ -static struct class soc_camera_host_class = { - .owner = THIS_MODULE, - .name = "camera_host", -}; - static void dummy_release(struct device *dev) { } -int soc_camera_host_register(struct soc_camera_host *ici, struct module *owner) +int soc_camera_host_register(struct soc_camera_host *ici) { int ret; struct soc_camera_host *ix; - if (!ici->vbq_ops || !ici->add || !ici->remove || !owner) + if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove) return -EINVAL; /* Number might be equal to the platform device ID */ - sprintf(ici->dev.bus_id, "camera_host%d", ici->nr); - ici->dev.class = &soc_camera_host_class; + dev_set_name(&ici->dev, "camera_host%d", ici->nr); mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { @@ -785,7 +775,6 @@ int soc_camera_host_register(struct soc_camera_host *ici, struct module *owner) list_add_tail(&ici->list, &hosts); mutex_unlock(&list_lock); - ici->owner = owner; ici->dev.release = dummy_release; ret = device_register(&ici->dev); @@ -819,7 +808,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) if (icd->dev.parent == &ici->dev) { device_unregister(&icd->dev); /* Not before device_unregister(), .remove - * needs parent to call ici->remove() */ + * needs parent to call ici->ops->remove() */ icd->dev.parent = NULL; memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj)); } @@ -857,8 +846,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) icd->devnum = num; icd->dev.bus = &soc_camera_bus_type; - snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id), - "%u-%u", icd->iface, icd->devnum); + dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); icd->dev.release = dummy_release; @@ -878,6 +866,35 @@ void soc_camera_device_unregister(struct soc_camera_device *icd) } EXPORT_SYMBOL(soc_camera_device_unregister); +static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { + .vidioc_querycap = soc_camera_querycap, + .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, + .vidioc_enum_input = soc_camera_enum_input, + .vidioc_g_input = soc_camera_g_input, + .vidioc_s_input = soc_camera_s_input, + .vidioc_s_std = soc_camera_s_std, + .vidioc_reqbufs = soc_camera_reqbufs, + .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, + .vidioc_querybuf = soc_camera_querybuf, + .vidioc_qbuf = soc_camera_qbuf, + .vidioc_dqbuf = soc_camera_dqbuf, + .vidioc_streamon = soc_camera_streamon, + .vidioc_streamoff = soc_camera_streamoff, + .vidioc_queryctrl = soc_camera_queryctrl, + .vidioc_g_ctrl = soc_camera_g_ctrl, + .vidioc_s_ctrl = soc_camera_s_ctrl, + .vidioc_cropcap = soc_camera_cropcap, + .vidioc_g_crop = soc_camera_g_crop, + .vidioc_s_crop = soc_camera_s_crop, + .vidioc_g_chip_ident = soc_camera_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = soc_camera_g_register, + .vidioc_s_register = soc_camera_s_register, +#endif +}; + int soc_camera_video_start(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); @@ -894,45 +911,19 @@ int soc_camera_video_start(struct soc_camera_device *icd) strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); /* Maybe better &ici->dev */ - vdev->dev = &icd->dev; - vdev->type = VID_TYPE_CAPTURE; + vdev->parent = &icd->dev; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; + vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN, - vdev->vidioc_querycap = soc_camera_querycap; - vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap; - vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap; - vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap; - vdev->vidioc_enum_input = soc_camera_enum_input; - vdev->vidioc_g_input = soc_camera_g_input; - vdev->vidioc_s_input = soc_camera_s_input; - vdev->vidioc_s_std = soc_camera_s_std; - vdev->vidioc_reqbufs = soc_camera_reqbufs; - vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap; - vdev->vidioc_querybuf = soc_camera_querybuf; - vdev->vidioc_qbuf = soc_camera_qbuf; - vdev->vidioc_dqbuf = soc_camera_dqbuf; - vdev->vidioc_streamon = soc_camera_streamon; - vdev->vidioc_streamoff = soc_camera_streamoff; - vdev->vidioc_queryctrl = soc_camera_queryctrl; - vdev->vidioc_g_ctrl = soc_camera_g_ctrl; - vdev->vidioc_s_ctrl = soc_camera_s_ctrl; - vdev->vidioc_cropcap = soc_camera_cropcap; - vdev->vidioc_g_crop = soc_camera_g_crop; - vdev->vidioc_s_crop = soc_camera_s_crop; - vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident; -#ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = soc_camera_g_register; - vdev->vidioc_s_register = soc_camera_s_register; -#endif icd->current_fmt = &icd->formats[0]; err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); if (err < 0) { - dev_err(vdev->dev, "video_register_device failed\n"); + dev_err(vdev->parent, "video_register_device failed\n"); goto evidregd; } icd->vdev = vdev; @@ -950,7 +941,7 @@ void soc_camera_video_stop(struct soc_camera_device *icd) { struct video_device *vdev = icd->vdev; - dev_dbg(&icd->dev, "%s\n", __FUNCTION__); + dev_dbg(&icd->dev, "%s\n", __func__); if (!icd->dev.parent || !vdev) return; @@ -970,14 +961,9 @@ static int __init soc_camera_init(void) ret = driver_register(&ic_drv); if (ret) goto edrvr; - ret = class_register(&soc_camera_host_class); - if (ret) - goto eclr; return 0; -eclr: - driver_unregister(&ic_drv); edrvr: bus_unregister(&soc_camera_bus_type); return ret; @@ -985,7 +971,6 @@ edrvr: static void __exit soc_camera_exit(void) { - class_unregister(&soc_camera_host_class); driver_unregister(&ic_drv); bus_unregister(&soc_camera_bus_type); }