greybus: improve module cleanup code

When a module gets destroyed all of its state and the state of its
interfaces and connections (etc.) need to be torn down.  This is
not now being done properly.  Add this teardown code.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
Alex Elder 2014-10-20 23:01:04 -05:00 коммит произвёл Greg Kroah-Hartman
Родитель fb305c335c
Коммит 697e55d35d
8 изменённых файлов: 78 добавлений и 11 удалений

Просмотреть файл

@ -145,6 +145,14 @@ int gb_battery_device_init(struct gb_connection *connection)
return 0;
}
void gb_battery_device_exit(struct gb_connection *connection)
{
struct gb_battery *gb = connection->private;
power_supply_unregister(&gb->bat);
kfree(gb);
}
void gb_battery_disconnect(struct gb_module *gmod)
{
#if 0

Просмотреть файл

@ -220,3 +220,27 @@ int gb_connection_init(struct gb_connection *connection)
}
return -ENXIO;
}
void gb_connection_exit(struct gb_connection *connection)
{
switch (connection->protocol) {
case GREYBUS_PROTOCOL_I2C:
gb_i2c_device_exit(connection);
break;
case GREYBUS_PROTOCOL_GPIO:
gb_gpio_controller_exit(connection);
break;
case GREYBUS_PROTOCOL_BATTERY:
gb_battery_device_exit(connection);
break;
case GREYBUS_PROTOCOL_CONTROL:
case GREYBUS_PROTOCOL_AP:
case GREYBUS_PROTOCOL_UART:
case GREYBUS_PROTOCOL_HID:
case GREYBUS_PROTOCOL_VENDOR:
default:
gb_connection_err(connection, "unimplemented protocol %u",
(u32)connection->protocol);
break;
}
}

Просмотреть файл

@ -35,6 +35,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
void gb_connection_destroy(struct gb_connection *connection);
int gb_connection_init(struct gb_connection *connection);
void gb_connection_exit(struct gb_connection *connection);
struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
u16 cport_id);

Просмотреть файл

@ -119,10 +119,9 @@ static void greybus_module_release(struct device *dev)
{
struct gb_module *gmod = to_gb_module(dev);
kfree(gmod);
gb_module_destroy(gmod);
}
static struct device_type greybus_module_type = {
.name = "greybus_module",
.release = greybus_module_release,
@ -157,7 +156,7 @@ void gb_add_module(struct greybus_host_device *hd, u8 module_id,
*/
if (!gb_manifest_parse(gmod, data, size)) {
dev_err(hd->parent, "manifest error\n");
goto error;
goto err_module;
}
/*
@ -180,14 +179,14 @@ void gb_add_module(struct greybus_host_device *hd, u8 module_id,
retval = device_add(&gmod->dev);
if (retval)
goto error;
goto err_device;
gb_module_interfaces_init(gmod);
return;
error:
gb_module_destroy(gmod);
return;
err_device:
put_device(&gmod->dev);
err_module:
greybus_module_release(&gmod->dev);
}

Просмотреть файл

@ -265,8 +265,13 @@ void gb_deregister_cport_complete(u16 cport_id);
extern const struct attribute_group *greybus_module_groups[];
int gb_i2c_device_init(struct gb_connection *connection);
void gb_i2c_device_exit(struct gb_connection *connection);
int gb_battery_device_init(struct gb_connection *connection);
void gb_battery_device_exit(struct gb_connection *connection);
int gb_gpio_controller_init(struct gb_connection *connection);
void gb_gpio_controller_exit(struct gb_connection *connection);
int gb_tty_init(void);
void gb_tty_exit(void);

Просмотреть файл

@ -54,6 +54,8 @@ void gb_interface_destroy(struct gb_interface *interface)
list_del(&interface->links);
spin_unlock_irq(&gb_interfaces_lock);
gb_interface_connections_exit(interface);
/* kref_put(gmod); */
kfree(interface);
}
@ -72,3 +74,15 @@ int gb_interface_connections_init(struct gb_interface *interface)
return ret;
}
void gb_interface_connections_exit(struct gb_interface *interface)
{
struct gb_connection *connection;
struct gb_connection *next;
list_for_each_entry_safe(connection, next, &interface->connections,
interface_links) {
gb_connection_exit(connection);
gb_connection_destroy(connection);
}
}

Просмотреть файл

@ -23,5 +23,6 @@ struct gb_interface *gb_interface_create(struct gb_module *gmod, u8 module_id);
void gb_interface_destroy(struct gb_interface *interface);
int gb_interface_connections_init(struct gb_interface *interface);
void gb_interface_connections_exit(struct gb_interface *interface);
#endif /* __INTERFACE_H */

Просмотреть файл

@ -44,6 +44,15 @@ const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
return NULL;
}
static void gb_module_interfaces_exit(struct gb_module *gmod)
{
struct gb_interface *interface;
struct gb_interface *next;
list_for_each_entry_safe(interface, next, &gmod->interfaces, links)
gb_interface_destroy(interface);
}
/*
* A Greybus module represents a user-replacable component on an Ara
* phone.
@ -62,7 +71,7 @@ struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
return NULL;
gmod->hd = hd; /* XXX refcount? */
gmod->module_id = module_id;
gmod->module_id = module_id; /* XXX check for dups */
INIT_LIST_HEAD(&gmod->interfaces);
spin_lock_irq(&gb_modules_lock);
@ -80,15 +89,21 @@ void gb_module_destroy(struct gb_module *gmod)
if (WARN_ON(!gmod))
return;
kfree(gmod->product_string);
kfree(gmod->vendor_string);
spin_lock_irq(&gb_modules_lock);
list_del(&gmod->links);
spin_unlock_irq(&gb_modules_lock);
gb_module_interfaces_exit(gmod);
/* XXX Do something with gmod->gb_tty */
put_device(&gmod->dev);
/* kfree(gmod->dev->name); */
kfree(gmod->product_string);
kfree(gmod->vendor_string);
/* kref_put(module->hd); */
kfree(gmod);
}