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
}
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;
+ }
+}
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);
{
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,
*/
if (!gb_manifest_parse(gmod, data, size)) {
dev_err(hd->parent, "manifest error\n");
- goto error;
+ goto err_module;
}
/*
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);
}
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);
list_del(&interface->links);
spin_unlock_irq(&gb_interfaces_lock);
+ gb_interface_connections_exit(interface);
+
/* kref_put(gmod); */
kfree(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);
+ }
+}
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 */
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.
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);
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);
}