Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 153945
b: refs/heads/master
c: f0222c7
h: refs/heads/master
i:
  153943: 184a3a0
v: v3
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jun 23, 2009
1 parent b7a1c0a commit d2128fa
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 90135c96869fa0ef3182282b2a661b57fcdb7230
refs/heads/master: f0222c7d860f09a61bec5e500539f28db0184b38
105 changes: 105 additions & 0 deletions trunk/drivers/media/video/v4l2-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);

if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);

if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}

error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
Expand Down Expand Up @@ -852,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);

if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);

if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}

error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
Expand All @@ -872,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr);

/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
struct i2c_board_info *info, const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;

BUG_ON(!v4l2_dev);

if (module_name)
request_module(module_name);

/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
client = i2c_new_probed_device(adapter, info, probe_addrs);
else
client = i2c_new_device(adapter, info);

/* Note: by loading the module first we are certain that c->driver
will be set if the driver was found. If the module was not loaded
first, then the i2c core tries to delay-load the module for us,
and then c->driver is still NULL until the module is finally
loaded. This delay-load mechanism doesn't work if other drivers
want to use the i2c device, so explicitly loading the module
is the best alternative. */
if (client == NULL || client->driver == NULL)
goto error;

/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
goto error;
sd = i2c_get_clientdata(client);

/* Register with the v4l2_device which increases the module's
use count as well. */
if (v4l2_device_register_subdev(v4l2_dev, sd))
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);

if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config,
info->irq, info->platform_data);

if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}

error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
if (client && sd == NULL)
i2c_unregister_device(client);
return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);

struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
struct i2c_board_info info;

/* Setup the i2c board info with the device type and
the device address. */
memset(&info, 0, sizeof(info));
strlcpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
info.irq = irq;
info.platform_data = platform_data;

return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
&info, probe_addrs);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);

/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
{
Expand Down
16 changes: 16 additions & 0 deletions trunk/include/media/v4l2-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type, u8 addr);

/* Load an i2c module and return an initialized v4l2_subdev struct.
Only call request_module if module_name != NULL.
The client_type argument is the name of the chip that's on the adapter. */
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs);

struct i2c_board_info;

struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
struct i2c_board_info *info, const unsigned short *probe_addrs);

/* Initialize an v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops);
Expand Down
7 changes: 6 additions & 1 deletion trunk/include/media/v4l2-subdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ struct v4l2_decode_vbi_line {
not yet implemented) since ops provide proper type-checking.
*/

/* init: initialize the sensor registors to some sort of reasonable default
/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev*
functions after the v4l2_subdev was registered. It is used to pass
platform data to the subdev which can be used during initialization.
init: initialize the sensor registors to some sort of reasonable default
values. Do not use for new drivers and should be removed in existing
drivers.
Expand All @@ -96,6 +100,7 @@ struct v4l2_decode_vbi_line {
struct v4l2_subdev_core_ops {
int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
int (*log_status)(struct v4l2_subdev *sd);
int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
int (*init)(struct v4l2_subdev *sd, u32 val);
int (*load_fw)(struct v4l2_subdev *sd);
int (*reset)(struct v4l2_subdev *sd, u32 val);
Expand Down

0 comments on commit d2128fa

Please sign in to comment.