diff options
author | Jean Delvare <khali@linux-fr.org> | 2005-08-09 14:17:55 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-09-05 12:14:25 -0400 |
commit | a89ba0bc02e82920a0f4137aa5d655ac0366cc28 (patch) | |
tree | 98489ed77a287a81ff4ad7233fd543e59e58c328 | |
parent | 3b6c0634cc989f0735a1541ccf9288947685cab5 (diff) |
[PATCH] I2C: Rewrite i2c_probe
i2c_probe was quite complex and slow, so I rewrote it in a more
efficient and hopefully clearer way.
Note that this slightly changes the way the module parameters are
handled. This shouldn't change anything for the most common cases
though.
For one thing, the function now respects the order of the parameters
for address probing. It used to always do lower addresses first. The
new approach gives the user more control.
For another, ignore addresses don't overrule probe addresses anymore.
This could have been restored the way it was at the cost of a few more
lines of code, but I don't think it's worth it. Both lists are given
as module parameters, so a user would be quite silly to specify the
same addresses in both lists. The normal addresses list is the only
one that isn't controlled by a module parameter, thus is the only one
the user may reasonably want to remove an address from.
Another significant change is the fact that i2c_probe() will no more
stop when a detection function returns -ENODEV. Just because a driver
found a chip it doesn't support isn't a valid reason to stop all
probings for this one driver. This closes the long standing lm_sensors
ticket #1807.
http://www2.lm-sensors.nu/~lm78/readticket.cgi?ticket=1807
I updated the documentation accordingly.
In terms of algorithmic complexity, the new code is way better. If
I is the ignore address count, P the probe address count, N the
normal address count and F the force address count, the old code
was doing 128 * (F + I + P + N) iterations max, while the new code
does F + P + ((I+1) * N) iterations max. For the most common case
where F, I and P are empty, this is down from 128 * N to N.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | Documentation/i2c/writing-clients | 7 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 165 |
2 files changed, 93 insertions, 79 deletions
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 97e138cbb2a9..077275722a7c 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients | |||
@@ -241,9 +241,10 @@ Below, some things are only needed if this is a `sensors' driver. Those | |||
241 | parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ | 241 | parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ |
242 | markers. | 242 | markers. |
243 | 243 | ||
244 | This function should only return an error (any value != 0) if there is | 244 | Returning an error different from -ENODEV in a detect function will cause |
245 | some reason why no more detection should be done anymore. If the | 245 | the detection to stop: other addresses and adapters won't be scanned. |
246 | detection just fails for this address, return 0. | 246 | This should only be done on fatal or internal errors, such as a memory |
247 | shortage or i2c_attach_client failing. | ||
247 | 248 | ||
248 | For now, you can ignore the `flags' parameter. It is there for future use. | 249 | For now, you can ignore the `flags' parameter. It is there for future use. |
249 | 250 | ||
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 372b5996d045..bee0148dfab8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -662,107 +662,120 @@ int i2c_control(struct i2c_client *client, | |||
662 | * Will not work for 10-bit addresses! | 662 | * Will not work for 10-bit addresses! |
663 | * ---------------------------------------------------- | 663 | * ---------------------------------------------------- |
664 | */ | 664 | */ |
665 | /* Return: kind (>= 0) if force found, -1 if not found */ | 665 | static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, |
666 | static inline int i2c_probe_forces(struct i2c_adapter *adapter, int addr, | 666 | int (*found_proc) (struct i2c_adapter *, int, int)) |
667 | unsigned short **forces) | ||
668 | { | 667 | { |
669 | unsigned short kind; | 668 | int err; |
670 | int j, adap_id = i2c_adapter_id(adapter); | 669 | |
671 | 670 | /* Make sure the address is valid */ | |
672 | for (kind = 0; forces[kind]; kind++) { | 671 | if (addr < 0x03 || addr > 0x77) { |
673 | for (j = 0; forces[kind][j] != I2C_CLIENT_END; j += 2) { | 672 | dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", |
674 | if ((forces[kind][j] == adap_id || | 673 | addr); |
675 | forces[kind][j] == ANY_I2C_BUS) | 674 | return -EINVAL; |
676 | && forces[kind][j + 1] == addr) { | ||
677 | dev_dbg(&adapter->dev, "found force parameter, " | ||
678 | "addr 0x%02x, kind %u\n", addr, kind); | ||
679 | return kind; | ||
680 | } | ||
681 | } | ||
682 | } | 675 | } |
683 | 676 | ||
684 | return -1; | 677 | /* Skip if already in use */ |
678 | if (i2c_check_addr(adapter, addr)) | ||
679 | return 0; | ||
680 | |||
681 | /* Make sure there is something at this address, unless forced */ | ||
682 | if (kind < 0 | ||
683 | && i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0) | ||
684 | return 0; | ||
685 | |||
686 | /* Finally call the custom detection function */ | ||
687 | err = found_proc(adapter, addr, kind); | ||
688 | |||
689 | /* -ENODEV can be returned if there is a chip at the given address | ||
690 | but it isn't supported by this chip driver. We catch it here as | ||
691 | this isn't an error. */ | ||
692 | return (err == -ENODEV) ? 0 : err; | ||
685 | } | 693 | } |
686 | 694 | ||
687 | int i2c_probe(struct i2c_adapter *adapter, | 695 | int i2c_probe(struct i2c_adapter *adapter, |
688 | struct i2c_client_address_data *address_data, | 696 | struct i2c_client_address_data *address_data, |
689 | int (*found_proc) (struct i2c_adapter *, int, int)) | 697 | int (*found_proc) (struct i2c_adapter *, int, int)) |
690 | { | 698 | { |
691 | int addr,i,found,err; | 699 | int i, err; |
692 | int adap_id = i2c_adapter_id(adapter); | 700 | int adap_id = i2c_adapter_id(adapter); |
693 | 701 | ||
694 | /* Forget it if we can't probe using SMBUS_QUICK */ | 702 | /* Forget it if we can't probe using SMBUS_QUICK */ |
695 | if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) | 703 | if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) |
696 | return -1; | 704 | return -1; |
697 | 705 | ||
698 | for (addr = 0x00; addr <= 0x7f; addr++) { | 706 | /* Force entries are done first, and are not affected by ignore |
699 | 707 | entries */ | |
700 | /* Skip if already in use */ | 708 | if (address_data->forces) { |
701 | if (i2c_check_addr(adapter,addr)) | 709 | unsigned short **forces = address_data->forces; |
702 | continue; | 710 | int kind; |
703 | 711 | ||
704 | /* If it is in one of the force entries, we don't do any detection | 712 | for (kind = 0; forces[kind]; kind++) { |
705 | at all */ | 713 | for (i = 0; forces[kind][i] != I2C_CLIENT_END; |
706 | found = 0; | 714 | i += 2) { |
707 | 715 | if (forces[kind][i] == adap_id | |
708 | if (address_data->forces) { | 716 | || forces[kind][i] == ANY_I2C_BUS) { |
709 | int kind = i2c_probe_forces(adapter, addr, | 717 | dev_dbg(&adapter->dev, "found force " |
710 | address_data->forces); | 718 | "parameter for adapter %d, " |
711 | if (kind >= 0) { /* force found */ | 719 | "addr 0x%02x, kind %d\n", |
712 | if ((err = found_proc(adapter, addr, kind))) | 720 | adap_id, forces[kind][i + 1], |
713 | return err; | 721 | kind); |
714 | continue; | 722 | err = i2c_probe_address(adapter, |
715 | } | 723 | forces[kind][i + 1], |
716 | } | 724 | kind, found_proc); |
717 | 725 | if (err) | |
718 | /* If this address is in one of the ignores, we can forget about | 726 | return err; |
719 | it right now */ | 727 | } |
720 | for (i = 0; | ||
721 | !found && (address_data->ignore[i] != I2C_CLIENT_END); | ||
722 | i += 2) { | ||
723 | if (((adap_id == address_data->ignore[i]) || | ||
724 | ((address_data->ignore[i] == ANY_I2C_BUS))) && | ||
725 | (addr == address_data->ignore[i+1])) { | ||
726 | dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, " | ||
727 | "addr %04x\n", adap_id ,addr); | ||
728 | found = 1; | ||
729 | } | 728 | } |
730 | } | 729 | } |
731 | if (found) | 730 | } |
732 | continue; | ||
733 | 731 | ||
734 | /* Now, we will do a detection, but only if it is in the normal or | 732 | /* Probe entries are done second, and are not affected by ignore |
735 | probe entries */ | 733 | entries either */ |
736 | for (i = 0; | 734 | for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { |
737 | !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); | 735 | if (address_data->probe[i] == adap_id |
738 | i += 1) { | 736 | || address_data->probe[i] == ANY_I2C_BUS) { |
739 | if (addr == address_data->normal_i2c[i]) { | 737 | dev_dbg(&adapter->dev, "found probe parameter for " |
740 | found = 1; | 738 | "adapter %d, addr 0x%02x\n", adap_id, |
741 | dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, " | 739 | address_data->probe[i + 1]); |
742 | "addr %02x\n", adap_id, addr); | 740 | err = i2c_probe_address(adapter, |
743 | } | 741 | address_data->probe[i + 1], |
742 | -1, found_proc); | ||
743 | if (err) | ||
744 | return err; | ||
744 | } | 745 | } |
746 | } | ||
745 | 747 | ||
746 | for (i = 0; | 748 | /* Normal entries are done last, unless shadowed by an ignore entry */ |
747 | !found && (address_data->probe[i] != I2C_CLIENT_END); | 749 | for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { |
748 | i += 2) { | 750 | int j, ignore; |
749 | if (((adap_id == address_data->probe[i]) || | 751 | |
750 | ((address_data->probe[i] == ANY_I2C_BUS))) && | 752 | ignore = 0; |
751 | (addr == address_data->probe[i+1])) { | 753 | for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; |
752 | found = 1; | 754 | j += 2) { |
753 | dev_dbg(&adapter->dev, "found probe parameter for adapter %d, " | 755 | if ((address_data->ignore[j] == adap_id || |
754 | "addr %04x\n", adap_id,addr); | 756 | address_data->ignore[j] == ANY_I2C_BUS) |
757 | && address_data->ignore[j + 1] | ||
758 | == address_data->normal_i2c[i]) { | ||
759 | dev_dbg(&adapter->dev, "found ignore " | ||
760 | "parameter for adapter %d, " | ||
761 | "addr 0x%02x\n", adap_id, | ||
762 | address_data->ignore[j + 1]); | ||
755 | } | 763 | } |
764 | ignore = 1; | ||
765 | break; | ||
756 | } | 766 | } |
757 | if (!found) | 767 | if (ignore) |
758 | continue; | 768 | continue; |
759 | 769 | ||
760 | /* OK, so we really should examine this address. First check | 770 | dev_dbg(&adapter->dev, "found normal entry for adapter %d, " |
761 | whether there is some client here at all! */ | 771 | "addr 0x%02x\n", adap_id, |
762 | if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) | 772 | address_data->normal_i2c[i]); |
763 | if ((err = found_proc(adapter,addr,-1))) | 773 | err = i2c_probe_address(adapter, address_data->normal_i2c[i], |
764 | return err; | 774 | -1, found_proc); |
775 | if (err) | ||
776 | return err; | ||
765 | } | 777 | } |
778 | |||
766 | return 0; | 779 | return 0; |
767 | } | 780 | } |
768 | 781 | ||