Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7b4fbc50fabb810523be522fe7ec5cc40f85c7a1
Commit:     7b4fbc50fabb810523be522fe7ec5cc40f85c7a1
Parent:     5cedb05db3c3084c9641403dd24c310a6b3ea19f
Author:     David Brownell <[EMAIL PROTECTED]>
AuthorDate: Tue May 1 23:26:30 2007 +0200
Committer:  Jean Delvare <[EMAIL PROTECTED]>
CommitDate: Tue May 1 23:26:30 2007 +0200

    i2c: i2c stack can probe()
    
    One of a series of I2C infrastructure updates to support enumeration using
    the standard Linux driver model.
    
    This patch updates probe() and associated hotplug/coldplug support, but
    not remove().  Nothing yet _uses_ it to create I2C devices, so those
    hotplug/coldplug mechanisms will be the only externally visible change.
    This patch will be an overall NOP since the I2C stack doesn't yet create
    clients/devices except as part of binding them to legacy drivers.
    
    Some code is moved earlier in the source code, helping group more of the
    per-device infrastructure in one place and simplifying handling per-device
    attributes.
    
    Terminology being adopted:  "legacy drivers" create devices (i2c_client)
    themselves, while "new style" ones follow the driver model (the i2c_client
    is handed to the probe routine).  It's an either/or thing; the two models
    don't mix, and drivers that try mixing them won't even be registered.
    
    Signed-off-by: David Brownell <[EMAIL PROTECTED]>
    Signed-off-by: Jean Delvare <[EMAIL PROTECTED]>
---
 drivers/i2c/i2c-core.c |  141 +++++++++++++++++++++++++++++++++--------------
 include/linux/i2c.h    |   13 ++++-
 2 files changed, 110 insertions(+), 44 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index fd921ce..a2ad83a 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -44,15 +44,58 @@ static DEFINE_IDR(i2c_adapter_idr);
 
 /* ------------------------------------------------------------------------- */
 
-/* match always succeeds, as we want the probe() to tell if we really accept 
this match */
 static int i2c_device_match(struct device *dev, struct device_driver *drv)
 {
-       return 1;
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct i2c_driver       *driver = to_i2c_driver(drv);
+
+       /* make legacy i2c drivers bypass driver model probing entirely;
+        * such drivers scan each i2c adapter/bus themselves.
+        */
+       if (!driver->probe)
+               return 0;
+
+       /* new style drivers use the same kind of driver matching policy
+        * as platform devices or SPI:  compare device and driver IDs.
+        */
+       return strcmp(client->driver_name, drv->name) == 0;
 }
 
+#ifdef CONFIG_HOTPLUG
+
+/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
+static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
+                     char *buffer, int buffer_size)
+{
+       struct i2c_client       *client = to_i2c_client(dev);
+       int                     i = 0, length = 0;
+
+       /* by definition, legacy drivers can't hotplug */
+       if (dev->driver || !client->driver_name)
+               return 0;
+
+       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+                       "MODALIAS=%s", client->driver_name))
+               return -ENOMEM;
+       envp[i] = NULL;
+       dev_dbg(dev, "uevent\n");
+       return 0;
+}
+
+#else
+#define i2c_device_uevent      NULL
+#endif /* CONFIG_HOTPLUG */
+
 static int i2c_device_probe(struct device *dev)
 {
-       return -ENODEV;
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct i2c_driver       *driver = to_i2c_driver(dev->driver);
+
+       if (!driver->probe)
+               return -ENODEV;
+       client->driver = driver;
+       dev_dbg(dev, "probe\n");
+       return driver->probe(client);
 }
 
 static int i2c_device_remove(struct device *dev)
@@ -95,9 +138,38 @@ static int i2c_device_resume(struct device * dev)
        return driver->resume(to_i2c_client(dev));
 }
 
+static void i2c_client_release(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       complete(&client->released);
+}
+
+static ssize_t show_client_name(struct device *dev, struct device_attribute 
*attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%s\n", client->name);
+}
+
+static ssize_t show_modalias(struct device *dev, struct device_attribute 
*attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return client->driver_name
+               ? sprintf(buf, "%s\n", client->driver_name)
+               : 0;
+}
+
+static struct device_attribute i2c_dev_attrs[] = {
+       __ATTR(name, S_IRUGO, show_client_name, NULL),
+       /* modalias helps coldplug:  modprobe $(cat .../modalias) */
+       __ATTR(modalias, S_IRUGO, show_modalias, NULL),
+       { },
+};
+
 struct bus_type i2c_bus_type = {
        .name           = "i2c",
+       .dev_attrs      = i2c_dev_attrs,
        .match          = i2c_device_match,
+       .uevent         = i2c_device_uevent,
        .probe          = i2c_device_probe,
        .remove         = i2c_device_remove,
        .shutdown       = i2c_device_shutdown,
@@ -134,31 +206,6 @@ struct class i2c_adapter_class = {
 };
 
 
-static void i2c_client_release(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       complete(&client->released);
-}
-
-static ssize_t show_client_name(struct device *dev, struct device_attribute 
*attr, char *buf)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       return sprintf(buf, "%s\n", client->name);
-}
-
-/*
- * We can't use the DEVICE_ATTR() macro here, as we used the same name for
- * an i2c adapter attribute (above).
- */
-static struct device_attribute dev_attr_client_name =
-       __ATTR(name, S_IRUGO, &show_client_name, NULL);
-
-
-/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
- */
-
 /* -----
  * i2c_add_adapter is called from within the algorithm layer,
  * when a new hw adapter registers. A new device is register to be
@@ -208,7 +255,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)
 
        dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
 
-       /* inform drivers of new adapters */
+       /* let legacy drivers scan this bus for matching devices */
        list_for_each(item,&drivers) {
                driver = list_entry(item, struct i2c_driver, list);
                if (driver->attach_adapter)
@@ -292,16 +339,32 @@ int i2c_del_adapter(struct i2c_adapter *adap)
 }
 
 
