|
@@ -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);
|
|
|
}
|
|
|
|
|
|
|