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 7c701f3..4580209 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 e3bb25f..28e1f28 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 e0aae42..109727f 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 5b1d5dd..63665a2 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 780d163..202f141 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 f3e3bdd..c23ac98 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);