greybus: endo: hook up endos into the device tree
authorGreg Kroah-Hartman <gregkh@google.com>
Tue, 7 Apr 2015 18:27:15 +0000 (20:27 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Thu, 9 Apr 2015 20:50:09 +0000 (22:50 +0200)
This hooks up the endo, and modules, into the device tree.  All modules
for a specific endo are created when the host device is initialized.
When an interface is registered, the correct module for it is found and
that module is used for the sysfs tree.  When the interface is removed,
the reference on the module is dropped.

When the host device goes away, the whole endo and modules are removed
at once.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Reviewed-by: Alex Elder <elder@linaro.org>
drivers/staging/greybus/core.c
drivers/staging/greybus/endo.c
drivers/staging/greybus/greybus.h
drivers/staging/greybus/interface.c
drivers/staging/greybus/module.c
drivers/staging/greybus/module.h

index 7c701f398a4dcfafa9b71ba763bb72de1a78fc5c..45802099729443df3747713c8bdb2a054a041dde 100644 (file)
@@ -198,15 +198,25 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
        INIT_LIST_HEAD(&hd->connections);
        ida_init(&hd->cport_id_map);
 
+       hd->endo = gb_endo_create(hd);
+       if (!hd->endo) {
+               greybus_remove_hd(hd);
+               return NULL;
+       }
+
        return hd;
 }
 EXPORT_SYMBOL_GPL(greybus_create_hd);
 
 void greybus_remove_hd(struct greybus_host_device *hd)
 {
-       /* Tear down all modules that happen to be associated with this host
-        * controller */
+       /*
+        * Tear down all interfaces, modules, and the endo that is associated
+        * with this host controller before freeing the memory associated with
+        * the host controller.
+        */
        gb_remove_interfaces(hd);
+       gb_endo_remove(hd->endo);
        kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
 }
 EXPORT_SYMBOL_GPL(greybus_remove_hd);
index e3bb25f7ec2b4dbfe01725882f66961c4726d848..28e1f2871bf876d3c9b0637ee8a690ed0240f8b9 100644 (file)
@@ -91,7 +91,7 @@ static int create_modules(struct gb_endo *endo)
        }
 
        for (i = 0; endo_modules[i] != 0x00; ++i) {
-//             module = gb_module_create(&endo->dev, endo_modules[i]);
+               module = gb_module_create(&endo->dev, endo_modules[i]);
                if (!module)
                        return -EINVAL;
        }
@@ -99,16 +99,6 @@ static int create_modules(struct gb_endo *endo)
        return 0;
 }
 
-static void remove_modules(struct gb_endo *endo)
-{
-       /*
-        * We really don't care how many modules have been created, or what the
-        * configuration of them are, let's just enumerate over everything in
-        * the system and delete all found modules.
-        */
-
-}
-
 struct gb_endo *gb_endo_create(struct greybus_host_device *hd)
 {
        struct gb_endo *endo;
@@ -156,8 +146,8 @@ void gb_endo_remove(struct gb_endo *endo)
        if (!endo)
                return;
 
-       /* remove all modules first */
-       remove_modules(endo);
+       /* remove all modules for this endo */
+       gb_module_remove_all(endo);
 
        device_unregister(&endo->dev);
 }
index e0aae42fc4ce62f61ae5987fe77fb9814db72b29..109727f9f7c2b16cd8b02395b0e1b2e71dcde01e 100644 (file)
@@ -98,6 +98,8 @@ struct greybus_host_device {
        /* Host device buffer constraints */
        size_t buffer_size_max;
 
+       struct gb_endo *endo;
+
        /* Private data for the host driver */
        unsigned long hd_priv[0] __aligned(sizeof(s64));
 };
index 5b1d5dde3c90715654057948ff86312cb709155a..63665a2d80153a7d709ad43ea08e7f6d28b0ebfd 100644 (file)
@@ -92,7 +92,7 @@ static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
                return NULL;
        }
 
-       module = gb_module_find_or_create(hd, get_module_id(interface_id));
+       module = gb_module_find(hd, get_module_id(interface_id));
        if (!module)
                return NULL;
 
@@ -157,7 +157,7 @@ static void gb_interface_destroy(struct gb_interface *intf)
 
        module = intf->module;
        device_unregister(&intf->dev);
