]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/staging/greybus/protocol.c
greybus: connection: Save major/minor supported by module
[karo-tx-linux.git] / drivers / staging / greybus / protocol.c
index 8df2b4e7b802fb366aec4093b9f0a75363894069..ba80f552fa31a1be0bcb0d743a8a88ade0c46558 100644 (file)
@@ -1,11 +1,14 @@
 /*
  * 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 */
@@ -13,7 +16,7 @@ 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, u8 major, u8 minor)
+static struct gb_protocol *gb_protocol_find(u8 id, u8 major, u8 minor)
 {
        struct gb_protocol *protocol;
 
@@ -38,14 +41,15 @@ static struct gb_protocol *_gb_protocol_find(u8 id, u8 major, u8 minor)
        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
@@ -74,7 +78,7 @@ bool gb_protocol_register(struct gb_protocol *protocol)
                /* A matching protocol has already been registered */
                spin_unlock_irq(&gb_protocols_lock);
 
-               return false;
+               return -EEXIST;
        }
 
        /*
@@ -84,8 +88,17 @@ bool gb_protocol_register(struct gb_protocol *protocol)
        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.
@@ -93,18 +106,21 @@ bool gb_protocol_register(struct gb_protocol *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)
@@ -112,8 +128,12 @@ bool gb_protocol_deregister(struct gb_protocol *protocol)
        }
        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)
@@ -122,11 +142,15 @@ 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);
 
@@ -139,64 +163,58 @@ struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor)
        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);
 }