diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-20 02:42:34 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-20 02:42:34 -0300 |
commit | 9f85fbc44d99a2327bf2fb9be850bb9844c8c8c7 (patch) | |
tree | 0324b3b860c87deb12ebf9db240678d402302f01 | |
parent | d1f8343e844fdb906b58a31d33e5d69c8e7853ad (diff) | |
parent | 94a0e644a33260b89beb679752d5da322e1474c4 (diff) | |
download | mediapointer-dvb-s2-9f85fbc44d99a2327bf2fb9be850bb9844c8c8c7.tar.gz mediapointer-dvb-s2-9f85fbc44d99a2327bf2fb9be850bb9844c8c8c7.tar.bz2 |
merge: http://www.linuxtv.org/hg/~hverkuil/v4l-dvb-cafe
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | linux/drivers/media/video/cafe_ccic.c | 424 | ||||
-rw-r--r-- | linux/drivers/media/video/ov7670.c | 565 | ||||
-rw-r--r-- | linux/drivers/media/video/v4l2-subdev.c | 8 | ||||
-rw-r--r-- | linux/include/media/v4l2-chip-ident.h | 27 | ||||
-rw-r--r-- | linux/include/media/v4l2-subdev.h | 6 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-dbg.cpp | 10 |
6 files changed, 408 insertions, 632 deletions
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c index b6c328187..2619d77ef 100644 --- a/linux/drivers/media/video/cafe_ccic.c +++ b/linux/drivers/media/video/cafe_ccic.c @@ -11,6 +11,12 @@ * * Written by Jonathan Corbet, corbet@lwn.net. * + * v4l2_device/v4l2_subdev conversion by: + * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl> + * + * Note: this conversion is untested! Please contact the linux-media + * mailinglist if you can test this, together with the test results. + * * This file may be distributed under the terms of the GNU General * Public License, version 2. */ @@ -26,7 +32,7 @@ #include <linux/spinlock.h> #include <linux/videodev2.h> #include "compat.h" -#include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-chip-ident.h> #include <linux/device.h> @@ -34,7 +40,6 @@ #include <linux/list.h> #include <linux/dma-mapping.h> #include <linux/delay.h> -#include <linux/debugfs.h> #include <linux/jiffies.h> #include <linux/vmalloc.h> @@ -137,6 +142,7 @@ struct cafe_sio_buffer { */ struct cafe_camera { + struct v4l2_device v4l2_dev; enum cafe_state state; unsigned long flags; /* Buffer status, mainly (dev_lock) */ int users; /* How many open FDs */ @@ -146,9 +152,10 @@ struct cafe_camera * Subsystem structures. */ struct pci_dev *pdev; - struct video_device v4ldev; + struct video_device vdev; struct i2c_adapter i2c_adapter; - struct i2c_client *sensor; + struct v4l2_subdev *sensor; + unsigned short sensor_addr; unsigned char __iomem *regs; struct list_head dev_list; /* link to other devices */ @@ -181,10 +188,6 @@ struct cafe_camera /* Misc */ wait_queue_head_t smbus_wait; /* Waiting on i2c events */ wait_queue_head_t iowait; /* Waiting on frame data */ -#ifdef CONFIG_VIDEO_ADV_DEBUG - struct dentry *dfs_regs; - struct dentry *dfs_cam_regs; -#endif }; /* @@ -196,6 +199,13 @@ struct cafe_camera #define CF_DMA_ACTIVE 3 /* A frame is incoming */ #define CF_CONFIG_NEEDED 4 /* Must configure hardware */ +#define sensor_call(cam, o, f, args...) \ + v4l2_subdev_call(cam->sensor, o, f, ##args) + +static inline struct cafe_camera *to_cam(struct v4l2_device *dev) +{ + return container_of(dev, struct cafe_camera, v4l2_dev); +} /* @@ -239,59 +249,7 @@ static void cafe_set_config_needed(struct cafe_camera *cam, int needed) /* ---------------------------------------------------------------------*/ -/* - * We keep a simple list of known devices to search at open time. - */ -static LIST_HEAD(cafe_dev_list); -static DEFINE_MUTEX(cafe_dev_list_lock); - -static void cafe_add_dev(struct cafe_camera *cam) -{ - mutex_lock(&cafe_dev_list_lock); - list_add_tail(&cam->dev_list, &cafe_dev_list); - mutex_unlock(&cafe_dev_list_lock); -} - -static void cafe_remove_dev(struct cafe_camera *cam) -{ - mutex_lock(&cafe_dev_list_lock); - list_del(&cam->dev_list); - mutex_unlock(&cafe_dev_list_lock); -} -static struct cafe_camera *cafe_find_dev(int minor) -{ - struct cafe_camera *cam; - - mutex_lock(&cafe_dev_list_lock); - list_for_each_entry(cam, &cafe_dev_list, dev_list) { - if (cam->v4ldev.minor == minor) - goto done; - } - cam = NULL; - done: - mutex_unlock(&cafe_dev_list_lock); - return cam; -} - - -static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev) -{ - struct cafe_camera *cam; - - mutex_lock(&cafe_dev_list_lock); - list_for_each_entry(cam, &cafe_dev_list, dev_list) { - if (cam->pdev == pdev) - goto done; - } - cam = NULL; - done: - mutex_unlock(&cafe_dev_list_lock); - return cam; -} - - -/* ------------------------------------------------------------------------ */ /* * Device register I/O */ @@ -482,24 +440,11 @@ static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char rw, u8 command, int size, union i2c_smbus_data *data) { - struct cafe_camera *cam = i2c_get_adapdata(adapter); + struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter); + struct cafe_camera *cam = to_cam(v4l2_dev); int ret = -EINVAL; /* - * Refuse to talk to anything but OV cam chips. We should - * never even see an attempt to do so, but one never knows. - */ -#if 0 /* client needs to talk during attach process */ - if (! cam->sensor) { - cam_err(cam, "SMBUS xfer with no client\n"); - return -EINVAL; - } -#endif - if (cam->sensor && addr != cam->sensor->addr) { - cam_err(cam, "funky smbus addr %d\n", addr); - return -EINVAL; - } - /* * This interface would appear to only do byte data ops. OK * it can do word too, but the cam chip has no use for that. */ @@ -537,38 +482,9 @@ static struct i2c_algorithm cafe_smbus_algo = { }; /* Somebody is on the bus */ -static int cafe_cam_init(struct cafe_camera *cam); static void cafe_ctlr_stop_dma(struct cafe_camera *cam); static void cafe_ctlr_power_down(struct cafe_camera *cam); -static int cafe_smbus_attach(struct i2c_client *client) -{ - struct cafe_camera *cam = i2c_get_adapdata(client->adapter); - - /* - * Don't talk to chips we don't recognize. - */ - if (client->driver->id == I2C_DRIVERID_OV7670) { - cam->sensor = client; - return cafe_cam_init(cam); - } - return -EINVAL; -} - -static int cafe_smbus_detach(struct i2c_client *client) -{ - struct cafe_camera *cam = i2c_get_adapdata(client->adapter); - - if (cam->sensor == client) { - cafe_ctlr_stop_dma(cam); - cafe_ctlr_power_down(cam); - cam_err(cam, "lost the sensor!\n"); - cam->sensor = NULL; /* Bummer, no camera */ - cam->state = S_NOTREADY; - } - return 0; -} - static int cafe_smbus_setup(struct cafe_camera *cam) { struct i2c_adapter *adap = &cam->i2c_adapter; @@ -577,12 +493,10 @@ static int cafe_smbus_setup(struct cafe_camera *cam) cafe_smbus_enable_irq(cam); adap->id = I2C_HW_SMBUS_CAFE; adap->owner = THIS_MODULE; - adap->client_register = cafe_smbus_attach; - adap->client_unregister = cafe_smbus_detach; adap->algo = &cafe_smbus_algo; strcpy(adap->name, "cafe_ccic"); adap->dev.parent = &cam->pdev->dev; - i2c_set_adapdata(adap, cam); + i2c_set_adapdata(adap, &cam->v4l2_dev); ret = i2c_add_adapter(adap); if (ret) printk(KERN_ERR "Unable to register cafe i2c adapter\n"); @@ -816,9 +730,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) * Control 1 is power down, set to 0 to operate. */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ -// mdelay(1); /* Marvell says 1ms will do it */ +/* mdelay(1); */ /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); -// mdelay(1); /* Enough? */ +/* mdelay(1); */ /* Enough? */ spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); /* Just to be sure */ } @@ -840,23 +754,9 @@ static void cafe_ctlr_power_down(struct cafe_camera *cam) * Communications with the sensor. */ -static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg) -{ - struct i2c_client *sc = cam->sensor; - int ret; - - if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL) - return -EINVAL; - ret = sc->driver->command(sc, cmd, arg); - if (ret == -EPERM) /* Unsupported command */ - return 0; - return ret; -} - static int __cafe_cam_reset(struct cafe_camera *cam) { - int zero = 0; - return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero); + return sensor_call(cam, core, reset, 0); } /* @@ -876,14 +776,13 @@ static int cafe_cam_init(struct cafe_camera *cam) if (ret) goto out; chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR; - chip.match.addr = cam->sensor->addr; - ret = __cafe_cam_cmd(cam, VIDIOC_DBG_G_CHIP_IDENT, &chip); + chip.match.addr = cam->sensor_addr; + ret = sensor_call(cam, core, g_chip_ident, &chip); if (ret) goto out; cam->sensor_type = chip.ident; -// if (cam->sensor->addr != OV7xx0_SID) { if (cam->sensor_type != V4L2_IDENT_OV7670) { - cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); + cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type); ret = -EINVAL; goto out; } @@ -907,21 +806,21 @@ static int cafe_cam_set_flip(struct cafe_camera *cam) memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CID_VFLIP; ctrl.value = flip; - return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl); + return sensor_call(cam, core, s_ctrl, &ctrl); } static int cafe_cam_configure(struct cafe_camera *cam) { struct v4l2_format fmt; - int ret, zero = 0; + int ret; if (cam->state != S_IDLE) return -EINVAL; fmt.fmt.pix = cam->pix_format; - ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero); + ret = sensor_call(cam, core, init, 0); if (ret == 0) - ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt); + ret = sensor_call(cam, video, s_fmt, &fmt); /* * OV7670 does weird things if flip is set *before* format... */ @@ -1481,11 +1380,8 @@ static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma) static int cafe_v4l_open(struct file *filp) { - struct cafe_camera *cam; + struct cafe_camera *cam = video_drvdata(filp); - cam = cafe_find_dev(video_devdata(filp)->minor); - if (cam == NULL) - return -ENODEV; filp->private_data = cam; mutex_lock(&cam->s_mutex); @@ -1539,11 +1435,11 @@ static unsigned int cafe_v4l_poll(struct file *filp, static int cafe_vidioc_queryctrl(struct file *filp, void *priv, struct v4l2_queryctrl *qc) { - struct cafe_camera *cam = filp->private_data; + struct cafe_camera *cam = priv; int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc); + ret = sensor_call(cam, core, queryctrl, qc); mutex_unlock(&cam->s_mutex); return ret; } @@ -1552,11 +1448,11 @@ static int cafe_vidioc_queryctrl(struct file *filp, void *priv, static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, struct v4l2_control *ctrl) { - struct cafe_camera *cam = filp->private_data; + struct cafe_camera *cam = priv; int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl); + ret = sensor_call(cam, core, g_ctrl, ctrl); mutex_unlock(&cam->s_mutex); return ret; } @@ -1565,11 +1461,11 @@ static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, struct v4l2_control *ctrl) { - struct cafe_camera *cam = filp->private_data; + struct cafe_camera *cam = priv; int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl); + ret = sensor_call(cam, core, s_ctrl, ctrl); mutex_unlock(&cam->s_mutex); return ret; } @@ -1611,7 +1507,7 @@ static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp, if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt); + ret = sensor_call(cam, video, enum_fmt, fmt); mutex_unlock(&cam->s_mutex); return ret; } @@ -1624,7 +1520,7 @@ static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt); + ret = sensor_call(cam, video, try_fmt, fmt); mutex_unlock(&cam->s_mutex); return ret; } @@ -1733,7 +1629,7 @@ static int cafe_vidioc_g_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms); + ret = sensor_call(cam, video, g_parm, parms); mutex_unlock(&cam->s_mutex); parms->parm.capture.readbuffers = n_dma_bufs; return ret; @@ -1746,20 +1642,52 @@ static int cafe_vidioc_s_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->s_mutex); - ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms); + ret = sensor_call(cam, video, s_parm, parms); mutex_unlock(&cam->s_mutex); parms->parm.capture.readbuffers = n_dma_bufs; return ret; } +static int cafe_vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + struct cafe_camera *cam = priv; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (v4l2_chip_match_host(&chip->match)) { + chip->ident = V4L2_IDENT_CAFE; + return 0; + } + return sensor_call(cam, core, g_chip_ident, chip); +} -static void cafe_v4l_dev_release(struct video_device *vd) +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cafe_vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) { - struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); + struct cafe_camera *cam = priv; - kfree(cam); + if (v4l2_chip_match_host(®->match)) { + reg->val = cafe_reg_read(cam, reg->reg); + reg->size = 4; + return 0; + } + return sensor_call(cam, core, g_register, reg); } +static int cafe_vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct cafe_camera *cam = priv; + + if (v4l2_chip_match_host(®->match)) { + cafe_reg_write(cam, reg->reg, reg->val); + return 0; + } + return sensor_call(cam, core, s_register, reg); +} +#endif /* * This template device holds all of those v4l2 methods; we @@ -1797,6 +1725,11 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { .vidioc_s_ctrl = cafe_vidioc_s_ctrl, .vidioc_g_parm = cafe_vidioc_g_parm, .vidioc_s_parm = cafe_vidioc_s_parm, + .vidioc_g_chip_ident = cafe_vidioc_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cafe_vidioc_g_register, + .vidioc_s_register = cafe_vidioc_s_register, +#endif }; static struct video_device cafe_v4l_template = { @@ -1807,15 +1740,10 @@ static struct video_device cafe_v4l_template = { .fops = &cafe_v4l_fops, .ioctl_ops = &cafe_v4l_ioctl_ops, - .release = cafe_v4l_dev_release, + .release = video_device_release_empty, }; - - - - - /* ---------------------------------------------------------------------- */ /* * Interrupt handler stuff @@ -1969,127 +1897,6 @@ static irqreturn_t cafe_irq(int irq, void *data) /* -------------------------------------------------------------------------- */ -#ifdef CONFIG_VIDEO_ADV_DEBUG -/* - * Debugfs stuff. - */ - -static char cafe_debug_buf[1024]; -static struct dentry *cafe_dfs_root; - -static void cafe_dfs_setup(void) -{ - cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL); - if (IS_ERR(cafe_dfs_root)) { - cafe_dfs_root = NULL; /* Never mind */ - printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n"); - } -} - -static void cafe_dfs_shutdown(void) -{ - if (cafe_dfs_root) - debugfs_remove(cafe_dfs_root); -} - -static int cafe_dfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t cafe_dfs_read_regs(struct file *file, - char __user *buf, size_t count, loff_t *ppos) -{ - struct cafe_camera *cam = file->private_data; - char *s = cafe_debug_buf; - int offset; - - for (offset = 0; offset < 0x44; offset += 4) - s += sprintf(s, "%02x: %08x\n", offset, - cafe_reg_read(cam, offset)); - for (offset = 0x88; offset <= 0x90; offset += 4) - s += sprintf(s, "%02x: %08x\n", offset, - cafe_reg_read(cam, offset)); - for (offset = 0xb4; offset <= 0xbc; offset += 4) - s += sprintf(s, "%02x: %08x\n", offset, - cafe_reg_read(cam, offset)); - for (offset = 0x3000; offset <= 0x300c; offset += 4) - s += sprintf(s, "%04x: %08x\n", offset, - cafe_reg_read(cam, offset)); - return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, - s - cafe_debug_buf); -} - -static const struct file_operations cafe_dfs_reg_ops = { - .owner = THIS_MODULE, - .read = cafe_dfs_read_regs, - .open = cafe_dfs_open -}; - -static ssize_t cafe_dfs_read_cam(struct file *file, - char __user *buf, size_t count, loff_t *ppos) -{ - struct cafe_camera *cam = file->private_data; - char *s = cafe_debug_buf; - int offset; - - if (! cam->sensor) - return -EINVAL; - for (offset = 0x0; offset < 0x8a; offset++) - { - u8 v; - - cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v); - s += sprintf(s, "%02x: %02x\n", offset, v); - } - return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, - s - cafe_debug_buf); -} - -static const struct file_operations cafe_dfs_cam_ops = { - .owner = THIS_MODULE, - .read = cafe_dfs_read_cam, - .open = cafe_dfs_open -}; - - - -static void cafe_dfs_cam_setup(struct cafe_camera *cam) -{ - char fname[40]; - - if (!cafe_dfs_root) - return; - sprintf(fname, "regs-%d", cam->v4ldev.num); - cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, - cam, &cafe_dfs_reg_ops); - sprintf(fname, "cam-%d", cam->v4ldev.num); - cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, - cam, &cafe_dfs_cam_ops); -} - - -static void cafe_dfs_cam_shutdown(struct cafe_camera *cam) -{ - if (! IS_ERR(cam->dfs_regs)) - debugfs_remove(cam->dfs_regs); - if (! IS_ERR(cam->dfs_cam_regs)) - debugfs_remove(cam->dfs_cam_regs); -} - -#else - -#define cafe_dfs_setup() -#define cafe_dfs_shutdown() -#define cafe_dfs_cam_setup(cam) -#define cafe_dfs_cam_shutdown(cam) -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - - - - -/* ------------------------------------------------------------------------*/ /* * PCI interface stuff. */ @@ -2107,6 +1914,10 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); if (cam == NULL) goto out; + ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev); + if (ret) + goto out_free; + mutex_init(&cam->s_mutex); mutex_lock(&cam->s_mutex); spin_lock_init(&cam->dev_lock); @@ -2125,14 +1936,14 @@ static int cafe_pci_probe(struct pci_dev *pdev, */ ret = pci_enable_device(pdev); if (ret) - goto out_free; + goto out_unreg; pci_set_master(pdev); ret = -EIO; cam->regs = pci_iomap(pdev, 0, 0); if (! cam->regs) { printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); - goto out_free; + goto out_unreg; } ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); if (ret) @@ -2152,17 +1963,31 @@ static int cafe_pci_probe(struct pci_dev *pdev, ret = cafe_smbus_setup(cam); if (ret) goto out_freeirq; + + cam->sensor_addr = 0x42; + cam->sensor = v4l2_i2c_new_subdev(&cam->i2c_adapter, + "ov7670", "ov7670", cam->sensor_addr); + if (cam->sensor == NULL) { + ret = -ENODEV; + goto out_smbus; + } + ret = cafe_cam_init(cam); + if (ret) + goto out_smbus; + /* * Get the v4l2 setup done. */ mutex_lock(&cam->s_mutex); - cam->v4ldev = cafe_v4l_template; - cam->v4ldev.debug = 0; -// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; - cam->v4ldev.parent = &pdev->dev; - ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); + cam->vdev = cafe_v4l_template; + cam->vdev.debug = 0; +/* cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/ + cam->vdev.v4l2_dev = &cam->v4l2_dev; + ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); if (ret) goto out_smbus; + video_set_drvdata(&cam->vdev, cam); + /* * If so requested, try to get our DMA buffers now. */ @@ -2172,21 +1997,21 @@ static int cafe_pci_probe(struct pci_dev *pdev, " will try again later."); } - cafe_dfs_cam_setup(cam); mutex_unlock(&cam->s_mutex); - cafe_add_dev(cam); return 0; - out_smbus: +out_smbus: cafe_smbus_shutdown(cam); - out_freeirq: +out_freeirq: cafe_ctlr_power_down(cam); free_irq(pdev->irq, cam); - out_iounmap: +out_iounmap: pci_iounmap(pdev, cam->regs); - out_free: +out_free: + v4l2_device_unregister(&cam->v4l2_dev); +out_unreg: kfree(cam); - out: +out: return ret; } @@ -2197,25 +2022,23 @@ static int cafe_pci_probe(struct pci_dev *pdev, static void cafe_shutdown(struct cafe_camera *cam) { /* FIXME: Make sure we take care of everything here */ - cafe_dfs_cam_shutdown(cam); if (cam->n_sbufs > 0) /* What if they are still mapped? Shouldn't be, but... */ cafe_free_sio_buffers(cam); - cafe_remove_dev(cam); cafe_ctlr_stop_dma(cam); cafe_ctlr_power_down(cam); cafe_smbus_shutdown(cam); cafe_free_dma_bufs(cam); free_irq(cam->pdev->irq, cam); pci_iounmap(cam->pdev, cam->regs); - video_unregister_device(&cam->v4ldev); - /* kfree(cam); done in v4l_release () */ + video_unregister_device(&cam->vdev); } static void cafe_pci_remove(struct pci_dev *pdev) { - struct cafe_camera *cam = cafe_find_by_pdev(pdev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); if (cam == NULL) { printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); @@ -2225,6 +2048,8 @@ static void cafe_pci_remove(struct pci_dev *pdev) if (cam->users > 0) cam_warn(cam, "Removing a device with users!\n"); cafe_shutdown(cam); + v4l2_device_unregister(&cam->v4l2_dev); + kfree(cam); /* No unlock - it no longer exists */ } @@ -2235,7 +2060,8 @@ static void cafe_pci_remove(struct pci_dev *pdev) */ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct cafe_camera *cam = cafe_find_by_pdev(pdev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); int ret; enum cafe_state cstate; @@ -2253,7 +2079,8 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int cafe_pci_resume(struct pci_dev *pdev) { - struct cafe_camera *cam = cafe_find_by_pdev(pdev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct cafe_camera *cam = to_cam(v4l2_dev); int ret = 0; ret = pci_restore_state(pdev); @@ -2314,13 +2141,11 @@ static int __init cafe_init(void) printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", CAFE_VERSION); - cafe_dfs_setup(); ret = pci_register_driver(&cafe_pci_driver); if (ret) { printk(KERN_ERR "Unable to register cafe_ccic driver\n"); goto out; } - request_module("ov7670"); /* FIXME want something more general */ ret = 0; out: @@ -2331,7 +2156,6 @@ static int __init cafe_init(void) static void __exit cafe_exit(void) { pci_unregister_driver(&cafe_pci_driver); - cafe_dfs_shutdown(); } module_init(cafe_init); diff --git a/linux/drivers/media/video/ov7670.c b/linux/drivers/media/video/ov7670.c index f0e1a56eb..263f20669 100644 --- a/linux/drivers/media/video/ov7670.c +++ b/linux/drivers/media/video/ov7670.c @@ -12,12 +12,11 @@ */ #include <linux/init.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> +#include <linux/i2c.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> -#include <linux/i2c.h> +#include <media/v4l2-i2c-drv.h> #include "compat.h" @@ -25,6 +24,10 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); MODULE_LICENSE("GPL"); +static int debug; +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + /* * Basic window sizes. These probably belong somewhere more globally * useful. @@ -190,11 +193,16 @@ MODULE_LICENSE("GPL"); */ struct ov7670_format_struct; /* coming later */ struct ov7670_info { + struct v4l2_subdev sd; struct ov7670_format_struct *fmt; /* Current format */ unsigned char sat; /* Saturation value */ int hue; /* Hue value */ }; +static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov7670_info, sd); +} @@ -401,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = { * Low-level register I/O. */ -static int ov7670_read(struct i2c_client *c, unsigned char reg, +static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, unsigned char *value) { + struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - ret = i2c_smbus_read_byte_data(c, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret >= 0) { - *value = (unsigned char) ret; + *value = (unsigned char)ret; ret = 0; } return ret; } -static int ov7670_write(struct i2c_client *c, unsigned char reg, +static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, unsigned char value) { - int ret = i2c_smbus_write_byte_data(c, reg, value); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = i2c_smbus_write_byte_data(client, reg, value); + if (reg == REG_COM7 && (value & COM7_RESET)) msleep(2); /* Wait for reset to run */ return ret; @@ -426,20 +437,20 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg, #if 0 /* Not currently used, but maybe should be */ -static int ov7670_write_mask(struct i2c_client *c, unsigned char reg, +static int ov7670_write_mask(struct v4l2_subdev *sd, unsigned char reg, unsigned char value, unsigned char mask) { unsigned char v; int ret, tries = 0; - ret = ov7670_read(c, reg, &v); + ret = ov7670_read(sd, reg, &v); if (ret < 0) return ret; v &= ~mask; v |= (value & mask); msleep(10); /* FIXME experiment */ do { - ret = ov7670_write(c, reg, v); + ret = ov7670_write(sd, reg, v); } while (ret < 0 && ++tries < 3); return ret; } @@ -449,10 +460,10 @@ static int ov7670_write_mask(struct i2c_client *c, unsigned char reg, /* * Write a list of register settings; ff/ff stops the process. */ -static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) +static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals) { while (vals->reg_num != 0xff || vals->value != 0xff) { - int ret = ov7670_write(c, vals->reg_num, vals->value); + int ret = ov7670_write(sd, vals->reg_num, vals->value); if (ret < 0) return ret; vals++; @@ -464,34 +475,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) /* * Stuff that knows about the sensor. */ -static void ov7670_reset(struct i2c_client *client) +static int ov7670_reset(struct v4l2_subdev *sd, u32 val) { - ov7670_write(client, REG_COM7, COM7_RESET); + ov7670_write(sd, REG_COM7, COM7_RESET); msleep(1); + return 0; } -static int ov7670_init(struct i2c_client *client) +static int ov7670_init(struct v4l2_subdev *sd, u32 val) { - return ov7670_write_array(client, ov7670_default_regs); + return ov7670_write_array(sd, ov7670_default_regs); } -static int ov7670_detect(struct i2c_client *client) +static int ov7670_detect(struct v4l2_subdev *sd) { unsigned char v; int ret; - ret = ov7670_init(client); + ret = ov7670_init(sd, 0); if (ret < 0) return ret; - ret = ov7670_read(client, REG_MIDH, &v); + ret = ov7670_read(sd, REG_MIDH, &v); if (ret < 0) return ret; if (v != 0x7f) /* OV manuf. id. */ return -ENODEV; - ret = ov7670_read(client, REG_MIDL, &v); + ret = ov7670_read(sd, REG_MIDL, &v); if (ret < 0) return ret; if (v != 0xa2) @@ -499,12 +511,12 @@ static int ov7670_detect(struct i2c_client *client) /* * OK, we know we have an OmniVision chip...but which one? */ - ret = ov7670_read(client, REG_PID, &v); + ret = ov7670_read(sd, REG_PID, &v); if (ret < 0) return ret; if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ return -ENODEV; - ret = ov7670_read(client, REG_VER, &v); + ret = ov7670_read(sd, REG_VER, &v); if (ret < 0) return ret; if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ @@ -649,7 +661,7 @@ static struct ov7670_win_size { /* * Store a set of start/stop values into the camera. */ -static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, +static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, int vstart, int vstop) { int ret; @@ -659,26 +671,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is * a mystery "edge offset" value in the top two bits of href. */ - ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); - ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); - ret += ov7670_read(client, REG_HREF, &v); + ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff); + ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff); + ret += ov7670_read(sd, REG_HREF, &v); v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); msleep(10); - ret += ov7670_write(client, REG_HREF, v); + ret += ov7670_write(sd, REG_HREF, v); /* * Vertical: similar arrangement, but only 10 bits. */ - ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); - ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); - ret += ov7670_read(client, REG_VREF, &v); + ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff); + ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff); + ret += ov7670_read(sd, REG_VREF, &v); v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); msleep(10); - ret += ov7670_write(client, REG_VREF, v); + ret += ov7670_write(sd, REG_VREF, v); return ret; } -static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) +static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) { struct ov7670_format_struct *ofmt; @@ -693,7 +705,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) } -static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, +static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, + struct v4l2_format *fmt, struct ov7670_format_struct **ret_fmt, struct ov7670_win_size **ret_wsize) { @@ -737,18 +750,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, return 0; } +static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + return ov7670_try_fmt_internal(sd, fmt, NULL, NULL); +} + /* * Set a format. */ -static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) +static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) { int ret; struct ov7670_format_struct *ovfmt; struct ov7670_win_size *wsize; - struct ov7670_info *info = i2c_get_clientdata(c); - unsigned char com7, clkrc; + struct ov7670_info *info = to_state(sd); + unsigned char com7, clkrc = 0; - ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); + ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); if (ret) return ret; /* @@ -757,7 +775,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) * the colors. */ if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { - ret = ov7670_read(c, REG_CLKRC, &clkrc); + ret = ov7670_read(sd, REG_CLKRC, &clkrc); if (ret) return ret; } @@ -769,20 +787,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) */ com7 = ovfmt->regs[0].value; com7 |= wsize->com7_bit; - ov7670_write(c, REG_COM7, com7); + ov7670_write(sd, REG_COM7, com7); /* * Now write the rest of the array. Also store start/stops */ - ov7670_write_array(c, ovfmt->regs + 1); - ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, + ov7670_write_array(sd, ovfmt->regs + 1); + ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, wsize->vstop); ret = 0; if (wsize->regs) - ret = ov7670_write_array(c, wsize->regs); + ret = ov7670_write_array(sd, wsize->regs); info->fmt = ovfmt; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) - ret = ov7670_write(c, REG_CLKRC, clkrc); + ret = ov7670_write(sd, REG_CLKRC, clkrc); return ret; } @@ -790,7 +808,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) * Implement G/S_PARM. There is a "high quality" mode we could try * to do someday; for now, we just do the frame rate tweak. */ -static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) +static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) { struct v4l2_captureparm *cp = &parms->parm.capture; unsigned char clkrc; @@ -798,7 +816,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = ov7670_read(c, REG_CLKRC, &clkrc); + ret = ov7670_read(sd, REG_CLKRC, &clkrc); if (ret < 0) return ret; memset(cp, 0, sizeof(struct v4l2_captureparm)); @@ -810,7 +828,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) return 0; } -static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) +static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) { struct v4l2_captureparm *cp = &parms->parm.capture; struct v4l2_fract *tpf = &cp->timeperframe; @@ -824,7 +842,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) /* * CLKRC has a reserved bit, so let's preserve it. */ - ret = ov7670_read(c, REG_CLKRC, &clkrc); + ret = ov7670_read(sd, REG_CLKRC, &clkrc); if (ret < 0) return ret; if (tpf->numerator == 0 || tpf->denominator == 0) @@ -838,7 +856,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) clkrc = (clkrc & 0x80) | div; tpf->numerator = 1; tpf->denominator = OV7670_FRAME_RATE/div; - return ov7670_write(c, REG_CLKRC, clkrc); + return ov7670_write(sd, REG_CLKRC, clkrc); } @@ -851,17 +869,17 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) /* * Fetch and store the color matrix. */ -static int ov7670_get_cmatrix(struct i2c_client *client, +static int ov7670_get_cmatrix(struct v4l2_subdev *sd, int matrix[CMATRIX_LEN]) { int i, ret; unsigned char signbits; - ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); + ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits); for (i = 0; i < CMATRIX_LEN; i++) { unsigned char raw; - ret += ov7670_read(client, REG_CMATRIX_BASE + i, &raw); + ret += ov7670_read(sd, REG_CMATRIX_BASE + i, &raw); matrix[i] = (int) raw; if (signbits & (1 << i)) matrix[i] *= -1; @@ -873,7 +891,7 @@ static int ov7670_get_cmatrix(struct i2c_client *client, -static int ov7670_store_cmatrix(struct i2c_client *client, +static int ov7670_store_cmatrix(struct v4l2_subdev *sd, int matrix[CMATRIX_LEN]) { int i, ret; @@ -883,7 +901,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client, * Weird crap seems to exist in the upper part of * the sign bits register, so let's preserve it. */ - ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); + ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits); signbits &= 0xc0; for (i = 0; i < CMATRIX_LEN; i++) { @@ -902,9 +920,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client, else raw = matrix[i] & 0xff; } - ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); + ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw); } - ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); + ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits); return ret; } @@ -987,29 +1005,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info, -static int ov7670_t_sat(struct i2c_client *client, int value) +static int ov7670_s_sat(struct v4l2_subdev *sd, int value) { - struct ov7670_info *info = i2c_get_clientdata(client); + struct ov7670_info *info = to_state(sd); int matrix[CMATRIX_LEN]; int ret; info->sat = value; ov7670_calc_cmatrix(info, matrix); - ret = ov7670_store_cmatrix(client, matrix); + ret = ov7670_store_cmatrix(sd, matrix); return ret; } -static int ov7670_q_sat(struct i2c_client *client, __s32 *value) +static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value) { - struct ov7670_info *info = i2c_get_clientdata(client); + struct ov7670_info *info = to_state(sd); *value = info->sat; return 0; } -static int ov7670_t_hue(struct i2c_client *client, int value) +static int ov7670_s_hue(struct v4l2_subdev *sd, int value) { - struct ov7670_info *info = i2c_get_clientdata(client); + struct ov7670_info *info = to_state(sd); int matrix[CMATRIX_LEN]; int ret; @@ -1017,14 +1035,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value) return -EINVAL; info->hue = value; ov7670_calc_cmatrix(info, matrix); - ret = ov7670_store_cmatrix(client, matrix); + ret = ov7670_store_cmatrix(sd, matrix); return ret; } -static int ov7670_q_hue(struct i2c_client *client, __s32 *value) +static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value) { - struct ov7670_info *info = i2c_get_clientdata(client); + struct ov7670_info *info = to_state(sd); *value = info->hue; return 0; @@ -1038,8 +1056,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v) { if ((v & 0x80) == 0) return v + 128; - else - return 128 - (v & 0x7f); + return 128 - (v & 0x7f); } @@ -1047,369 +1064,279 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) { if (v > 127) return v & 0x7f; - else - return (128 - v) | 0x80; + return (128 - v) | 0x80; } -static int ov7670_t_brightness(struct i2c_client *client, int value) +static int ov7670_s_brightness(struct v4l2_subdev *sd, int value) { unsigned char com8 = 0, v; int ret; - ov7670_read(client, REG_COM8, &com8); + ov7670_read(sd, REG_COM8, &com8); com8 &= ~COM8_AEC; - ov7670_write(client, REG_COM8, com8); + ov7670_write(sd, REG_COM8, com8); v = ov7670_abs_to_sm(value); - ret = ov7670_write(client, REG_BRIGHT, v); + ret = ov7670_write(sd, REG_BRIGHT, v); return ret; } -static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) +static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value) { unsigned char v = 0; - int ret = ov7670_read(client, REG_BRIGHT, &v); + int ret = ov7670_read(sd, REG_BRIGHT, &v); *value = ov7670_sm_to_abs(v); return ret; } -static int ov7670_t_contrast(struct i2c_client *client, int value) +static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) { - return ov7670_write(client, REG_CONTRAS, (unsigned char) value); + return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); } -static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) +static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value) { unsigned char v = 0; - int ret = ov7670_read(client, REG_CONTRAS, &v); + int ret = ov7670_read(sd, REG_CONTRAS, &v); *value = v; return ret; } -static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) +static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value) { int ret; unsigned char v = 0; - ret = ov7670_read(client, REG_MVFP, &v); + ret = ov7670_read(sd, REG_MVFP, &v); *value = (v & MVFP_MIRROR) == MVFP_MIRROR; return ret; } -static int ov7670_t_hflip(struct i2c_client *client, int value) +static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) { unsigned char v = 0; int ret; - ret = ov7670_read(client, REG_MVFP, &v); + ret = ov7670_read(sd, REG_MVFP, &v); if (value) v |= MVFP_MIRROR; else v &= ~MVFP_MIRROR; msleep(10); /* FIXME */ - ret += ov7670_write(client, REG_MVFP, v); + ret += ov7670_write(sd, REG_MVFP, v); return ret; } -static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) +static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value) { int ret; unsigned char v = 0; - ret = ov7670_read(client, REG_MVFP, &v); + ret = ov7670_read(sd, REG_MVFP, &v); *value = (v & MVFP_FLIP) == MVFP_FLIP; return ret; } -static int ov7670_t_vflip(struct i2c_client *client, int value) +static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) { unsigned char v = 0; int ret; - ret = ov7670_read(client, REG_MVFP, &v); + ret = ov7670_read(sd, REG_MVFP, &v); if (value) v |= MVFP_FLIP; else v &= ~MVFP_FLIP; msleep(10); /* FIXME */ - ret += ov7670_write(client, REG_MVFP, v); + ret += ov7670_write(sd, REG_MVFP, v); return ret; } - -static struct ov7670_control { - struct v4l2_queryctrl qc; - int (*query)(struct i2c_client *c, __s32 *value); - int (*tweak)(struct i2c_client *c, int value); -} ov7670_controls[] = +static int ov7670_queryctrl(struct v4l2_subdev *sd, + struct v4l2_queryctrl *qc) { - { - .qc = { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0x80, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .tweak = ov7670_t_brightness, - .query = ov7670_q_brightness, - }, - { - .qc = { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0x40, /* XXX ov7670 spec */ - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .tweak = ov7670_t_contrast, - .query = ov7670_q_contrast, - }, - { - .qc = { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 256, - .step = 1, - .default_value = 0x80, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .tweak = ov7670_t_sat, - .query = ov7670_q_sat, - }, - { - .qc = { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HUE", - .minimum = -180, - .maximum = 180, - .step = 5, - .default_value = 0, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .tweak = ov7670_t_hue, - .query = ov7670_q_hue, - }, - { - .qc = { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .tweak = ov7670_t_vflip, - .query = ov7670_q_vflip, - }, - { - .qc = { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .tweak = ov7670_t_hflip, - .query = ov7670_q_hflip, - }, -}; -#define N_CONTROLS (ARRAY_SIZE(ov7670_controls)) + /* Fill in min, max, step and default value for these controls. */ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); + case V4L2_CID_VFLIP: + case V4L2_CID_HFLIP: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); + } + return -EINVAL; +} -static struct ov7670_control *ov7670_find_control(__u32 id) +static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - int i; - - for (i = 0; i < N_CONTROLS; i++) - if (ov7670_controls[i].qc.id == id) - return ov7670_controls + i; - return NULL; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + return ov7670_g_brightness(sd, &ctrl->value); + case V4L2_CID_CONTRAST: + return ov7670_g_contrast(sd, &ctrl->value); + case V4L2_CID_SATURATION: + return ov7670_g_sat(sd, &ctrl->value); + case V4L2_CID_HUE: + return ov7670_g_hue(sd, &ctrl->value); + case V4L2_CID_VFLIP: + return ov7670_g_vflip(sd, &ctrl->value); + case V4L2_CID_HFLIP: + return ov7670_g_hflip(sd, &ctrl->value); + } + return -EINVAL; } +static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + return ov7670_s_brightness(sd, ctrl->value); + case V4L2_CID_CONTRAST: + return ov7670_s_contrast(sd, ctrl->value); + case V4L2_CID_SATURATION: + return ov7670_s_sat(sd, ctrl->value); + case V4L2_CID_HUE: + return ov7670_s_hue(sd, ctrl->value); + case V4L2_CID_VFLIP: + return ov7670_s_vflip(sd, ctrl->value); + case V4L2_CID_HFLIP: + return ov7670_s_hflip(sd, ctrl->value); + } + return -EINVAL; +} -static int ov7670_queryctrl(struct i2c_client *client, - struct v4l2_queryctrl *qc) +static int ov7670_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) { - struct ov7670_control *ctrl = ov7670_find_control(qc->id); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (ctrl == NULL) - return -EINVAL; - *qc = ctrl->qc; - return 0; + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0); } -static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned char val = 0; int ret; - if (octrl == NULL) + if (!v4l2_chip_match_i2c_client(client, ®->match)) return -EINVAL; - ret = octrl->query(client, &ctrl->value); - if (ret >= 0) - return 0; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = ov7670_read(sd, reg->reg & 0xff, &val); + reg->val = val; + reg->size = 1; return ret; } -static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - struct ov7670_control *octrl = ov7670_find_control(ctrl->id); - int ret; + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (octrl == NULL) + if (!v4l2_chip_match_i2c_client(client, ®->match)) return -EINVAL; - ret = octrl->tweak(client, ctrl->value); - if (ret >= 0) - return 0; - return ret; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + ov7670_write(sd, reg->reg & 0xff, reg->val & 0xff); + return 0; } +#endif +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops ov7670_core_ops = { + .g_chip_ident = ov7670_g_chip_ident, + .g_ctrl = ov7670_g_ctrl, + .s_ctrl = ov7670_s_ctrl, + .queryctrl = ov7670_queryctrl, + .reset = ov7670_reset, + .init = ov7670_init, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov7670_g_register, + .s_register = ov7670_s_register, +#endif +}; +static const struct v4l2_subdev_video_ops ov7670_video_ops = { + .enum_fmt = ov7670_enum_fmt, + .try_fmt = ov7670_try_fmt, + .s_fmt = ov7670_s_fmt, + .s_parm = ov7670_s_parm, + .g_parm = ov7670_g_parm, +}; +static const struct v4l2_subdev_ops ov7670_ops = { + .core = &ov7670_core_ops, + .video = &ov7670_video_ops, +}; +/* ----------------------------------------------------------------------- */ - -/* - * Basic i2c stuff. - */ -static struct i2c_driver ov7670_driver; - -static int ov7670_attach(struct i2c_adapter *adapter) +static int ov7670_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int ret; - struct i2c_client *client; + struct v4l2_subdev *sd; struct ov7670_info *info; + int ret; - /* - * For now: only deal with adapters we recognize. - */ - if (adapter->id != I2C_HW_SMBUS_CAFE) - return -ENODEV; - - client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); - if (! client) + info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL); + if (info == NULL) return -ENOMEM; - client->adapter = adapter; - client->addr = OV7670_I2C_ADDR; - client->driver = &ov7670_driver, - strcpy(client->name, "OV7670"); - /* - * Set up our info structure. - */ - info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); - if (! info) { - ret = -ENOMEM; - goto out_free; + sd = &info->sd; + v4l2_i2c_subdev_init(sd, client, &ov7670_ops); + + /* Make sure it's an ov7670 */ + ret = ov7670_detect(sd); + if (ret) { + v4l_dbg(1, debug, client, + "chip found @ 0x%x (%s) is not an ov7670 chip.\n", + client->addr << 1, client->adapter->name); + kfree(info); + return ret; } + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + info->fmt = &ov7670_formats[0]; info->sat = 128; /* Review this */ - i2c_set_clientdata(client, info); - /* - * Make sure it's an ov7670 - */ - ret = ov7670_detect(client); - if (ret) - goto out_free_info; - ret = i2c_attach_client(client); - if (ret) - goto out_free_info; return 0; - - out_free_info: - kfree(info); - out_free: - kfree(client); - return ret; } -static int ov7670_detach(struct i2c_client *client) +static int ov7670_remove(struct i2c_client *client) { - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - kfree(client); - return 0; -} - + struct v4l2_subdev *sd = i2c_get_clientdata(client); -static int ov7670_command(struct i2c_client *client, unsigned int cmd, - void *arg) -{ - switch (cmd) { - case VIDIOC_DBG_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); - - case VIDIOC_INT_RESET: - ov7670_reset(client); - return 0; - - case VIDIOC_INT_INIT: - return ov7670_init(client); - - case VIDIOC_ENUM_FMT: - return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); - case VIDIOC_TRY_FMT: - return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); - case VIDIOC_S_FMT: - return ov7670_s_fmt(client, (struct v4l2_format *) arg); - case VIDIOC_QUERYCTRL: - return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); - case VIDIOC_S_CTRL: - return ov7670_s_ctrl(client, (struct v4l2_control *) arg); - case VIDIOC_G_CTRL: - return ov7670_g_ctrl(client, (struct v4l2_control *) arg); - case VIDIOC_S_PARM: - return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); - case VIDIOC_G_PARM: - return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); - } - return -EINVAL; + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + return 0; } - - -static struct i2c_driver ov7670_driver = { - .driver = { - .name = "ov7670", - }, - .id = I2C_DRIVERID_OV7670, - .attach_adapter = ov7670_attach, - .detach_client = ov7670_detach, - .command = ov7670_command, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id ov7670_id[] = { + { "ov7670", 0 }, + { } }; +MODULE_DEVICE_TABLE(i2c, ov7670_id); - -/* - * Module initialization - */ -static int __init ov7670_mod_init(void) -{ - printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); - return i2c_add_driver(&ov7670_driver); -} - -static void __exit ov7670_mod_exit(void) -{ - i2c_del_driver(&ov7670_driver); -} - -module_init(ov7670_mod_init); -module_exit(ov7670_mod_exit); +#endif +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "ov7670", + .probe = ov7670_probe, + .remove = ov7670_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = ov7670_id, +#endif +}; diff --git a/linux/drivers/media/video/v4l2-subdev.c b/linux/drivers/media/video/v4l2-subdev.c index 923ec8d01..dc881671d 100644 --- a/linux/drivers/media/video/v4l2-subdev.c +++ b/linux/drivers/media/video/v4l2-subdev.c @@ -98,6 +98,10 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg) return v4l2_subdev_call(sd, video, g_vbi_data, arg); case VIDIOC_G_SLICED_VBI_CAP: return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg); + case VIDIOC_ENUM_FMT: + return v4l2_subdev_call(sd, video, enum_fmt, arg); + case VIDIOC_TRY_FMT: + return v4l2_subdev_call(sd, video, try_fmt, arg); case VIDIOC_S_FMT: return v4l2_subdev_call(sd, video, s_fmt, arg); case VIDIOC_G_FMT: @@ -112,6 +116,10 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg) return v4l2_subdev_call(sd, video, s_stream, 1); case VIDIOC_STREAMOFF: return v4l2_subdev_call(sd, video, s_stream, 0); + case VIDIOC_S_PARM: + return v4l2_subdev_call(sd, video, s_parm, arg); + case VIDIOC_G_PARM: + return v4l2_subdev_call(sd, video, g_parm, arg); default: return v4l2_subdev_call(sd, core, ioctl, cmd, arg); diff --git a/linux/include/media/v4l2-chip-ident.h b/linux/include/media/v4l2-chip-ident.h index ca2aa6d7e..1be461a29 100644 --- a/linux/include/media/v4l2-chip-ident.h +++ b/linux/include/media/v4l2-chip-ident.h @@ -146,21 +146,12 @@ enum { /* module tda9840: just ident 9840 */ V4L2_IDENT_TDA9840 = 9840, + /* module cafe_ccic, just ident 8801 */ + V4L2_IDENT_CAFE = 8801, + /* module tw9910: just ident 9910 */ V4L2_IDENT_TW9910 = 9910, - /* module cs53132a: just ident 53132 */ - V4L2_IDENT_CS53l32A = 53132, - - /* module upd64031a: just ident 64031 */ - V4L2_IDENT_UPD64031A = 64031, - - /* module upd64083: just ident 64083 */ - V4L2_IDENT_UPD64083 = 64083, - - /* module m52790: just ident 52790 */ - V4L2_IDENT_M52790 = 52790, - /* module msp3400: reserved range 34000-34999 and 44000-44999 */ V4L2_IDENT_MSPX4XX = 34000, /* generic MSPX4XX identifier, only use internally (tveeprom.c). */ @@ -237,6 +228,18 @@ enum { V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */ V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */ V4L2_IDENT_MT9T031 = 45020, + + /* module cs53132a: just ident 53132 */ + V4L2_IDENT_CS53l32A = 53132, + + /* module upd64031a: just ident 64031 */ + V4L2_IDENT_UPD64031A = 64031, + + /* module upd64083: just ident 64083 */ + V4L2_IDENT_UPD64083 = 64083, + + /* module m52790: just ident 52790 */ + V4L2_IDENT_M52790 = 52790, }; #endif diff --git a/linux/include/media/v4l2-subdev.h b/linux/include/media/v4l2-subdev.h index 1b97a2c33..d7a72d2d1 100644 --- a/linux/include/media/v4l2-subdev.h +++ b/linux/include/media/v4l2-subdev.h @@ -118,8 +118,12 @@ struct v4l2_subdev_video_ops { int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std); int (*g_input_status)(struct v4l2_subdev *sd, u32 *status); int (*s_stream)(struct v4l2_subdev *sd, int enable); - int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt); + int (*enum_fmt)(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc); int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt); + int (*try_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt); + int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt); + int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); + int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param); }; struct v4l2_subdev_ops { diff --git a/v4l2-apps/util/v4l2-dbg.cpp b/v4l2-apps/util/v4l2-dbg.cpp index f427d4442..424b0fffe 100644 --- a/v4l2-apps/util/v4l2-dbg.cpp +++ b/v4l2-apps/util/v4l2-dbg.cpp @@ -713,6 +713,9 @@ int main(int argc, char **argv) case V4L2_IDENT_CX23418: name = "cx23418"; break; + case V4L2_IDENT_CAFE: + name = "cafe"; + break; default: if (get_reg.match.type == V4L2_CHIP_MATCH_I2C_DRIVER) name = get_reg.match.name; @@ -726,6 +729,8 @@ int main(int argc, char **argv) print_regs(fd, &get_reg, 0, 0xff, stride); } else if (name == "saa7127") { print_regs(fd, &get_reg, 0, 0x7f, stride); + } else if (name == "ov7670") { + print_regs(fd, &get_reg, 0, 0x89, stride); } else if (name == "cx25840") { print_regs(fd, &get_reg, 0, 2, stride); print_regs(fd, &get_reg, 0x100, 0x15f, stride); @@ -738,6 +743,11 @@ int main(int argc, char **argv) print_regs(fd, &get_reg, 0x02000000, 0x020000ff, stride); } else if (name == "cx23418") { print_regs(fd, &get_reg, 0x02c40000, 0x02c409c7, stride); + } else if (name == "cafe") { + print_regs(fd, &get_reg, 0, 0x43, stride); + print_regs(fd, &get_reg, 0x88, 0x8f, stride); + print_regs(fd, &get_reg, 0xb4, 0xbb, stride); + print_regs(fd, &get_reg, 0x3000, 0x300c, stride); } else { /* unknown chip, dump 0-0xff by default */ print_regs(fd, &get_reg, 0, 0xff, stride); |