V4L/DVB (10874): w9968cf/ovcamchip: convert to v4l2_subdev.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Hans Verkuil 2009-03-08 10:19:44 -03:00 committed by Mauro Carvalho Chehab
parent 4e06839fc7
commit 3160fbc556
4 changed files with 126 additions and 206 deletions

View File

@ -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"
@ -44,6 +47,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/* Registers common to all chips, that are needed for detection */
#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
@ -61,10 +65,6 @@ static char *chip_names[NUM_CC_TYPES] = {
[CC_OV6630AF] = "OV6630AF",
};
/* Forward declarations */
static struct i2c_driver driver;
static struct i2c_client client_template;
/* ----------------------------------------------------------------------- */
int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
@ -253,112 +253,36 @@ static int ovcamchip_detect(struct i2c_client *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) {
if (init_camchip(c) < 0)
return -ENODEV;
} else {
if (ov6xx0_detect(c) < 0) {
PERROR("Failed to init OV6xx0");
return -EIO;
}
}
} else {
/* 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;
}
/* Test for 6xx0 */
PDEBUG(3, "Testing for 0V6xx0");
if (ov6xx0_detect(c) < 0) {
PERROR("Failed to init OV6xx0");
return -EIO;
}
return 0;
}
/* ----------------------------------------------------------------------- */
static int ovcamchip_attach(struct i2c_adapter *adap)
static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
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);
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 +303,10 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
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 +322,80 @@ static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
}
}
static int ovcamchip_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
.driver = {
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;
}
/* ----------------------------------------------------------------------- */
static const struct i2c_device_id ovcamchip_id[] = {
{ "ovcamchip", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "ovcamchip",
},
.id = I2C_DRIVERID_OVCAMCHIP,
.attach_adapter = ovcamchip_attach,
.detach_client = ovcamchip_detach,
.command = ovcamchip_command,
.probe = ovcamchip_probe,
.remove = ovcamchip_remove,
.id_table = ovcamchip_id,
};
static struct i2c_client client_template = {
.name = "(unset)",
.driver = &driver,
};
static int __init ovcamchip_init(void)
{
#ifdef DEBUG
ovcamchip_debug = debug;
#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);

View File

@ -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,6 +47,7 @@ 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... */
@ -53,6 +55,11 @@ struct ovcamchip {
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;
extern struct ovcamchip_ops ov7x10_ops;

View File

@ -68,7 +68,6 @@ MODULE_VERSION(W9968CF_MODULE_VERSION);
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_SPECIFIC_DEBUG;
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, &param_nv[0], 0444);
module_param_array(packet_size, uint, &param_nv[1], 0444);
@ -144,18 +140,6 @@ module_param(debug, ushort, 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 "
@ -443,8 +427,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
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);
@ -1443,19 +1425,11 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
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 */
addr <<= 1;
@ -1463,8 +1437,17 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
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;
@ -1491,7 +1474,6 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
DBG(4, "Unsupported I2C transfer mode (%d)", size)
return -EINVAL;
}
return err;
}
@ -1504,44 +1486,6 @@ static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
}
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;
}
static int w9968cf_i2c_init(struct w9968cf_device* cam)
{
int err = 0;
@ -1554,15 +1498,13 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
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,
.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...")
@ -2165,13 +2107,9 @@ w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
static int
w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
{
struct i2c_client* c = cam->sensor_client;
int rc = 0;
int rc;
if (!c || !c->driver || !c->driver->command)
return -EINVAL;
rc = c->driver->command(c, cmd, arg);
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;
}
@ -2346,7 +2284,7 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam)
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;
@ -2651,6 +2589,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
w9968cf_deallocate_memory(cam);
kfree(cam->control_buffer);
kfree(cam->data_buffer);
v4l2_device_unregister(&cam->v4l2_dev);
mutex_unlock(&w9968cf_devlist_mutex);
}
@ -3480,6 +3419,11 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
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)
@ -3578,12 +3522,13 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
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 */
@ -3604,9 +3549,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
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);
@ -3628,14 +3572,12 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
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);
}

View File

@ -43,7 +43,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 */
@ -265,7 +264,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);
}
/****************************************************************************
* Macros for debugging *