Commit dbb8894e authored by Alex Elder's avatar Alex Elder Committed by Greg Kroah-Hartman

greybus: order the protocols list

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: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 0e447657
...@@ -17,10 +17,24 @@ static struct gb_protocol *_gb_protocol_find(u8 id, u8 major, u8 minor) ...@@ -17,10 +17,24 @@ static struct gb_protocol *_gb_protocol_find(u8 id, u8 major, u8 minor)
{ {
struct gb_protocol *protocol; struct gb_protocol *protocol;
list_for_each_entry(protocol, &gb_protocols, links) list_for_each_entry(protocol, &gb_protocols, links) {
if (protocol->id == id && protocol->major == major if (protocol->id < id)
&& protocol->minor == minor) continue;
return protocol; 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; return NULL;
} }
...@@ -38,24 +52,52 @@ bool gb_protocol_register(u8 id, u8 major, u8 minor) ...@@ -38,24 +52,52 @@ bool gb_protocol_register(u8 id, u8 major, u8 minor)
protocol->major = major; protocol->major = major;
protocol->minor = minor; 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); 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); 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 */ /* Returns true if successful, false otherwise */
bool gb_protocol_deregister(struct gb_protocol *protocol) bool gb_protocol_deregister(struct gb_protocol *protocol)
{ {
u8 protocol_count; u8 protocol_count = 0;
spin_lock_irq(&gb_protocols_lock); spin_lock_irq(&gb_protocols_lock);
protocol = _gb_protocol_find(protocol->id, protocol->major, protocol = _gb_protocol_find(protocol->id, protocol->major,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment