diff options
author | Jean Delvare <khali@linux-fr.org> | 2010-06-03 05:33:52 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2010-06-03 05:33:52 -0400 |
commit | 3a89db5f30576654bf1b0036af9b50ed5ab1b6c5 (patch) | |
tree | d603ebb2bd97c3beb5baa6132a1871e8dd939954 | |
parent | 63e4e80218803ff506b3ea4f2349b17916a35730 (diff) |
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 <khali@linux-fr.org>
Cc: Matthieu Castet <castet.matthieu@free.fr>
-rw-r--r-- | drivers/i2c/i2c-core.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f744f73e3ff5..96f01331544d 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) | |||
371 | EXPORT_SYMBOL(i2c_verify_client); | 371 | EXPORT_SYMBOL(i2c_verify_client); |
372 | 372 | ||
373 | 373 | ||
374 | /* This is a permissive address validity check, I2C address map constraints | ||
375 | * are purposedly not enforced, except for the general call address. */ | ||
376 | static int i2c_check_client_addr_validity(const struct i2c_client *client) | ||
377 | { | ||
378 | if (client->flags & I2C_CLIENT_TEN) { | ||
379 | /* 10-bit address, all values are valid */ | ||
380 | if (client->addr > 0x3ff) | ||
381 | return -EINVAL; | ||
382 | } else { | ||
383 | /* 7-bit address, reject the general call address */ | ||
384 | if (client->addr == 0x00 || client->addr > 0x7f) | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | return 0; | ||
388 | } | ||
389 | |||
374 | /** | 390 | /** |
375 | * i2c_new_device - instantiate an i2c device | 391 | * i2c_new_device - instantiate an i2c device |
376 | * @adap: the adapter managing the device | 392 | * @adap: the adapter managing the device |
@@ -410,6 +426,14 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) | |||
410 | 426 | ||
411 | strlcpy(client->name, info->type, sizeof(client->name)); | 427 | strlcpy(client->name, info->type, sizeof(client->name)); |
412 | 428 | ||
429 | /* Check for address validity */ | ||
430 | status = i2c_check_client_addr_validity(client); | ||
431 | if (status) { | ||
432 | dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", | ||
433 | client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); | ||
434 | goto out_err_silent; | ||
435 | } | ||
436 | |||
413 | /* Check for address business */ | 437 | /* Check for address business */ |
414 | status = i2c_check_addr(adap, client->addr); | 438 | status = i2c_check_addr(adap, client->addr); |
415 | if (status) | 439 | if (status) |
@@ -436,6 +460,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) | |||
436 | out_err: | 460 | out_err: |
437 | dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " | 461 | dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " |
438 | "(%d)\n", client->name, client->addr, status); | 462 | "(%d)\n", client->name, client->addr, status); |
463 | out_err_silent: | ||
439 | kfree(client); | 464 | kfree(client); |
440 | return NULL; | 465 | return NULL; |
441 | } | 466 | } |
@@ -561,15 +586,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, | |||
561 | return -EINVAL; | 586 | return -EINVAL; |
562 | } | 587 | } |
563 | 588 | ||
564 | if (info.addr < 0x03 || info.addr > 0x77) { | ||
565 | dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", | ||
566 | info.addr); | ||
567 | return -EINVAL; | ||
568 | } | ||
569 | |||
570 | client = i2c_new_device(adap, &info); | 589 | client = i2c_new_device(adap, &info); |
571 | if (!client) | 590 | if (!client) |
572 | return -EEXIST; | 591 | return -EINVAL; |
573 | 592 | ||
574 | /* Keep track of the added device */ | 593 | /* Keep track of the added device */ |
575 | i2c_lock_adapter(adap); | 594 | i2c_lock_adapter(adap); |