The patch number 10874 was added via Hans Verkuil <[email protected]>
to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel
If anyone has any objections, please let us know by sending a message to:
Linux Media Mailing List <[email protected]>
------
From: Hans Verkuil <[email protected]>
w9968cf/ovcamchip: convert to v4l2_subdev.
Priority: normal
Signed-off-by: Hans Verkuil <[email protected]>
---
linux/drivers/media/video/ovcamchip/ovcamchip_core.c | 258 +++++------
linux/drivers/media/video/ovcamchip/ovcamchip_priv.h | 7
linux/drivers/media/video/w9968cf.c | 119 +----
linux/drivers/media/video/w9968cf.h | 8
4 files changed, 166 insertions(+), 226 deletions(-)
diff -r e8c008b9e211 -r 203620165de2
linux/drivers/media/video/ovcamchip/ovcamchip_core.c
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c Sun Mar 08
10:56:19 2009 +0100
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c Sun Mar 08
14:19:44 2009 +0100
@@ -15,6 +15,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv.h>
#include "ovcamchip_priv.h"
#define DRIVER_VERSION "v2.27 for Linux 2.6"
@@ -43,6 +46,20 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = {
+ /* ov7xxx */
+ 0x42 >> 1, 0x46 >> 1, 0x4a >> 1, 0x4e >> 1,
+ 0x52 >> 1, 0x56 >> 1, 0x5a >> 1, 0x5e >> 1,
+ /* ov6xxx */
+ 0xc0 >> 1, 0xc4 >> 1, 0xc8 >> 1, 0xcc >> 1,
+ 0xd0 >> 1, 0xd4 >> 1, 0xd8 >> 1, 0xdc >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+#endif
/* Registers common to all chips, that are needed for detection */
#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
@@ -60,10 +77,6 @@ static char *chip_names[NUM_CC_TYPES] =
[CC_OV6630AE] = "OV6630AE",
[CC_OV6630AF] = "OV6630AF",
};
-
-/* Forward declarations */
-static struct i2c_driver driver;
-static struct i2c_client client_template;
/* ----------------------------------------------------------------------- */
@@ -253,112 +266,36 @@ static int ovcamchip_detect(struct i2c_c
/* Test for 7xx0 */
PDEBUG(3, "Testing for 0V7xx0");
- c->addr = OV7xx0_SID;
- if (init_camchip(c) < 0) {
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- c->addr = OV6xx0_SID;
- if (init_camchip(c) < 0) {
- return -ENODEV;
- } else {
- if (ov6xx0_detect(c) < 0) {
- PERROR("Failed to init OV6xx0");
- return -EIO;
- }
- }
- } else {
+ if (init_camchip(c) < 0)
+ return -ENODEV;
+ /* 7-bit addresses with bit 0 set are for the OV7xx0 */
+ if (c->addr & 1) {
if (ov7xx0_detect(c) < 0) {
PERROR("Failed to init OV7xx0");
return -EIO;
}
- }
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int ovcamchip_attach(struct i2c_adapter *adap)
-{
- int rc = 0;
- struct ovcamchip *ov;
- struct i2c_client *c;
-
- /* I2C is not a PnP bus, so we can never be certain that we're talking
- * to the right chip. To prevent damage to EEPROMS and such, only
- * attach to adapters that are known to contain OV camera chips. */
-
- switch (adap->id) {
- case I2C_HW_SMBUS_OV511:
- case I2C_HW_SMBUS_OV518:
- case I2C_HW_SMBUS_W9968CF:
- PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
- break;
- default:
- PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
- return -ENODEV;
- }
-
- c = kmalloc(sizeof *c, GFP_KERNEL);
- if (!c) {
- rc = -ENOMEM;
- goto no_client;
- }
- memcpy(c, &client_template, sizeof *c);
- c->adapter = adap;
- strcpy(c->name, "OV????");
-
- ov = kzalloc(sizeof *ov, GFP_KERNEL);
- if (!ov) {
- rc = -ENOMEM;
- goto no_ov;
- }
- i2c_set_clientdata(c, ov);
-
- rc = ovcamchip_detect(c);
- if (rc < 0)
- goto error;
-
- strcpy(c->name, chip_names[ov->subtype]);
-
- PDEBUG(1, "Camera chip detection complete");
-
- i2c_attach_client(c);
-
- return rc;
-error:
- kfree(ov);
-no_ov:
- kfree(c);
-no_client:
- PDEBUG(1, "returning %d", rc);
- return rc;
-}
-
-static int ovcamchip_detach(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
-
- rc = ov->sops->free(c);
- if (rc < 0)
- return rc;
-
- i2c_detach_client(c);
-
- kfree(ov);
- kfree(c);
- return 0;
-}
-
-static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
+ return 0;
+ }
+ /* Test for 6xx0 */
+ PDEBUG(3, "Testing for 0V6xx0");
+ if (ov6xx0_detect(c) < 0) {
+ PERROR("Failed to init OV6xx0");
+ return -EIO;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void
*arg)
+{
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
if (!ov->initialized &&
cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
cmd != OVCAMCHIP_CMD_INITIALIZE) {
- dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
+ v4l2_err(sd, "Camera chip not initialized yet!\n");
return -EPERM;
}
@@ -379,10 +316,10 @@ static int ovcamchip_command(struct i2c_
if (ov->mono) {
if (ov->subtype != CC_OV7620)
- dev_warn(&c->dev, "Warning: Monochrome not "
+ v4l2_warn(sd, "Monochrome not "
"implemented for this chip\n");
else
- dev_info(&c->dev, "Initializing chip as "
+ v4l2_info(sd, "Initializing chip as "
"monochrome\n");
}
@@ -398,37 +335,84 @@ static int ovcamchip_command(struct i2c_
}
}
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
- .driver = {
- .name = "ovcamchip",
- },
- .id = I2C_DRIVERID_OVCAMCHIP,
- .attach_adapter = ovcamchip_attach,
- .detach_client = ovcamchip_detach,
- .command = ovcamchip_command,
-};
-
-static struct i2c_client client_template = {
- .name = "(unset)",
- .driver = &driver,
-};
-
-static int __init ovcamchip_init(void)
-{
-#ifdef DEBUG
- ovcamchip_debug = debug;
+static int ovcamchip_command(struct i2c_client *client, unsigned cmd, void
*arg)
+{
+ return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
+ .ioctl = ovcamchip_ioctl,
+};
+
+static const struct v4l2_subdev_ops ovcamchip_ops = {
+ .core = &ovcamchip_core_ops,
+};
+
+static int ovcamchip_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ovcamchip *ov;
+ struct v4l2_subdev *sd;
+ int rc = 0;
+
+ ov = kzalloc(sizeof *ov, GFP_KERNEL);
+ if (!ov) {
+ rc = -ENOMEM;
+ goto no_ov;
+ }
+ sd = &ov->sd;
+ v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
+
+ rc = ovcamchip_detect(client);
+ if (rc < 0)
+ goto error;
+
+ v4l_info(client, "%s found @ 0x%02x (%s)\n",
+ chip_names[ov->subtype], client->addr << 1,
client->adapter->name);
+
+ PDEBUG(1, "Camera chip detection complete");
+
+ return rc;
+error:
+ kfree(ov);
+no_ov:
+ PDEBUG(1, "returning %d", rc);
+ return rc;
+}
+
+static int ovcamchip_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ovcamchip *ov = to_ovcamchip(sd);
+ int rc;
+
+ v4l2_device_unregister_subdev(sd);
+ rc = ov->sops->free(client);
+ if (rc < 0)
+ return rc;
+
+ kfree(ov);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id ovcamchip_id[] = {
+ { "ovcamchip", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
+
#endif
-
- PINFO(DRIVER_VERSION " : " DRIVER_DESC);
- return i2c_add_driver(&driver);
-}
-
-static void __exit ovcamchip_exit(void)
-{
- i2c_del_driver(&driver);
-}
-
-module_init(ovcamchip_init);
-module_exit(ovcamchip_exit);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "ovcamchip",
+ .command = ovcamchip_command,
+ .probe = ovcamchip_probe,
+ .remove = ovcamchip_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = ovcamchip_id,
+#endif
+};
diff -r e8c008b9e211 -r 203620165de2
linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h Sun Mar 08
10:56:19 2009 +0100
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h Sun Mar 08
14:19:44 2009 +0100
@@ -16,6 +16,7 @@
#define __LINUX_OVCAMCHIP_PRIV_H
#include <linux/i2c.h>
+#include <media/v4l2-subdev.h>
#include <media/ovcamchip.h>
#ifdef DEBUG
@@ -46,12 +47,18 @@ struct ovcamchip_ops {
};
struct ovcamchip {
+ struct v4l2_subdev sd;
struct ovcamchip_ops *sops;
void *spriv; /* Private data for OV7x10.c etc... */
int subtype; /* = SEN_OV7610 etc... */
int mono; /* Monochrome chip? (invalid until init) */
int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
};
+
+static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ovcamchip, sd);
+}
extern struct ovcamchip_ops ov6x20_ops;
extern struct ovcamchip_ops ov6x30_ops;
diff -r e8c008b9e211 -r 203620165de2 linux/drivers/media/video/w9968cf.c
--- a/linux/drivers/media/video/w9968cf.c Sun Mar 08 10:56:19 2009 +0100
+++ b/linux/drivers/media/video/w9968cf.c Sun Mar 08 14:19:44 2009 +0100
@@ -68,7 +68,6 @@ MODULE_LICENSE(W9968CF_MODULE_LICENSE);
MODULE_LICENSE(W9968CF_MODULE_LICENSE);
MODULE_SUPPORTED_DEVICE("Video");
-static int ovmod_load = W9968CF_OVMOD_LOAD;
static unsigned short simcams = W9968CF_SIMCAMS;
static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
@@ -111,9 +110,6 @@ static int specific_debug = W9968CF_SPEC
static unsigned int param_nv[24]; /* number of values per parameter */
-#ifdef CONFIG_MODULES
-module_param(ovmod_load, bool, 0644);
-#endif
module_param(simcams, ushort, 0644);
module_param_array(video_nr, short, ¶m_nv[0], 0444);
module_param_array(packet_size, uint, ¶m_nv[1], 0444);
@@ -144,18 +140,6 @@ module_param(specific_debug, bool, 0644)
module_param(specific_debug, bool, 0644);
#endif
-#ifdef CONFIG_MODULES
-MODULE_PARM_DESC(ovmod_load,
- "\n<0|1> Automatic 'ovcamchip' module loading."
- "\n0 disabled, 1 enabled."
- "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
- "\nmodule in the system, according to its configuration, and"
- "\nattempts to load that module automatically. This action is"
- "\nperformed once as soon as the 'w9968cf' module is loaded"
- "\ninto memory."
- "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
- "\n");
-#endif
MODULE_PARM_DESC(simcams,
"\n<n> Number of cameras allowed to stream simultaneously."
"\nn may vary from 0 to "
@@ -447,8 +431,6 @@ static int w9968cf_i2c_smbus_xfer(struct
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data*);
static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
/* Memory management */
static void* rvmalloc(unsigned long size);
@@ -1451,18 +1433,10 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapte
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
- struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+ struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
+ struct w9968cf_device *cam = to_cam(v4l2_dev);
u8 i;
int err = 0;
-
- switch (addr) {
- case OV6xx0_SID:
- case OV7xx0_SID:
- break;
- default:
- DBG(4, "Rejected slave ID 0x%04X", addr)
- return -EINVAL;
- }
if (size == I2C_SMBUS_BYTE) {
/* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
@@ -1471,8 +1445,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapte
if (read_write == I2C_SMBUS_WRITE)
err = w9968cf_i2c_adap_write_byte(cam, addr, command);
else if (read_write == I2C_SMBUS_READ)
- err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
+ for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+ err = w9968cf_i2c_adap_read_byte(cam, addr,
+ &data->byte);
+ if (err) {
+ if (w9968cf_smbus_refresh_bus(cam)) {
+ err = -EIO;
+ break;
+ }
+ } else
+ break;
+ }
} else if (size == I2C_SMBUS_BYTE_DATA) {
addr <<= 1;
@@ -1499,7 +1482,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapte
DBG(4, "Unsupported I2C transfer mode (%d)", size)
return -EINVAL;
}
-
return err;
}
@@ -1509,44 +1491,6 @@ static u32 w9968cf_i2c_func(struct i2c_a
return I2C_FUNC_SMBUS_READ_BYTE |
I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
- int id = client->driver->id, err = 0;
-
- if (id == I2C_DRIVERID_OVCAMCHIP) {
- cam->sensor_client = client;
- err = w9968cf_sensor_init(cam);
- if (err) {
- cam->sensor_client = NULL;
- return err;
- }
- } else {
- DBG(4, "Rejected client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
- return -EINVAL;
- }
-
- DBG(5, "I2C attach client [%s] with driver [%s]",
- client->name, client->driver->driver.name)
-
- return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
- struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
- if (cam->sensor_client == client)
- cam->sensor_client = NULL;
-
- DBG(5, "I2C detach client [%s]", client->name)
-
- return 0;
}
@@ -1565,15 +1509,16 @@ static int w9968cf_i2c_init(struct w9968
static struct i2c_adapter adap = {
.id = I2C_HW_SMBUS_W9968CF,
.owner = THIS_MODULE,
- .client_register = w9968cf_i2c_attach_inform,
- .client_unregister = w9968cf_i2c_detach_inform,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
.algo = &algo,
};
memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
strcpy(cam->i2c_adapter.name, "w9968cf");
cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
- i2c_set_adapdata(&cam->i2c_adapter, cam);
+ i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
DBG(6, "Registering I2C adapter with kernel...")
@@ -2176,13 +2121,9 @@ static int
static int
w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
{
- struct i2c_client* c = cam->sensor_client;
- int rc = 0;
-
- if (!c || !c->driver || !c->driver->command)
- return -EINVAL;
-
- rc = c->driver->command(c, cmd, arg);
+ int rc;
+
+ rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
/* The I2C driver returns -EPERM on non-supported controls */
return (rc < 0 && rc != -EPERM) ? rc : 0;
}
@@ -2357,7 +2298,7 @@ static int w9968cf_sensor_init(struct w9
goto error;
/* NOTE: Make sure width and height are a multiple of 16 */
- switch (cam->sensor_client->addr) {
+ switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
case OV6xx0_SID:
cam->maxwidth = 352;
cam->maxheight = 288;
@@ -2662,6 +2603,7 @@ static void w9968cf_release_resources(st
w9968cf_deallocate_memory(cam);
kfree(cam->control_buffer);
kfree(cam->data_buffer);
+ v4l2_device_unregister(&cam->v4l2_dev);
mutex_unlock(&w9968cf_devlist_mutex);
}
@@ -3491,6 +3433,11 @@ w9968cf_usb_probe(struct usb_interface*
struct list_head* ptr;
u8 sc = 0; /* number of simultaneous cameras */
static unsigned short dev_nr; /* 0 - we are handling device number n */
+ static unsigned short addrs[] = {
+ OV7xx0_SID,
+ OV6xx0_SID,
+ I2C_CLIENT_END
+ };
if (le16_to_cpu(udev->descriptor.idVendor) ==
winbond_id_table[0].idVendor &&
le16_to_cpu(udev->descriptor.idProduct) ==
winbond_id_table[0].idProduct)
@@ -3589,12 +3536,13 @@ w9968cf_usb_probe(struct usb_interface*
w9968cf_turn_on_led(cam);
w9968cf_i2c_init(cam);
+ cam->sensor_sd = v4l2_i2c_new_probed_subdev(&cam->i2c_adapter,
+ "ovcamchip", "ovcamchip", addrs);
usb_set_intfdata(intf, cam);
mutex_unlock(&cam->dev_mutex);
- if (ovmod_load)
- request_module("ovcamchip");
+ err = w9968cf_sensor_init(cam);
return 0;
fail: /* Free unused memory */
@@ -3615,9 +3563,8 @@ static void w9968cf_usb_disconnect(struc
struct w9968cf_device* cam =
(struct w9968cf_device*)usb_get_intfdata(intf);
- down_write(&w9968cf_disconnect);
-
if (cam) {
+ down_write(&w9968cf_disconnect);
/* Prevent concurrent accesses to data */
mutex_lock(&cam->dev_mutex);
@@ -3639,14 +3586,12 @@ static void w9968cf_usb_disconnect(struc
w9968cf_release_resources(cam);
mutex_unlock(&cam->dev_mutex);
+ up_write(&w9968cf_disconnect);
if (!cam->users) {
- v4l2_device_unregister(&cam->v4l2_dev);
kfree(cam);
}
}
-
- up_write(&w9968cf_disconnect);
}
diff -r e8c008b9e211 -r 203620165de2 linux/drivers/media/video/w9968cf.h
--- a/linux/drivers/media/video/w9968cf.h Sun Mar 08 10:56:19 2009 +0100
+++ b/linux/drivers/media/video/w9968cf.h Sun Mar 08 14:19:44 2009 +0100
@@ -44,7 +44,6 @@
* Default values *
****************************************************************************/
-#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */
#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
/* Comment/uncomment the following line to enable/disable debugging messages */
@@ -266,7 +265,7 @@ struct w9968cf_device {
/* I2C interface to kernel */
struct i2c_adapter i2c_adapter;
- struct i2c_client* sensor_client;
+ struct v4l2_subdev *sensor_sd;
/* Locks */
struct mutex dev_mutex, /* for probe, disconnect,open and close */
@@ -277,6 +276,11 @@ struct w9968cf_device {
char command[16]; /* name of the program holding the device */
};
+
+static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
+}
/****************************************************************************
---
Patch is available at:
http://linuxtv.org/hg/v4l-dvb/rev/203620165de2fc9ff6f4f5ce0f925a6e0e11d57a
_______________________________________________
linuxtv-commits mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits