greybus: order the protocols list
authorAlex Elder <elder@linaro.org>
Wed, 5 Nov 2014 22:12:52 +0000 (16:12 -0600)
committerGreg Kroah-Hartman <greg@kroah.com>
Wed, 5 Nov 2014 22:21:24 +0000 (14:21 -0800)
Add protocols to the global list in sorted order, based on their
protocol id, and then their major and minor version number.

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

index 347d52c..6fec32e 100644 (file)
@@ -17,10 +17,24 @@ static struct gb_protocol *_gb_protocol_find(u8 id, u8 major, u8 minor)
 {
        struct gb_protocol *protocol;
 
-       list_for_each_entry(protocol, &gb_protocols, links)
-               if (protocol->id == id && protocol->major == major
-                                       && protocol->minor == minor)
-                       return protocol;
+       list_for_each_entry(protocol, &gb_protocols, links) {
+               if (protocol->id < id)
+                       continue;
+               if (protocol->id > id)
+                       break;
+
+               if (protocol->major > major)
+                       continue;
+               if (protocol->major < major)
+                       break;
+
+               if (protocol->minor > minor)
+                       continue;
+               if (protocol->minor < minor)
+                       break;
+
+               return protocol;
+       }
        return NULL;
 }
 
@@ -38,24 +52,52 @@ bool gb_protocol_register(u8 id, u8 major, u8 minor)
        protocol->major = major;
        protocol->minor = minor;
 
+       /*
+        * The protocols list is sorted first by protocol id (low to
+        * high), then by major version (high to low), and finally
+        * by minor version (high to low).  Searching only by
+        * protocol id will produce the newest implemented version
+        * of the protocol.
+        */
        spin_lock_irq(&gb_protocols_lock);
-       existing = _gb_protocol_find(id, major, minor);
-       if (!existing)
-               list_add(&protocol->links, &gb_protocols);
-       spin_unlock_irq(&gb_protocols_lock);
 
-       if (existing) {
+       list_for_each_entry(existing, &gb_protocols, links) {
+               if (existing->id < id)
+                       continue;
+               if (existing->id > id)
+                       break;
+
+               if (existing->major > major)
+                       continue;
+               if (existing->major < major)
+                       break;
+
+               if (existing->minor > minor)
+                       continue;
+               if (existing->minor < minor)
+                       break;
+
+               /* A matching protocol has already been registered */
+               spin_unlock_irq(&gb_protocols_lock);
                kfree(protocol);
-               protocol = NULL;
+
+               return false;
        }
 
-       return protocol != NULL;
+       /*
+        * We need to insert the protocol here, before the existing one
+        * (or before the head if we searched the whole list)
+        */
+       list_add_tail(&protocol->links, &existing->links);
+       spin_unlock_irq(&gb_protocols_lock);
+
+       return true;
 }
 
 /* Returns true if successful, false otherwise */
 bool gb_protocol_deregister(struct gb_protocol *protocol)
 {
-       u8 protocol_count;
+       u8 protocol_count = 0;
 
        spin_lock_irq(&gb_protocols_lock);
        protocol = _gb_protocol_find(protocol->id, protocol->major,