-/* -----
- * What follows is the "upwards" interface: commands for talking to clients,
- * which implement the functions to access the physical information of the
- * chips.
+/* ------------------------------------------------------------------------- */
+
+/*
+ * An i2c_driver is used with one or more i2c_client (device) nodes to access
+ * i2c slave chips, on a bus instance associated with some i2c_adapter.  There
+ * are two models for binding the driver to its device:  "new style" drivers
+ * follow the standard Linux driver model and just respond to probe() calls
+ * issued if the driver core sees they match(); "legacy" drivers create device
+ * nodes themselves.
  */
 
 int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 {
        int res;
 
+       /* new style driver methods can't mix with legacy ones */
+       if (driver->probe) {
+               if (driver->attach_adapter || driver->detach_adapter
+                               || driver->detach_client) {
+                       printk(KERN_WARNING
+                                       "i2c-core: driver [%s] is confused\n",
+                                       driver->driver.name);
+                       return -EINVAL;
+               }
+       }
+
        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
@@ -315,7 +378,7 @@ int i2c_register_driver(struct module *owner, struct 
i2c_driver *driver)
        list_add_tail(&driver->list,&drivers);
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
-       /* now look for instances of driver on our adapters */
+       /* legacy drivers scan i2c busses directly */
        if (driver->attach_adapter) {
                struct i2c_adapter *adapter;
 
@@ -380,6 +443,8 @@ int i2c_del_driver(struct i2c_driver *driver)
        return 0;
 }
 
+/* ------------------------------------------------------------------------- */
+
 static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
        struct list_head   *item;
@@ -430,9 +495,6 @@ int i2c_attach_client(struct i2c_client *client)
        res = device_register(&client->dev);
        if (res)
                goto out_list;
-       res = device_create_file(&client->dev, &dev_attr_client_name);
-       if (res)
-               goto out_unregister;
        mutex_unlock(&adapter->clist_lock);
 
        if (adapter->client_register)  {
@@ -445,10 +507,6 @@ int i2c_attach_client(struct i2c_client *client)
 
        return 0;
 
-out_unregister:
-       init_completion(&client->released); /* Needed? */
-       device_unregister(&client->dev);
-       wait_for_completion(&client->released);
 out_list:
        list_del(&client->list);
        dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
@@ -483,7 +541,6 @@ int i2c_detach_client(struct i2c_client *client)
        mutex_lock(&adapter->clist_lock);
        list_del(&client->list);
        init_completion(&client->released);
-       device_remove_file(&client->dev, &dev_attr_client_name);
        device_unregister(&client->dev);
        mutex_unlock(&adapter->clist_lock);
        wait_for_completion(&client->released);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 563c965..8dcccc0 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -113,7 +113,7 @@ struct i2c_driver {
         * can be used by the driver to test if the bus meets its conditions
         * & seek for the presence of the chip(s) it supports. If found, it
         * registers the client(s) that are on the bus to the i2c admin. via
-        * i2c_attach_client.
+        * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)
         */
        int (*attach_adapter)(struct i2c_adapter *);
        int (*detach_adapter)(struct i2c_adapter *);
@@ -121,10 +121,16 @@ struct i2c_driver {
        /* tells the driver that a client is about to be deleted & gives it
         * the chance to remove its private data. Also, if the client struct
         * has been dynamically allocated by the driver in the function above,
-        * it must be freed here.
+        * it must be freed here.  (LEGACY I2C DRIVERS ONLY)
         */
        int (*detach_client)(struct i2c_client *);
 
+       /* Standard driver model interfaces, for "new style" i2c drivers.
+        * With the driver model, device enumeration is NEVER done by drivers;
+        * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
+        */
+       int (*probe)(struct i2c_client *);
+
        /* driver model interfaces that don't relate to enumeration  */
        void (*shutdown)(struct i2c_client *);
        int (*suspend)(struct i2c_client *, pm_message_t mesg);
@@ -148,6 +154,8 @@ struct i2c_driver {
  * @name: Indicates the type of the device, usually a chip name that's
  *     generic enough to hide second-sourcing and compatible revisions.
  * @dev: Driver model device node for the slave.
+ * @driver_name: Identifies new-style driver used with this device; also
+ *     used as the module name for hotplug/coldplug modprobe support.
  *
  * An i2c_client identifies a single device (i.e. chip) connected to an
  * i2c bus. The behaviour is defined by the routines of the driver.
@@ -163,6 +171,7 @@ struct i2c_client {
        int usage_count;                /* How many accesses currently  */
                                        /* to the client                */
        struct device dev;              /* the device structure         */
+       char driver_name[KOBJ_NAME_LEN];
        struct list_head list;
        struct completion released;
 };
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to