greybus: protocol: split binding of prototcols to connections out of init
authorGreg Kroah-Hartman <greg@kroah.com>
Tue, 23 Dec 2014 23:16:53 +0000 (15:16 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Wed, 24 Dec 2014 05:04:02 +0000 (21:04 -0800)
When adding a new protocol to the system, walk all bundles and try to
hook up any connections that do not have a protocol already.  This sets
the stage to allow for protocols to be loaded at any time, not just
before the device is seen in the system.

Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
drivers/staging/greybus/bundle.c
drivers/staging/greybus/bundle.h
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.h
drivers/staging/greybus/operation.c
drivers/staging/greybus/protocol.c

index 28a8222..973ea39 100644 (file)
@@ -45,6 +45,36 @@ struct device_type greybus_bundle_type = {
 /* XXX This could be per-host device or per-module */
 static DEFINE_SPINLOCK(gb_bundles_lock);
 
+static int __bundle_bind_protocols(struct device *dev, void *data)
+{
+       struct gb_bundle *bundle;
+       struct gb_connection *connection;
+
+       if (!is_gb_bundle(dev))
+               return 0;
+
+       bundle = to_gb_bundle(dev);
+
+       list_for_each_entry(connection, &bundle->connections, bundle_links) {
+               gb_connection_bind_protocol(connection);
+       }
+
+       return 0;
+}
+
+/*
+ * Walk all bundles in the system, and see if any connections are not bound to a
+ * specific prototcol.  If they are not, then try to find one for it and bind it
+ * to it.
+ *
+ * This is called after registering a new protocol.
+ */
+void gb_bundle_bind_protocols(void)
+{
+       bus_for_each_dev(&greybus_bus_type, NULL, NULL,
+                        __bundle_bind_protocols);
+}
+
 /*
  * Create a gb_bundle structure to represent a discovered
  * bundle.  Returns a pointer to the new bundle or a null
index c3c66fa..e11d456 100644 (file)
@@ -30,5 +30,6 @@ void gb_bundle_destroy(struct gb_interface *intf);
 int gb_bundle_init(struct gb_interface *intf, u8 module_id, u8 device_id);
 
 struct gb_bundle *gb_bundle_find(struct gb_interface *intf, u8 bundle_id);
+void gb_bundle_bind_protocols(void);
 
 #endif /* __BUNDLE_H */
index 191df53..2f70837 100644 (file)
@@ -124,6 +124,32 @@ struct device_type greybus_connection_type = {
        .release =      gb_connection_release,
 };
 
+
+void gb_connection_bind_protocol(struct gb_connection *connection)
+{
+       struct gb_bundle *bundle;
+       struct gb_protocol *protocol;
+
+       /* If we already have a protocol bound here, just return */
+       if (connection->protocol)
+               return;
+
+       protocol = gb_protocol_get(connection->protocol_id,
+                                  connection->major,
+                                  connection->minor);
+       if (!protocol)
+               return;
+       connection->protocol = protocol;
+
+       /*
+        * If we have a valid device_id for the bundle, then we have an active
+        * device, so bring up the connection at the same time.
+        * */
+       bundle = connection->bundle;
+       if (bundle->device_id != 0xff)
+               gb_connection_init(connection);
+}
+
 /*
  * Set up a Greybus connection, representing the bidirectional link
  * between a CPort on a (local) Greybus host device and a CPort on
@@ -148,13 +174,9 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
        if (!connection)
                return NULL;
 
-       /* XXX Will have to establish connections to get version */
-       connection->protocol = gb_protocol_get(protocol_id, major, minor);
-       if (!connection->protocol) {
-               pr_err("protocol 0x%02hhx not found\n", protocol_id);
-               kfree(connection);
-               return NULL;
-       }
+       connection->protocol_id = protocol_id;
+       connection->major = major;
+       connection->minor = minor;
 
        hd = bundle->intf->hd;
        connection->hd = hd;
@@ -187,6 +209,12 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
                return NULL;
        }
 
+       /* XXX Will have to establish connections to get version */
+       gb_connection_bind_protocol(connection);
+       if (!connection->protocol)
+               dev_warn(&bundle->dev,
+                        "protocol 0x%02hhx handler not found\n", protocol_id);
+
        spin_lock_irq(&gb_connections_lock);
        list_add_tail(&connection->hd_links, &hd->connections);
        list_add_tail(&connection->bundle_links, &bundle->connections);
@@ -250,8 +278,8 @@ int gb_connection_init(struct gb_connection *connection)
        int ret;
 
        if (!connection->protocol) {
-               gb_connection_err(connection, "uninitialized connection");
-               return -EIO;
+               dev_warn(&connection->dev, "init without protocol.\n");
+               return 0;
        }
 
        /* Need to enable the connection to initialize it */
@@ -266,7 +294,7 @@ int gb_connection_init(struct gb_connection *connection)
 void gb_connection_exit(struct gb_connection *connection)
 {
        if (!connection->protocol) {
-               gb_connection_err(connection, "uninitialized connection");
+               dev_warn(&connection->dev, "exit without protocol.\n");
                return;
        }
        connection->state = GB_CONNECTION_STATE_DESTROYING;
index caf52b8..b07df79 100644 (file)
@@ -33,6 +33,9 @@ struct gb_connection {
        struct list_head                bundle_links;
 
        struct gb_protocol              *protocol;
+       u8                              protocol_id;
+       u8                              major;
+       u8                              minor;
 
        enum gb_connection_state        state;
 
@@ -58,4 +61,6 @@ void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id,
 __printf(2, 3)
 void gb_connection_err(struct gb_connection *connection, const char *fmt, ...);
 
+void gb_connection_bind_protocol(struct gb_connection *connection);
+
 #endif /* __CONNECTION_H */
index 087e0cc..44cfd50 100644 (file)
@@ -206,6 +206,9 @@ static void gb_operation_request_handle(struct gb_operation *operation)
 {
        struct gb_protocol *protocol = operation->connection->protocol;
 
+       if (!protocol)
+               return;
+
        /*
         * If the protocol has no incoming request handler, report
         * an error and mark the request bad.
index 7536a30..2527532 100644 (file)
@@ -84,6 +84,12 @@ int gb_protocol_register(struct gb_protocol *protocol)
        list_add_tail(&protocol->links, &existing->links);
        spin_unlock_irq(&gb_protocols_lock);
 
+       /*
+        * Go try to bind any unbound connections, as we have a
+        * new protocol in the system
+        */
+       gb_bundle_bind_protocols();
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(gb_protocol_register);