greybus: Remove "-gb" suffix from .c files
authorViresh Kumar <viresh.kumar@linaro.org>
Wed, 21 Jan 2015 10:40:40 +0000 (16:10 +0530)
committerGreg Kroah-Hartman <greg@kroah.com>
Thu, 22 Jan 2015 03:27:20 +0000 (11:27 +0800)
Some files are prefixed with "gb-" and some are suffixed with "-gb". The
rationale behind the first one is that the modules would be named so, i.e.
gb-*.ko. But there is no reason to keep the "-gb" suffix in the second case.

Remove the unnecessary suffix.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
13 files changed:
drivers/staging/greybus/Makefile
drivers/staging/greybus/gpio-gb.c [deleted file]
drivers/staging/greybus/gpio.c [new file with mode: 0644]
drivers/staging/greybus/i2c-gb.c [deleted file]
drivers/staging/greybus/i2c.c [new file with mode: 0644]
drivers/staging/greybus/pwm-gb.c [deleted file]
drivers/staging/greybus/pwm.c [new file with mode: 0644]
drivers/staging/greybus/sdio-gb.c [deleted file]
drivers/staging/greybus/sdio.c [new file with mode: 0644]
drivers/staging/greybus/uart-gb.c [deleted file]
drivers/staging/greybus/uart.c [new file with mode: 0644]
drivers/staging/greybus/usb-gb.c [deleted file]
drivers/staging/greybus/usb.c [new file with mode: 0644]

index a5d5470974bac1c5e979094bb5a0f3edca5ea74c..55b4a37c58fbb5b5924e29ebfa7ea75001adeb39 100644 (file)
@@ -10,12 +10,12 @@ greybus-y :=        core.o          \
                operation.o
 
 gb-phy-y :=    gpb.o           \
-               sdio-gb.o       \
-               uart-gb.o       \
-               pwm-gb.o        \
-               gpio-gb.o       \
-               i2c-gb.o        \
-               usb-gb.o
+               sdio.o  \
+               uart.o  \
+               pwm.o   \
+               gpio.o  \
+               i2c.o   \
+               usb.o
 
 obj-m += greybus.o
 obj-m += gb-phy.o
diff --git a/drivers/staging/greybus/gpio-gb.c b/drivers/staging/greybus/gpio-gb.c
deleted file mode 100644 (file)
index 4997588..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * GPIO Greybus driver.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
-#include "greybus.h"
-
-struct gb_gpio_line {
-       /* The following has to be an array of line_max entries */
-       /* --> make them just a flags field */
-       u8                      active:    1,
-                               direction: 1,   /* 0 = output, 1 = input */
-                               value:     1;   /* 0 = low, 1 = high */
-       u16                     debounce_usec;
-};
-
-struct gb_gpio_controller {
-       struct gb_connection    *connection;
-       u8                      version_major;
-       u8                      version_minor;
-       u8                      line_max;       /* max line number */
-       struct gb_gpio_line     *lines;
-
-       struct gpio_chip        chip;
-};
-#define gpio_chip_to_gb_gpio_controller(chip) \
-       container_of(chip, struct gb_gpio_controller, chip)
-
-/* Version of the Greybus GPIO protocol we support */
-#define        GB_GPIO_VERSION_MAJOR           0x00
-#define        GB_GPIO_VERSION_MINOR           0x01
-
-/* Greybus GPIO request types */
-#define        GB_GPIO_TYPE_INVALID            0x00
-#define        GB_GPIO_TYPE_PROTOCOL_VERSION   0x01
-#define        GB_GPIO_TYPE_LINE_COUNT         0x02
-#define        GB_GPIO_TYPE_ACTIVATE           0x03
-#define        GB_GPIO_TYPE_DEACTIVATE         0x04
-#define        GB_GPIO_TYPE_GET_DIRECTION      0x05
-#define        GB_GPIO_TYPE_DIRECTION_IN       0x06
-#define        GB_GPIO_TYPE_DIRECTION_OUT      0x07
-#define        GB_GPIO_TYPE_GET_VALUE          0x08
-#define        GB_GPIO_TYPE_SET_VALUE          0x09
-#define        GB_GPIO_TYPE_SET_DEBOUNCE       0x0a
-#define        GB_GPIO_TYPE_RESPONSE           0x80    /* OR'd with rest */
-
-#define        GB_GPIO_DEBOUNCE_USEC_DEFAULT   0       /* microseconds */
-
-/* version request has no payload */
-struct gb_gpio_proto_version_response {
-       __u8    major;
-       __u8    minor;
-};
-
-/* line count request has no payload */
-struct gb_gpio_line_count_response {
-       __u8    count;
-};
-
-struct gb_gpio_activate_request {
-       __u8    which;
-};
-/* activate response has no payload */
-
-struct gb_gpio_deactivate_request {
-       __u8    which;
-};
-/* deactivate response has no payload */
-
-struct gb_gpio_get_direction_request {
-       __u8    which;
-};
-struct gb_gpio_get_direction_response {
-       __u8    direction;
-};
-
-struct gb_gpio_direction_in_request {
-       __u8    which;
-};
-/* direction in response has no payload */
-
-struct gb_gpio_direction_out_request {
-       __u8    which;
-       __u8    value;
-};
-/* direction out response has no payload */
-
-struct gb_gpio_get_value_request {
-       __u8    which;
-};
-struct gb_gpio_get_value_response {
-       __u8    value;
-};
-
-struct gb_gpio_set_value_request {
-       __u8    which;
-       __u8    value;
-};
-/* set value response has no payload */
-
-struct gb_gpio_set_debounce_request {
-       __u8    which;
-       __le16  usec;
-};
-/* debounce response has no payload */
-
-
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_gpio_proto_version_operation(struct gb_gpio_controller *ggc)
-{
-       struct gb_gpio_proto_version_response response;
-       int ret;
-
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_PROTOCOL_VERSION,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       if (response.major > GB_GPIO_VERSION_MAJOR) {
-               pr_err("unsupported major version (%hhu > %hhu)\n",
-                       response.major, GB_GPIO_VERSION_MAJOR);
-               return -ENOTSUPP;
-       }
-       ggc->version_major = response.major;
-       ggc->version_minor = response.minor;
-       return 0;
-}
-
-static int gb_gpio_line_count_operation(struct gb_gpio_controller *ggc)
-{
-       struct gb_gpio_line_count_response response;
-       int ret;
-
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_LINE_COUNT,
-                               NULL, 0, &response, sizeof(response));
-       if (!ret)
-               ggc->line_max = response.count;
-       return ret;
-}
-
-static int gb_gpio_activate_operation(struct gb_gpio_controller *ggc, u8 which)
-{
-       struct gb_gpio_activate_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_ACTIVATE,
-                                &request, sizeof(request), NULL, 0);
-       if (!ret)
-               ggc->lines[which].active = true;
-       return ret;
-}
-
-static int gb_gpio_deactivate_operation(struct gb_gpio_controller *ggc,
-                                       u8 which)
-{
-       struct gb_gpio_deactivate_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DEACTIVATE,
-                                &request, sizeof(request), NULL, 0);
-       if (!ret)
-               ggc->lines[which].active = false;
-       return ret;
-}
-
-static int gb_gpio_get_direction_operation(struct gb_gpio_controller *ggc,
-                                       u8 which)
-{
-       struct gb_gpio_get_direction_request request;
-       struct gb_gpio_get_direction_response response;
-       int ret;
-       u8 direction;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_DIRECTION,
-                               &request, sizeof(request),
-                               &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       direction = response.direction;
-       if (direction && direction != 1)
-               pr_warn("gpio %u direction was %u (should be 0 or 1)\n",
-                       which, direction);
-       ggc->lines[which].direction = direction ? 1 : 0;
-       return 0;
-}
-
-static int gb_gpio_direction_in_operation(struct gb_gpio_controller *ggc,
-                                       u8 which)
-{
-       struct gb_gpio_direction_in_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_IN,
-                               &request, sizeof(request), NULL, 0);
-       if (!ret)
-               ggc->lines[which].direction = 1;
-       return ret;
-}
-
-static int gb_gpio_direction_out_operation(struct gb_gpio_controller *ggc,
-                                       u8 which, bool value_high)
-{
-       struct gb_gpio_direction_out_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       request.value = value_high ? 1 : 0;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_OUT,
-                               &request, sizeof(request), NULL, 0);
-       if (!ret)
-               ggc->lines[which].direction = 0;
-       return ret;
-}
-
-static int gb_gpio_get_value_operation(struct gb_gpio_controller *ggc,
-                                       u8 which)
-{
-       struct gb_gpio_get_value_request request;
-       struct gb_gpio_get_value_response response;
-       int ret;
-       u8 value;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_VALUE,
-                               &request, sizeof(request),
-                               &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       value = response.value;
-       if (value && value != 1)
-               pr_warn("gpio %u value was %u (should be 0 or 1)\n",
-                       which, value);
-       ggc->lines[which].value = value ? 1 : 0;
-       return 0;
-}
-
-static int gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
-                                       u8 which, bool value_high)
-{
-       struct gb_gpio_set_value_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       request.value = value_high ? 1 : 0;
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_VALUE,
-                               &request, sizeof(request), NULL, 0);
-       if (!ret) {
-               /* XXX should this set direction to out? */
-               ggc->lines[which].value = request.value;
-       }
-       return ret;
-}
-
-static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *ggc,
-                                       u8 which, u16 debounce_usec)
-{
-       struct gb_gpio_set_debounce_request request;
-       int ret;
-
-       if (which > ggc->line_max)
-               return -EINVAL;
-
-       request.which = which;
-       request.usec = cpu_to_le16(debounce_usec);
-       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_DEBOUNCE,
-                               &request, sizeof(request), NULL, 0);
-       if (!ret)
-               ggc->lines[which].debounce_usec = debounce_usec;
-       return ret;
-}
-
-static int gb_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       ret = gb_gpio_activate_operation(gb_gpio_controller, (u8)offset);
-       if (ret)
-               ;       /* return ret; */
-       return 0;
-}
-
-static void gb_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       int ret;
-
-       if (offset >= chip->ngpio) {
-               pr_err("bad offset %u supplied (must be 0..%u)\n",
-                       offset, chip->ngpio - 1);
-               return;
-       }
-       ret = gb_gpio_deactivate_operation(gb_gpio_controller, (u8)offset);
-       if (ret)
-               ;       /* return ret; */
-}
-
-static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       u8 which;
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       which = (u8)offset;
-       ret = gb_gpio_get_direction_operation(gb_gpio_controller, which);
-       if (ret)
-               ;       /* return ret; */
-       return gb_gpio_controller->lines[which].direction ? 1 : 0;
-}
-
-static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       ret = gb_gpio_direction_in_operation(gb_gpio_controller, (u8)offset);
-       if (ret)
-               ;       /* return ret; */
-       return 0;
-}
-
-static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-                                       int value)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       ret = gb_gpio_direction_out_operation(gb_gpio_controller, (u8)offset, !!value);
-       if (ret)
-               ;       /* return ret; */
-       return 0;
-}
-
-static int gb_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       u8 which;
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       which = (u8)offset;
-       ret = gb_gpio_get_value_operation(gb_gpio_controller, which);
-       if (ret)
-               return ret;
-       return (int)gb_gpio_controller->lines[which].value;
-}
-
-static void gb_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       int ret;
-
-       if (offset < 0 || offset >= chip->ngpio) {
-               pr_err("bad offset %u supplied (must be 0..%u)\n",
-                       offset, chip->ngpio - 1);
-               return;
-       }
-       ret = gb_gpio_set_value_operation(gb_gpio_controller, (u8)offset, !!value);
-       if (ret)
-               ;       /* return ret; */
-}
-
-static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
-                                       unsigned debounce)
-{
-       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
-       u16 usec;
-       int ret;
-
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-       if (debounce > (unsigned int)U16_MAX)
-               return -EINVAL;
-       usec = (u8)debounce;
-       ret = gb_gpio_set_debounce_operation(gb_gpio_controller, (u8)offset, usec);
-       if (ret)
-               ;       /* return ret; */
-
-       return 0;       /* XXX */
-}
-
-static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       if (offset >= chip->ngpio)
-               return -EINVAL;
-
-       return 0;       /* XXX */
-}
-
-static void gb_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-       return; /* XXX */
-}
-
-static int gb_gpio_controller_setup(struct gb_gpio_controller *gb_gpio_controller)
-{
-       u32 line_count;
-       size_t size;
-       int ret;
-
-       /* First thing we need to do is check the version */
-       ret = gb_gpio_proto_version_operation(gb_gpio_controller);
-       if (ret)
-               ;       /* return ret; */
-
-       /* Now find out how many lines there are */
-       ret = gb_gpio_line_count_operation(gb_gpio_controller);
-       if (ret)
-               ;       /* return ret; */
-       line_count = (u32)gb_gpio_controller->line_max + 1;
-       size = line_count * sizeof(*gb_gpio_controller->lines);
-       gb_gpio_controller->lines = kzalloc(size, GFP_KERNEL);
-       if (!gb_gpio_controller->lines)
-               return -ENOMEM;
-
-       return ret;
-}
-
-static int gb_gpio_connection_init(struct gb_connection *connection)
-{
-       struct gb_gpio_controller *gb_gpio_controller;
-       struct gpio_chip *gpio;
-       int ret;
-
-       gb_gpio_controller = kzalloc(sizeof(*gb_gpio_controller), GFP_KERNEL);
-       if (!gb_gpio_controller)
-               return -ENOMEM;
-       gb_gpio_controller->connection = connection;
-       connection->private = gb_gpio_controller;
-
-       ret = gb_gpio_controller_setup(gb_gpio_controller);
-       if (ret)
-               goto out_err;
-
-       gpio = &gb_gpio_controller->chip;
-
-       gpio->label = "greybus_gpio";
-       gpio->owner = THIS_MODULE;      /* XXX Module get? */
-
-       gpio->request = gb_gpio_request;
-       gpio->free = gb_gpio_free;
-       gpio->get_direction = gb_gpio_get_direction;
-       gpio->direction_input = gb_gpio_direction_input;
-       gpio->direction_output = gb_gpio_direction_output;
-       gpio->get = gb_gpio_get;
-       gpio->set = gb_gpio_set;
-       gpio->set_debounce = gb_gpio_set_debounce;
-       gpio->to_irq = gb_gpio_to_irq;
-       gpio->dbg_show = gb_gpio_dbg_show;
-
-       gpio->base = -1;                /* Allocate base dynamically */
-       gpio->ngpio = gb_gpio_controller->line_max + 1;
-       gpio->can_sleep = true;         /* XXX */
-
-       ret = gpiochip_add(gpio);
-       if (ret) {
-               pr_err("Failed to register GPIO\n");
-               return ret;
-       }
-
-       return 0;
-out_err:
-       kfree(gb_gpio_controller);
-       return ret;
-}
-
-static void gb_gpio_connection_exit(struct gb_connection *connection)
-{
-       struct gb_gpio_controller *gb_gpio_controller = connection->private;
-
-       if (!gb_gpio_controller)
-               return;
-
-       gb_gpiochip_remove(&gb_gpio_controller->chip);
-       /* kref_put(gb_gpio_controller->connection) */
-       kfree(gb_gpio_controller);
-}
-
-static struct gb_protocol gpio_protocol = {
-       .name                   = "gpio",
-       .id                     = GREYBUS_PROTOCOL_GPIO,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_gpio_connection_init,
-       .connection_exit        = gb_gpio_connection_exit,
-       .request_recv           = NULL, /* no incoming requests */
-};
-
-int gb_gpio_protocol_init(void)
-{
-       return gb_protocol_register(&gpio_protocol);
-}
-
-void gb_gpio_protocol_exit(void)
-{
-       gb_protocol_deregister(&gpio_protocol);
-}
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
new file mode 100644 (file)
index 0000000..4997588
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * GPIO Greybus driver.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include "greybus.h"
+
+struct gb_gpio_line {
+       /* The following has to be an array of line_max entries */
+       /* --> make them just a flags field */
+       u8                      active:    1,
+                               direction: 1,   /* 0 = output, 1 = input */
+                               value:     1;   /* 0 = low, 1 = high */
+       u16                     debounce_usec;
+};
+
+struct gb_gpio_controller {
+       struct gb_connection    *connection;
+       u8                      version_major;
+       u8                      version_minor;
+       u8                      line_max;       /* max line number */
+       struct gb_gpio_line     *lines;
+
+       struct gpio_chip        chip;
+};
+#define gpio_chip_to_gb_gpio_controller(chip) \
+       container_of(chip, struct gb_gpio_controller, chip)
+
+/* Version of the Greybus GPIO protocol we support */
+#define        GB_GPIO_VERSION_MAJOR           0x00
+#define        GB_GPIO_VERSION_MINOR           0x01
+
+/* Greybus GPIO request types */
+#define        GB_GPIO_TYPE_INVALID            0x00
+#define        GB_GPIO_TYPE_PROTOCOL_VERSION   0x01
+#define        GB_GPIO_TYPE_LINE_COUNT         0x02
+#define        GB_GPIO_TYPE_ACTIVATE           0x03
+#define        GB_GPIO_TYPE_DEACTIVATE         0x04
+#define        GB_GPIO_TYPE_GET_DIRECTION      0x05
+#define        GB_GPIO_TYPE_DIRECTION_IN       0x06
+#define        GB_GPIO_TYPE_DIRECTION_OUT      0x07
+#define        GB_GPIO_TYPE_GET_VALUE          0x08
+#define        GB_GPIO_TYPE_SET_VALUE          0x09
+#define        GB_GPIO_TYPE_SET_DEBOUNCE       0x0a
+#define        GB_GPIO_TYPE_RESPONSE           0x80    /* OR'd with rest */
+
+#define        GB_GPIO_DEBOUNCE_USEC_DEFAULT   0       /* microseconds */
+
+/* version request has no payload */
+struct gb_gpio_proto_version_response {
+       __u8    major;
+       __u8    minor;
+};
+
+/* line count request has no payload */
+struct gb_gpio_line_count_response {
+       __u8    count;
+};
+
+struct gb_gpio_activate_request {
+       __u8    which;
+};
+/* activate response has no payload */
+
+struct gb_gpio_deactivate_request {
+       __u8    which;
+};
+/* deactivate response has no payload */
+
+struct gb_gpio_get_direction_request {
+       __u8    which;
+};
+struct gb_gpio_get_direction_response {
+       __u8    direction;
+};
+
+struct gb_gpio_direction_in_request {
+       __u8    which;
+};
+/* direction in response has no payload */
+
+struct gb_gpio_direction_out_request {
+       __u8    which;
+       __u8    value;
+};
+/* direction out response has no payload */
+
+struct gb_gpio_get_value_request {
+       __u8    which;
+};
+struct gb_gpio_get_value_response {
+       __u8    value;
+};
+
+struct gb_gpio_set_value_request {
+       __u8    which;
+       __u8    value;
+};
+/* set value response has no payload */
+
+struct gb_gpio_set_debounce_request {
+       __u8    which;
+       __le16  usec;
+};
+/* debounce response has no payload */
+
+
+/*
+ * This request only uses the connection field, and if successful,
+ * fills in the major and minor protocol version of the target.
+ */
+static int gb_gpio_proto_version_operation(struct gb_gpio_controller *ggc)
+{
+       struct gb_gpio_proto_version_response response;
+       int ret;
+
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_PROTOCOL_VERSION,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       if (response.major > GB_GPIO_VERSION_MAJOR) {
+               pr_err("unsupported major version (%hhu > %hhu)\n",
+                       response.major, GB_GPIO_VERSION_MAJOR);
+               return -ENOTSUPP;
+       }
+       ggc->version_major = response.major;
+       ggc->version_minor = response.minor;
+       return 0;
+}
+
+static int gb_gpio_line_count_operation(struct gb_gpio_controller *ggc)
+{
+       struct gb_gpio_line_count_response response;
+       int ret;
+
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_LINE_COUNT,
+                               NULL, 0, &response, sizeof(response));
+       if (!ret)
+               ggc->line_max = response.count;
+       return ret;
+}
+
+static int gb_gpio_activate_operation(struct gb_gpio_controller *ggc, u8 which)
+{
+       struct gb_gpio_activate_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_ACTIVATE,
+                                &request, sizeof(request), NULL, 0);
+       if (!ret)
+               ggc->lines[which].active = true;
+       return ret;
+}
+
+static int gb_gpio_deactivate_operation(struct gb_gpio_controller *ggc,
+                                       u8 which)
+{
+       struct gb_gpio_deactivate_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DEACTIVATE,
+                                &request, sizeof(request), NULL, 0);
+       if (!ret)
+               ggc->lines[which].active = false;
+       return ret;
+}
+
+static int gb_gpio_get_direction_operation(struct gb_gpio_controller *ggc,
+                                       u8 which)
+{
+       struct gb_gpio_get_direction_request request;
+       struct gb_gpio_get_direction_response response;
+       int ret;
+       u8 direction;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_DIRECTION,
+                               &request, sizeof(request),
+                               &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       direction = response.direction;
+       if (direction && direction != 1)
+               pr_warn("gpio %u direction was %u (should be 0 or 1)\n",
+                       which, direction);
+       ggc->lines[which].direction = direction ? 1 : 0;
+       return 0;
+}
+
+static int gb_gpio_direction_in_operation(struct gb_gpio_controller *ggc,
+                                       u8 which)
+{
+       struct gb_gpio_direction_in_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_IN,
+                               &request, sizeof(request), NULL, 0);
+       if (!ret)
+               ggc->lines[which].direction = 1;
+       return ret;
+}
+
+static int gb_gpio_direction_out_operation(struct gb_gpio_controller *ggc,
+                                       u8 which, bool value_high)
+{
+       struct gb_gpio_direction_out_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       request.value = value_high ? 1 : 0;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_DIRECTION_OUT,
+                               &request, sizeof(request), NULL, 0);
+       if (!ret)
+               ggc->lines[which].direction = 0;
+       return ret;
+}
+
+static int gb_gpio_get_value_operation(struct gb_gpio_controller *ggc,
+                                       u8 which)
+{
+       struct gb_gpio_get_value_request request;
+       struct gb_gpio_get_value_response response;
+       int ret;
+       u8 value;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_GET_VALUE,
+                               &request, sizeof(request),
+                               &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       value = response.value;
+       if (value && value != 1)
+               pr_warn("gpio %u value was %u (should be 0 or 1)\n",
+                       which, value);
+       ggc->lines[which].value = value ? 1 : 0;
+       return 0;
+}
+
+static int gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
+                                       u8 which, bool value_high)
+{
+       struct gb_gpio_set_value_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       request.value = value_high ? 1 : 0;
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_VALUE,
+                               &request, sizeof(request), NULL, 0);
+       if (!ret) {
+               /* XXX should this set direction to out? */
+               ggc->lines[which].value = request.value;
+       }
+       return ret;
+}
+
+static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *ggc,
+                                       u8 which, u16 debounce_usec)
+{
+       struct gb_gpio_set_debounce_request request;
+       int ret;
+
+       if (which > ggc->line_max)
+               return -EINVAL;
+
+       request.which = which;
+       request.usec = cpu_to_le16(debounce_usec);
+       ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_DEBOUNCE,
+                               &request, sizeof(request), NULL, 0);
+       if (!ret)
+               ggc->lines[which].debounce_usec = debounce_usec;
+       return ret;
+}
+
+static int gb_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       ret = gb_gpio_activate_operation(gb_gpio_controller, (u8)offset);
+       if (ret)
+               ;       /* return ret; */
+       return 0;
+}
+
+static void gb_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       int ret;
+
+       if (offset >= chip->ngpio) {
+               pr_err("bad offset %u supplied (must be 0..%u)\n",
+                       offset, chip->ngpio - 1);
+               return;
+       }
+       ret = gb_gpio_deactivate_operation(gb_gpio_controller, (u8)offset);
+       if (ret)
+               ;       /* return ret; */
+}
+
+static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       u8 which;
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       which = (u8)offset;
+       ret = gb_gpio_get_direction_operation(gb_gpio_controller, which);
+       if (ret)
+               ;       /* return ret; */
+       return gb_gpio_controller->lines[which].direction ? 1 : 0;
+}
+
+static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       ret = gb_gpio_direction_in_operation(gb_gpio_controller, (u8)offset);
+       if (ret)
+               ;       /* return ret; */
+       return 0;
+}
+
+static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       ret = gb_gpio_direction_out_operation(gb_gpio_controller, (u8)offset, !!value);
+       if (ret)
+               ;       /* return ret; */
+       return 0;
+}
+
+static int gb_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       u8 which;
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       which = (u8)offset;
+       ret = gb_gpio_get_value_operation(gb_gpio_controller, which);
+       if (ret)
+               return ret;
+       return (int)gb_gpio_controller->lines[which].value;
+}
+
+static void gb_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       int ret;
+
+       if (offset < 0 || offset >= chip->ngpio) {
+               pr_err("bad offset %u supplied (must be 0..%u)\n",
+                       offset, chip->ngpio - 1);
+               return;
+       }
+       ret = gb_gpio_set_value_operation(gb_gpio_controller, (u8)offset, !!value);
+       if (ret)
+               ;       /* return ret; */
+}
+
+static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+                                       unsigned debounce)
+{
+       struct gb_gpio_controller *gb_gpio_controller = gpio_chip_to_gb_gpio_controller(chip);
+       u16 usec;
+       int ret;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+       if (debounce > (unsigned int)U16_MAX)
+               return -EINVAL;
+       usec = (u8)debounce;
+       ret = gb_gpio_set_debounce_operation(gb_gpio_controller, (u8)offset, usec);
+       if (ret)
+               ;       /* return ret; */
+
+       return 0;       /* XXX */
+}
+
+static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+
+       return 0;       /* XXX */
+}
+
+static void gb_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       return; /* XXX */
+}
+
+static int gb_gpio_controller_setup(struct gb_gpio_controller *gb_gpio_controller)
+{
+       u32 line_count;
+       size_t size;
+       int ret;
+
+       /* First thing we need to do is check the version */
+       ret = gb_gpio_proto_version_operation(gb_gpio_controller);
+       if (ret)
+               ;       /* return ret; */
+
+       /* Now find out how many lines there are */
+       ret = gb_gpio_line_count_operation(gb_gpio_controller);
+       if (ret)
+               ;       /* return ret; */
+       line_count = (u32)gb_gpio_controller->line_max + 1;
+       size = line_count * sizeof(*gb_gpio_controller->lines);
+       gb_gpio_controller->lines = kzalloc(size, GFP_KERNEL);
+       if (!gb_gpio_controller->lines)
+               return -ENOMEM;
+
+       return ret;
+}
+
+static int gb_gpio_connection_init(struct gb_connection *connection)
+{
+       struct gb_gpio_controller *gb_gpio_controller;
+       struct gpio_chip *gpio;
+       int ret;
+
+       gb_gpio_controller = kzalloc(sizeof(*gb_gpio_controller), GFP_KERNEL);
+       if (!gb_gpio_controller)
+               return -ENOMEM;
+       gb_gpio_controller->connection = connection;
+       connection->private = gb_gpio_controller;
+
+       ret = gb_gpio_controller_setup(gb_gpio_controller);
+       if (ret)
+               goto out_err;
+
+       gpio = &gb_gpio_controller->chip;
+
+       gpio->label = "greybus_gpio";
+       gpio->owner = THIS_MODULE;      /* XXX Module get? */
+
+       gpio->request = gb_gpio_request;
+       gpio->free = gb_gpio_free;
+       gpio->get_direction = gb_gpio_get_direction;
+       gpio->direction_input = gb_gpio_direction_input;
+       gpio->direction_output = gb_gpio_direction_output;
+       gpio->get = gb_gpio_get;
+       gpio->set = gb_gpio_set;
+       gpio->set_debounce = gb_gpio_set_debounce;
+       gpio->to_irq = gb_gpio_to_irq;
+       gpio->dbg_show = gb_gpio_dbg_show;
+
+       gpio->base = -1;                /* Allocate base dynamically */
+       gpio->ngpio = gb_gpio_controller->line_max + 1;
+       gpio->can_sleep = true;         /* XXX */
+
+       ret = gpiochip_add(gpio);
+       if (ret) {
+               pr_err("Failed to register GPIO\n");
+               return ret;
+       }
+
+       return 0;
+out_err:
+       kfree(gb_gpio_controller);
+       return ret;
+}
+
+static void gb_gpio_connection_exit(struct gb_connection *connection)
+{
+       struct gb_gpio_controller *gb_gpio_controller = connection->private;
+
+       if (!gb_gpio_controller)
+               return;
+
+       gb_gpiochip_remove(&gb_gpio_controller->chip);
+       /* kref_put(gb_gpio_controller->connection) */
+       kfree(gb_gpio_controller);
+}
+
+static struct gb_protocol gpio_protocol = {
+       .name                   = "gpio",
+       .id                     = GREYBUS_PROTOCOL_GPIO,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_gpio_connection_init,
+       .connection_exit        = gb_gpio_connection_exit,
+       .request_recv           = NULL, /* no incoming requests */
+};
+
+int gb_gpio_protocol_init(void)
+{
+       return gb_protocol_register(&gpio_protocol);
+}
+
+void gb_gpio_protocol_exit(void)
+{
+       gb_protocol_deregister(&gpio_protocol);
+}
diff --git a/drivers/staging/greybus/i2c-gb.c b/drivers/staging/greybus/i2c-gb.c
deleted file mode 100644 (file)
index c967ae3..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * I2C bridge driver for the Greybus "generic" I2C module.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-
-#include "greybus.h"
-
-struct gb_i2c_device {
-       struct gb_connection    *connection;
-       u8                      version_major;
-       u8                      version_minor;
-
-       u32                     functionality;
-       u16                     timeout_msec;
-       u8                      retries;
-
-       struct i2c_adapter      adapter;
-};
-
-/* Version of the Greybus i2c protocol we support */
-#define        GB_I2C_VERSION_MAJOR            0x00
-#define        GB_I2C_VERSION_MINOR            0x01
-
-/* Greybus i2c request types */
-#define        GB_I2C_TYPE_INVALID             0x00
-#define        GB_I2C_TYPE_PROTOCOL_VERSION    0x01
-#define        GB_I2C_TYPE_FUNCTIONALITY       0x02
-#define        GB_I2C_TYPE_TIMEOUT             0x03
-#define        GB_I2C_TYPE_RETRIES             0x04
-#define        GB_I2C_TYPE_TRANSFER            0x05
-#define        GB_I2C_TYPE_RESPONSE            0x80    /* OR'd with rest */
-
-#define        GB_I2C_RETRIES_DEFAULT          3
-#define        GB_I2C_TIMEOUT_DEFAULT          1000    /* milliseconds */
-
-/* version request has no payload */
-struct gb_i2c_proto_version_response {
-       __u8    major;
-       __u8    minor;
-};
-
-/* functionality request has no payload */
-struct gb_i2c_functionality_response {
-       __le32  functionality;
-};
-
-struct gb_i2c_timeout_request {
-       __le16  msec;
-};
-/* timeout response has no payload */
-
-struct gb_i2c_retries_request {
-       __u8    retries;
-};
-/* retries response has no payload */
-
-/*
- * Outgoing data immediately follows the op count and ops array.
- * The data for each write (master -> slave) op in the array is sent
- * in order, with no (e.g. pad) bytes separating them.
- *
- * Short reads cause the entire transfer request to fail So response
- * payload consists only of bytes read, and the number of bytes is
- * exactly what was specified in the corresponding op.  Like
- * outgoing data, the incoming data is in order and contiguous.
- */
-struct gb_i2c_transfer_op {
-       __le16  addr;
-       __le16  flags;
-       __le16  size;
-};
-
-struct gb_i2c_transfer_request {
-       __le16                          op_count;
-       struct gb_i2c_transfer_op       ops[0];         /* op_count of these */
-};
-struct gb_i2c_transfer_response {
-       __u8                            data[0];        /* inbound data */
-};
-
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_i2c_proto_version_operation(struct gb_i2c_device *gb_i2c_dev)
-{
-       struct gb_i2c_proto_version_response response;
-       int ret;
-
-       ret = gb_operation_sync(gb_i2c_dev->connection,
-                               GB_I2C_TYPE_PROTOCOL_VERSION,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       if (response.major > GB_I2C_VERSION_MAJOR) {
-               pr_err("unsupported major version (%hhu > %hhu)\n",
-                       response.major, GB_I2C_VERSION_MAJOR);
-               return -ENOTSUPP;
-       }
-       gb_i2c_dev->version_major = response.major;
-       gb_i2c_dev->version_minor = response.minor;
-       return 0;
-}
-
-/*
- * Map Greybus i2c functionality bits into Linux ones
- */
-static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)
-{
-       return gb_i2c_functionality;    /* All bits the same for now */
-}
-
-static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
-{
-       struct gb_i2c_functionality_response response;
-       u32 functionality;
-       int ret;
-
-       ret = gb_operation_sync(gb_i2c_dev->connection,
-                               GB_I2C_TYPE_FUNCTIONALITY,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       functionality = le32_to_cpu(response.functionality);
-       gb_i2c_dev->functionality = gb_i2c_functionality_map(functionality);
-
-       return 0;
-}
-
-static int gb_i2c_timeout_operation(struct gb_i2c_device *gb_i2c_dev, u16 msec)
-{
-       struct gb_i2c_timeout_request request;
-       int ret;
-
-       request.msec = cpu_to_le16(msec);
-       ret = gb_operation_sync(gb_i2c_dev->connection, GB_I2C_TYPE_TIMEOUT,
-                               &request, sizeof(request), NULL, 0);
-       if (ret)
-               pr_err("timeout operation failed (%d)\n", ret);
-       else
-               gb_i2c_dev->timeout_msec = msec;
-
-       return ret;
-}
-
-static int gb_i2c_retries_operation(struct gb_i2c_device *gb_i2c_dev,
-                               u8 retries)
-{
-       struct gb_i2c_retries_request request;
-       int ret;
-
-       request.retries = retries;
-       ret = gb_operation_sync(gb_i2c_dev->connection, GB_I2C_TYPE_RETRIES,
-                               &request, sizeof(request), NULL, 0);
-       if (ret)
-               pr_err("retries operation failed (%d)\n", ret);
-       else
-               gb_i2c_dev->retries = retries;
-
-       return ret;
-}
-
-
-/*
- * Map Linux i2c_msg flags into Greybus i2c transfer op flags.
- */
-static u16 gb_i2c_transfer_op_flags_map(u16 flags)
-{
-       return flags;   /* All flags the same for now */
-}
-
-static void
-gb_i2c_fill_transfer_op(struct gb_i2c_transfer_op *op, struct i2c_msg *msg)
-{
-       u16 flags = gb_i2c_transfer_op_flags_map(msg->flags);
-
-       op->addr = cpu_to_le16(msg->addr);
-       op->flags = cpu_to_le16(flags);
-       op->size = cpu_to_le16(msg->len);
-}
-
-static struct gb_operation *
-gb_i2c_transfer_request(struct gb_connection *connection,
-                               struct i2c_msg *msgs, u32 msg_count)
-{
-       struct gb_i2c_transfer_request *request;
-       struct gb_operation *operation;
-       struct gb_i2c_transfer_op *op;
-       struct i2c_msg *msg;
-       u32 data_out_size = 0;
-       u32 data_in_size = 0;
-       size_t request_size;
-       void *data;
-       u16 op_count;
-       u32 i;
-
-       if (msg_count > (u32)U16_MAX) {
-               gb_connection_err(connection, "msg_count (%u) too big",
-                                       msg_count);
-               return NULL;
-       }
-       op_count = (u16)msg_count;
-
-       /*
-        * In addition to space for all message descriptors we need
-        * to have enough to hold all outbound message data.
-        */
-       msg = msgs;
-       for (i = 0; i < msg_count; i++, msg++)
-               if (msg->flags & I2C_M_RD)
-                       data_in_size += (u32)msg->len;
-               else
-                       data_out_size += (u32)msg->len;
-
-       request_size = sizeof(*request);
-       request_size += msg_count * sizeof(*op);
-       request_size += data_out_size;
-
-       /* Response consists only of incoming data */
-       operation = gb_operation_create(connection, GB_I2C_TYPE_TRANSFER,
-                               request_size, data_in_size);
-       if (!operation)
-               return NULL;
-
-       request = operation->request->payload;
-       request->op_count = cpu_to_le16(op_count);
-       /* Fill in the ops array */
-       op = &request->ops[0];
-       msg = msgs;
-       for (i = 0; i < msg_count; i++)
-               gb_i2c_fill_transfer_op(op++, msg++);
-
-       if (!data_out_size)
-               return operation;
-
-       /* Copy over the outgoing data; it starts after the last op */
-       data = op;
-       msg = msgs;
-       for (i = 0; i < msg_count; i++) {
-               if (!(msg->flags & I2C_M_RD)) {
-                       memcpy(data, msg->buf, msg->len);
-                       data += msg->len;
-               }
-               msg++;
-       }
-
-       return operation;
-}
-
-static void gb_i2c_transfer_response(struct i2c_msg *msgs, u32 msg_count,
-                               struct gb_i2c_transfer_response *response)
-{
-       struct i2c_msg *msg = msgs;
-       u8 *data;
-       u32 i;
-
-       if (!response)
-               return;
-       data = response->data;
-       for (i = 0; i < msg_count; i++) {
-               if (msg->flags & I2C_M_RD) {
-                       memcpy(msg->buf, data, msg->len);
-                       data += msg->len;
-               }
-               msg++;
-       }
-}
-
-/*
- * Some i2c transfer operations return results that are expected.
- */
-static bool gb_i2c_expected_transfer_error(int errno)
-{
-       return errno == -EAGAIN || errno == -ENODEV;
-}
-
-static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,
-                                       struct i2c_msg *msgs, u32 msg_count)
-{
-       struct gb_connection *connection = gb_i2c_dev->connection;
-       struct gb_operation *operation;
-       int ret;
-
-       operation = gb_i2c_transfer_request(connection, msgs, msg_count);
-       if (!operation)
-               return -ENOMEM;
-
-       ret = gb_operation_request_send_sync(operation);
-       if (!ret) {
-               struct gb_i2c_transfer_response *response;
-
-               response = operation->response->payload;
-               gb_i2c_transfer_response(msgs, msg_count, response);
-               ret = msg_count;
-       } else if (!gb_i2c_expected_transfer_error(ret)) {
-               pr_err("transfer operation failed (%d)\n", ret);
-       }
-       gb_operation_destroy(operation);
-
-       return ret;
-}
-
-static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
-               int msg_count)
-{
-       struct gb_i2c_device *gb_i2c_dev;
-
-       gb_i2c_dev = i2c_get_adapdata(adap);
-
-       return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);
-}
-
-#if 0
-/* Later */
-static int gb_i2c_smbus_xfer(struct i2c_adapter *adap,
-                       u16 addr, unsigned short flags, char read_write,
-                       u8 command, int size, union i2c_smbus_data *data)
-{
-       struct gb_i2c_device *gb_i2c_dev;
-
-       gb_i2c_dev = i2c_get_adapdata(adap);
-
-       return 0;
-}
-#endif
-
-static u32 gb_i2c_functionality(struct i2c_adapter *adap)
-{
-       struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);
-
-       return gb_i2c_dev->functionality;
-}
-
-static const struct i2c_algorithm gb_i2c_algorithm = {
-       .master_xfer    = gb_i2c_master_xfer,
-       /* .smbus_xfer  = gb_i2c_smbus_xfer, */
-       .functionality  = gb_i2c_functionality,
-};
-
-/*
- * Do initial setup of the i2c device.  This includes verifying we
- * can support it (based on the protocol version it advertises).
- * If that's OK, we get and cached its functionality bits, and
- * set up the retry count and timeout.
- *
- * Note: gb_i2c_dev->connection is assumed to have been valid.
- */
-static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
-{
-       int ret;
-
-       /* First thing we need to do is check the version */
-       ret = gb_i2c_proto_version_operation(gb_i2c_dev);
-       if (ret)
-               return ret;
-
-       /* Assume the functionality never changes, just get it once */
-       ret = gb_i2c_functionality_operation(gb_i2c_dev);
-       if (ret)
-               return ret;
-
-       /* Set up our default retry count and timeout */
-       ret = gb_i2c_retries_operation(gb_i2c_dev, GB_I2C_RETRIES_DEFAULT);
-       if (ret)
-               return ret;
-
-       return gb_i2c_timeout_operation(gb_i2c_dev, GB_I2C_TIMEOUT_DEFAULT);
-}
-
-static int gb_i2c_connection_init(struct gb_connection *connection)
-{
-       struct gb_i2c_device *gb_i2c_dev;
-       struct i2c_adapter *adapter;
-       int ret;
-
-       gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL);
-       if (!gb_i2c_dev)
-               return -ENOMEM;
-
-       gb_i2c_dev->connection = connection;    /* refcount? */
-       connection->private = gb_i2c_dev;
-
-       ret = gb_i2c_device_setup(gb_i2c_dev);
-       if (ret)
-               goto out_err;
-
-       /* Looks good; up our i2c adapter */
-       adapter = &gb_i2c_dev->adapter;
-       adapter->owner = THIS_MODULE;
-       adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-       adapter->algo = &gb_i2c_algorithm;
-       /* adapter->algo_data = what? */
-       adapter->timeout = gb_i2c_dev->timeout_msec * HZ / 1000;
-       adapter->retries = gb_i2c_dev->retries;
-
-       adapter->dev.parent = &connection->dev;
-       snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");
-       i2c_set_adapdata(adapter, gb_i2c_dev);
-
-       ret = i2c_add_adapter(adapter);
-       if (ret)
-               goto out_err;
-
-       return 0;
-out_err:
-       /* kref_put(gb_i2c_dev->connection) */
-       kfree(gb_i2c_dev);
-
-       return ret;
-}
-
-static void gb_i2c_connection_exit(struct gb_connection *connection)
-{
-       struct gb_i2c_device *gb_i2c_dev = connection->private;
-
-       i2c_del_adapter(&gb_i2c_dev->adapter);
-       /* kref_put(gb_i2c_dev->connection) */
-       kfree(gb_i2c_dev);
-}
-
-static struct gb_protocol i2c_protocol = {
-       .name                   = "i2c",
-       .id                     = GREYBUS_PROTOCOL_I2C,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_i2c_connection_init,
-       .connection_exit        = gb_i2c_connection_exit,
-       .request_recv           = NULL, /* no incoming requests */
-};
-
-int gb_i2c_protocol_init(void)
-{
-       return gb_protocol_register(&i2c_protocol);
-}
-
-void gb_i2c_protocol_exit(void)
-{
-       gb_protocol_deregister(&i2c_protocol);
-}
diff --git a/drivers/staging/greybus/i2c.c b/drivers/staging/greybus/i2c.c
new file mode 100644 (file)
index 0000000..c967ae3
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * I2C bridge driver for the Greybus "generic" I2C module.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "greybus.h"
+
+struct gb_i2c_device {
+       struct gb_connection    *connection;
+       u8                      version_major;
+       u8                      version_minor;
+
+       u32                     functionality;
+       u16                     timeout_msec;
+       u8                      retries;
+
+       struct i2c_adapter      adapter;
+};
+
+/* Version of the Greybus i2c protocol we support */
+#define        GB_I2C_VERSION_MAJOR            0x00
+#define        GB_I2C_VERSION_MINOR            0x01
+
+/* Greybus i2c request types */
+#define        GB_I2C_TYPE_INVALID             0x00
+#define        GB_I2C_TYPE_PROTOCOL_VERSION    0x01
+#define        GB_I2C_TYPE_FUNCTIONALITY       0x02
+#define        GB_I2C_TYPE_TIMEOUT             0x03
+#define        GB_I2C_TYPE_RETRIES             0x04
+#define        GB_I2C_TYPE_TRANSFER            0x05
+#define        GB_I2C_TYPE_RESPONSE            0x80    /* OR'd with rest */
+
+#define        GB_I2C_RETRIES_DEFAULT          3
+#define        GB_I2C_TIMEOUT_DEFAULT          1000    /* milliseconds */
+
+/* version request has no payload */
+struct gb_i2c_proto_version_response {
+       __u8    major;
+       __u8    minor;
+};
+
+/* functionality request has no payload */
+struct gb_i2c_functionality_response {
+       __le32  functionality;
+};
+
+struct gb_i2c_timeout_request {
+       __le16  msec;
+};
+/* timeout response has no payload */
+
+struct gb_i2c_retries_request {
+       __u8    retries;
+};
+/* retries response has no payload */
+
+/*
+ * Outgoing data immediately follows the op count and ops array.
+ * The data for each write (master -> slave) op in the array is sent
+ * in order, with no (e.g. pad) bytes separating them.
+ *
+ * Short reads cause the entire transfer request to fail So response
+ * payload consists only of bytes read, and the number of bytes is
+ * exactly what was specified in the corresponding op.  Like
+ * outgoing data, the incoming data is in order and contiguous.
+ */
+struct gb_i2c_transfer_op {
+       __le16  addr;
+       __le16  flags;
+       __le16  size;
+};
+
+struct gb_i2c_transfer_request {
+       __le16                          op_count;
+       struct gb_i2c_transfer_op       ops[0];         /* op_count of these */
+};
+struct gb_i2c_transfer_response {
+       __u8                            data[0];        /* inbound data */
+};
+
+/*
+ * This request only uses the connection field, and if successful,
+ * fills in the major and minor protocol version of the target.
+ */
+static int gb_i2c_proto_version_operation(struct gb_i2c_device *gb_i2c_dev)
+{
+       struct gb_i2c_proto_version_response response;
+       int ret;
+
+       ret = gb_operation_sync(gb_i2c_dev->connection,
+                               GB_I2C_TYPE_PROTOCOL_VERSION,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       if (response.major > GB_I2C_VERSION_MAJOR) {
+               pr_err("unsupported major version (%hhu > %hhu)\n",
+                       response.major, GB_I2C_VERSION_MAJOR);
+               return -ENOTSUPP;
+       }
+       gb_i2c_dev->version_major = response.major;
+       gb_i2c_dev->version_minor = response.minor;
+       return 0;
+}
+
+/*
+ * Map Greybus i2c functionality bits into Linux ones
+ */
+static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)
+{
+       return gb_i2c_functionality;    /* All bits the same for now */
+}
+
+static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
+{
+       struct gb_i2c_functionality_response response;
+       u32 functionality;
+       int ret;
+
+       ret = gb_operation_sync(gb_i2c_dev->connection,
+                               GB_I2C_TYPE_FUNCTIONALITY,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       functionality = le32_to_cpu(response.functionality);
+       gb_i2c_dev->functionality = gb_i2c_functionality_map(functionality);
+
+       return 0;
+}
+
+static int gb_i2c_timeout_operation(struct gb_i2c_device *gb_i2c_dev, u16 msec)
+{
+       struct gb_i2c_timeout_request request;
+       int ret;
+
+       request.msec = cpu_to_le16(msec);
+       ret = gb_operation_sync(gb_i2c_dev->connection, GB_I2C_TYPE_TIMEOUT,
+                               &request, sizeof(request), NULL, 0);
+       if (ret)
+               pr_err("timeout operation failed (%d)\n", ret);
+       else
+               gb_i2c_dev->timeout_msec = msec;
+
+       return ret;
+}
+
+static int gb_i2c_retries_operation(struct gb_i2c_device *gb_i2c_dev,
+                               u8 retries)
+{
+       struct gb_i2c_retries_request request;
+       int ret;
+
+       request.retries = retries;
+       ret = gb_operation_sync(gb_i2c_dev->connection, GB_I2C_TYPE_RETRIES,
+                               &request, sizeof(request), NULL, 0);
+       if (ret)
+               pr_err("retries operation failed (%d)\n", ret);
+       else
+               gb_i2c_dev->retries = retries;
+
+       return ret;
+}
+
+
+/*
+ * Map Linux i2c_msg flags into Greybus i2c transfer op flags.
+ */
+static u16 gb_i2c_transfer_op_flags_map(u16 flags)
+{
+       return flags;   /* All flags the same for now */
+}
+
+static void
+gb_i2c_fill_transfer_op(struct gb_i2c_transfer_op *op, struct i2c_msg *msg)
+{
+       u16 flags = gb_i2c_transfer_op_flags_map(msg->flags);
+
+       op->addr = cpu_to_le16(msg->addr);
+       op->flags = cpu_to_le16(flags);
+       op->size = cpu_to_le16(msg->len);
+}
+
+static struct gb_operation *
+gb_i2c_transfer_request(struct gb_connection *connection,
+                               struct i2c_msg *msgs, u32 msg_count)
+{
+       struct gb_i2c_transfer_request *request;
+       struct gb_operation *operation;
+       struct gb_i2c_transfer_op *op;
+       struct i2c_msg *msg;
+       u32 data_out_size = 0;
+       u32 data_in_size = 0;
+       size_t request_size;
+       void *data;
+       u16 op_count;
+       u32 i;
+
+       if (msg_count > (u32)U16_MAX) {
+               gb_connection_err(connection, "msg_count (%u) too big",
+                                       msg_count);
+               return NULL;
+       }
+       op_count = (u16)msg_count;
+
+       /*
+        * In addition to space for all message descriptors we need
+        * to have enough to hold all outbound message data.
+        */
+       msg = msgs;
+       for (i = 0; i < msg_count; i++, msg++)
+               if (msg->flags & I2C_M_RD)
+                       data_in_size += (u32)msg->len;
+               else
+                       data_out_size += (u32)msg->len;
+
+       request_size = sizeof(*request);
+       request_size += msg_count * sizeof(*op);
+       request_size += data_out_size;
+
+       /* Response consists only of incoming data */
+       operation = gb_operation_create(connection, GB_I2C_TYPE_TRANSFER,
+                               request_size, data_in_size);
+       if (!operation)
+               return NULL;
+
+       request = operation->request->payload;
+       request->op_count = cpu_to_le16(op_count);
+       /* Fill in the ops array */
+       op = &request->ops[0];
+       msg = msgs;
+       for (i = 0; i < msg_count; i++)
+               gb_i2c_fill_transfer_op(op++, msg++);
+
+       if (!data_out_size)
+               return operation;
+
+       /* Copy over the outgoing data; it starts after the last op */
+       data = op;
+       msg = msgs;
+       for (i = 0; i < msg_count; i++) {
+               if (!(msg->flags & I2C_M_RD)) {
+                       memcpy(data, msg->buf, msg->len);
+                       data += msg->len;
+               }
+               msg++;
+       }
+
+       return operation;
+}
+
+static void gb_i2c_transfer_response(struct i2c_msg *msgs, u32 msg_count,
+                               struct gb_i2c_transfer_response *response)
+{
+       struct i2c_msg *msg = msgs;
+       u8 *data;
+       u32 i;
+
+       if (!response)
+               return;
+       data = response->data;
+       for (i = 0; i < msg_count; i++) {
+               if (msg->flags & I2C_M_RD) {
+                       memcpy(msg->buf, data, msg->len);
+                       data += msg->len;
+               }
+               msg++;
+       }
+}
+
+/*
+ * Some i2c transfer operations return results that are expected.
+ */
+static bool gb_i2c_expected_transfer_error(int errno)
+{
+       return errno == -EAGAIN || errno == -ENODEV;
+}
+
+static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,
+                                       struct i2c_msg *msgs, u32 msg_count)
+{
+       struct gb_connection *connection = gb_i2c_dev->connection;
+       struct gb_operation *operation;
+       int ret;
+
+       operation = gb_i2c_transfer_request(connection, msgs, msg_count);
+       if (!operation)
+               return -ENOMEM;
+
+       ret = gb_operation_request_send_sync(operation);
+       if (!ret) {
+               struct gb_i2c_transfer_response *response;
+
+               response = operation->response->payload;
+               gb_i2c_transfer_response(msgs, msg_count, response);
+               ret = msg_count;
+       } else if (!gb_i2c_expected_transfer_error(ret)) {
+               pr_err("transfer operation failed (%d)\n", ret);
+       }
+       gb_operation_destroy(operation);
+
+       return ret;
+}
+
+static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+               int msg_count)
+{
+       struct gb_i2c_device *gb_i2c_dev;
+
+       gb_i2c_dev = i2c_get_adapdata(adap);
+
+       return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);
+}
+
+#if 0
+/* Later */
+static int gb_i2c_smbus_xfer(struct i2c_adapter *adap,
+                       u16 addr, unsigned short flags, char read_write,
+                       u8 command, int size, union i2c_smbus_data *data)
+{
+       struct gb_i2c_device *gb_i2c_dev;
+
+       gb_i2c_dev = i2c_get_adapdata(adap);
+
+       return 0;
+}
+#endif
+
+static u32 gb_i2c_functionality(struct i2c_adapter *adap)
+{
+       struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);
+
+       return gb_i2c_dev->functionality;
+}
+
+static const struct i2c_algorithm gb_i2c_algorithm = {
+       .master_xfer    = gb_i2c_master_xfer,
+       /* .smbus_xfer  = gb_i2c_smbus_xfer, */
+       .functionality  = gb_i2c_functionality,
+};
+
+/*
+ * Do initial setup of the i2c device.  This includes verifying we
+ * can support it (based on the protocol version it advertises).
+ * If that's OK, we get and cached its functionality bits, and
+ * set up the retry count and timeout.
+ *
+ * Note: gb_i2c_dev->connection is assumed to have been valid.
+ */
+static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
+{
+       int ret;
+
+       /* First thing we need to do is check the version */
+       ret = gb_i2c_proto_version_operation(gb_i2c_dev);
+       if (ret)
+               return ret;
+
+       /* Assume the functionality never changes, just get it once */
+       ret = gb_i2c_functionality_operation(gb_i2c_dev);
+       if (ret)
+               return ret;
+
+       /* Set up our default retry count and timeout */
+       ret = gb_i2c_retries_operation(gb_i2c_dev, GB_I2C_RETRIES_DEFAULT);
+       if (ret)
+               return ret;
+
+       return gb_i2c_timeout_operation(gb_i2c_dev, GB_I2C_TIMEOUT_DEFAULT);
+}
+
+static int gb_i2c_connection_init(struct gb_connection *connection)
+{
+       struct gb_i2c_device *gb_i2c_dev;
+       struct i2c_adapter *adapter;
+       int ret;
+
+       gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL);
+       if (!gb_i2c_dev)
+               return -ENOMEM;
+
+       gb_i2c_dev->connection = connection;    /* refcount? */
+       connection->private = gb_i2c_dev;
+
+       ret = gb_i2c_device_setup(gb_i2c_dev);
+       if (ret)
+               goto out_err;
+
+       /* Looks good; up our i2c adapter */
+       adapter = &gb_i2c_dev->adapter;
+       adapter->owner = THIS_MODULE;
+       adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       adapter->algo = &gb_i2c_algorithm;
+       /* adapter->algo_data = what? */
+       adapter->timeout = gb_i2c_dev->timeout_msec * HZ / 1000;
+       adapter->retries = gb_i2c_dev->retries;
+
+       adapter->dev.parent = &connection->dev;
+       snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");
+       i2c_set_adapdata(adapter, gb_i2c_dev);
+
+       ret = i2c_add_adapter(adapter);
+       if (ret)
+               goto out_err;
+
+       return 0;
+out_err:
+       /* kref_put(gb_i2c_dev->connection) */
+       kfree(gb_i2c_dev);
+
+       return ret;
+}
+
+static void gb_i2c_connection_exit(struct gb_connection *connection)
+{
+       struct gb_i2c_device *gb_i2c_dev = connection->private;
+
+       i2c_del_adapter(&gb_i2c_dev->adapter);
+       /* kref_put(gb_i2c_dev->connection) */
+       kfree(gb_i2c_dev);
+}
+
+static struct gb_protocol i2c_protocol = {
+       .name                   = "i2c",
+       .id                     = GREYBUS_PROTOCOL_I2C,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_i2c_connection_init,
+       .connection_exit        = gb_i2c_connection_exit,
+       .request_recv           = NULL, /* no incoming requests */
+};
+
+int gb_i2c_protocol_init(void)
+{
+       return gb_protocol_register(&i2c_protocol);
+}
+
+void gb_i2c_protocol_exit(void)
+{
+       gb_protocol_deregister(&i2c_protocol);
+}
diff --git a/drivers/staging/greybus/pwm-gb.c b/drivers/staging/greybus/pwm-gb.c
deleted file mode 100644 (file)
index 91f7b87..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * PWM Greybus driver.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pwm.h>
-#include "greybus.h"
-
-struct gb_pwm_chip {
-       struct gb_connection    *connection;
-       u8                      version_major;
-       u8                      version_minor;
-       u8                      pwm_max;        /* max pwm number */
-
-       struct pwm_chip         chip;
-       struct pwm_chip         *pwm;
-};
-#define pwm_chip_to_gb_pwm_chip(chip) \
-       container_of(chip, struct gb_pwm_chip, chip)
-
-/* Version of the Greybus PWM protocol we support */
-#define        GB_PWM_VERSION_MAJOR            0x00
-#define        GB_PWM_VERSION_MINOR            0x01
-
-/* Greybus PWM request types */
-#define        GB_PWM_TYPE_INVALID             0x00
-#define        GB_PWM_TYPE_PROTOCOL_VERSION    0x01
-#define        GB_PWM_TYPE_PWM_COUNT           0x02
-#define        GB_PWM_TYPE_ACTIVATE            0x03
-#define        GB_PWM_TYPE_DEACTIVATE          0x04
-#define        GB_PWM_TYPE_CONFIG              0x05
-#define        GB_PWM_TYPE_POLARITY            0x06
-#define        GB_PWM_TYPE_ENABLE              0x07
-#define        GB_PWM_TYPE_DISABLE             0x08
-#define        GB_PWM_TYPE_RESPONSE            0x80    /* OR'd with rest */
-
-/* version request has no payload */
-struct gb_pwm_proto_version_response {
-       __u8    major;
-       __u8    minor;
-};
-
-/* pwm count request has no payload */
-struct gb_pwm_count_response {
-       __u8    count;
-};
-
-struct gb_pwm_activate_request {
-       __u8    which;
-};
-
-struct gb_pwm_deactivate_request {
-       __u8    which;
-};
-
-struct gb_pwm_config_request {
-       __u8    which;
-       __le32  duty;
-       __le32  period;
-};
-
-struct gb_pwm_polarity_request {
-       __u8    which;
-       __u8    polarity;
-};
-
-struct gb_pwm_enable_request {
-       __u8    which;
-};
-
-struct gb_pwm_disable_request {
-       __u8    which;
-};
-
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_pwm_proto_version_operation(struct gb_pwm_chip *pwmc)
-{
-       struct gb_pwm_proto_version_response response;
-       int ret;
-
-       ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PROTOCOL_VERSION,
-                               NULL, 0, &response, sizeof(response));
-
-       if (ret)
-               return ret;
-
-       if (response.major > GB_PWM_VERSION_MAJOR) {
-               pr_err("unsupported major version (%hhu > %hhu)\n",
-                       response.major, GB_PWM_VERSION_MAJOR);
-               return -ENOTSUPP;
-       }
-       pwmc->version_major = response.major;
-       pwmc->version_minor = response.minor;
-       return 0;
-}
-
-static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
-{
-       struct gb_pwm_count_response response;
-       int ret;
-
-       ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-       pwmc->pwm_max = response.count;
-       return 0;
-}
-
-static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
-                                    u8 which)
-{
-       struct gb_pwm_activate_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
-                                      u8 which)
-{
-       struct gb_pwm_deactivate_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
-                                  u8 which, u32 duty, u32 period)
-{
-       struct gb_pwm_config_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       request.duty = cpu_to_le32(duty);
-       request.period = cpu_to_le32(period);
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,
-                                &request, sizeof(request), NULL, 0);
-}
-
-
-static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
-                                        u8 which, u8 polarity)
-{
-       struct gb_pwm_polarity_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       request.polarity = polarity;
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
-                                  u8 which)
-{
-       struct gb_pwm_enable_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
-                                   u8 which)
-{
-       struct gb_pwm_disable_request request;
-
-       if (which > pwmc->pwm_max)
-               return -EINVAL;
-
-       request.which = which;
-       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
-};
-
-static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       if (test_bit(PWMF_ENABLED, &pwm->flags))
-               dev_warn(chip->dev, "freeing PWM device without disabling\n");
-
-       gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
-}
-
-static int gb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                        int duty_ns, int period_ns)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       return gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_ns, period_ns);
-};
-
-static int gb_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
-                              enum pwm_polarity polarity)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       return gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, polarity);
-};
-
-static int gb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
-};
-
-static void gb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
-
-       gb_pwm_disable_operation(pwmc, pwm->hwpwm);
-};
-
-static const struct pwm_ops gb_pwm_ops = {
-       .request = gb_pwm_request,
-       .free = gb_pwm_free,
-       .config = gb_pwm_config,
-       .set_polarity = gb_pwm_set_polarity,
-       .enable = gb_pwm_enable,
-       .disable = gb_pwm_disable,
-       .owner = THIS_MODULE,
-};
-
-static int gb_pwm_connection_init(struct gb_connection *connection)
-{
-       struct gb_pwm_chip *pwmc;
-       struct pwm_chip *pwm;
-       int ret;
-
-       pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
-       if (!pwmc)
-               return -ENOMEM;
-       pwmc->connection = connection;
-       connection->private = pwmc;
-
-       /* Check for compatible protocol version */
-       ret = gb_pwm_proto_version_operation(pwmc);
-       if (ret)
-               goto out_err;
-
-       /* Query number of pwms present */
-       ret = gb_pwm_count_operation(pwmc);
-       if (ret)
-               goto out_err;
-
-       pwm = &pwmc->chip;
-
-       pwm->dev = &connection->dev;
-       pwm->ops = &gb_pwm_ops;
-       pwm->base = -1;                 /* Allocate base dynamically */
-       pwm->npwm = pwmc->pwm_max + 1;
-       pwm->can_sleep = true;          /* FIXME */
-
-       ret = pwmchip_add(pwm);
-       if (ret) {
-               pr_err("Failed to register PWM\n");
-               return ret;
-       }
-
-       return 0;
-out_err:
-       kfree(pwmc);
-       return ret;
-}
-
-static void gb_pwm_connection_exit(struct gb_connection *connection)
-{
-       struct gb_pwm_chip *pwmc = connection->private;
-
-       if (!pwmc)
-               return;
-
-       pwmchip_remove(&pwmc->chip);
-       /* kref_put(pwmc->connection) */
-       kfree(pwmc);
-}
-
-static struct gb_protocol pwm_protocol = {
-       .name                   = "pwm",
-       .id                     = GREYBUS_PROTOCOL_PWM,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_pwm_connection_init,
-       .connection_exit        = gb_pwm_connection_exit,
-       .request_recv           = NULL, /* no incoming requests */
-};
-
-int gb_pwm_protocol_init(void)
-{
-       return gb_protocol_register(&pwm_protocol);
-}
-
-void gb_pwm_protocol_exit(void)
-{
-       gb_protocol_deregister(&pwm_protocol);
-}
diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c
new file mode 100644 (file)
index 0000000..91f7b87
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * PWM Greybus driver.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include "greybus.h"
+
+struct gb_pwm_chip {
+       struct gb_connection    *connection;
+       u8                      version_major;
+       u8                      version_minor;
+       u8                      pwm_max;        /* max pwm number */
+
+       struct pwm_chip         chip;
+       struct pwm_chip         *pwm;
+};
+#define pwm_chip_to_gb_pwm_chip(chip) \
+       container_of(chip, struct gb_pwm_chip, chip)
+
+/* Version of the Greybus PWM protocol we support */
+#define        GB_PWM_VERSION_MAJOR            0x00
+#define        GB_PWM_VERSION_MINOR            0x01
+
+/* Greybus PWM request types */
+#define        GB_PWM_TYPE_INVALID             0x00
+#define        GB_PWM_TYPE_PROTOCOL_VERSION    0x01
+#define        GB_PWM_TYPE_PWM_COUNT           0x02
+#define        GB_PWM_TYPE_ACTIVATE            0x03
+#define        GB_PWM_TYPE_DEACTIVATE          0x04
+#define        GB_PWM_TYPE_CONFIG              0x05
+#define        GB_PWM_TYPE_POLARITY            0x06
+#define        GB_PWM_TYPE_ENABLE              0x07
+#define        GB_PWM_TYPE_DISABLE             0x08
+#define        GB_PWM_TYPE_RESPONSE            0x80    /* OR'd with rest */
+
+/* version request has no payload */
+struct gb_pwm_proto_version_response {
+       __u8    major;
+       __u8    minor;
+};
+
+/* pwm count request has no payload */
+struct gb_pwm_count_response {
+       __u8    count;
+};
+
+struct gb_pwm_activate_request {
+       __u8    which;
+};
+
+struct gb_pwm_deactivate_request {
+       __u8    which;
+};
+
+struct gb_pwm_config_request {
+       __u8    which;
+       __le32  duty;
+       __le32  period;
+};
+
+struct gb_pwm_polarity_request {
+       __u8    which;
+       __u8    polarity;
+};
+
+struct gb_pwm_enable_request {
+       __u8    which;
+};
+
+struct gb_pwm_disable_request {
+       __u8    which;
+};
+
+/*
+ * This request only uses the connection field, and if successful,
+ * fills in the major and minor protocol version of the target.
+ */
+static int gb_pwm_proto_version_operation(struct gb_pwm_chip *pwmc)
+{
+       struct gb_pwm_proto_version_response response;
+       int ret;
+
+       ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PROTOCOL_VERSION,
+                               NULL, 0, &response, sizeof(response));
+
+       if (ret)
+               return ret;
+
+       if (response.major > GB_PWM_VERSION_MAJOR) {
+               pr_err("unsupported major version (%hhu > %hhu)\n",
+                       response.major, GB_PWM_VERSION_MAJOR);
+               return -ENOTSUPP;
+       }
+       pwmc->version_major = response.major;
+       pwmc->version_minor = response.minor;
+       return 0;
+}
+
+static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
+{
+       struct gb_pwm_count_response response;
+       int ret;
+
+       ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+       pwmc->pwm_max = response.count;
+       return 0;
+}
+
+static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
+                                    u8 which)
+{
+       struct gb_pwm_activate_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
+                                      u8 which)
+{
+       struct gb_pwm_deactivate_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
+                                  u8 which, u32 duty, u32 period)
+{
+       struct gb_pwm_config_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       request.duty = cpu_to_le32(duty);
+       request.period = cpu_to_le32(period);
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,
+                                &request, sizeof(request), NULL, 0);
+}
+
+
+static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
+                                        u8 which, u8 polarity)
+{
+       struct gb_pwm_polarity_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       request.polarity = polarity;
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
+                                  u8 which)
+{
+       struct gb_pwm_enable_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
+                                   u8 which)
+{
+       struct gb_pwm_disable_request request;
+
+       if (which > pwmc->pwm_max)
+               return -EINVAL;
+
+       request.which = which;
+       return gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       return gb_pwm_activate_operation(pwmc, pwm->hwpwm);
+};
+
+static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               dev_warn(chip->dev, "freeing PWM device without disabling\n");
+
+       gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
+}
+
+static int gb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                        int duty_ns, int period_ns)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       return gb_pwm_config_operation(pwmc, pwm->hwpwm, duty_ns, period_ns);
+};
+
+static int gb_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+                              enum pwm_polarity polarity)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       return gb_pwm_set_polarity_operation(pwmc, pwm->hwpwm, polarity);
+};
+
+static int gb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       return gb_pwm_enable_operation(pwmc, pwm->hwpwm);
+};
+
+static void gb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
+
+       gb_pwm_disable_operation(pwmc, pwm->hwpwm);
+};
+
+static const struct pwm_ops gb_pwm_ops = {
+       .request = gb_pwm_request,
+       .free = gb_pwm_free,
+       .config = gb_pwm_config,
+       .set_polarity = gb_pwm_set_polarity,
+       .enable = gb_pwm_enable,
+       .disable = gb_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int gb_pwm_connection_init(struct gb_connection *connection)
+{
+       struct gb_pwm_chip *pwmc;
+       struct pwm_chip *pwm;
+       int ret;
+
+       pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
+       if (!pwmc)
+               return -ENOMEM;
+       pwmc->connection = connection;
+       connection->private = pwmc;
+
+       /* Check for compatible protocol version */
+       ret = gb_pwm_proto_version_operation(pwmc);
+       if (ret)
+               goto out_err;
+
+       /* Query number of pwms present */
+       ret = gb_pwm_count_operation(pwmc);
+       if (ret)
+               goto out_err;
+
+       pwm = &pwmc->chip;
+
+       pwm->dev = &connection->dev;
+       pwm->ops = &gb_pwm_ops;
+       pwm->base = -1;                 /* Allocate base dynamically */
+       pwm->npwm = pwmc->pwm_max + 1;
+       pwm->can_sleep = true;          /* FIXME */
+
+       ret = pwmchip_add(pwm);
+       if (ret) {
+               pr_err("Failed to register PWM\n");
+               return ret;
+       }
+
+       return 0;
+out_err:
+       kfree(pwmc);
+       return ret;
+}
+
+static void gb_pwm_connection_exit(struct gb_connection *connection)
+{
+       struct gb_pwm_chip *pwmc = connection->private;
+
+       if (!pwmc)
+               return;
+
+       pwmchip_remove(&pwmc->chip);
+       /* kref_put(pwmc->connection) */
+       kfree(pwmc);
+}
+
+static struct gb_protocol pwm_protocol = {
+       .name                   = "pwm",
+       .id                     = GREYBUS_PROTOCOL_PWM,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_pwm_connection_init,
+       .connection_exit        = gb_pwm_connection_exit,
+       .request_recv           = NULL, /* no incoming requests */
+};
+
+int gb_pwm_protocol_init(void)
+{
+       return gb_protocol_register(&pwm_protocol);
+}
+
+void gb_pwm_protocol_exit(void)
+{
+       gb_protocol_deregister(&pwm_protocol);
+}
diff --git a/drivers/staging/greybus/sdio-gb.c b/drivers/staging/greybus/sdio-gb.c
deleted file mode 100644 (file)
index d324846..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SD/MMC Greybus driver.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-
-#include "greybus.h"
-
-struct gb_sdio_host {
-       struct gb_connection *connection;
-       struct mmc_host *mmc;
-       struct mmc_request *mrq;
-       // FIXME - some lock?
-};
-
-static void gb_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       // FIXME - do something here...
-}
-
-static void gb_sd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       // FIXME - do something here...
-}
-
-static int gb_sd_get_ro(struct mmc_host *mmc)
-{
-       // FIXME - do something here...
-       return 0;
-}
-
-static const struct mmc_host_ops gb_sd_ops = {
-       .request        = gb_sd_request,
-       .set_ios        = gb_sd_set_ios,
-       .get_ro         = gb_sd_get_ro,
-};
-
-static int gb_sdio_connection_init(struct gb_connection *connection)
-{
-       struct mmc_host *mmc;
-       struct gb_sdio_host *host;
-
-       mmc = mmc_alloc_host(sizeof(*host), &connection->dev);
-       if (!mmc)
-               return -ENOMEM;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-
-       mmc->ops = &gb_sd_ops;
-       // FIXME - set up size limits we can handle.
-       // FIXME - register the host controller.
-
-       host->connection = connection;
-       connection->private = host;
-       return 0;
-}
-
-static void gb_sdio_connection_exit(struct gb_connection *connection)
-{
-       struct mmc_host *mmc;
-       struct gb_sdio_host *host;
-
-       host = connection->private;
-       if (!host)
-               return;
-
-       mmc = host->mmc;
-       mmc_remove_host(mmc);
-       mmc_free_host(mmc);
-       connection->private = NULL;
-}
-
-static struct gb_protocol sdio_protocol = {
-       .name                   = "sdio",
-       .id                     = GREYBUS_PROTOCOL_SDIO,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_sdio_connection_init,
-       .connection_exit        = gb_sdio_connection_exit,
-       .request_recv           = NULL, /* no incoming requests */
-};
-
-int gb_sdio_protocol_init(void)
-{
-       return gb_protocol_register(&sdio_protocol);
-}
-
-void gb_sdio_protocol_exit(void)
-{
-       gb_protocol_deregister(&sdio_protocol);
-}
diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c
new file mode 100644 (file)
index 0000000..d324846
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SD/MMC Greybus driver.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+
+#include "greybus.h"
+
+struct gb_sdio_host {
+       struct gb_connection *connection;
+       struct mmc_host *mmc;
+       struct mmc_request *mrq;
+       // FIXME - some lock?
+};
+
+static void gb_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       // FIXME - do something here...
+}
+
+static void gb_sd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       // FIXME - do something here...
+}
+
+static int gb_sd_get_ro(struct mmc_host *mmc)
+{
+       // FIXME - do something here...
+       return 0;
+}
+
+static const struct mmc_host_ops gb_sd_ops = {
+       .request        = gb_sd_request,
+       .set_ios        = gb_sd_set_ios,
+       .get_ro         = gb_sd_get_ro,
+};
+
+static int gb_sdio_connection_init(struct gb_connection *connection)
+{
+       struct mmc_host *mmc;
+       struct gb_sdio_host *host;
+
+       mmc = mmc_alloc_host(sizeof(*host), &connection->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+
+       mmc->ops = &gb_sd_ops;
+       // FIXME - set up size limits we can handle.
+       // FIXME - register the host controller.
+
+       host->connection = connection;
+       connection->private = host;
+       return 0;
+}
+
+static void gb_sdio_connection_exit(struct gb_connection *connection)
+{
+       struct mmc_host *mmc;
+       struct gb_sdio_host *host;
+
+       host = connection->private;
+       if (!host)
+               return;
+
+       mmc = host->mmc;
+       mmc_remove_host(mmc);
+       mmc_free_host(mmc);
+       connection->private = NULL;
+}
+
+static struct gb_protocol sdio_protocol = {
+       .name                   = "sdio",
+       .id                     = GREYBUS_PROTOCOL_SDIO,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_sdio_connection_init,
+       .connection_exit        = gb_sdio_connection_exit,
+       .request_recv           = NULL, /* no incoming requests */
+};
+
+int gb_sdio_protocol_init(void)
+{
+       return gb_protocol_register(&sdio_protocol);
+}
+
+void gb_sdio_protocol_exit(void)
+{
+       gb_protocol_deregister(&sdio_protocol);
+}
diff --git a/drivers/staging/greybus/uart-gb.c b/drivers/staging/greybus/uart-gb.c
deleted file mode 100644 (file)
index 0320620..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * UART driver for the Greybus "generic" UART module.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- *
- * Heavily based on drivers/usb/class/cdc-acm.c and
- * drivers/usb/serial/usb-serial.c.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/mutex.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/idr.h>
-#include <linux/fs.h>
-#include <linux/kdev_t.h>
-
-#include "greybus.h"
-
-#define GB_NUM_MINORS  255     /* 255 is enough for anyone... */
-#define GB_NAME                "ttyGB"
-
-/* Version of the Greybus PWM protocol we support */
-#define GB_UART_VERSION_MAJOR          0x00
-#define GB_UART_VERSION_MINOR          0x01
-
-/* Greybus UART request types */
-#define GB_UART_REQ_INVALID                    0x00
-#define GB_UART_REQ_PROTOCOL_VERSION           0x01
-#define GB_UART_REQ_SEND_DATA                  0x02
-#define GB_UART_REQ_RECEIVE_DATA               0x03    /* Unsolicited data */
-#define GB_UART_REQ_SET_LINE_CODING            0x04
-#define GB_UART_REQ_SET_CONTROL_LINE_STATE     0x05
-#define GB_UART_REQ_SET_BREAK                  0x06
-#define GB_UART_REQ_SERIAL_STATE               0x07    /* Unsolicited data */
-#define GB_UART_TYPE_RESPONSE                  0x80    /* OR'd with rest */
-
-struct gb_uart_proto_version_response {
-       __u8    major;
-       __u8    minor;
-};
-
-struct gb_uart_send_data_request {
-       __le16  size;
-       __u8    data[0];
-};
-
-struct gb_serial_line_coding {
-       __le32  rate;
-       __u8    format;
-#define GB_SERIAL_1_STOP_BITS          0
-#define GB_SERIAL_1_5_STOP_BITS                1
-#define GB_SERIAL_2_STOP_BITS          2
-
-       __u8    parity;
-#define GB_SERIAL_NO_PARITY            0
-#define GB_SERIAL_ODD_PARITY           1
-#define GB_SERIAL_EVEN_PARITY          2
-#define GB_SERIAL_MARK_PARITY          3
-#define GB_SERIAL_SPACE_PARITY         4
-
-       __u8    data;
-} __attribute__ ((packed));
-
-struct gb_uart_set_line_coding_request {
-       struct gb_serial_line_coding    line_coding;
-};
-
-/* output control lines */
-#define GB_UART_CTRL_DTR               0x01
-#define GB_UART_CTRL_RTS               0x02
-
-struct gb_uart_set_control_line_state_request {
-       __le16  control;
-};
-
-struct gb_uart_set_break_request {
-       __u8    state;
-};
-
-/* input control lines and line errors */
-#define GB_UART_CTRL_DCD               0x01
-#define GB_UART_CTRL_DSR               0x02
-#define GB_UART_CTRL_BRK               0x04
-#define GB_UART_CTRL_RI                        0x08
-
-#define GB_UART_CTRL_FRAMING           0x10
-#define GB_UART_CTRL_PARITY            0x20
-#define GB_UART_CTRL_OVERRUN           0x40
-
-struct gb_uart_serial_state_request {
-       __u16   control;
-};
-
-struct gb_tty {
-       struct tty_port port;
-       struct gb_connection *connection;
-       u16 cport_id;
-       unsigned int minor;
-       unsigned char clocal;
-       bool disconnected;
-       spinlock_t read_lock;
-       spinlock_t write_lock;
-       struct async_icount iocount;
-       struct async_icount oldcount;
-       wait_queue_head_t wioctl;
-       struct mutex mutex;
-       u8 version_major;
-       u8 version_minor;
-       unsigned int ctrlin;    /* input control lines */
-       unsigned int ctrlout;   /* output control lines */
-       struct gb_serial_line_coding line_coding;
-};
-
-
-static struct tty_driver *gb_tty_driver;
-static DEFINE_IDR(tty_minors);
-static DEFINE_MUTEX(table_lock);
-static atomic_t reference_count = ATOMIC_INIT(0);
-
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int get_version(struct gb_tty *tty)
-{
-       struct gb_uart_proto_version_response response;
-       int ret;
-
-       ret = gb_operation_sync(tty->connection,
-                               GB_UART_REQ_PROTOCOL_VERSION,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       if (response.major > GB_UART_VERSION_MAJOR) {
-               pr_err("unsupported major version (%hhu > %hhu)\n",
-                       response.major, GB_UART_VERSION_MAJOR);
-               return -ENOTSUPP;
-       }
-       tty->version_major = response.major;
-       tty->version_minor = response.minor;
-
-       pr_debug("%s: version_major = %u version_minor = %u\n",
-               __func__, tty->version_major, tty->version_minor);
-       return 0;
-}
-
-static int send_data(struct gb_tty *tty, u16 size, const u8 *data)
-{
-       struct gb_uart_send_data_request *request;
-       int retval;
-
-       if (!data || !size)
-               return 0;
-
-       request = kmalloc(sizeof(*request) + size, GFP_KERNEL);
-       if (!request)
-               return -ENOMEM;
-
-       request->size = cpu_to_le16(size);
-       memcpy(&request->data[0], data, size);
-       retval = gb_operation_sync(tty->connection, GB_UART_REQ_SEND_DATA,
-                                  request, sizeof(*request) + size, NULL, 0);
-
-       kfree(request);
-       return retval;
-}
-
-static int send_line_coding(struct gb_tty *tty)
-{
-       struct gb_uart_set_line_coding_request request;
-
-       memcpy(&request.line_coding, &tty->line_coding,
-              sizeof(tty->line_coding));
-       return gb_operation_sync(tty->connection, GB_UART_REQ_SET_LINE_CODING,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int send_control(struct gb_tty *tty, u16 control)
-{
-       struct gb_uart_set_control_line_state_request request;
-
-       request.control = cpu_to_le16(control);
-       return gb_operation_sync(tty->connection,
-                                GB_UART_REQ_SET_CONTROL_LINE_STATE,
-                                &request, sizeof(request), NULL, 0);
-}
-
-static int send_break(struct gb_tty *tty, u8 state)
-{
-       struct gb_uart_set_break_request request;
-
-       if ((state != 0) && (state != 1)) {
-               dev_err(&tty->connection->dev,
-                       "invalid break state of %d\n", state);
-               return -EINVAL;
-       }
-
-       request.state = state;
-       return gb_operation_sync(tty->connection, GB_UART_REQ_SET_BREAK,
-                                &request, sizeof(request), NULL, 0);
-}
-
-
-static struct gb_tty *get_gb_by_minor(unsigned minor)
-{
-       struct gb_tty *gb_tty;
-
-       mutex_lock(&table_lock);
-       gb_tty = idr_find(&tty_minors, minor);
-       if (gb_tty) {
-               mutex_lock(&gb_tty->mutex);
-               if (gb_tty->disconnected) {
-                       mutex_unlock(&gb_tty->mutex);
-                       gb_tty = NULL;
-               } else {
-                       tty_port_get(&gb_tty->port);
-                       mutex_unlock(&gb_tty->mutex);
-               }
-       }
-       mutex_unlock(&table_lock);
-       return gb_tty;
-}
-
-static int alloc_minor(struct gb_tty *gb_tty)
-{
-       int minor;
-
-       mutex_lock(&table_lock);
-       minor = idr_alloc(&tty_minors, gb_tty, 0, GB_NUM_MINORS, GFP_KERNEL);
-       mutex_unlock(&table_lock);
-       if (minor >= 0)
-               gb_tty->minor = minor;
-       return minor;
-}
-
-static void release_minor(struct gb_tty *gb_tty)
-{
-       int minor = gb_tty->minor;
-
-       gb_tty->minor = 0;      /* Maybe should use an invalid value instead */
-       mutex_lock(&table_lock);
-       idr_remove(&tty_minors, minor);
-       mutex_unlock(&table_lock);
-}
-
-static int gb_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty;
-       int retval;
-
-       gb_tty = get_gb_by_minor(tty->index);
-       if (!gb_tty)
-               return -ENODEV;
-
-       retval = tty_standard_install(driver, tty);
-       if (retval)
-               goto error;
-
-       tty->driver_data = gb_tty;
-       return 0;
-error:
-       tty_port_put(&gb_tty->port);
-       return retval;
-}
-
-static int gb_tty_open(struct tty_struct *tty, struct file *file)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       return tty_port_open(&gb_tty->port, tty, file);
-}
-
-static void gb_tty_close(struct tty_struct *tty, struct file *file)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       tty_port_close(&gb_tty->port, tty, file);
-}
-
-static void gb_tty_cleanup(struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       tty_port_put(&gb_tty->port);
-}
-
-static void gb_tty_hangup(struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       tty_port_hangup(&gb_tty->port);
-}
-
-static int gb_tty_write(struct tty_struct *tty, const unsigned char *buf,
-                       int count)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       return send_data(gb_tty, count, buf);
-}
-
-static int gb_tty_write_room(struct tty_struct *tty)
-{
-//     struct gb_tty *gb_tty = tty->driver_data;
-
-       // FIXME - how much do we want to say we have room for?
-       return 0;
-}
-
-static int gb_tty_chars_in_buffer(struct tty_struct *tty)
-{
-//     struct gb_tty *gb_tty = tty->driver_data;
-
-       // FIXME - how many left to send?
-       return 0;
-}
-
-static int gb_tty_break_ctl(struct tty_struct *tty, int state)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       return send_break(gb_tty, state ? 1 : 0);
-}
-
-static void gb_tty_set_termios(struct tty_struct *tty,
-                              struct ktermios *termios_old)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-       struct ktermios *termios = &tty->termios;
-       struct gb_serial_line_coding newline;
-       int newctrl = gb_tty->ctrlout;
-
-       newline.rate = cpu_to_le32(tty_get_baud_rate(tty));
-       newline.format = termios->c_cflag & CSTOPB ? 2 : 0;
-       newline.parity = termios->c_cflag & PARENB ?
-                               (termios->c_cflag & PARODD ? 1 : 2) +
-                               (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
-
-       switch (termios->c_cflag & CSIZE) {
-       case CS5:
-               newline.data = 5;
-               break;
-       case CS6:
-               newline.data = 6;
-               break;
-       case CS7:
-               newline.data = 7;
-               break;
-       case CS8:
-       default:
-               newline.data = 8;
-               break;
-       }
-
-       /* FIXME: needs to clear unsupported bits in the termios */
-       gb_tty->clocal = ((termios->c_cflag & CLOCAL) != 0);
-
-       if (C_BAUD(tty) == B0) {
-               newline.rate = gb_tty->line_coding.rate;
-               newctrl &= GB_UART_CTRL_DTR;
-       } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) {
-               newctrl |= GB_UART_CTRL_DTR;
-       }
-
-       if (newctrl != gb_tty->ctrlout) {
-               gb_tty->ctrlout = newctrl;
-               send_control(gb_tty, newctrl);
-       }
-
-       if (memcpy(&gb_tty->line_coding, &newline, sizeof(newline))) {
-               memcpy(&gb_tty->line_coding, &newline, sizeof(newline));
-               send_line_coding(gb_tty);
-       }
-}
-
-static int gb_tty_tiocmget(struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       return (gb_tty->ctrlout & GB_UART_CTRL_DTR ? TIOCM_DTR : 0) |
-              (gb_tty->ctrlout & GB_UART_CTRL_RTS ? TIOCM_RTS : 0) |
-              (gb_tty->ctrlin  & GB_UART_CTRL_DSR ? TIOCM_DSR : 0) |
-              (gb_tty->ctrlin  & GB_UART_CTRL_RI  ? TIOCM_RI  : 0) |
-              (gb_tty->ctrlin  & GB_UART_CTRL_DCD ? TIOCM_CD  : 0) |
-              TIOCM_CTS;
-}
-
-static int gb_tty_tiocmset(struct tty_struct *tty, unsigned int set,
-                          unsigned int clear)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-       unsigned int newctrl = gb_tty->ctrlout;
-
-       set = (set & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
-             (set & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
-       clear = (clear & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
-               (clear & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
-
-       newctrl = (newctrl & ~clear) | set;
-       if (gb_tty->ctrlout == newctrl)
-               return 0;
-
-       gb_tty->ctrlout = newctrl;
-       return send_control(gb_tty, newctrl);
-}
-
-static void gb_tty_throttle(struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-       unsigned char stop_char;
-       int retval;
-
-       if (I_IXOFF(tty)) {
-               stop_char = STOP_CHAR(tty);
-               retval = gb_tty_write(tty, &stop_char, 1);
-               if (retval <= 0)
-                       return;
-       }
-
-       if (tty->termios.c_cflag & CRTSCTS) {
-               gb_tty->ctrlout &= ~GB_UART_CTRL_RTS;
-               retval = send_control(gb_tty, gb_tty->ctrlout);
-       }
-
-}
-
-static void gb_tty_unthrottle(struct tty_struct *tty)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-       unsigned char start_char;
-       int retval;
-
-       if (I_IXOFF(tty)) {
-               start_char = START_CHAR(tty);
-               retval = gb_tty_write(tty, &start_char, 1);
-               if (retval <= 0)
-                       return;
-       }
-
-       if (tty->termios.c_cflag & CRTSCTS) {
-               gb_tty->ctrlout |= GB_UART_CTRL_RTS;
-               retval = send_control(gb_tty, gb_tty->ctrlout);
-       }
-}
-
-static int get_serial_info(struct gb_tty *gb_tty,
-                          struct serial_struct __user *info)
-{
-       struct serial_struct tmp;
-
-       if (!info)
-               return -EINVAL;
-
-       memset(&tmp, 0, sizeof(tmp));
-       tmp.flags = ASYNC_LOW_LATENCY | ASYNC_SKIP_TEST;
-       tmp.type = PORT_16550A;
-       tmp.line = gb_tty->minor;
-       tmp.xmit_fifo_size = 16;
-       tmp.baud_base = 9600;
-       tmp.close_delay = gb_tty->port.close_delay / 10;
-       tmp.closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                               ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10;
-
-       if (copy_to_user(info, &tmp, sizeof(tmp)))
-               return -EFAULT;
-       return 0;
-}
-
-static int set_serial_info(struct gb_tty *gb_tty,
-                          struct serial_struct __user *newinfo)
-{
-       struct serial_struct new_serial;
-       unsigned int closing_wait;
-       unsigned int close_delay;
-       int retval = 0;
-
-       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
-               return -EFAULT;
-
-       close_delay = new_serial.close_delay * 10;
-       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
-
-       mutex_lock(&gb_tty->port.mutex);
-       if (!capable(CAP_SYS_ADMIN)) {
-               if ((close_delay != gb_tty->port.close_delay) ||
-                   (closing_wait != gb_tty->port.closing_wait))
-                       retval = -EPERM;
-               else
-                       retval = -EOPNOTSUPP;
-       } else {
-               gb_tty->port.close_delay = close_delay;
-               gb_tty->port.closing_wait = closing_wait;
-       }
-       mutex_unlock(&gb_tty->port.mutex);
-       return retval;
-}
-
-static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg)
-{
-       int retval = 0;
-       DECLARE_WAITQUEUE(wait, current);
-       struct async_icount old;
-       struct async_icount new;
-
-       if (!(arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD)))
-               return -EINVAL;
-
-       do {
-               spin_lock_irq(&gb_tty->read_lock);
-               old = gb_tty->oldcount;
-               new = gb_tty->iocount;
-               gb_tty->oldcount = new;
-               spin_unlock_irq(&gb_tty->read_lock);
-
-               if ((arg & TIOCM_DSR) && (old.dsr != new.dsr))
-                       break;
-               if ((arg & TIOCM_CD) && (old.dcd != new.dcd))
-                       break;
-               if ((arg & TIOCM_RI) && (old.rng != new.rng))
-                       break;
-
-               add_wait_queue(&gb_tty->wioctl, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-               remove_wait_queue(&gb_tty->wioctl, &wait);
-               if (gb_tty->disconnected) {
-                       if (arg & TIOCM_CD)
-                               break;
-                       retval = -ENODEV;
-               } else if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-               }
-       } while (!retval);
-
-       return retval;
-}
-
-static int get_serial_usage(struct gb_tty *gb_tty,
-                           struct serial_icounter_struct __user *count)
-{
-       struct serial_icounter_struct icount;
-       int retval = 0;
-
-       memset(&icount, 0, sizeof(icount));
-       icount.dsr = gb_tty->iocount.dsr;
-       icount.rng = gb_tty->iocount.rng;
-       icount.dcd = gb_tty->iocount.dcd;
-       icount.frame = gb_tty->iocount.frame;
-       icount.overrun = gb_tty->iocount.overrun;
-       icount.parity = gb_tty->iocount.parity;
-       icount.brk = gb_tty->iocount.brk;
-
-       if (copy_to_user(count, &icount, sizeof(icount)) > 0)
-               retval = -EFAULT;
-
-       return retval;
-}
-
-static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
-                       unsigned long arg)
-{
-       struct gb_tty *gb_tty = tty->driver_data;
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return get_serial_info(gb_tty,
-                                      (struct serial_struct __user *)arg);
-       case TIOCSSERIAL:
-               return set_serial_info(gb_tty,
-                                      (struct serial_struct __user *)arg);
-       case TIOCMIWAIT:
-               return wait_serial_change(gb_tty, arg);
-       case TIOCGICOUNT:
-               return get_serial_usage(gb_tty,
-                                       (struct serial_icounter_struct __user *)arg);
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-
-static const struct tty_operations gb_ops = {
-       .install =              gb_tty_install,
-       .open =                 gb_tty_open,
-       .close =                gb_tty_close,
-       .cleanup =              gb_tty_cleanup,
-       .hangup =               gb_tty_hangup,
-       .write =                gb_tty_write,
-       .write_room =           gb_tty_write_room,
-       .ioctl =                gb_tty_ioctl,
-       .throttle =             gb_tty_throttle,
-       .unthrottle =           gb_tty_unthrottle,
-       .chars_in_buffer =      gb_tty_chars_in_buffer,
-       .break_ctl =            gb_tty_break_ctl,
-       .set_termios =          gb_tty_set_termios,
-       .tiocmget =             gb_tty_tiocmget,
-       .tiocmset =             gb_tty_tiocmset,
-};
-
-
-static int gb_tty_init(void);
-static void gb_tty_exit(void);
-
-static int gb_uart_connection_init(struct gb_connection *connection)
-{
-       struct gb_tty *gb_tty;
-       struct device *tty_dev;
-       int retval;
-       int minor;
-
-       /* First time here, initialize the tty structures */
-       if (atomic_inc_return(&reference_count) == 1) {
-               retval = gb_tty_init();
-               if (retval) {
-                       atomic_dec(&reference_count);
-                       return retval;
-               }
-       }
-
-       gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL);
-       if (!gb_tty)
-               return -ENOMEM;
-       gb_tty->connection = connection;
-       connection->private = gb_tty;
-
-       /* Check for compatible protocol version */
-       retval = get_version(gb_tty);
-       if (retval)
-               goto error_version;
-
-       minor = alloc_minor(gb_tty);
-       if (minor < 0) {
-               if (minor == -ENOSPC) {
-                       dev_err(&connection->dev,
-                               "no more free minor numbers\n");
-                       return -ENODEV;
-               }
-               return minor;
-       }
-
-       gb_tty->minor = minor;
-       spin_lock_init(&gb_tty->write_lock);
-       spin_lock_init(&gb_tty->read_lock);
-       init_waitqueue_head(&gb_tty->wioctl);
-       mutex_init(&gb_tty->mutex);
-
-       send_control(gb_tty, gb_tty->ctrlout);
-
-       /* initialize the uart to be 9600n81 */
-       gb_tty->line_coding.rate = cpu_to_le32(9600);
-       gb_tty->line_coding.format = GB_SERIAL_1_STOP_BITS;
-       gb_tty->line_coding.parity = GB_SERIAL_NO_PARITY;
-       gb_tty->line_coding.data = 8;
-       send_line_coding(gb_tty);
-
-       tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor,
-                                          &connection->dev);
-       if (IS_ERR(tty_dev)) {
-               retval = PTR_ERR(tty_dev);
-               goto error;
-       }
-
-       return 0;
-error:
-       release_minor(gb_tty);
-error_version:
-       connection->private = NULL;
-       kfree(gb_tty);
-       return retval;
-}
-
-static void gb_uart_connection_exit(struct gb_connection *connection)
-{
-       struct gb_tty *gb_tty = connection->private;
-       struct tty_struct *tty;
-
-       if (!gb_tty)
-               return;
-
-       mutex_lock(&gb_tty->mutex);
-       gb_tty->disconnected = true;
-
-       wake_up_all(&gb_tty->wioctl);
-       connection->private = NULL;
-       mutex_unlock(&gb_tty->mutex);
-
-       tty = tty_port_tty_get(&gb_tty->port);
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-       /* FIXME - stop all traffic */
-
-       tty_unregister_device(gb_tty_driver, gb_tty->minor);
-
-       /* FIXME - free transmit / receive buffers */
-
-       tty_port_put(&gb_tty->port);
-
-       kfree(gb_tty);
-
-       /* If last device is gone, tear down the tty structures */
-       if (atomic_dec_return(&reference_count) == 0)
-               gb_tty_exit();
-}
-
-static int gb_tty_init(void)
-{
-       int retval = 0;
-
-       gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, 0);
-       if (IS_ERR(gb_tty_driver)) {
-               pr_err("Can not allocate tty driver\n");
-               retval = -ENOMEM;
-               goto fail_unregister_dev;
-       }
-
-       gb_tty_driver->driver_name = "gb";
-       gb_tty_driver->name = GB_NAME;
-       gb_tty_driver->major = 0;
-       gb_tty_driver->minor_start = 0;
-       gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
-       gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gb_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-       gb_tty_driver->init_termios = tty_std_termios;
-       gb_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       tty_set_operations(gb_tty_driver, &gb_ops);
-
-       retval = tty_register_driver(gb_tty_driver);
-       if (retval) {
-               pr_err("Can not register tty driver: %d\n", retval);
-               goto fail_put_gb_tty;
-       }
-
-       return 0;
-
-fail_put_gb_tty:
-       put_tty_driver(gb_tty_driver);
-fail_unregister_dev:
-       return retval;
-}
-
-static void gb_tty_exit(void)
-{
-       int major = MAJOR(gb_tty_driver->major);
-       int minor = gb_tty_driver->minor_start;
-
-       tty_unregister_driver(gb_tty_driver);
-       put_tty_driver(gb_tty_driver);
-       unregister_chrdev_region(MKDEV(major, minor), GB_NUM_MINORS);
-}
-
-static struct gb_protocol uart_protocol = {
-       .name                   = "uart",
-       .id                     = GREYBUS_PROTOCOL_UART,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_uart_connection_init,
-       .connection_exit        = gb_uart_connection_exit,
-       .request_recv           = NULL, /* FIXME we have 2 types of requests!!! */
-};
-
-int gb_uart_protocol_init(void)
-{
-       return gb_protocol_register(&uart_protocol);
-}
-
-void gb_uart_protocol_exit(void)
-{
-       gb_protocol_deregister(&uart_protocol);
-}
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
new file mode 100644 (file)
index 0000000..0320620
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * UART driver for the Greybus "generic" UART module.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ *
+ * Heavily based on drivers/usb/class/cdc-acm.c and
+ * drivers/usb/serial/usb-serial.c.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/idr.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+
+#include "greybus.h"
+
+#define GB_NUM_MINORS  255     /* 255 is enough for anyone... */
+#define GB_NAME                "ttyGB"
+
+/* Version of the Greybus PWM protocol we support */
+#define GB_UART_VERSION_MAJOR          0x00
+#define GB_UART_VERSION_MINOR          0x01
+
+/* Greybus UART request types */
+#define GB_UART_REQ_INVALID                    0x00
+#define GB_UART_REQ_PROTOCOL_VERSION           0x01
+#define GB_UART_REQ_SEND_DATA                  0x02
+#define GB_UART_REQ_RECEIVE_DATA               0x03    /* Unsolicited data */
+#define GB_UART_REQ_SET_LINE_CODING            0x04
+#define GB_UART_REQ_SET_CONTROL_LINE_STATE     0x05
+#define GB_UART_REQ_SET_BREAK                  0x06
+#define GB_UART_REQ_SERIAL_STATE               0x07    /* Unsolicited data */
+#define GB_UART_TYPE_RESPONSE                  0x80    /* OR'd with rest */
+
+struct gb_uart_proto_version_response {
+       __u8    major;
+       __u8    minor;
+};
+
+struct gb_uart_send_data_request {
+       __le16  size;
+       __u8    data[0];
+};
+
+struct gb_serial_line_coding {
+       __le32  rate;
+       __u8    format;
+#define GB_SERIAL_1_STOP_BITS          0
+#define GB_SERIAL_1_5_STOP_BITS                1
+#define GB_SERIAL_2_STOP_BITS          2
+
+       __u8    parity;
+#define GB_SERIAL_NO_PARITY            0
+#define GB_SERIAL_ODD_PARITY           1
+#define GB_SERIAL_EVEN_PARITY          2
+#define GB_SERIAL_MARK_PARITY          3
+#define GB_SERIAL_SPACE_PARITY         4
+
+       __u8    data;
+} __attribute__ ((packed));
+
+struct gb_uart_set_line_coding_request {
+       struct gb_serial_line_coding    line_coding;
+};
+
+/* output control lines */
+#define GB_UART_CTRL_DTR               0x01
+#define GB_UART_CTRL_RTS               0x02
+
+struct gb_uart_set_control_line_state_request {
+       __le16  control;
+};
+
+struct gb_uart_set_break_request {
+       __u8    state;
+};
+
+/* input control lines and line errors */
+#define GB_UART_CTRL_DCD               0x01
+#define GB_UART_CTRL_DSR               0x02
+#define GB_UART_CTRL_BRK               0x04
+#define GB_UART_CTRL_RI                        0x08
+
+#define GB_UART_CTRL_FRAMING           0x10
+#define GB_UART_CTRL_PARITY            0x20
+#define GB_UART_CTRL_OVERRUN           0x40
+
+struct gb_uart_serial_state_request {
+       __u16   control;
+};
+
+struct gb_tty {
+       struct tty_port port;
+       struct gb_connection *connection;
+       u16 cport_id;
+       unsigned int minor;
+       unsigned char clocal;
+       bool disconnected;
+       spinlock_t read_lock;
+       spinlock_t write_lock;
+       struct async_icount iocount;
+       struct async_icount oldcount;
+       wait_queue_head_t wioctl;
+       struct mutex mutex;
+       u8 version_major;
+       u8 version_minor;
+       unsigned int ctrlin;    /* input control lines */
+       unsigned int ctrlout;   /* output control lines */
+       struct gb_serial_line_coding line_coding;
+};
+
+
+static struct tty_driver *gb_tty_driver;
+static DEFINE_IDR(tty_minors);
+static DEFINE_MUTEX(table_lock);
+static atomic_t reference_count = ATOMIC_INIT(0);
+
+/*
+ * This request only uses the connection field, and if successful,
+ * fills in the major and minor protocol version of the target.
+ */
+static int get_version(struct gb_tty *tty)
+{
+       struct gb_uart_proto_version_response response;
+       int ret;
+
+       ret = gb_operation_sync(tty->connection,
+                               GB_UART_REQ_PROTOCOL_VERSION,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       if (response.major > GB_UART_VERSION_MAJOR) {
+               pr_err("unsupported major version (%hhu > %hhu)\n",
+                       response.major, GB_UART_VERSION_MAJOR);
+               return -ENOTSUPP;
+       }
+       tty->version_major = response.major;
+       tty->version_minor = response.minor;
+
+       pr_debug("%s: version_major = %u version_minor = %u\n",
+               __func__, tty->version_major, tty->version_minor);
+       return 0;
+}
+
+static int send_data(struct gb_tty *tty, u16 size, const u8 *data)
+{
+       struct gb_uart_send_data_request *request;
+       int retval;
+
+       if (!data || !size)
+               return 0;
+
+       request = kmalloc(sizeof(*request) + size, GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->size = cpu_to_le16(size);
+       memcpy(&request->data[0], data, size);
+       retval = gb_operation_sync(tty->connection, GB_UART_REQ_SEND_DATA,
+                                  request, sizeof(*request) + size, NULL, 0);
+
+       kfree(request);
+       return retval;
+}
+
+static int send_line_coding(struct gb_tty *tty)
+{
+       struct gb_uart_set_line_coding_request request;
+
+       memcpy(&request.line_coding, &tty->line_coding,
+              sizeof(tty->line_coding));
+       return gb_operation_sync(tty->connection, GB_UART_REQ_SET_LINE_CODING,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int send_control(struct gb_tty *tty, u16 control)
+{
+       struct gb_uart_set_control_line_state_request request;
+
+       request.control = cpu_to_le16(control);
+       return gb_operation_sync(tty->connection,
+                                GB_UART_REQ_SET_CONTROL_LINE_STATE,
+                                &request, sizeof(request), NULL, 0);
+}
+
+static int send_break(struct gb_tty *tty, u8 state)
+{
+       struct gb_uart_set_break_request request;
+
+       if ((state != 0) && (state != 1)) {
+               dev_err(&tty->connection->dev,
+                       "invalid break state of %d\n", state);
+               return -EINVAL;
+       }
+
+       request.state = state;
+       return gb_operation_sync(tty->connection, GB_UART_REQ_SET_BREAK,
+                                &request, sizeof(request), NULL, 0);
+}
+
+
+static struct gb_tty *get_gb_by_minor(unsigned minor)
+{
+       struct gb_tty *gb_tty;
+
+       mutex_lock(&table_lock);
+       gb_tty = idr_find(&tty_minors, minor);
+       if (gb_tty) {
+               mutex_lock(&gb_tty->mutex);
+               if (gb_tty->disconnected) {
+                       mutex_unlock(&gb_tty->mutex);
+                       gb_tty = NULL;
+               } else {
+                       tty_port_get(&gb_tty->port);
+                       mutex_unlock(&gb_tty->mutex);
+               }
+       }
+       mutex_unlock(&table_lock);
+       return gb_tty;
+}
+
+static int alloc_minor(struct gb_tty *gb_tty)
+{
+       int minor;
+
+       mutex_lock(&table_lock);
+       minor = idr_alloc(&tty_minors, gb_tty, 0, GB_NUM_MINORS, GFP_KERNEL);
+       mutex_unlock(&table_lock);
+       if (minor >= 0)
+               gb_tty->minor = minor;
+       return minor;
+}
+
+static void release_minor(struct gb_tty *gb_tty)
+{
+       int minor = gb_tty->minor;
+
+       gb_tty->minor = 0;      /* Maybe should use an invalid value instead */
+       mutex_lock(&table_lock);
+       idr_remove(&tty_minors, minor);
+       mutex_unlock(&table_lock);
+}
+
+static int gb_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty;
+       int retval;
+
+       gb_tty = get_gb_by_minor(tty->index);
+       if (!gb_tty)
+               return -ENODEV;
+
+       retval = tty_standard_install(driver, tty);
+       if (retval)
+               goto error;
+
+       tty->driver_data = gb_tty;
+       return 0;
+error:
+       tty_port_put(&gb_tty->port);
+       return retval;
+}
+
+static int gb_tty_open(struct tty_struct *tty, struct file *file)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       return tty_port_open(&gb_tty->port, tty, file);
+}
+
+static void gb_tty_close(struct tty_struct *tty, struct file *file)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       tty_port_close(&gb_tty->port, tty, file);
+}
+
+static void gb_tty_cleanup(struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       tty_port_put(&gb_tty->port);
+}
+
+static void gb_tty_hangup(struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       tty_port_hangup(&gb_tty->port);
+}
+
+static int gb_tty_write(struct tty_struct *tty, const unsigned char *buf,
+                       int count)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       return send_data(gb_tty, count, buf);
+}
+
+static int gb_tty_write_room(struct tty_struct *tty)
+{
+//     struct gb_tty *gb_tty = tty->driver_data;
+
+       // FIXME - how much do we want to say we have room for?
+       return 0;
+}
+
+static int gb_tty_chars_in_buffer(struct tty_struct *tty)
+{
+//     struct gb_tty *gb_tty = tty->driver_data;
+
+       // FIXME - how many left to send?
+       return 0;
+}
+
+static int gb_tty_break_ctl(struct tty_struct *tty, int state)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       return send_break(gb_tty, state ? 1 : 0);
+}
+
+static void gb_tty_set_termios(struct tty_struct *tty,
+                              struct ktermios *termios_old)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+       struct ktermios *termios = &tty->termios;
+       struct gb_serial_line_coding newline;
+       int newctrl = gb_tty->ctrlout;
+
+       newline.rate = cpu_to_le32(tty_get_baud_rate(tty));
+       newline.format = termios->c_cflag & CSTOPB ? 2 : 0;
+       newline.parity = termios->c_cflag & PARENB ?
+                               (termios->c_cflag & PARODD ? 1 : 2) +
+                               (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               newline.data = 5;
+               break;
+       case CS6:
+               newline.data = 6;
+               break;
+       case CS7:
+               newline.data = 7;
+               break;
+       case CS8:
+       default:
+               newline.data = 8;
+               break;
+       }
+
+       /* FIXME: needs to clear unsupported bits in the termios */
+       gb_tty->clocal = ((termios->c_cflag & CLOCAL) != 0);
+
+       if (C_BAUD(tty) == B0) {
+               newline.rate = gb_tty->line_coding.rate;
+               newctrl &= GB_UART_CTRL_DTR;
+       } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) {
+               newctrl |= GB_UART_CTRL_DTR;
+       }
+
+       if (newctrl != gb_tty->ctrlout) {
+               gb_tty->ctrlout = newctrl;
+               send_control(gb_tty, newctrl);
+       }
+
+       if (memcpy(&gb_tty->line_coding, &newline, sizeof(newline))) {
+               memcpy(&gb_tty->line_coding, &newline, sizeof(newline));
+               send_line_coding(gb_tty);
+       }
+}
+
+static int gb_tty_tiocmget(struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       return (gb_tty->ctrlout & GB_UART_CTRL_DTR ? TIOCM_DTR : 0) |
+              (gb_tty->ctrlout & GB_UART_CTRL_RTS ? TIOCM_RTS : 0) |
+              (gb_tty->ctrlin  & GB_UART_CTRL_DSR ? TIOCM_DSR : 0) |
+              (gb_tty->ctrlin  & GB_UART_CTRL_RI  ? TIOCM_RI  : 0) |
+              (gb_tty->ctrlin  & GB_UART_CTRL_DCD ? TIOCM_CD  : 0) |
+              TIOCM_CTS;
+}
+
+static int gb_tty_tiocmset(struct tty_struct *tty, unsigned int set,
+                          unsigned int clear)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+       unsigned int newctrl = gb_tty->ctrlout;
+
+       set = (set & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
+             (set & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
+       clear = (clear & TIOCM_DTR ? GB_UART_CTRL_DTR : 0) |
+               (clear & TIOCM_RTS ? GB_UART_CTRL_RTS : 0);
+
+       newctrl = (newctrl & ~clear) | set;
+       if (gb_tty->ctrlout == newctrl)
+               return 0;
+
+       gb_tty->ctrlout = newctrl;
+       return send_control(gb_tty, newctrl);
+}
+
+static void gb_tty_throttle(struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+       unsigned char stop_char;
+       int retval;
+
+       if (I_IXOFF(tty)) {
+               stop_char = STOP_CHAR(tty);
+               retval = gb_tty_write(tty, &stop_char, 1);
+               if (retval <= 0)
+                       return;
+       }
+
+       if (tty->termios.c_cflag & CRTSCTS) {
+               gb_tty->ctrlout &= ~GB_UART_CTRL_RTS;
+               retval = send_control(gb_tty, gb_tty->ctrlout);
+       }
+
+}
+
+static void gb_tty_unthrottle(struct tty_struct *tty)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+       unsigned char start_char;
+       int retval;
+
+       if (I_IXOFF(tty)) {
+               start_char = START_CHAR(tty);
+               retval = gb_tty_write(tty, &start_char, 1);
+               if (retval <= 0)
+                       return;
+       }
+
+       if (tty->termios.c_cflag & CRTSCTS) {
+               gb_tty->ctrlout |= GB_UART_CTRL_RTS;
+               retval = send_control(gb_tty, gb_tty->ctrlout);
+       }
+}
+
+static int get_serial_info(struct gb_tty *gb_tty,
+                          struct serial_struct __user *info)
+{
+       struct serial_struct tmp;
+
+       if (!info)
+               return -EINVAL;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.flags = ASYNC_LOW_LATENCY | ASYNC_SKIP_TEST;
+       tmp.type = PORT_16550A;
+       tmp.line = gb_tty->minor;
+       tmp.xmit_fifo_size = 16;
+       tmp.baud_base = 9600;
+       tmp.close_delay = gb_tty->port.close_delay / 10;
+       tmp.closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                               ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10;
+
+       if (copy_to_user(info, &tmp, sizeof(tmp)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_serial_info(struct gb_tty *gb_tty,
+                          struct serial_struct __user *newinfo)
+{
+       struct serial_struct new_serial;
+       unsigned int closing_wait;
+       unsigned int close_delay;
+       int retval = 0;
+
+       if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+               return -EFAULT;
+
+       close_delay = new_serial.close_delay * 10;
+       closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+
+       mutex_lock(&gb_tty->port.mutex);
+       if (!capable(CAP_SYS_ADMIN)) {
+               if ((close_delay != gb_tty->port.close_delay) ||
+                   (closing_wait != gb_tty->port.closing_wait))
+                       retval = -EPERM;
+               else
+                       retval = -EOPNOTSUPP;
+       } else {
+               gb_tty->port.close_delay = close_delay;
+               gb_tty->port.closing_wait = closing_wait;
+       }
+       mutex_unlock(&gb_tty->port.mutex);
+       return retval;
+}
+
+static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg)
+{
+       int retval = 0;
+       DECLARE_WAITQUEUE(wait, current);
+       struct async_icount old;
+       struct async_icount new;
+
+       if (!(arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD)))
+               return -EINVAL;
+
+       do {
+               spin_lock_irq(&gb_tty->read_lock);
+               old = gb_tty->oldcount;
+               new = gb_tty->iocount;
+               gb_tty->oldcount = new;
+               spin_unlock_irq(&gb_tty->read_lock);
+
+               if ((arg & TIOCM_DSR) && (old.dsr != new.dsr))
+                       break;
+               if ((arg & TIOCM_CD) && (old.dcd != new.dcd))
+                       break;
+               if ((arg & TIOCM_RI) && (old.rng != new.rng))
+                       break;
+
+               add_wait_queue(&gb_tty->wioctl, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+               remove_wait_queue(&gb_tty->wioctl, &wait);
+               if (gb_tty->disconnected) {
+                       if (arg & TIOCM_CD)
+                               break;
+                       retval = -ENODEV;
+               } else if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+               }
+       } while (!retval);
+
+       return retval;
+}
+
+static int get_serial_usage(struct gb_tty *gb_tty,
+                           struct serial_icounter_struct __user *count)
+{
+       struct serial_icounter_struct icount;
+       int retval = 0;
+
+       memset(&icount, 0, sizeof(icount));
+       icount.dsr = gb_tty->iocount.dsr;
+       icount.rng = gb_tty->iocount.rng;
+       icount.dcd = gb_tty->iocount.dcd;
+       icount.frame = gb_tty->iocount.frame;
+       icount.overrun = gb_tty->iocount.overrun;
+       icount.parity = gb_tty->iocount.parity;
+       icount.brk = gb_tty->iocount.brk;
+
+       if (copy_to_user(count, &icount, sizeof(icount)) > 0)
+               retval = -EFAULT;
+
+       return retval;
+}
+
+static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct gb_tty *gb_tty = tty->driver_data;
+
+       switch (cmd) {
+       case TIOCGSERIAL:
+               return get_serial_info(gb_tty,
+                                      (struct serial_struct __user *)arg);
+       case TIOCSSERIAL:
+               return set_serial_info(gb_tty,
+                                      (struct serial_struct __user *)arg);
+       case TIOCMIWAIT:
+               return wait_serial_change(gb_tty, arg);
+       case TIOCGICOUNT:
+               return get_serial_usage(gb_tty,
+                                       (struct serial_icounter_struct __user *)arg);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+
+static const struct tty_operations gb_ops = {
+       .install =              gb_tty_install,
+       .open =                 gb_tty_open,
+       .close =                gb_tty_close,
+       .cleanup =              gb_tty_cleanup,
+       .hangup =               gb_tty_hangup,
+       .write =                gb_tty_write,
+       .write_room =           gb_tty_write_room,
+       .ioctl =                gb_tty_ioctl,
+       .throttle =             gb_tty_throttle,
+       .unthrottle =           gb_tty_unthrottle,
+       .chars_in_buffer =      gb_tty_chars_in_buffer,
+       .break_ctl =            gb_tty_break_ctl,
+       .set_termios =          gb_tty_set_termios,
+       .tiocmget =             gb_tty_tiocmget,
+       .tiocmset =             gb_tty_tiocmset,
+};
+
+
+static int gb_tty_init(void);
+static void gb_tty_exit(void);
+
+static int gb_uart_connection_init(struct gb_connection *connection)
+{
+       struct gb_tty *gb_tty;
+       struct device *tty_dev;
+       int retval;
+       int minor;
+
+       /* First time here, initialize the tty structures */
+       if (atomic_inc_return(&reference_count) == 1) {
+               retval = gb_tty_init();
+               if (retval) {
+                       atomic_dec(&reference_count);
+                       return retval;
+               }
+       }
+
+       gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL);
+       if (!gb_tty)
+               return -ENOMEM;
+       gb_tty->connection = connection;
+       connection->private = gb_tty;
+
+       /* Check for compatible protocol version */
+       retval = get_version(gb_tty);
+       if (retval)
+               goto error_version;
+
+       minor = alloc_minor(gb_tty);
+       if (minor < 0) {
+               if (minor == -ENOSPC) {
+                       dev_err(&connection->dev,
+                               "no more free minor numbers\n");
+                       return -ENODEV;
+               }
+               return minor;
+       }
+
+       gb_tty->minor = minor;
+       spin_lock_init(&gb_tty->write_lock);
+       spin_lock_init(&gb_tty->read_lock);
+       init_waitqueue_head(&gb_tty->wioctl);
+       mutex_init(&gb_tty->mutex);
+
+       send_control(gb_tty, gb_tty->ctrlout);
+
+       /* initialize the uart to be 9600n81 */
+       gb_tty->line_coding.rate = cpu_to_le32(9600);
+       gb_tty->line_coding.format = GB_SERIAL_1_STOP_BITS;
+       gb_tty->line_coding.parity = GB_SERIAL_NO_PARITY;
+       gb_tty->line_coding.data = 8;
+       send_line_coding(gb_tty);
+
+       tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor,
+                                          &connection->dev);
+       if (IS_ERR(tty_dev)) {
+               retval = PTR_ERR(tty_dev);
+               goto error;
+       }
+
+       return 0;
+error:
+       release_minor(gb_tty);
+error_version:
+       connection->private = NULL;
+       kfree(gb_tty);
+       return retval;
+}
+
+static void gb_uart_connection_exit(struct gb_connection *connection)
+{
+       struct gb_tty *gb_tty = connection->private;
+       struct tty_struct *tty;
+
+       if (!gb_tty)
+               return;
+
+       mutex_lock(&gb_tty->mutex);
+       gb_tty->disconnected = true;
+
+       wake_up_all(&gb_tty->wioctl);
+       connection->private = NULL;
+       mutex_unlock(&gb_tty->mutex);
+
+       tty = tty_port_tty_get(&gb_tty->port);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+       /* FIXME - stop all traffic */
+
+       tty_unregister_device(gb_tty_driver, gb_tty->minor);
+
+       /* FIXME - free transmit / receive buffers */
+
+       tty_port_put(&gb_tty->port);
+
+       kfree(gb_tty);
+
+       /* If last device is gone, tear down the tty structures */
+       if (atomic_dec_return(&reference_count) == 0)
+               gb_tty_exit();
+}
+
+static int gb_tty_init(void)
+{
+       int retval = 0;
+
+       gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, 0);
+       if (IS_ERR(gb_tty_driver)) {
+               pr_err("Can not allocate tty driver\n");
+               retval = -ENOMEM;
+               goto fail_unregister_dev;
+       }
+
+       gb_tty_driver->driver_name = "gb";
+       gb_tty_driver->name = GB_NAME;
+       gb_tty_driver->major = 0;
+       gb_tty_driver->minor_start = 0;
+       gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gb_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       gb_tty_driver->init_termios = tty_std_termios;
+       gb_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty_set_operations(gb_tty_driver, &gb_ops);
+
+       retval = tty_register_driver(gb_tty_driver);
+       if (retval) {
+               pr_err("Can not register tty driver: %d\n", retval);
+               goto fail_put_gb_tty;
+       }
+
+       return 0;
+
+fail_put_gb_tty:
+       put_tty_driver(gb_tty_driver);
+fail_unregister_dev:
+       return retval;
+}
+
+static void gb_tty_exit(void)
+{
+       int major = MAJOR(gb_tty_driver->major);
+       int minor = gb_tty_driver->minor_start;
+
+       tty_unregister_driver(gb_tty_driver);
+       put_tty_driver(gb_tty_driver);
+       unregister_chrdev_region(MKDEV(major, minor), GB_NUM_MINORS);
+}
+
+static struct gb_protocol uart_protocol = {
+       .name                   = "uart",
+       .id                     = GREYBUS_PROTOCOL_UART,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_uart_connection_init,
+       .connection_exit        = gb_uart_connection_exit,
+       .request_recv           = NULL, /* FIXME we have 2 types of requests!!! */
+};
+
+int gb_uart_protocol_init(void)
+{
+       return gb_protocol_register(&uart_protocol);
+}
+
+void gb_uart_protocol_exit(void)
+{
+       gb_protocol_deregister(&uart_protocol);
+}
diff --git a/drivers/staging/greybus/usb-gb.c b/drivers/staging/greybus/usb-gb.c
deleted file mode 100644 (file)
index 010ef9e..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * USB host driver for the Greybus "generic" USB module.
- *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-
-#include "greybus.h"
-
-/* Version of the Greybus USB protocol we support */
-#define GB_USB_VERSION_MAJOR           0x00
-#define GB_USB_VERSION_MINOR           0x01
-
-/* Greybus USB request types */
-#define GB_USB_TYPE_INVALID            0x00
-#define GB_USB_TYPE_PROTOCOL_VERSION   0x01
-#define GB_USB_TYPE_HCD_STOP           0x02
-#define GB_USB_TYPE_HCD_START          0x03
-#define GB_USB_TYPE_URB_ENQUEUE                0x04
-#define GB_USB_TYPE_URB_DEQUEUE                0x05
-#define GB_USB_TYPE_ENDPOINT_DISABLE   0x06
-#define GB_USB_TYPE_HUB_CONTROL                0x07
-#define GB_USB_TYPE_GET_FRAME_NUMBER   0x08
-#define GB_USB_TYPE_HUB_STATUS_DATA    0x09
-
-struct gb_usb_proto_version_response {
-       __u8    major;
-       __u8    minor;
-};
-
-struct gb_usb_urb_enqueue_request {
-       __le32 pipe;
-       __le32 transfer_flags;
-       __le32 transfer_buffer_length;
-       __le32 maxpacket;
-       __le32 interval;
-       __le64 hcpriv_ep;
-       __le32 number_of_packets;
-       u8 setup_packet[8];
-       u8 payload[0];
-};
-
-struct gb_usb_urb_dequeue_request {
-       __le64 hcpriv_ep;
-};
-
-struct gb_usb_endpoint_disable_request {
-       __le64  hcpriv;
-};
-
-struct gb_usb_hub_control_request {
-       __le16 typeReq;
-       __le16 wValue;
-       __le16 wIndex;
-       __le16 wLength;
-};
-
-struct gb_usb_hub_control_response {
-       u8 buf[0];
-};
-
-struct gb_usb_header {
-       __le16  size;
-       __le16  id;
-       __u8    type;
-};
-
-struct gb_usb_hub_status {
-       __le32 status;
-       __le16 buf_size;
-       u8 buf[0];
-};
-
-static struct gb_usb_hub_status *hub_status;   // FIXME!!!
-static DEFINE_SPINLOCK(hub_status_lock);
-static atomic_t frame_number;                  // FIXME!!!
-
-struct gb_usb_device {
-       struct gb_connection *connection;
-
-       struct usb_hcd *hcd;
-       u8 version_major;
-       u8 version_minor;
-};
-
-#define to_gb_usb_device(d) ((struct gb_usb_device*) d->hcd_priv)
-
-static int get_version(struct gb_usb_device *dev)
-{
-       struct gb_usb_proto_version_response response;
-       int ret;
-
-       ret = gb_operation_sync(dev->connection,
-                               GB_USB_TYPE_PROTOCOL_VERSION,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
-       if (response.major > GB_USB_VERSION_MAJOR) {
-               pr_err("unsupported major version (%hhu > %hhu)\n",
-                       response.major, GB_USB_VERSION_MAJOR);
-               return -ENOTSUPP;
-       }
-       dev->version_major = response.major;
-       dev->version_minor = response.minor;
-       return 0;
-}
-
-static void hcd_stop(struct usb_hcd *hcd)
-{
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       int ret;
-
-       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
-                               NULL, 0, NULL, 0);
-       if (ret)
-               dev_err(&dev->connection->dev, "HCD stop failed '%d'\n", ret);
-}
-
-static int hcd_start(struct usb_hcd *hcd)
-{
-       struct usb_bus *bus = hcd_to_bus(hcd);
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       int ret;
-
-       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
-                               NULL, 0, NULL, 0);
-       if (ret) {
-               dev_err(&dev->connection->dev, "HCD start failed '%d'\n", ret);
-               return ret;
-       }
-
-       hcd->state = HC_STATE_RUNNING;
-       if (bus->root_hub)
-               usb_hcd_resume_root_hub(hcd);
-       return 0;
-}
-
-static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
-{
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       struct gb_usb_urb_enqueue_request *request;
-       struct gb_operation *operation;
-       int ret;
-
-       operation = gb_operation_create(dev->connection,
-                                       GB_USB_TYPE_URB_ENQUEUE,
-                                       sizeof(*request) +
-                                       urb->transfer_buffer_length, 0);
-       if (!operation)
-               return -ENODEV;
-
-       request = operation->request->payload;
-       request->pipe = cpu_to_le32(urb->pipe);
-       request->transfer_flags = cpu_to_le32(urb->transfer_flags);
-       request->transfer_buffer_length = cpu_to_le32(urb->transfer_buffer_length);
-       request->interval = cpu_to_le32(urb->interval);
-       request->hcpriv_ep = cpu_to_le64(urb->ep->hcpriv);
-       request->number_of_packets = cpu_to_le32(urb->number_of_packets);
-
-       memcpy(request->setup_packet, urb->setup_packet, 8);
-       memcpy(&request->payload, urb->transfer_buffer,
-              urb->transfer_buffer_length);
-
-       ret = gb_operation_request_send_sync(operation);
-       gb_operation_destroy(operation);
-
-       return ret;
-}
-
-static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-{
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       struct gb_usb_urb_dequeue_request request;
-       int ret;
-
-       urb->ep->hcpriv = NULL;
-       request.hcpriv_ep = cpu_to_le64(urb->hcpriv);
-       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_URB_DEQUEUE,
-                               &request, sizeof(request), NULL, 0);
-       urb->hcpriv = NULL;
-       return ret;
-}
-
-static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
-{
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       struct gb_usb_endpoint_disable_request request;
-       int ret;
-
-       request.hcpriv = cpu_to_le64(ep->hcpriv);
-       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_ENDPOINT_DISABLE,
-                               &request, sizeof(request), NULL, 0);
-       ep->hcpriv = NULL;
-}
-
-static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
-{
-}
-
-static int get_frame_number(struct usb_hcd *hcd)
-{
-       return atomic_read(&frame_number);
-}
-
-static int hub_status_data(struct usb_hcd *hcd, char *buf)
-{
-       int retval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hub_status_lock, flags);
-       memcpy(buf, hub_status->buf, le16_to_cpu(hub_status->buf_size));
-       retval = le32_to_cpu(hub_status->status);
-       spin_unlock_irqrestore(&hub_status_lock, flags);
-
-       return retval;
-}
-
-static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
-                      char *buf, u16 wLength)
-{
-       struct gb_usb_hub_control_request request;
-       struct gb_usb_device *dev = to_gb_usb_device(hcd);
-       int ret;
-
-       request.typeReq = cpu_to_le16(typeReq);
-       request.wValue = cpu_to_le16(wValue);
-       request.wIndex = cpu_to_le16(wIndex);
-       request.wLength = cpu_to_le16(wLength);
-
-       // FIXME - buf needs to come back in struct gb_usb_hub_control_response
-       // for some types of requests, depending on typeReq.  Do we do this in a
-       // "generic" way, or only ask for a response for the ones we "know" need
-       // a response (a small subset of all valid typeReq, thankfully.)
-       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HUB_CONTROL,
-                               &request, sizeof(request), NULL, 0);
-
-       return ret;
-}
-
-static struct hc_driver usb_gb_hc_driver = {
-       .description = "greybus_usb",
-       .product_desc = "GB-Bridge USB Controller", /* TODO: Get this from GPB ?*/
-       .flags = HCD_MEMORY | HCD_USB2, /* FIXME: Get this from GPB */
-       .hcd_priv_size = sizeof(struct gb_usb_device),
-
-       .start = hcd_start,
-       .stop = hcd_stop,
-       .urb_enqueue = urb_enqueue,
-       .urb_dequeue = urb_dequeue,
-       .endpoint_disable = endpoint_disable,
-       .endpoint_reset = endpoint_reset,
-       .get_frame_number = get_frame_number,
-       .hub_status_data = hub_status_data,
-       .hub_control = hub_control,
-};
-
-#if 0
-static inline void gb_usb_handle_get_frame_number(struct gbuf *gbuf)
-{
-       __le32 frame_num;
-       const size_t packet_size = sizeof(struct gb_usb_header) +
-                                  sizeof(frame_num);
-       struct gb_usb_header* hdr = gbuf->transfer_buffer;
-
-       if (le16_to_cpu(hdr->size) != packet_size) {
-               pr_err("%s(): dropping packet too small\n", __func__);
-               return;
-       }
-
-       frame_num = (__le32) ((char*) gbuf->transfer_buffer +
-                             sizeof(struct gb_usb_header));
-       atomic_set(&frame_number, le32_to_cpu(frame_num));
-}
-
-static inline void gb_usb_handle_hubs_status_data(struct gbuf *gbuf)
-{
-       struct gb_usb_hub_status *new_hubstatus, *hubstatus;
-       struct gb_usb_header* hdr = gbuf->transfer_buffer;
-       const size_t min_packet_size = sizeof(struct gb_usb_header) +
-                                      sizeof(struct gb_usb_hub_status);
-       unsigned long flags;
-
-       if (le16_to_cpu(hdr->size) < min_packet_size) {
-               pr_err("%s(): dropping packet too small\n", __func__);
-               return;
-       }
-
-       hubstatus = (struct gb_usb_hub_status*) ((char*) gbuf->transfer_buffer
-                                               + sizeof(struct gb_usb_header));
-
-       if (le16_to_cpu(hdr->size) != min_packet_size + hubstatus->buf_size) {
-               pr_err("%s(): invalid packet size, dropping packet\n",
-                      __func__);
-               return;
-       }
-
-       new_hubstatus = kmalloc(hubstatus->buf_size, GFP_KERNEL);
-       memcpy(&new_hubstatus, hubstatus, hubstatus->buf_size);
-
-       spin_lock_irqsave(&hub_status_lock, flags);
-       hubstatus = hub_status;
-       hub_status = new_hubstatus;
-       spin_unlock_irqrestore(&hub_status_lock, flags);
-
-       kfree(hubstatus);
-}
-
-static void gb_usb_in_handler(struct gbuf *gbuf)
-{
-       struct gb_usb_header* hdr = gbuf->transfer_buffer;
-
-       switch (hdr->type) {
-               case GB_USB_TYPE_GET_FRAME_NUMBER:
-                       gb_usb_handle_get_frame_number(gbuf);
-                       break;
-
-               case GB_USB_TYPE_HUB_STATUS_DATA:
-                       gb_usb_handle_hubs_status_data(gbuf);
-                       break;
-       }
-}
-#endif
-
-static int gb_usb_connection_init(struct gb_connection *connection)
-{
-       struct device *dev = &connection->dev;
-       struct gb_usb_device *gb_usb_dev;
-
-       int retval;
-
-       gb_usb_dev = kzalloc(sizeof(*gb_usb_dev), GFP_KERNEL);
-       if (!gb_usb_dev)
-               return -ENOMEM;
-
-       gb_usb_dev->connection = connection;
-       connection->private = gb_usb_dev;
-
-       /* Check for compatible protocol version */
-       retval = get_version(gb_usb_dev);
-       if (retval)
-               goto error_create_hcd;
-
-       gb_usb_dev->hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
-       if (!gb_usb_dev->hcd) {
-               retval = -ENODEV;
-               goto error_create_hcd;
-       }
-
-       gb_usb_dev->hcd->has_tt = 1;
-       gb_usb_dev->hcd->hcd_priv[0] = (unsigned long) gb_usb_dev;
-
-       retval = usb_add_hcd(gb_usb_dev->hcd, 0, 0);
-       if (retval)
-               goto error_add_hcd;
-
-       return 0;
-error_add_hcd:
-       usb_put_hcd(gb_usb_dev->hcd);
-error_create_hcd:
-       kfree(gb_usb_dev);
-       return retval;
-}
-
-static void gb_usb_connection_exit(struct gb_connection *connection)
-{
-       // FIXME - tear everything down!
-}
-
-static struct gb_protocol usb_protocol = {
-       .name                   = "usb",
-       .id                     = GREYBUS_PROTOCOL_USB,
-       .major                  = 0,
-       .minor                  = 1,
-       .connection_init        = gb_usb_connection_init,
-       .connection_exit        = gb_usb_connection_exit,
-       .request_recv           = NULL, /* FIXME we have requests!!! */
-};
-
-int gb_usb_protocol_init(void)
-{
-       return gb_protocol_register(&usb_protocol);
-}
-
-void gb_usb_protocol_exit(void)
-{
-       gb_protocol_deregister(&usb_protocol);
-}
diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c
new file mode 100644 (file)
index 0000000..010ef9e
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * USB host driver for the Greybus "generic" USB module.
+ *
+ * Copyright 2014 Google Inc.
+ * Copyright 2014 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "greybus.h"
+
+/* Version of the Greybus USB protocol we support */
+#define GB_USB_VERSION_MAJOR           0x00
+#define GB_USB_VERSION_MINOR           0x01
+
+/* Greybus USB request types */
+#define GB_USB_TYPE_INVALID            0x00
+#define GB_USB_TYPE_PROTOCOL_VERSION   0x01
+#define GB_USB_TYPE_HCD_STOP           0x02
+#define GB_USB_TYPE_HCD_START          0x03
+#define GB_USB_TYPE_URB_ENQUEUE                0x04
+#define GB_USB_TYPE_URB_DEQUEUE                0x05
+#define GB_USB_TYPE_ENDPOINT_DISABLE   0x06
+#define GB_USB_TYPE_HUB_CONTROL                0x07
+#define GB_USB_TYPE_GET_FRAME_NUMBER   0x08
+#define GB_USB_TYPE_HUB_STATUS_DATA    0x09
+
+struct gb_usb_proto_version_response {
+       __u8    major;
+       __u8    minor;
+};
+
+struct gb_usb_urb_enqueue_request {
+       __le32 pipe;
+       __le32 transfer_flags;
+       __le32 transfer_buffer_length;
+       __le32 maxpacket;
+       __le32 interval;
+       __le64 hcpriv_ep;
+       __le32 number_of_packets;
+       u8 setup_packet[8];
+       u8 payload[0];
+};
+
+struct gb_usb_urb_dequeue_request {
+       __le64 hcpriv_ep;
+};
+
+struct gb_usb_endpoint_disable_request {
+       __le64  hcpriv;
+};
+
+struct gb_usb_hub_control_request {
+       __le16 typeReq;
+       __le16 wValue;
+       __le16 wIndex;
+       __le16 wLength;
+};
+
+struct gb_usb_hub_control_response {
+       u8 buf[0];
+};
+
+struct gb_usb_header {
+       __le16  size;
+       __le16  id;
+       __u8    type;
+};
+
+struct gb_usb_hub_status {
+       __le32 status;
+       __le16 buf_size;
+       u8 buf[0];
+};
+
+static struct gb_usb_hub_status *hub_status;   // FIXME!!!
+static DEFINE_SPINLOCK(hub_status_lock);
+static atomic_t frame_number;                  // FIXME!!!
+
+struct gb_usb_device {
+       struct gb_connection *connection;
+
+       struct usb_hcd *hcd;
+       u8 version_major;
+       u8 version_minor;
+};
+
+#define to_gb_usb_device(d) ((struct gb_usb_device*) d->hcd_priv)
+
+static int get_version(struct gb_usb_device *dev)
+{
+       struct gb_usb_proto_version_response response;
+       int ret;
+
+       ret = gb_operation_sync(dev->connection,
+                               GB_USB_TYPE_PROTOCOL_VERSION,
+                               NULL, 0, &response, sizeof(response));
+       if (ret)
+               return ret;
+
+       if (response.major > GB_USB_VERSION_MAJOR) {
+               pr_err("unsupported major version (%hhu > %hhu)\n",
+                       response.major, GB_USB_VERSION_MAJOR);
+               return -ENOTSUPP;
+       }
+       dev->version_major = response.major;
+       dev->version_minor = response.minor;
+       return 0;
+}
+
+static void hcd_stop(struct usb_hcd *hcd)
+{
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       int ret;
+
+       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
+                               NULL, 0, NULL, 0);
+       if (ret)
+               dev_err(&dev->connection->dev, "HCD stop failed '%d'\n", ret);
+}
+
+static int hcd_start(struct usb_hcd *hcd)
+{
+       struct usb_bus *bus = hcd_to_bus(hcd);
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       int ret;
+
+       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
+                               NULL, 0, NULL, 0);
+       if (ret) {
+               dev_err(&dev->connection->dev, "HCD start failed '%d'\n", ret);
+               return ret;
+       }
+
+       hcd->state = HC_STATE_RUNNING;
+       if (bus->root_hub)
+               usb_hcd_resume_root_hub(hcd);
+       return 0;
+}
+
+static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
+{
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       struct gb_usb_urb_enqueue_request *request;
+       struct gb_operation *operation;
+       int ret;
+
+       operation = gb_operation_create(dev->connection,
+                                       GB_USB_TYPE_URB_ENQUEUE,
+                                       sizeof(*request) +
+                                       urb->transfer_buffer_length, 0);
+       if (!operation)
+               return -ENODEV;
+
+       request = operation->request->payload;
+       request->pipe = cpu_to_le32(urb->pipe);
+       request->transfer_flags = cpu_to_le32(urb->transfer_flags);
+       request->transfer_buffer_length = cpu_to_le32(urb->transfer_buffer_length);
+       request->interval = cpu_to_le32(urb->interval);
+       request->hcpriv_ep = cpu_to_le64(urb->ep->hcpriv);
+       request->number_of_packets = cpu_to_le32(urb->number_of_packets);
+
+       memcpy(request->setup_packet, urb->setup_packet, 8);
+       memcpy(&request->payload, urb->transfer_buffer,
+              urb->transfer_buffer_length);
+
+       ret = gb_operation_request_send_sync(operation);
+       gb_operation_destroy(operation);
+
+       return ret;
+}
+
+static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       struct gb_usb_urb_dequeue_request request;
+       int ret;
+
+       urb->ep->hcpriv = NULL;
+       request.hcpriv_ep = cpu_to_le64(urb->hcpriv);
+       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_URB_DEQUEUE,
+                               &request, sizeof(request), NULL, 0);
+       urb->hcpriv = NULL;
+       return ret;
+}
+
+static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       struct gb_usb_endpoint_disable_request request;
+       int ret;
+
+       request.hcpriv = cpu_to_le64(ep->hcpriv);
+       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_ENDPOINT_DISABLE,
+                               &request, sizeof(request), NULL, 0);
+       ep->hcpriv = NULL;
+}
+
+static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+}
+
+static int get_frame_number(struct usb_hcd *hcd)
+{
+       return atomic_read(&frame_number);
+}
+
+static int hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       int retval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hub_status_lock, flags);
+       memcpy(buf, hub_status->buf, le16_to_cpu(hub_status->buf_size));
+       retval = le32_to_cpu(hub_status->status);
+       spin_unlock_irqrestore(&hub_status_lock, flags);
+
+       return retval;
+}
+
+static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
+                      char *buf, u16 wLength)
+{
+       struct gb_usb_hub_control_request request;
+       struct gb_usb_device *dev = to_gb_usb_device(hcd);
+       int ret;
+
+       request.typeReq = cpu_to_le16(typeReq);
+       request.wValue = cpu_to_le16(wValue);
+       request.wIndex = cpu_to_le16(wIndex);
+       request.wLength = cpu_to_le16(wLength);
+
+       // FIXME - buf needs to come back in struct gb_usb_hub_control_response
+       // for some types of requests, depending on typeReq.  Do we do this in a
+       // "generic" way, or only ask for a response for the ones we "know" need
+       // a response (a small subset of all valid typeReq, thankfully.)
+       ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HUB_CONTROL,
+                               &request, sizeof(request), NULL, 0);
+
+       return ret;
+}
+
+static struct hc_driver usb_gb_hc_driver = {
+       .description = "greybus_usb",
+       .product_desc = "GB-Bridge USB Controller", /* TODO: Get this from GPB ?*/
+       .flags = HCD_MEMORY | HCD_USB2, /* FIXME: Get this from GPB */
+       .hcd_priv_size = sizeof(struct gb_usb_device),
+
+       .start = hcd_start,
+       .stop = hcd_stop,
+       .urb_enqueue = urb_enqueue,
+       .urb_dequeue = urb_dequeue,
+       .endpoint_disable = endpoint_disable,
+       .endpoint_reset = endpoint_reset,
+       .get_frame_number = get_frame_number,
+       .hub_status_data = hub_status_data,
+       .hub_control = hub_control,
+};
+
+#if 0
+static inline void gb_usb_handle_get_frame_number(struct gbuf *gbuf)
+{
+       __le32 frame_num;
+       const size_t packet_size = sizeof(struct gb_usb_header) +
+                                  sizeof(frame_num);
+       struct gb_usb_header* hdr = gbuf->transfer_buffer;
+
+       if (le16_to_cpu(hdr->size) != packet_size) {
+               pr_err("%s(): dropping packet too small\n", __func__);
+               return;
+       }
+
+       frame_num = (__le32) ((char*) gbuf->transfer_buffer +
+                             sizeof(struct gb_usb_header));
+       atomic_set(&frame_number, le32_to_cpu(frame_num));
+}
+
+static inline void gb_usb_handle_hubs_status_data(struct gbuf *gbuf)
+{
+       struct gb_usb_hub_status *new_hubstatus, *hubstatus;
+       struct gb_usb_header* hdr = gbuf->transfer_buffer;
+       const size_t min_packet_size = sizeof(struct gb_usb_header) +
+                                      sizeof(struct gb_usb_hub_status);
+       unsigned long flags;
+
+       if (le16_to_cpu(hdr->size) < min_packet_size) {
+               pr_err("%s(): dropping packet too small\n", __func__);
+               return;
+       }
+
+       hubstatus = (struct gb_usb_hub_status*) ((char*) gbuf->transfer_buffer
+                                               + sizeof(struct gb_usb_header));
+
+       if (le16_to_cpu(hdr->size) != min_packet_size + hubstatus->buf_size) {
+               pr_err("%s(): invalid packet size, dropping packet\n",
+                      __func__);
+               return;
+       }
+
+       new_hubstatus = kmalloc(hubstatus->buf_size, GFP_KERNEL);
+       memcpy(&new_hubstatus, hubstatus, hubstatus->buf_size);
+
+       spin_lock_irqsave(&hub_status_lock, flags);
+       hubstatus = hub_status;
+       hub_status = new_hubstatus;
+       spin_unlock_irqrestore(&hub_status_lock, flags);
+
+       kfree(hubstatus);
+}
+
+static void gb_usb_in_handler(struct gbuf *gbuf)
+{
+       struct gb_usb_header* hdr = gbuf->transfer_buffer;
+
+       switch (hdr->type) {
+               case GB_USB_TYPE_GET_FRAME_NUMBER:
+                       gb_usb_handle_get_frame_number(gbuf);
+                       break;
+
+               case GB_USB_TYPE_HUB_STATUS_DATA:
+                       gb_usb_handle_hubs_status_data(gbuf);
+                       break;
+       }
+}
+#endif
+
+static int gb_usb_connection_init(struct gb_connection *connection)
+{
+       struct device *dev = &connection->dev;
+       struct gb_usb_device *gb_usb_dev;
+
+       int retval;
+
+       gb_usb_dev = kzalloc(sizeof(*gb_usb_dev), GFP_KERNEL);
+       if (!gb_usb_dev)
+               return -ENOMEM;
+
+       gb_usb_dev->connection = connection;
+       connection->private = gb_usb_dev;
+
+       /* Check for compatible protocol version */
+       retval = get_version(gb_usb_dev);
+       if (retval)
+               goto error_create_hcd;
+
+       gb_usb_dev->hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
+       if (!gb_usb_dev->hcd) {
+               retval = -ENODEV;
+               goto error_create_hcd;
+       }
+
+       gb_usb_dev->hcd->has_tt = 1;
+       gb_usb_dev->hcd->hcd_priv[0] = (unsigned long) gb_usb_dev;
+
+       retval = usb_add_hcd(gb_usb_dev->hcd, 0, 0);
+       if (retval)
+               goto error_add_hcd;
+
+       return 0;
+error_add_hcd:
+       usb_put_hcd(gb_usb_dev->hcd);
+error_create_hcd:
+       kfree(gb_usb_dev);
+       return retval;
+}
+
+static void gb_usb_connection_exit(struct gb_connection *connection)
+{
+       // FIXME - tear everything down!
+}
+
+static struct gb_protocol usb_protocol = {
+       .name                   = "usb",
+       .id                     = GREYBUS_PROTOCOL_USB,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_usb_connection_init,
+       .connection_exit        = gb_usb_connection_exit,
+       .request_recv           = NULL, /* FIXME we have requests!!! */
+};
+
+int gb_usb_protocol_init(void)
+{
+       return gb_protocol_register(&usb_protocol);
+}
+
+void gb_usb_protocol_exit(void)
+{
+       gb_protocol_deregister(&usb_protocol);
+}