-       gb_module_remove(module);
+       put_device(&module->dev);
 }
 
 /**
index 780d163b3e0000df9be5e540b52fca723283f059..202f141c7fe33cd436d70d21e089528fe2d2e044 100644 (file)
@@ -94,16 +94,22 @@ u8 get_module_id(u8 interface_id)
        return interface_id;
 }
 
+struct module_find {
+       struct gb_endo *endo;
+       u8 module_id;
+};
+
 static int module_find(struct device *dev, void *data)
 {
        struct gb_module *module;
-       u8 *module_id = data;
+       struct module_find *find = data;
 
        if (!is_gb_module(dev))
                return 0;
 
        module = to_gb_module(dev);
-       if (module->module_id == *module_id)
+       if ((module->module_id == find->module_id) &&
+           (module->dev.parent == &find->endo->dev))
                return 1;
 
        return 0;
@@ -113,21 +119,24 @@ static int module_find(struct device *dev, void *data)
  * Search the list of modules in the system.  If one is found, return it, with
  * the reference count incremented.
  */
-static struct gb_module *gb_module_find(u8 module_id)
+struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id)
 {
        struct device *dev;
        struct gb_module *module = NULL;
+       struct module_find find;
+
+       find.module_id = module_id;
+       find.endo = hd->endo;
 
        dev = bus_find_device(&greybus_bus_type, NULL,
-                             &module_id, module_find);
+                             &find, module_find);
        if (dev)
                module = to_gb_module(dev);
 
        return module;
 }
 
-static struct gb_module *gb_module_create(struct greybus_host_device *hd,
-                                         u8 module_id)
+struct gb_module *gb_module_create(struct device *parent, u8 module_id)
 {
        struct gb_module *module;
        int retval;
@@ -137,12 +146,11 @@ static struct gb_module *gb_module_create(struct greybus_host_device *hd,
                return NULL;
 
        module->module_id = module_id;
-       module->refcount = 1;
-       module->dev.parent = hd->parent;
+       module->dev.parent = parent;
        module->dev.bus = &greybus_bus_type;
        module->dev.type = &greybus_module_type;
        module->dev.groups = module_groups;
-       module->dev.dma_mask = hd->parent->dma_mask;
+       module->dev.dma_mask = parent->dma_mask;
        device_initialize(&module->dev);
        dev_set_name(&module->dev, "%d", module_id);
 
@@ -158,26 +166,22 @@ static struct gb_module *gb_module_create(struct greybus_host_device *hd,
        return module;
 }
 
-struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
-                                          u8 module_id)
+static int module_remove(struct device *dev, void *data)
 {
        struct gb_module *module;
+       struct gb_endo *endo = data;
 
-       module = gb_module_find(module_id);
-       if (module) {
-               module->refcount++;
-               return module;
-       }
+       if (!is_gb_module(dev))
+               return 0;
+
+       module = to_gb_module(dev);
+       if (module->dev.parent == &endo->dev)
+               device_unregister(&module->dev);
 
-       return gb_module_create(hd, module_id);
+       return 0;
 }
 
-void gb_module_remove(struct gb_module *module)
+void gb_module_remove_all(struct gb_endo *endo)
 {
-       if (!module)
-               return;
-
-       if (!--module->refcount)
-               device_unregister(&module->dev);
+       bus_for_each_dev(&greybus_bus_type, NULL, endo, module_remove);
 }
-
index f3e3bdd6a67182a8f749e7b5e84eeea8b182e0e2..c23ac98fc1ba2847db51f76d1109e480cba82807 100644 (file)
 struct gb_module {
        struct device dev;
        u8 module_id;           /* Physical location within the Endo */
-       u16 refcount;
 };
 #define to_gb_module(d) container_of(d, struct gb_module, dev)
 
 struct greybus_host_device;
 
 /* Greybus "private" definitions */
-struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
-                                          u8 module_id);
-void gb_module_remove(struct gb_module *module);
+struct gb_module *gb_module_find(struct greybus_host_device *hd, u8 module_id);
+struct gb_module *gb_module_create(struct device *parent, u8 module_id);
+void gb_module_remove_all(struct gb_endo *endo);
 
 u8 get_module_id(u8 interface_id);