On Sat, 7 Jun 2008 09:35:15 +0200, Jean Delvare wrote:
> None of these solutions make me totally happy, but I guess that the
> most reasonable one is the second one (have i2c-core allocate
> i2c_client and pass it to detect callbacks.) Maybe if we document
> properly that the only thing one is allowed to do with this i2c_client
> is call i2c_smbus_read_byte_data() and i2c_smbus_read_word_data(), it's
> acceptable. I welcome comments and ideas on this problem.

Here's what it would look like (patch applies on top of the last series
I posted, for the moment.) That's probably better than my original
proposal. The diffstat clearly shows how it simplifies the detect
callback of each chip driver.

---
 drivers/hwmon/f75375s.c |   24 +++++-----------------
 drivers/hwmon/lm75.c    |   35 ++++++++------------------------
 drivers/hwmon/lm90.c    |   34 +++++++++----------------------
 drivers/i2c/i2c-core.c  |   50 +++++++++++++++++++++++++++++------------------
 include/linux/i2c.h     |    3 --
 5 files changed, 57 insertions(+), 89 deletions(-)

--- linux-2.6.26-rc5.orig/drivers/hwmon/f75375s.c       2008-06-07 
10:52:59.000000000 +0200
+++ linux-2.6.26-rc5/drivers/hwmon/f75375s.c    2008-06-07 11:14:47.000000000 
+0200
@@ -114,7 +114,7 @@ struct f75375_data {
        s8 temp_max_hyst[2];
 };
 
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind,
+static int f75375_detect(struct i2c_client *client, int kind,
                         struct i2c_board_info *info);
 static int f75375_probe(struct i2c_client *client,
                        const struct i2c_device_id *id);
@@ -679,21 +679,13 @@ static int f75375_remove(struct i2c_clie
 }
 
 /* This function is called by i2c_probe */
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind,
+static int f75375_detect(struct i2c_client *client, int kind,
                         struct i2c_board_info *info)
 {
-       struct i2c_client *client;
+       struct i2c_adapter *adapter = client->adapter;
        u8 version = 0;
-       int err = -ENODEV;
        const char *name = "";
 
-       if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
-       }
-       client->addr = address;
-       client->adapter = adapter;
-
        if (kind < 0) {
                u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
                u16 chipid = f75375_read16(client, F75375_CHIP_ID);
@@ -706,10 +698,9 @@ static int f75375_detect(struct i2c_adap
                        dev_err(&adapter->dev,
                                "failed,%02X,%02X,%02X\n",
                                chipid, version, vendid);
-                       goto exit_free;
+                       return -ENODEV;
                }
        }
-       err = 0;        /* detection OK */
 
        if (kind == f75375) {
                name = "f75375";
@@ -718,12 +709,9 @@ static int f75375_detect(struct i2c_adap
        }
        dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
        strlcpy(info->type, name, I2C_NAME_SIZE);
-       info->addr = address;
+       info->addr = client->addr;
 
-exit_free:
-       kfree(client);
-exit:
-       return err;
+       return 0;
 }
 
 static int __init sensors_f75375_init(void)
--- linux-2.6.26-rc5.orig/drivers/hwmon/lm75.c  2008-06-06 20:25:48.000000000 
+0200
+++ linux-2.6.26-rc5/drivers/hwmon/lm75.c       2008-06-07 11:20:37.000000000 
+0200
@@ -217,28 +217,15 @@ static int lm75_remove(struct i2c_client
        return 0;
 }
 
-static int lm75_detect(struct i2c_adapter *adapter, int address, int kind,
+static int lm75_detect(struct i2c_client *new_client, int kind,
                       struct i2c_board_info *info)
 {
+       struct i2c_adapter *adapter = new_client->adapter;
        int i;
-       struct i2c_client *new_client;
-       int err = -ENODEV;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_WORD_DATA))
-               goto exit;
-
-       /* OK. For now, we presume we have a valid address. We create the
-          client structure, even though there may be no sensor present.
-          But it allows us to use i2c_smbus_read_*_data() calls. */
-       new_client = kzalloc(sizeof *new_client, GFP_KERNEL);
-       if (!new_client) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       new_client->addr = address;
-       new_client->adapter = adapter;
+               return -ENODEV;
 
        /* Now, we do the remaining detection. There is no identification-
           dedicated register so we have to rely on several tricks:
@@ -258,37 +245,33 @@ static int lm75_detect(struct i2c_adapte
                 || i2c_smbus_read_word_data(new_client, 5) != hyst
                 || i2c_smbus_read_word_data(new_client, 6) != hyst
                 || i2c_smbus_read_word_data(new_client, 7) != hyst)
-                       goto exit_free;
+                       return -ENODEV;
                os = i2c_smbus_read_word_data(new_client, 3);
                if (i2c_smbus_read_word_data(new_client, 4) != os
                 || i2c_smbus_read_word_data(new_client, 5) != os
                 || i2c_smbus_read_word_data(new_client, 6) != os
                 || i2c_smbus_read_word_data(new_client, 7) != os)
-                       goto exit_free;
+                       return -ENODEV;
 
                /* Unused bits */
                if (conf & 0xe0)
