greybus: improve module cleanup code
authorAlex Elder <elder@linaro.org>
Tue, 21 Oct 2014 04:01:04 +0000 (23:01 -0500)
committerGreg Kroah-Hartman <greg@kroah.com>
Tue, 21 Oct 2014 06:36:11 +0000 (14:36 +0800)
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>
drivers/staging/greybus/battery-gb.c
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.h
drivers/staging/greybus/core.c
drivers/staging/greybus/greybus.h
drivers/staging/greybus/interface.c
drivers/staging/greybus/interface.h
drivers/staging/greybus/module.c

index 5d0db61d49d25529d5b1d6837b2cdbf8eeaf13e0..a3b2bee77299644f3b120eabb567a5d199648414 100644 (file)
@@ -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
index 09fe25d5fee427ba026b15a9e35eb7095d448c34..e2340d8392ed072e789af6983018fdeb2ea1f587 100644 (file)
@@ -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;
+       }
+}
index bb22c52c2f019c1083f064f89af15a20e5211a07..685c1ffcb1ca8cabe18692350122b5dc1c952b4a 100644 (file)
@@ -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);
index b59dee171446bfd372df1707baa75368f9ca5cfa..bc27ad68cc8551db0501519595825b0731c9bf14 100644 (file)
@@ -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);
 }
 
index c09572c70392e32e38fd742468b96e627bbfcfc5..bbd90b4cec9116ced6d18271dcd2993e6bec8a34 100644 (file)
@@ -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);
index 0c2fdd3f7ea267ff1f57a9975b8f0ea8a8a7003a..645f05b3d590b552a6b5504bc1a56bc83ff12445 100644 (file)
@@ -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);
+       }
+}
index 1019a981f5f6eabf3e9d0a9c376c1023d41f033c..f0c9e1d5a3b3505ba268dd31a6a058584752c970 100644 (file)
@@ -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 */
index 699cd003e3673d4f5aec907d9847be06fc3e7965..2883947fb63087d4448ca03c7aef16126d9ef35a 100644 (file)
@@ -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);
 }