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>
INIT_LIST_HEAD(&hd->connections);
ida_init(&hd->cport_id_map);
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)
{
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_remove_interfaces(hd);
+ gb_endo_remove(hd->endo);
kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
}
EXPORT_SYMBOL_GPL(greybus_remove_hd);
kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
}
EXPORT_SYMBOL_GPL(greybus_remove_hd);
}
for (i = 0; endo_modules[i] != 0x00; ++i) {
}
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;
}
if (!module)
return -EINVAL;
}
-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;
struct gb_endo *gb_endo_create(struct greybus_host_device *hd)
{
struct gb_endo *endo;
- /* remove all modules first */
- remove_modules(endo);
+ /* remove all modules for this endo */
+ gb_module_remove_all(endo);
device_unregister(&endo->dev);
}
device_unregister(&endo->dev);
}
/* Host device buffer constraints */
size_t buffer_size_max;
/* 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));
};
/* Private data for the host driver */
unsigned long hd_priv[0] __aligned(sizeof(s64));
};
- 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;
if (!module)
return NULL;
module = intf->module;
device_unregister(&intf->dev);
module = intf->module;
device_unregister(&intf->dev);
- gb_module_remove(module);
+ put_device(&module->dev);
+struct module_find {
+ struct gb_endo *endo;
+ u8 module_id;
+};
+
static int module_find(struct device *dev, void *data)
{
struct gb_module *module;
static int module_find(struct device *dev, void *data)
{
struct gb_module *module;
+ struct module_find *find = data;
if (!is_gb_module(dev))
return 0;
module = to_gb_module(dev);
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))
* Search the list of modules in the system. If one is found, return it, with
* the reference count incremented.
*/
* 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 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,
dev = bus_find_device(&greybus_bus_type, NULL,
- &module_id, module_find);
if (dev)
module = to_gb_module(dev);
return module;
}
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;
{
struct gb_module *module;
int retval;
return NULL;
module->module_id = module_id;
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.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);
device_initialize(&module->dev);
dev_set_name(&module->dev, "%d", module_id);
-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_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);
-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);
struct gb_module {
struct device dev;
u8 module_id; /* Physical location within the Endo */
struct gb_module {
struct device dev;
u8 module_id; /* Physical location within the Endo */
};
#define to_gb_module(d) container_of(d, struct gb_module, dev)
struct greybus_host_device;
/* Greybus "private" definitions */
};
#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);
u8 get_module_id(u8 interface_id);