-                       goto exit_free;
+                       return -ENODEV;
 
                /* Addresses cycling */
                for (i = 8; i < 0xff; i += 8)
                        if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
                         || i2c_smbus_read_word_data(new_client, i + 2) != hyst
                         || i2c_smbus_read_word_data(new_client, i + 3) != os)
-                               goto exit_free;
+                               return -ENODEV;
        }
-       err = 0;        /* detection OK */
 
        /* NOTE: we treat "force=..." and "force_lm75=..." the same.
         * Only new-style driver binding distinguishes chip types.
         */
        strlcpy(info->type, "lm75", I2C_NAME_SIZE);
-       info->addr = address;
+       info->addr = new_client->addr;
 
-exit_free:
-       kfree(new_client);
-exit:
-       return err;
+       return 0;
 }
 
 static const struct i2c_device_id lm75_ids[] = {
--- linux-2.6.26-rc5.orig/drivers/hwmon/lm90.c  2008-06-06 20:25:48.000000000 
+0200
+++ linux-2.6.26-rc5/drivers/hwmon/lm90.c       2008-06-07 10:33:03.000000000 
+0200
@@ -187,8 +187,8 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99,
  * Functions declaration
  */
 
-static int lm90_detect(struct i2c_adapter *adapter, int address,
-                      int kind, struct i2c_board_info *info);
+static int lm90_detect(struct i2c_client *new_client, int kind,
+                      struct i2c_board_info *info);
 static int lm90_probe(struct i2c_client *client,
                      const struct i2c_device_id *id);
 static void lm90_init_client(struct i2c_client *client);
@@ -494,25 +494,15 @@ static int lm90_read_reg(struct i2c_clie
 }
 
 /* Returns -ENODEV if no supported device is detected */
-static int lm90_detect(struct i2c_adapter *adapter, int address, int kind,
+static int lm90_detect(struct i2c_client *new_client, int kind,
                       struct i2c_board_info *info)
 {
-       struct i2c_client *new_client;
-       int err = -ENODEV;
+       struct i2c_adapter *adapter = new_client->adapter;
+       int address = new_client->addr;
        const char *name = "";
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               goto exit;
-
-       new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!new_client) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       /* Enough to use smbus calls */
-       new_client->addr = address;
-       new_client->adapter = adapter;
+               return -ENODEV;
 
        /*
         * Now we do the remaining detection. A negative kind means that
@@ -540,7 +530,7 @@ static int lm90_detect(struct i2c_adapte
                                                LM90_REG_R_CONFIG1)) < 0
                 || (reg_convrate = i2c_smbus_read_byte_data(new_client,
                                                LM90_REG_R_CONVRATE)) < 0)
-                       goto exit_free;
+                       return -ENODEV;
                
                if ((address == 0x4C || address == 0x4D)
                 && man_id == 0x01) { /* National Semiconductor */
@@ -548,7 +538,7 @@ static int lm90_detect(struct i2c_adapte
 
                        if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
                                                LM90_REG_R_CONFIG2)) < 0)
-                               goto exit_free;
+                               return -ENODEV;
 
                        if ((reg_config1 & 0x2A) == 0x00
                         && (reg_config2 & 0xF8) == 0x00
@@ -612,10 +602,9 @@ static int lm90_detect(struct i2c_adapte
                        dev_info(&adapter->dev,
                            "Unsupported chip (man_id=0x%02X, "
                            "chip_id=0x%02X).\n", man_id, chip_id);
-                       goto exit_free;
+                       return -ENODEV;
                }
        }
-       err = 0;        /* detection OK */
 
        /* Fill the i2c board info */
        info->addr = address;
@@ -640,10 +629,7 @@ static int lm90_detect(struct i2c_adapte
        }
        strlcpy(info->type, name, I2C_NAME_SIZE);
 
