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:
parent
4e06839fc7
commit
3160fbc556
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
/* 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 = {
|
||||
.name = "ovcamchip",
|
||||
},
|
||||
.id = I2C_DRIVERID_OVCAMCHIP,
|
||||
.attach_adapter = ovcamchip_attach,
|
||||
.detach_client = ovcamchip_detach,
|
||||
.command = ovcamchip_command,
|
||||
static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
|
||||
.ioctl = ovcamchip_ioctl,
|
||||
};
|
||||
|
||||
static struct i2c_client client_template = {
|
||||
.name = "(unset)",
|
||||
.driver = &driver,
|
||||
static const struct v4l2_subdev_ops ovcamchip_ops = {
|
||||
.core = &ovcamchip_core_ops,
|
||||
};
|
||||
|
||||
static int __init ovcamchip_init(void)
|
||||
static int ovcamchip_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
ovcamchip_debug = debug;
|
||||
#endif
|
||||
struct ovcamchip *ov;
|
||||
struct v4l2_subdev *sd;
|
||||
int rc = 0;
|
||||
|
||||
PINFO(DRIVER_VERSION " : " DRIVER_DESC);
|
||||
return i2c_add_driver(&driver);
|
||||
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 void __exit ovcamchip_exit(void)
|
||||
static int ovcamchip_remove(struct i2c_client *client)
|
||||
{
|
||||
i2c_del_driver(&driver);
|
||||
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;
|
||||
}
|
||||
|
||||
module_init(ovcamchip_init);
|
||||
module_exit(ovcamchip_exit);
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
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",
|
||||
.command = ovcamchip_command,
|
||||
.probe = ovcamchip_probe,
|
||||
.remove = ovcamchip_remove,
|
||||
.id_table = ovcamchip_id,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ¶m_nv[0], 0444);
|
||||
module_param_array(packet_size, uint, ¶m_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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in New Issue