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>
This commit is contained in:
Alex Elder 2014-11-05 16:12:50 -06:00 committed by Greg Kroah-Hartman
parent 6b09938a48
commit 6ae7fa4520
3 changed files with 38 additions and 17 deletions

View file

@ -157,13 +157,16 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
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;

View file

@ -13,30 +13,31 @@ static DEFINE_SPINLOCK(gb_protocols_lock);
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 @@ bool gb_protocol_register(u8 id)
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 @@ bool gb_protocol_deregister(struct gb_protocol *protocol)
}
/* 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 @@ bool gb_protocol_get(struct gb_connection *connection, u8 id)
}
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 @@ bool gb_protocol_get(struct gb_connection *connection, u8 id)
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 @@ void gb_protocol_put(struct gb_connection *connection)
"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;
}

View file

@ -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 */