-exit_free:
-       kfree(new_client);
-exit:
-       return err;
+       return 0;
 }
 
 static int lm90_probe(struct i2c_client *new_client,
--- linux-2.6.26-rc5.orig/drivers/i2c/i2c-core.c        2008-06-06 
20:25:48.000000000 +0200
+++ linux-2.6.26-rc5/drivers/i2c/i2c-core.c     2008-06-07 10:48:06.000000000 
+0200
@@ -1226,11 +1226,12 @@ int i2c_probe(struct i2c_adapter *adapte
 EXPORT_SYMBOL(i2c_probe);
 
 /* Separate detection function for new-style drivers */
-static int i2c_detect_address(struct i2c_adapter *adapter,
-                             int addr, int kind, struct i2c_driver *driver)
+static int i2c_detect_address(struct i2c_client *temp_client, int kind,
+                             struct i2c_driver *driver)
 {
        struct i2c_board_info info;
-       struct i2c_client *client;
+       struct i2c_adapter *adapter = temp_client->adapter;
+       int addr = temp_client->addr;
        int err;
 
        /* Make sure the address is valid */
@@ -1258,7 +1259,7 @@ static int i2c_detect_address(struct i2c
 
        /* Finally call the custom detection function */
        memset(&info, 0, sizeof(struct i2c_board_info));
-       err = driver->detect(adapter, addr, kind, &info);
+       err = driver->detect(temp_client, kind, &info);
        if (err) {
                /* -ENODEV can be returned if there is a chip at the given 
address
                   but it isn't supported by this chip driver. We catch it here 
as
@@ -1271,6 +1272,8 @@ static int i2c_detect_address(struct i2c
                dev_err(&adapter->dev, "Detection function returned "
                        "inconsistent data for 0x%x\n", addr);
        } else {
+               struct i2c_client *client;
+
                /* Detection succeeded, instantiate the device */
                dev_dbg(&adapter->dev, "Creating %s at 0x%x\n",
                        info.type, info.addr);
@@ -1283,13 +1286,20 @@ static int i2c_detect_address(struct i2c
 static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
 {
        const struct i2c_client_address_data *address_data;
-       int i, err;
+       struct i2c_client *temp_client;
+       int i, err = 0;
        int adap_id = i2c_adapter_id(adapter);
 
        if (!driver->detect)
                return 0;
        address_data = driver->address_data;
 
+       /* Set up a temporary client to help detect callback */
+       temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (!temp_client)
+               return -ENOMEM;
+       temp_client->adapter = adapter;
+
        /* Force entries are done first, and are not affected by ignore
           entries */
        if (address_data->forces) {
@@ -1306,11 +1316,11 @@ static int i2c_detect(struct i2c_adapter
                                                "addr 0x%02x, kind %d\n",
                                                adap_id, forces[kind][i + 1],
                                                kind);
-                                       err = i2c_detect_address(adapter,
-                                               forces[kind][i + 1],
+                                       temp_client->addr = forces[kind][i + 1];
+                                       err = i2c_detect_address(temp_client,
                                                kind, driver);
                                        if (err)
-                                               return err;
+                                               goto exit_free;
                                }
                        }
                }
@@ -1320,11 +1330,12 @@ static int i2c_detect(struct i2c_adapter
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
                if (address_data->probe[0] == I2C_CLIENT_END
                 && address_data->normal_i2c[0] == I2C_CLIENT_END)
-                       return 0;
+                       goto exit_free;
 
                dev_warn(&adapter->dev, "SMBus Quick command not supported, "
                         "can't probe for chips\n");
-               return -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
+               goto exit_free;
        }
 
        /* Probe entries are done second, and are not affected by ignore
@@ -1335,17 +1346,16 @@ static int i2c_detect(struct i2c_adapter
                        dev_dbg(&adapter->dev, "found probe parameter for "
                                "adapter %d, addr 0x%02x\n", adap_id,
                                address_data->probe[i + 1]);
-                       err = i2c_detect_address(adapter,
-                                                address_data->probe[i + 1],
-                                                -1, driver);
+                       temp_client->addr = address_data->probe[i + 1];
+                       err = i2c_detect_address(temp_client, -1, driver);
                        if (err)
-                               return err;
+                               goto exit_free;
                }
        }
 
        /* Stop here if the classes do not match */
        if (!(adapter->class & driver->class))
-               return 0;
+               goto exit_free;
 
        /* Normal entries are done last, unless shadowed by an ignore entry */
        for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
@@ -1372,13 +1382,15 @@ static int i2c_detect(struct i2c_adapter
                dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
                        "addr 0x%02x\n", adap_id,
                        address_data->normal_i2c[i]);
-               err = i2c_detect_address(adapter, address_data->normal_i2c[i],
-                                        -1, driver);
+               temp_client->addr = address_data->normal_i2c[i];
+               err = i2c_detect_address(temp_client, -1, driver);
                if (err)
-                       return err;
+                       goto exit_free;
        }
 
-       return 0;
+ exit_free:
+       kfree(temp_client);
+       return err;
 }
 
 struct i2c_client *
--- linux-2.6.26-rc5.orig/include/linux/i2c.h   2008-06-06 20:25:48.000000000 
+0200
+++ linux-2.6.26-rc5/include/linux/i2c.h        2008-06-07 09:48:04.000000000 
+0200
@@ -148,8 +148,7 @@ struct i2c_driver {
        const struct i2c_device_id *id_table;
 
        /* Device detection callback for automatic device creation */
-       int (*detect)(struct i2c_adapter *, int address, int kind,
-                     struct i2c_board_info *);
+       int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);
        const struct i2c_client_address_data *address_data;
        struct list_head clients;
 };


-- 
Jean Delvare

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

Reply via email to