summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/legacy.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@hovoldconsulting.com>2016-01-19 12:51:16 +0100
committerGreg Kroah-Hartman <gregkh@google.com>2016-01-19 12:17:13 -0800
commit50dfb87865790bf8ef86a1c6898cde4e0df212fd (patch)
treedcc58670085cc25125e5cd1c8479fd2440afd8f5 /drivers/staging/greybus/legacy.c
parent84427943d2da5f55d5cc83d83ba2a75c2079d1dd (diff)
greybus: connection: move legacy-protocol handling to legacy driver
Move legacy protocol and connection handling to the legacy driver. Rename the former global functions using a common legacy_ prefix. Note that all legacy protocols suffer from a connection initialisation race in that the protocol-specific initialisation, which includes allocation of protocol-specific state containers, can not happen until *after* the connection has been enabled. This is a major flaw in the original design that we can now finally address by converting the legacy protocol drivers into proper bundle (class) drivers. Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/legacy.c')
-rw-r--r--drivers/staging/greybus/legacy.c106
1 files changed, 103 insertions, 3 deletions
diff --git a/drivers/staging/greybus/legacy.c b/drivers/staging/greybus/legacy.c
index e8d9cb93b831..fd847f42376f 100644
--- a/drivers/staging/greybus/legacy.c
+++ b/drivers/staging/greybus/legacy.c
@@ -9,6 +9,106 @@
#include "greybus.h"
#include "legacy.h"
+#include "protocol.h"
+
+
+static int legacy_connection_get_version(struct gb_connection *connection)
+{
+ int ret;
+
+ ret = gb_protocol_get_version(connection);
+ if (ret) {
+ dev_err(&connection->hd->dev,
+ "%s: failed to get protocol version: %d\n",
+ connection->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int legacy_connection_bind_protocol(struct gb_connection *connection)
+{
+ struct gb_protocol *protocol;
+
+ protocol = gb_protocol_get(connection->protocol_id,
+ connection->major,
+ connection->minor);
+ if (!protocol) {
+ dev_err(&connection->hd->dev,
+ "protocol 0x%02x version %u.%u not found\n",
+ connection->protocol_id,
+ connection->major, connection->minor);
+ return -EPROTONOSUPPORT;
+ }
+ connection->protocol = protocol;
+
+ return 0;
+}
+
+static void legacy_connection_unbind_protocol(struct gb_connection *connection)
+{
+ struct gb_protocol *protocol = connection->protocol;
+
+ gb_protocol_put(protocol);
+
+ connection->protocol = NULL;
+}
+
+static int legacy_request_handler(struct gb_operation *operation)
+{
+ struct gb_protocol *protocol = operation->connection->protocol;
+
+ return protocol->request_recv(operation->type, operation);
+}
+
+static int legacy_connection_init(struct gb_connection *connection)
+{
+ gb_request_handler_t handler;
+ int ret;
+
+ ret = legacy_connection_bind_protocol(connection);
+ if (ret)
+ return ret;
+
+ if (connection->protocol->request_recv)
+ handler = legacy_request_handler;
+ else
+ handler = NULL;
+
+ ret = gb_connection_enable(connection, handler);
+ if (ret)
+ goto err_unbind_protocol;
+
+ ret = legacy_connection_get_version(connection);
+ if (ret)
+ goto err_disable;
+
+ ret = connection->protocol->connection_init(connection);
+ if (ret)
+ goto err_disable;
+
+ return 0;
+
+err_disable:
+ gb_connection_disable(connection);
+err_unbind_protocol:
+ legacy_connection_unbind_protocol(connection);
+
+ return ret;
+}
+
+static void legacy_connection_exit(struct gb_connection *connection)
+{
+ if (connection->state == GB_CONNECTION_STATE_DISABLED)
+ return;
+
+ gb_connection_disable(connection);
+
+ connection->protocol->connection_exit(connection);
+
+ legacy_connection_unbind_protocol(connection);
+}
static int legacy_probe(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
@@ -23,7 +123,7 @@ static int legacy_probe(struct gb_bundle *bundle,
dev_dbg(&bundle->dev, "enabling connection %s\n",
connection->name);
- ret = gb_connection_legacy_init(connection);
+ ret = legacy_connection_init(connection);
if (ret)
goto err_connections_disable;
}
@@ -33,7 +133,7 @@ static int legacy_probe(struct gb_bundle *bundle,
err_connections_disable:
list_for_each_entry_reverse(connection, &bundle->connections,
bundle_links) {
- gb_connection_legacy_exit(connection);
+ legacy_connection_exit(connection);
}
return ret;
@@ -48,7 +148,7 @@ static void legacy_disconnect(struct gb_bundle *bundle)
list_for_each_entry_reverse(connection, &bundle->connections,
bundle_links) {
- gb_connection_legacy_exit(connection);
+ legacy_connection_exit(connection);
}
}