From 3a89db5f30576654bf1b0036af9b50ed5ab1b6c5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Jun 2010 11:33:52 +0200 Subject: [PATCH] i2c: Check for address validity on client registration Do basic address validity checks when a client is being registered. We already had checks in place for devices which are being detected, but not for devices which are simply instantiated. This is a very basic check. We don't want to do strict checking here because some devices are known to infringe the I2C address constraints (e.g. IR receivers at 7-bit address 0x7a while this value is supposedly reserved for 10-bit addresses.) So we assume the caller knows what it is doing. Signed-off-by: Jean Delvare Cc: Matthieu Castet --- drivers/i2c/i2c-core.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f744f73e3ff..96f01331544 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -371,6 +371,22 @@ struct i2c_client *i2c_verify_client(struct device *dev) EXPORT_SYMBOL(i2c_verify_client); +/* This is a permissive address validity check, I2C address map constraints + * are purposedly not enforced, except for the general call address. */ +static int i2c_check_client_addr_validity(const struct i2c_client *client) +{ + if (client->flags & I2C_CLIENT_TEN) { + /* 10-bit address, all values are valid */ + if (client->addr > 0x3ff) + return -EINVAL; + } else { + /* 7-bit address, reject the general call address */ + if (client->addr == 0x00 || client->addr > 0x7f) + return -EINVAL; + } + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -410,6 +426,14 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); + /* Check for address validity */ + status = i2c_check_client_addr_validity(client); + if (status) { + dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", + client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); + goto out_err_silent; + } + /* Check for address business */ status = i2c_check_addr(adap, client->addr); if (status) @@ -436,6 +460,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); +out_err_silent: kfree(client); return NULL; } @@ -561,15 +586,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EINVAL; } - if (info.addr < 0x03 || info.addr > 0x77) { - dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", - info.addr); - return -EINVAL; - } - client = i2c_new_device(adap, &info); if (!client) - return -EEXIST; + return -EINVAL; /* Keep track of the added device */ i2c_lock_adapter(adap); -- 2.39.3