From ada365c021ff668eae8fa17042a39d33a4cdf4e1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: separate S_FMT and S_CROP operations From: Guennadi Liakhovetski As host and camera drivers become more complex, differences between S_FMT and S_CROP functionality grow, this patch separates them. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/mt9m001.c | 19 +++- drivers/media/video/mt9m111.c | 56 +++++++--- drivers/media/video/mt9t031.c | 84 ++++++++++------ drivers/media/video/mt9v022.c | 62 +++++++---- drivers/media/video/mx3_camera.c | 157 +++++++++++++++++----------- drivers/media/video/ov772x.c | 31 +++++- drivers/media/video/pxa_camera.c | 67 +++++++++--- drivers/media/video/sh_mobile_ceu_camera.c | 17 ++- drivers/media/video/soc_camera.c | 20 ++-- drivers/media/video/soc_camera_platform.c | 9 ++- drivers/media/video/tw9910.c | 45 +++++--- include/media/soc_camera.h | 6 +- 12 files changed, 381 insertions(+), 192 deletions(-) --- linux/drivers/media/video/soc_camera.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 356b77e10..4c2a784fb 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -418,9 +418,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct v4l2_pix_format *pix = &f->fmt.pix; - __u32 pixfmt = pix->pixelformat; int ret; - struct v4l2_rect rect; WARN_ON(priv != file->private_data); @@ -436,23 +434,19 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, goto unlock; } - rect.left = icd->x_current; - rect.top = icd->y_current; - rect.width = pix->width; - rect.height = pix->height; - ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); + ret = ici->ops->set_fmt(icd, f); if (ret < 0) { goto unlock; } else if (!icd->current_fmt || - icd->current_fmt->fourcc != pixfmt) { + icd->current_fmt->fourcc != pix->pixelformat) { dev_err(&ici->dev, "Host driver hasn't set up current format correctly!\n"); ret = -EINVAL; goto unlock; } - icd->width = rect.width; - icd->height = rect.height; + icd->width = f->fmt.pix.width; + icd->height = f->fmt.pix.height; icf->vb_vidq.field = pix->field; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", @@ -462,7 +456,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, icd->width, icd->height); /* set physical bus parameters */ - ret = ici->ops->set_bus_param(icd, pixfmt); + ret = ici->ops->set_bus_param(icd, pix->pixelformat); unlock: mutex_unlock(&icf->vb_vidq.vb_lock); @@ -686,7 +680,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, /* Cropping is allowed during a running capture, guard consistency */ mutex_lock(&icf->vb_vidq.vb_lock); - ret = ici->ops->set_fmt(icd, 0, &a->c); + ret = ici->ops->set_crop(icd, &a->c); if (!ret) { icd->width = a->c.width; icd->height = a->c.height; @@ -919,6 +913,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) if (!ici || !ici->ops || !ici->ops->try_fmt || !ici->ops->set_fmt || + !ici->ops->set_crop || !ici->ops->set_bus_param || !ici->ops->querycap || !ici->ops->init_videobuf || @@ -999,6 +994,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) !icd->ops->release || !icd->ops->start_capture || !icd->ops->stop_capture || + !icd->ops->set_crop || !icd->ops->set_fmt || !icd->ops->try_fmt || !icd->ops->query_bus_param || -- cgit v1.2.3 From 7bc0a7a6ccbab2bff6c1ed73297765e4855db4be Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: configure drivers with a default format on open From: Guennadi Liakhovetski Currently soc-camera doesn't set up any image format without an explicit S_FMT. It seems this should be supported, since, for example, capture-example.c from v4l2-apps by default doesn't issue an S_FMT. This patch configures a default image format on open(). Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 100 ++++++++++++++++++++++++++------------ 1 files changed, 68 insertions(+), 32 deletions(-) --- linux/drivers/media/video/soc_camera.c | 100 ++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 32 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 4c2a784fb..10d8ecad1 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -31,6 +31,10 @@ #include #include "compat.h" +/* Default to VGA resolution */ +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 + static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); @@ -257,6 +261,44 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) vfree(icd->user_formats); } +/* Called with .vb_lock held */ +static int soc_camera_set_fmt(struct soc_camera_file *icf, + struct v4l2_format *f) +{ + struct soc_camera_device *icd = icf->icd; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + /* We always call try_fmt() before set_fmt() or set_crop() */ + ret = ici->ops->try_fmt(icd, f); + if (ret < 0) + return ret; + + ret = ici->ops->set_fmt(icd, f); + if (ret < 0) { + return ret; + } else if (!icd->current_fmt || + icd->current_fmt->fourcc != pix->pixelformat) { + dev_err(&ici->dev, + "Host driver hasn't set up current format correctly!\n"); + return -EINVAL; + } + + icd->width = pix->width; + icd->height = pix->height; + icf->vb_vidq.field = pix->field; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", + f->type); + + dev_dbg(&icd->dev, "set width: %d height: %d\n", + icd->width, icd->height); + + /* set physical bus parameters */ + return ici->ops->set_bus_param(icd, pix->pixelformat); +} + static int soc_camera_open(struct file *file) { struct video_device *vdev; @@ -298,6 +340,15 @@ static int soc_camera_open(struct file *file) /* Now we really have to activate the camera */ if (icd->use_count == 1) { + struct v4l2_format f = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt.pix = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .field = V4L2_FIELD_ANY, + }, + }; + ret = soc_camera_init_user_formats(icd); if (ret < 0) goto eiufmt; @@ -306,6 +357,14 @@ static int soc_camera_open(struct file *file) dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); goto eiciadd; } + + f.fmt.pix.pixelformat = icd->current_fmt->fourcc; + f.fmt.pix.colorspace = icd->current_fmt->colorspace; + + /* Try to configure with default parameters */ + ret = soc_camera_set_fmt(icf, &f); + if (ret < 0) + goto esfmt; } mutex_unlock(&icd->video_lock); @@ -317,7 +376,12 @@ static int soc_camera_open(struct file *file) return 0; - /* First two errors are entered with the .video_lock held */ + /* + * First three errors are entered with the .video_lock held + * and use_count == 1 + */ +esfmt: + ici->ops->remove(icd); eiciadd: soc_camera_free_user_formats(icd); eiufmt: @@ -416,16 +480,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, { 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); - struct v4l2_pix_format *pix = &f->fmt.pix; int ret; WARN_ON(priv != file->private_data); - ret = soc_camera_try_fmt_vid_cap(file, priv, f); - if (ret < 0) - return ret; - mutex_lock(&icf->vb_vidq.vb_lock); if (videobuf_queue_is_busy(&icf->vb_vidq)) { @@ -434,29 +492,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, goto unlock; } - ret = ici->ops->set_fmt(icd, f); - if (ret < 0) { - goto unlock; - } else if (!icd->current_fmt || - icd->current_fmt->fourcc != pix->pixelformat) { - dev_err(&ici->dev, - "Host driver hasn't set up current format correctly!\n"); - ret = -EINVAL; - goto unlock; - } - - icd->width = f->fmt.pix.width; - icd->height = f->fmt.pix.height; - icf->vb_vidq.field = pix->field; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", - f->type); - - dev_dbg(&icd->dev, "set width: %d height: %d\n", - icd->width, icd->height); - - /* set physical bus parameters */ - ret = ici->ops->set_bus_param(icd, pix->pixelformat); + ret = soc_camera_set_fmt(icf, f); unlock: mutex_unlock(&icf->vb_vidq.vb_lock); @@ -643,8 +679,8 @@ static int soc_camera_cropcap(struct file *file, void *fh, a->bounds.height = icd->height_max; a->defrect.left = icd->x_min; a->defrect.top = icd->y_min; - a->defrect.width = 640; - a->defrect.height = 480; + a->defrect.width = DEFAULT_WIDTH; + a->defrect.height = DEFAULT_HEIGHT; a->pixelaspect.numerator = 1; a->pixelaspect.denominator = 1; -- cgit v1.2.3 From a00a0b74b7fe24e815f70f49ac8b8cc073cdad80 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: configure drivers with a default format at probe time From: Guennadi Liakhovetski Currently soc-camera doesn't set up any image format without an explicit S_FMT. According to the API this should be supported, for example, capture-example.c from v4l2-apps by default doesn't issue an S_FMT. This patch moves negotiating of available host-camera format translations to probe() time, and restores the state from the last close() on the next open(). This is needed for some drivers, which power down or reset hardware after the last user closes the interface. This patch also has a nice side-effect of avoiding multiple allocation anf freeing of format translation tables. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 39 ++++++++++++++++++++++--------------- include/media/soc_camera.h | 1 + 2 files changed, 24 insertions(+), 16 deletions(-) --- linux/drivers/media/video/soc_camera.c | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 10d8ecad1..da6d224eb 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -287,7 +287,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, icd->width = pix->width; icd->height = pix->height; - icf->vb_vidq.field = pix->field; + icf->vb_vidq.field = + icd->field = pix->field; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -340,27 +342,24 @@ static int soc_camera_open(struct file *file) /* Now we really have to activate the camera */ if (icd->use_count == 1) { + /* Restore parameters before the last close() per V4L2 API */ struct v4l2_format f = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt.pix = { - .width = DEFAULT_WIDTH, - .height = DEFAULT_HEIGHT, - .field = V4L2_FIELD_ANY, + .width = icd->width, + .height = icd->height, + .field = icd->field, + .pixelformat = icd->current_fmt->fourcc, + .colorspace = icd->current_fmt->colorspace, }, }; - ret = soc_camera_init_user_formats(icd); - if (ret < 0) - goto eiufmt; ret = ici->ops->add(icd); if (ret < 0) { dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); goto eiciadd; } - f.fmt.pix.pixelformat = icd->current_fmt->fourcc; - f.fmt.pix.colorspace = icd->current_fmt->colorspace; - /* Try to configure with default parameters */ ret = soc_camera_set_fmt(icf, &f); if (ret < 0) @@ -383,8 +382,6 @@ static int soc_camera_open(struct file *file) esfmt: ici->ops->remove(icd); eiciadd: - soc_camera_free_user_formats(icd); -eiufmt: icd->use_count--; mutex_unlock(&icd->video_lock); module_put(ici->ops->owner); @@ -404,10 +401,9 @@ static int soc_camera_close(struct file *file) mutex_lock(&icd->video_lock); icd->use_count--; - if (!icd->use_count) { + if (!icd->use_count) ici->ops->remove(icd); - soc_camera_free_user_formats(icd); - } + mutex_unlock(&icd->video_lock); module_put(icd->ops->owner); @@ -875,9 +871,18 @@ static int soc_camera_probe(struct device *dev) qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0; + + ret = soc_camera_init_user_formats(icd); + if (ret < 0) + goto eiufmt; + + icd->height = DEFAULT_HEIGHT; + icd->width = DEFAULT_WIDTH; + icd->field = V4L2_FIELD_ANY; } - ici->ops->remove(icd); +eiufmt: + ici->ops->remove(icd); eiadd: mutex_unlock(&icd->video_lock); module_put(ici->ops->owner); @@ -896,6 +901,8 @@ static int soc_camera_remove(struct device *dev) if (icd->ops->remove) icd->ops->remove(icd); + soc_camera_free_user_formats(icd); + return 0; } -- cgit v1.2.3 From 894ef336d9eaaf5528b4e796e4d2c86b45c59b9b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 31 Mar 2009 08:44:22 +0200 Subject: soc-camera: fix breakage caused by 1fa5ae857bb14f6046205171d98506d8112dd74e From: Guennadi Liakhovetski soc-camera re-uses struct devices multiple times in calls to device_register(), therefore it has to reset the embedded struct kobject to avoid the "tried to init an initialized object" error, which then also erases its name. Now with the transition to kobject's name for device names, we have to re-initialise the name before each call to device_register(). Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) --- linux/drivers/media/video/soc_camera.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index da6d224eb..9e432d390 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -765,7 +765,10 @@ static int soc_camera_s_register(struct file *file, void *fh, static int device_register_link(struct soc_camera_device *icd) { - int ret = device_register(&icd->dev); + int ret = dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); + + if (!ret) + ret = device_register(&icd->dev); if (ret < 0) { /* Prevent calling device_unregister() */ @@ -1061,7 +1064,6 @@ int soc_camera_device_register(struct soc_camera_device *icd) icd->devnum = num; icd->dev.bus = &soc_camera_bus_type; - dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); icd->dev.release = dummy_release; icd->use_count = 0; -- cgit v1.2.3 From 0d6bf4267e7a2b8a78e1e92da9a4545bc82d29c5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 24 Apr 2009 17:55:48 +0200 Subject: soc-camera: remove an extra device generation from struct soc_camera_host From: Guennadi Liakhovetski Make camera devices direct children of host platform devices, move the inheritance management into the soc_camera.c core driver. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/mx1_camera.c | 35 +++++----- drivers/media/video/mx3_camera.c | 40 ++++++------ drivers/media/video/pxa_camera.c | 97 ++++++++++++++-------------- drivers/media/video/sh_mobile_ceu_camera.c | 21 +++--- drivers/media/video/soc_camera.c | 35 +++------- include/media/soc_camera.h | 4 +- 6 files changed, 107 insertions(+), 125 deletions(-) --- linux/drivers/media/video/soc_camera.c | 35 ++++++++++------------------------ 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 9e432d390..9dca8f470 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -280,7 +280,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, return ret; } else if (!icd->current_fmt || icd->current_fmt->fourcc != pix->pixelformat) { - dev_err(&ici->dev, + dev_err(ici->dev, "Host driver hasn't set up current format correctly!\n"); return -EINVAL; } @@ -795,7 +795,7 @@ static void scan_add_host(struct soc_camera_host *ici) list_for_each_entry(icd, &devices, list) { if (icd->iface == ici->nr) { - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; device_register_link(icd); } } @@ -819,7 +819,7 @@ static int scan_add_device(struct soc_camera_device *icd) list_for_each_entry(ici, &hosts, list) { if (icd->iface == ici->nr) { ret = 1; - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; break; } } @@ -953,7 +953,6 @@ static void dummy_release(struct device *dev) int soc_camera_host_register(struct soc_camera_host *ici) { - int ret; struct soc_camera_host *ix; if (!ici || !ici->ops || @@ -966,12 +965,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) !ici->ops->reqbufs || !ici->ops->add || !ici->ops->remove || - !ici->ops->poll) + !ici->ops->poll || + !ici->dev) return -EINVAL; - /* Number might be equal to the platform device ID */ - dev_set_name(&ici->dev, "camera_host%d", ici->nr); - mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { if (ix->nr == ici->nr) { @@ -980,26 +977,14 @@ int soc_camera_host_register(struct soc_camera_host *ici) } } + dev_set_drvdata(ici->dev, ici); + list_add_tail(&ici->list, &hosts); mutex_unlock(&list_lock); - ici->dev.release = dummy_release; - - ret = device_register(&ici->dev); - - if (ret) - goto edevr; - scan_add_host(ici); return 0; - -edevr: - mutex_lock(&list_lock); - list_del(&ici->list); - mutex_unlock(&list_lock); - - return ret; } EXPORT_SYMBOL(soc_camera_host_register); @@ -1013,7 +998,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) list_del(&ici->list); list_for_each_entry(icd, &devices, list) { - if (icd->dev.parent == &ici->dev) { + if (icd->dev.parent == ici->dev) { device_unregister(&icd->dev); /* Not before device_unregister(), .remove * needs parent to call ici->ops->remove() */ @@ -1024,7 +1009,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) mutex_unlock(&list_lock); - device_unregister(&ici->dev); + dev_set_drvdata(ici->dev, NULL); } EXPORT_SYMBOL(soc_camera_host_unregister); @@ -1131,7 +1116,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev = video_device_alloc(); if (!vdev) goto evidallocd; - dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); + dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); -- cgit v1.2.3 From ee56997de9033d06c740726754437b09ddebb039 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 May 2009 18:25:32 +0200 Subject: soc-camera: prepare for the platform driver conversion Add a platform driver to soc_camera.c. This way we preserve backwards compatibility with existing platforms and can start converting them one by one to the new platform-device soc-camera interface. Signed-off-by: Guennadi Liakhovetski --- linux/drivers/media/video/soc_camera.c | 71 +++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 9dca8f470..f792ab2e5 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -16,19 +16,21 @@ * published by the Free Software Foundation. */ -#include -#include #include -#include #include +#include +#include +#include +#include #include +#include #include +#include #include -#include #include +#include #include -#include #include "compat.h" /* Default to VGA resolution */ @@ -1160,6 +1162,57 @@ void soc_camera_video_stop(struct soc_camera_device *icd) } EXPORT_SYMBOL(soc_camera_video_stop); +static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) +{ + struct soc_camera_link *icl = pdev->dev.platform_data; + struct i2c_adapter *adap; + struct i2c_client *client; + + if (!icl) + return -EINVAL; + + adap = i2c_get_adapter(icl->i2c_adapter_id); + if (!adap) { + dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n", + icl->i2c_adapter_id); + /* -ENODEV and -ENXIO do not produce an error on probe()... */ + return -ENOENT; + } + + icl->board_info->platform_data = icl; + client = i2c_new_device(adap, icl->board_info); + if (!client) { + i2c_put_adapter(adap); + return -ENOMEM; + } + + platform_set_drvdata(pdev, client); + + return 0; +} + +static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) +{ + struct i2c_client *client = platform_get_drvdata(pdev); + + if (!client) + return -ENODEV; + + i2c_unregister_device(client); + i2c_put_adapter(client->adapter); + + return 0; +} + +static struct platform_driver soc_camera_pdrv = { + .probe = soc_camera_pdrv_probe, + .remove = __exit_p(soc_camera_pdrv_remove), + .driver = { + .name = "soc-camera-pdrv", + .owner = THIS_MODULE, + }, +}; + static int __init soc_camera_init(void) { int ret = bus_register(&soc_camera_bus_type); @@ -1169,8 +1222,14 @@ static int __init soc_camera_init(void) if (ret) goto edrvr; + ret = platform_driver_register(&soc_camera_pdrv); + if (ret) + goto epdr; + return 0; +epdr: + driver_unregister(&ic_drv); edrvr: bus_unregister(&soc_camera_bus_type); return ret; @@ -1178,6 +1237,7 @@ edrvr: static void __exit soc_camera_exit(void) { + platform_driver_unregister(&soc_camera_pdrv); driver_unregister(&ic_drv); bus_unregister(&soc_camera_bus_type); } @@ -1188,3 +1248,4 @@ module_exit(soc_camera_exit); MODULE_DESCRIPTION("Image capture bus driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:soc-camera-pdrv"); -- cgit v1.2.3 From e45c6d33fbee270c6642910bd7d706d602d72914 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 9 May 2009 21:40:45 +0200 Subject: soc-camera: Fix section mismatch warning From: Guennadi Liakhovetski modpost needs a __refdata marker in driver structs to ensure references to .probe and .remove functions from .devinit.text and .devexit.text sections respectively are valid. Add __refdata to soc_camera_pdrv platform driver. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) --- linux/drivers/media/video/soc_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index f792ab2e5..822052b25 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -1204,7 +1204,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) return 0; } -static struct platform_driver soc_camera_pdrv = { +static struct platform_driver __refdata soc_camera_pdrv = { .probe = soc_camera_pdrv_probe, .remove = __exit_p(soc_camera_pdrv_remove), .driver = { -- cgit v1.2.3 From 337800edfc26abd2a7b3a13733836f35244d8ca5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 4 Jun 2009 14:07:16 +0000 Subject: Add missing __devexit_p() From: Jean Delvare Add missing __devexit_p() to several drivers. Also add a few missing __init, __devinit and __exit markers. These errors could result in build failures depending on the kernel configuration. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/soc_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 822052b25..e4056a9c2 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -1206,7 +1206,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) static struct platform_driver __refdata soc_camera_pdrv = { .probe = soc_camera_pdrv_probe, - .remove = __exit_p(soc_camera_pdrv_remove), + .remove = __devexit_p(soc_camera_pdrv_remove), .driver = { .name = "soc-camera-pdrv", .owner = THIS_MODULE, -- cgit v1.2.3 From 12ca65f34438319e101f46e652524f0229f5bb74 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Jun 2009 15:31:25 +0200 Subject: soc_camera: Fix debug output of supported formats count From: Stefan Herbrechtsmeier The supported formats count must be set to 0 after debug output right before the second pass. Signed-off-by: Stefan Herbrechtsmeier Signed-off-by: Guennadi Liakhovetski Priority: high --- drivers/media/video/soc_camera.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) --- linux/drivers/media/video/soc_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index e4056a9c2..711e14109 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -238,11 +238,11 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) return -ENOMEM; icd->num_user_formats = fmts; - fmts = 0; dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); /* Second pass - actually fill data formats */ + fmts = 0; for (i = 0; i < icd->num_formats; i++) if (!ici->ops->get_formats) { icd->user_formats[i].host_fmt = icd->formats + i; -- cgit v1.2.3 From 23fc368d1e39ccddfbbf74673e172d7c3e8391aa Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Jun 2009 15:31:25 +0200 Subject: soc-camera: fix missing clean up on error path From: Guennadi Liakhovetski If soc_camera_init_user_formats() fails in soc_camera_probe(), we have to call client's .remove() method to unregister the video device. Reported-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski Priority: high --- drivers/media/video/soc_camera.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) --- linux/drivers/media/video/soc_camera.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 711e14109..4f315c1b7 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -878,8 +878,11 @@ static int soc_camera_probe(struct device *dev) (unsigned short)~0; ret = soc_camera_init_user_formats(icd); - if (ret < 0) + if (ret < 0) { + if (icd->ops->remove) + icd->ops->remove(icd); goto eiufmt; + } icd->height = DEFAULT_HEIGHT; icd->width = DEFAULT_WIDTH; @@ -903,8 +906,10 @@ static int soc_camera_remove(struct device *dev) { struct soc_camera_device *icd = to_soc_camera_dev(dev); + mutex_lock(&icd->video_lock); if (icd->ops->remove) icd->ops->remove(icd); + mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); @@ -1146,6 +1151,7 @@ evidallocd: } EXPORT_SYMBOL(soc_camera_video_start); +/* Called from client .remove() methods with .video_lock held */ void soc_camera_video_stop(struct soc_camera_device *icd) { struct video_device *vdev = icd->vdev; @@ -1155,10 +1161,8 @@ void soc_camera_video_stop(struct soc_camera_device *icd) if (!icd->dev.parent || !vdev) return; - mutex_lock(&icd->video_lock); video_unregister_device(vdev); icd->vdev = NULL; - mutex_unlock(&icd->video_lock); } EXPORT_SYMBOL(soc_camera_video_stop); -- cgit v1.2.3