greybus: identify protocol by id *and* version

Right now we only look up a protocol based on its protocol id.
Add support for maintaining a major and minor version as well, and
use them when looking up a protocol.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 1a8f53e..703c286 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -157,13 +157,16 @@
 	struct gb_connection *connection;
 	struct greybus_host_device *hd;
 	int retval;
+	u8 major = 0;
+	u8 minor = 1;
 
 	connection = kzalloc(sizeof(*connection), GFP_KERNEL);
 	if (!connection)
 		return NULL;
 
 	INIT_LIST_HEAD(&connection->protocol_links);
-	if (!gb_protocol_get(connection, protocol_id)) {
+	/* XXX Will have to establish connections to get version */
+	if (!gb_protocol_get(connection, protocol_id, major, minor)) {
 		pr_err("protocol 0x%02hhx not found\n", protocol_id);
 		kfree(connection);
 		return NULL;
diff --git a/drivers/staging/greybus/protocol.c b/drivers/staging/greybus/protocol.c
index e0bcd4b..704b180 100644
--- a/drivers/staging/greybus/protocol.c
+++ b/drivers/staging/greybus/protocol.c
@@ -13,30 +13,31 @@
 static LIST_HEAD(gb_protocols);
 
 /* Caller must hold gb_protocols_lock */
-static struct gb_protocol *_gb_protocol_find(u8 id)
+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)
+		if (protocol->id == id && protocol->major == major
+					&& protocol->minor == minor)
 			return protocol;
 	return NULL;
 }
 
 /* This is basically for debug */
-static struct gb_protocol *gb_protocol_find(u8 id)
+static struct gb_protocol *gb_protocol_find(u8 id, u8 major, u8 minor)
 {
 	struct gb_protocol *protocol;
 
 	spin_lock_irq(&gb_protocols_lock);
-	protocol = _gb_protocol_find(id);
+	protocol = _gb_protocol_find(id, major, minor);
 	spin_unlock_irq(&gb_protocols_lock);
 
 	return protocol;
 }
 
 /* Returns true if protocol was succesfully registered, false otherwise */
-bool gb_protocol_register(u8 id)
+bool gb_protocol_register(u8 id, u8 major, u8 minor)
 {
 	struct gb_protocol *protocol;
 	struct gb_protocol *existing;
@@ -46,10 +47,12 @@
 	if (!protocol)
 		return false;
 	protocol->id = id;
+	protocol->major = major;
+	protocol->minor = minor;
 	INIT_LIST_HEAD(&protocol->connections);
 
 	spin_lock_irq(&gb_protocols_lock);
-	existing = _gb_protocol_find(id);
+	existing = _gb_protocol_find(id, major, minor);
 	if (!existing)
 		list_add(&protocol->links, &gb_protocols);
 	spin_unlock_irq(&gb_protocols_lock);
@@ -77,7 +80,8 @@
 }
 
 /* Returns true if successful, false otherwise */
-bool gb_protocol_get(struct gb_connection *connection, u8 id)
+bool
+gb_protocol_get(struct gb_connection *connection, u8 id, u8 major, u8 minor)
 {
 	struct gb_protocol *protocol;
 
@@ -90,7 +94,7 @@
 	}
 
 	spin_lock_irq(&gb_protocols_lock);
-	protocol = _gb_protocol_find(id);
+	protocol = _gb_protocol_find(id, major, minor);
 	if (protocol)
 		list_add(&connection->protocol_links, &protocol->connections);
 	spin_unlock_irq(&gb_protocols_lock);
@@ -102,6 +106,8 @@
 void gb_protocol_put(struct gb_connection *connection)
 {
 	struct gb_protocol *protocol = connection->protocol;
+	u8 major = protocol->major;
+	u8 minor = protocol->minor;
 
 	/* Sanity checks */
 	if (list_empty(&connection->protocol_links)) {
@@ -109,9 +115,12 @@
 			"connection protocol not recorded");
 		return;
 	}
-	if (!protocol || gb_protocol_find(protocol->id) != protocol)  {
-		gb_connection_err(connection,
-			"connection has undefined protocol");
+	if (!protocol) {
+		gb_connection_err(connection, "connection has no protocol");
+		return;
+	}
+	if (gb_protocol_find(protocol->id, major, minor) != protocol)  {
+		gb_connection_err(connection, "connection protocol not found");
 		return;
 	}
 
diff --git a/drivers/staging/greybus/protocol.h b/drivers/staging/greybus/protocol.h
index d244e9d..d53f67d 100644
--- a/drivers/staging/greybus/protocol.h
+++ b/drivers/staging/greybus/protocol.h
@@ -11,16 +11,25 @@
 
 #include "greybus.h"
 
+/*
+ * Protocols having the same id but different major and/or minor
+ * version numbers are treated as distinct protocols.  If it makes
+ * sense someday we could group protocols having the same id.
+ */
 struct gb_protocol {
-	u8				id;
-	struct list_head		connections;	/* protocol users */
-	struct list_head		links;		/* global list */
+	u8			id;
+	u8			major;
+	u8			minor;
+
+	struct list_head	connections;	/* protocol users */
+	struct list_head	links;		/* global list */
 };
 
-bool gb_protocol_register(u8 id);
+bool gb_protocol_register(u8 id, u8 major, u8 minor);
 bool gb_protocol_deregister(struct gb_protocol *protocol);
 
-bool gb_protocol_get(struct gb_connection *connection, u8 id);
+bool gb_protocol_get(struct gb_connection *connection, u8 id,
+				u8 major, u8 minor);
 void gb_protocol_put(struct gb_connection *connection);
 
 #endif /* __PROTOCOL_H */