/*
* Greybus protocol handling
*
- * Copyright 2014 Google Inc.
+ * Copyright 2014-2015 Google Inc.
+ * Copyright 2014-2015 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "greybus.h"
/* Global list of registered protocols */
static LIST_HEAD(gb_protocols);
/* Caller must hold gb_protocols_lock */
-static struct gb_protocol *_gb_protocol_find(u8 id, u8 major, u8 minor)
+static struct gb_protocol *gb_protocol_find(u8 id, u8 major, u8 minor)
{
struct gb_protocol *protocol;
return NULL;
}
-/* Returns true if protocol was succesfully registered, false otherwise */
-bool gb_protocol_register(struct gb_protocol *protocol)
+int __gb_protocol_register(struct gb_protocol *protocol, struct module *module)
{
struct gb_protocol *existing;
u8 id = protocol->id;
u8 major = protocol->major;
u8 minor = protocol->minor;
+ protocol->owner = module;
+
/*
* The protocols list is sorted first by protocol id (low to
* high), then by major version (high to low), and finally
/* A matching protocol has already been registered */
spin_unlock_irq(&gb_protocols_lock);
- return false;
+ return -EEXIST;
}
/*
list_add_tail(&protocol->links, &existing->links);
spin_unlock_irq(&gb_protocols_lock);
- return true;
+ pr_info("Registered %s protocol.\n", protocol->name);
+
+ /*
+ * Go try to bind any unbound connections, as we have a
+ * new protocol in the system
+ */
+ gb_bundle_bind_protocols();
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(__gb_protocol_register);
/*
* De-register a previously registered protocol.
* XXX Currently this fails (and reports an error to the caller) if
* XXX the protocol is currently in use. We may want to forcefully
* XXX kill off a protocol and all its active users at some point.
- * XXX But I think that's better handled by quescing modules that
+ * XXX But I think that's better handled by quiescing modules that
* XXX have users and having those users drop their reference.
*
* Returns true if successful, false otherwise.
*/
-bool gb_protocol_deregister(struct gb_protocol *protocol)
+int gb_protocol_deregister(struct gb_protocol *protocol)
{
u8 protocol_count = 0;
+ if (!protocol)
+ return 0;
+
spin_lock_irq(&gb_protocols_lock);
- protocol = _gb_protocol_find(protocol->id, protocol->major,
- protocol->minor);
+ protocol = gb_protocol_find(protocol->id, protocol->major,
+ protocol->minor);
if (protocol) {
protocol_count = protocol->count;
if (!protocol_count)
}
spin_unlock_irq(&gb_protocols_lock);
+ if (protocol)
+ pr_info("Deregistered %s protocol.\n", protocol->name);
+
return protocol && !protocol_count;
}
+EXPORT_SYMBOL_GPL(gb_protocol_deregister);
/* Returns the requested protocol if available, or a null pointer */
struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor)
u8 protocol_count;
spin_lock_irq(&gb_protocols_lock);
- protocol = _gb_protocol_find(id, major, minor);
+ protocol = gb_protocol_find(id, major, minor);
if (protocol) {
- protocol_count = protocol->count;
- if (protocol_count != U8_MAX)
- protocol->count++;
+ if (!try_module_get(protocol->owner)) {
+ protocol = NULL;
+ } else {
+ protocol_count = protocol->count;
+ if (protocol_count != U8_MAX)
+ protocol->count++;
+ }
}
spin_unlock_irq(&gb_protocols_lock);
return protocol;
}
+int gb_protocol_get_version(struct gb_connection *connection, int type,
+ void *request, int request_size,
+ struct gb_protocol_version_response *response,
+ __u8 major)
+{
+ int retval;
+
+ retval = gb_operation_sync(connection, type, request, request_size,
+ response, sizeof(*response));
+ if (retval)
+ return retval;
+
+ if (response->major > major) {
+ dev_err(&connection->dev,
+ "unsupported major version (%hhu > %hhu)\n",
+ response->major, major);
+ return -ENOTSUPP;
+ }
+
+ connection->module_major = response->major;
+ connection->module_minor = response->minor;
+
+ dev_dbg(&connection->dev, "version_major = %u version_minor = %u\n",
+ response->major, response->minor);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gb_protocol_get_version);
+
void gb_protocol_put(struct gb_protocol *protocol)
{
- u8 major = protocol->major;
- u8 minor = protocol->minor;
+ u8 id;
+ u8 major;
+ u8 minor;
u8 protocol_count;
+ id = protocol->id;
+ major = protocol->major;
+ minor = protocol->minor;
+
spin_lock_irq(&gb_protocols_lock);
- protocol = _gb_protocol_find(protocol->id, protocol->major,
- protocol->minor);
+ protocol = gb_protocol_find(id, major, minor);
if (protocol) {
protocol_count = protocol->count;
if (protocol_count)
protocol->count--;
+ module_put(protocol->owner);
}
spin_unlock_irq(&gb_protocols_lock);
if (protocol)
WARN_ON(!protocol_count);
else
pr_err("protocol id %hhu version %hhu.%hhu not found\n",
- protocol->id, major, minor);
-}
-
-bool gb_protocol_init(void)
-{
- bool ret = true;
-
- if (!gb_battery_protocol_init()) {
- pr_err("error initializing battery protocol\n");
- ret = false;
- }
- if (!gb_gpio_protocol_init()) {
- pr_err("error initializing gpio protocol\n");
- ret = false;
- }
- if (!gb_i2c_protocol_init()) {
- pr_err("error initializing i2c protocol\n");
- ret = false;
- }
- if (!gb_pwm_protocol_init()) {
- pr_err("error initializing pwm protocol\n");
- ret = false;
- }
- if (!gb_uart_protocol_init()) {
- pr_err("error initializing uart protocol\n");
- ret = false;
- }
- if (!gb_sdio_protocol_init()) {
- pr_err("error initializing sdio protocol\n");
- ret = false;
- }
- return ret;
-}
-
-void gb_protocol_exit(void)
-{
- gb_sdio_protocol_exit();
- gb_uart_protocol_exit();
- gb_i2c_protocol_exit();
- gb_gpio_protocol_exit();
- gb_battery_protocol_exit();
+ id, major, minor);
}