]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/core/sdio_bus.c
mmc: struct device - replace bus_id with dev_name(), dev_set_name()
[linux-2.6-omap-h63xx.git] / drivers / mmc / core / sdio_bus.c
index 59c909e1c7c6c8f441ef5c2f48026c3588f577c1..46284b52739785bbc768c6458214e5c0936323a2 100644 (file)
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 
+#include "sdio_cis.h"
 #include "sdio_bus.h"
 
 #define dev_to_sdio_func(d)    container_of(d, struct sdio_func, dev)
+#define to_sdio_driver(d)      container_of(d, struct sdio_driver, drv)
+
+/* show configuration fields */
+#define sdio_config_attr(field, format_string)                         \
+static ssize_t                                                         \
+field##_show(struct device *dev, struct device_attribute *attr, char *buf)                             \
+{                                                                      \
+       struct sdio_func *func;                                         \
+                                                                       \
+       func = dev_to_sdio_func (dev);                                  \
+       return sprintf (buf, format_string, func->field);               \
+}
+
+sdio_config_attr(class, "0x%02x\n");
+sdio_config_attr(vendor, "0x%04x\n");
+sdio_config_attr(device, "0x%04x\n");
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct sdio_func *func = dev_to_sdio_func (dev);
+
+       return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
+                       func->class, func->vendor, func->device);
+}
+
+static struct device_attribute sdio_dev_attrs[] = {
+       __ATTR_RO(class),
+       __ATTR_RO(vendor),
+       __ATTR_RO(device),
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
+static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
+       const struct sdio_device_id *id)
+{
+       if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
+               return NULL;
+       if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
+               return NULL;
+       if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
+               return NULL;
+       return id;
+}
+
+static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
+       struct sdio_driver *sdrv)
+{
+       const struct sdio_device_id *ids;
+
+       ids = sdrv->id_table;
+
+       if (ids) {
+               while (ids->class || ids->vendor || ids->device) {
+                       if (sdio_match_one(func, ids))
+                               return ids;
+                       ids++;
+               }
+       }
+
+       return NULL;
+}
 
-/*
- * This currently matches any SDIO function to any driver in order
- * to help initial development and testing.
- */
 static int sdio_bus_match(struct device *dev, struct device_driver *drv)
 {
-       return 1;
+       struct sdio_func *func = dev_to_sdio_func(dev);
+       struct sdio_driver *sdrv = to_sdio_driver(drv);
+
+       if (sdio_match_device(func, sdrv))
+               return 1;
+
+       return 0;
 }
 
 static int
-sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-               int buf_size)
+sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       envp[0] = NULL;
+       struct sdio_func *func = dev_to_sdio_func(dev);
+
+       if (add_uevent_var(env,
+                       "SDIO_CLASS=%02X", func->class))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, 
+                       "SDIO_ID=%04X:%04X", func->vendor, func->device))
+               return -ENOMEM;
+
+       if (add_uevent_var(env,
+                       "MODALIAS=sdio:c%02Xv%04Xd%04X",
+                       func->class, func->vendor, func->device))
+               return -ENOMEM;
 
        return 0;
 }
 
 static int sdio_bus_probe(struct device *dev)
 {
-       return -ENODEV;
+       struct sdio_driver *drv = to_sdio_driver(dev->driver);
+       struct sdio_func *func = dev_to_sdio_func(dev);
+       const struct sdio_device_id *id;
+       int ret;
+
+       id = sdio_match_device(func, drv);
+       if (!id)
+               return -ENODEV;
+
+       /* Set the default block size so the driver is sure it's something
+        * sensible. */
+       sdio_claim_host(func);
+       ret = sdio_set_block_size(func, 0);
+       sdio_release_host(func);
+       if (ret)
+               return ret;
+
+       return drv->probe(func, id);
 }
 
 static int sdio_bus_remove(struct device *dev)
 {
+       struct sdio_driver *drv = to_sdio_driver(dev->driver);
+       struct sdio_func *func = dev_to_sdio_func(dev);
+
+       drv->remove(func);
+
+       if (func->irq_handler) {
+               printk(KERN_WARNING "WARNING: driver %s did not remove "
+                       "its interrupt handler!\n", drv->name);
+               sdio_claim_host(func);
+               sdio_release_irq(func);
+               sdio_release_host(func);
+       }
+
        return 0;
 }
 
 static struct bus_type sdio_bus_type = {
        .name           = "sdio",
+       .dev_attrs      = sdio_dev_attrs,
        .match          = sdio_bus_match,
        .uevent         = sdio_bus_uevent,
        .probe          = sdio_bus_probe,
@@ -67,10 +175,38 @@ void sdio_unregister_bus(void)
        bus_unregister(&sdio_bus_type);
 }
 
+/**
+ *     sdio_register_driver - register a function driver
+ *     @drv: SDIO function driver
+ */
+int sdio_register_driver(struct sdio_driver *drv)
+{
+       drv->drv.name = drv->name;
+       drv->drv.bus = &sdio_bus_type;
+       return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_register_driver);
+
+/**
+ *     sdio_unregister_driver - unregister a function driver
+ *     @drv: SDIO function driver
+ */
+void sdio_unregister_driver(struct sdio_driver *drv)
+{
+       drv->drv.bus = &sdio_bus_type;
+       driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_unregister_driver);
+
 static void sdio_release_func(struct device *dev)
 {
        struct sdio_func *func = dev_to_sdio_func(dev);
 
+       sdio_free_func_cis(func);
+
+       if (func->info)
+               kfree(func->info);
+
        kfree(func);
 }
 
@@ -81,12 +217,10 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
 {
        struct sdio_func *func;
 
-       func = kmalloc(sizeof(struct sdio_func), GFP_KERNEL);
+       func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
        if (!func)
                return ERR_PTR(-ENOMEM);
 
-       memset(func, 0, sizeof(struct sdio_func));
-
        func->card = card;
 
        device_initialize(&func->dev);
@@ -105,8 +239,7 @@ int sdio_add_func(struct sdio_func *func)
 {
        int ret;
 
-       snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
-                "%s:%d", mmc_card_id(func->card), func->num);
+       dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
 
        ret = device_add(&func->dev);
        if (ret == 0)