]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
greybus: Add control protocol support
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 22 Jun 2015 11:12:26 +0000 (16:42 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 24 Jun 2015 06:16:15 +0000 (23:16 -0700)
Add control protocol driver that is responsible for handling operations
on control CPort. The AP also needs to support incoming requests on its
control port. Features not implemented yet are marked as TODO for now.

NOTE: This also fixes cport-bundle-id to 0 and cport-id to 2 for control
protocol.

Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Makefile
drivers/staging/greybus/control.c [new file with mode: 0644]
drivers/staging/greybus/control.h [new file with mode: 0644]
drivers/staging/greybus/core.c
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus_protocols.h
drivers/staging/greybus/interface.h

index 1715f452a677028f2a4e447a01507b3f31385c97..4f66ff3a97136228ddef5182c8943975fef98186 100644 (file)
@@ -8,6 +8,7 @@ greybus-y :=    core.o          \
                bundle.o        \
                connection.o    \
                protocol.o      \
+               control.o       \
                operation.o
 
 gb-phy-y :=    gpbridge.o      \
diff --git a/drivers/staging/greybus/control.c b/drivers/staging/greybus/control.c
new file mode 100644 (file)
index 0000000..c19814d
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Greybus CPort control protocol.
+ *
+ * Copyright 2015 Google Inc.
+ * Copyright 2015 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "greybus.h"
+
+/* Define get_version() routine */
+define_get_version(gb_control, CONTROL);
+
+/* Get Manifest's size from the interface */
+int gb_control_get_manifest_size_operation(struct gb_interface *intf)
+{
+       struct gb_control_get_manifest_size_response response;
+       struct gb_connection *connection = intf->control->connection;
+       int ret;
+
+       ret = gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST_SIZE,
+                               NULL, 0, &response, sizeof(response));
+       if (ret) {
+               dev_err(&connection->dev,
+                       "%s: Manifest size get operation failed (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       return le16_to_cpu(response.size);
+}
+
+/* Reads Manifest from the interface */
+int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
+                                     size_t size)
+{
+       struct gb_connection *connection = intf->control->connection;
+
+       return gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST,
+                               NULL, 0, manifest, size);
+}
+
+int gb_control_connected_operation(struct gb_control *control, u16 cport_id)
+{
+       struct gb_control_connected_request request;
+
+       request.cport_id = cpu_to_le16(cport_id);
+       return gb_operation_sync(control->connection, GB_CONTROL_TYPE_CONNECTED,
+                                &request, sizeof(request), NULL, 0);
+}
+
+int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id)
+{
+       struct gb_control_disconnected_request request;
+
+       request.cport_id = cpu_to_le16(cport_id);
+       return gb_operation_sync(control->connection,
+                                GB_CONTROL_TYPE_DISCONNECTED, &request,
+                                sizeof(request), NULL, 0);
+}
+
+static int gb_control_request_recv(u8 type, struct gb_operation *op)
+{
+       struct gb_connection *connection = op->connection;
+       struct gb_protocol_version_response *version;
+
+       switch (type) {
+       case GB_CONTROL_TYPE_PROBE_AP:
+               // TODO
+               // Send authenticated block of data, confirming this module is
+               // an AP.
+               break;
+       case GB_CONTROL_TYPE_PROTOCOL_VERSION:
+               if (!gb_operation_response_alloc(op, sizeof(*version))) {
+                       dev_err(&connection->dev,
+                               "%s: error allocating response\n", __func__);
+                       return -ENOMEM;
+               }
+
+               version = op->response->payload;
+               version->major = GB_CONTROL_VERSION_MAJOR;
+               version->minor = GB_CONTROL_VERSION_MINOR;
+               break;
+       case GB_CONTROL_TYPE_CONNECTED:
+       case GB_CONTROL_TYPE_DISCONNECTED:
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return 0;
+}
+
+static int gb_control_connection_init(struct gb_connection *connection)
+{
+       struct gb_control *control;
+       int ret;
+
+       control = kzalloc(sizeof(*control), GFP_KERNEL);
+       if (!control)
+               return -ENOMEM;
+
+       control->connection = connection;
+       connection->private = control;
+
+       ret = get_version(control);
+       if (ret)
+               kfree(control);
+
+       /* Set interface's control connection */
+       connection->bundle->intf->control = control;
+
+       return ret;
+}
+
+static void gb_control_connection_exit(struct gb_connection *connection)
+{
+       struct gb_control *control = connection->private;
+
+       if (WARN_ON(connection->bundle->intf->control != control))
+               return;
+
+       connection->bundle->intf->control = NULL;
+       kfree(control);
+}
+
+static struct gb_protocol control_protocol = {
+       .name                   = "control",
+       .id                     = GREYBUS_PROTOCOL_CONTROL,
+       .major                  = 0,
+       .minor                  = 1,
+       .connection_init        = gb_control_connection_init,
+       .connection_exit        = gb_control_connection_exit,
+       .request_recv           = gb_control_request_recv,
+};
+
+int gb_control_protocol_init(void)
+{
+       return gb_protocol_register(&control_protocol);
+}
+
+void gb_control_protocol_exit(void)
+{
+       gb_protocol_deregister(&control_protocol);
+}
diff --git a/drivers/staging/greybus/control.h b/drivers/staging/greybus/control.h
new file mode 100644 (file)
index 0000000..6e41a2b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Greybus CPort control protocol
+ *
+ * Copyright 2015 Google Inc.
+ * Copyright 2015 Linaro Ltd.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#ifndef __CONTROL_H
+#define __CONTROL_H
+
+struct gb_control {
+       struct gb_connection    *connection;
+       u8                      version_major;
+       u8                      version_minor;
+};
+
+int gb_control_connected_operation(struct gb_control *control, u16 cport_id);
+int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id);
+int gb_control_get_manifest_size_operation(struct gb_interface *intf);
+int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
+                                     size_t size);
+
+int gb_control_protocol_init(void);
+void gb_control_protocol_exit(void);
+#endif /* __CONTROL_H */
index d4fffecb1abc6a0d945a4685b64dab3a13ddd103..8d16e10b7e94355b6b50967c78239ed3cdef81c3 100644 (file)
@@ -274,8 +274,16 @@ static int __init gb_init(void)
                goto error_endo;
        }
 
+       retval = gb_control_protocol_init();
+       if (retval) {
+               pr_err("gb_control_protocol_init failed\n");
+               goto error_control;
+       }
+
        return 0;       /* Success */
 
+error_control:
+       gb_endo_exit();
 error_endo:
        gb_operation_exit();
 error_operation:
@@ -291,6 +299,7 @@ module_init(gb_init);
 
 static void __exit gb_exit(void)
 {
+       gb_control_protocol_exit();
        gb_endo_exit();
        gb_operation_exit();
        gb_ap_exit();
index 5c6f9607cf73dc28ee273bea594aaea099ae3842..6874939e6d1e89584fe46960b205c3017070c89f 100644 (file)
@@ -28,6 +28,7 @@
 #include "endo.h"
 #include "svc.h"
 #include "module.h"
+#include "control.h"
 #include "interface.h"
 #include "bundle.h"
 #include "connection.h"
index c64f6cb10f9b08794a1440cd3f03847ba3184ee7..9f9b722de7df5b1b22c462a4d9477d26ba964706 100644 (file)
 #ifndef __GREYBUS_PROTOCOLS_H
 #define __GREYBUS_PROTOCOLS_H
 
+/* Control Protocol */
+
+/* Bundle-id and cport-id for control cport */
+#define GB_CONTROL_BUNDLE_ID                   0
+#define GB_CONTROL_CPORT_ID                    2
+
+/* Version of the Greybus control protocol we support */
+#define GB_CONTROL_VERSION_MAJOR               0x00
+#define GB_CONTROL_VERSION_MINOR               0x01
+
+/* Greybus control request types */
+#define GB_CONTROL_TYPE_INVALID                        0x00
+#define GB_CONTROL_TYPE_PROTOCOL_VERSION       0x01
+#define GB_CONTROL_TYPE_PROBE_AP               0x02
+#define GB_CONTROL_TYPE_GET_MANIFEST_SIZE      0x03
+#define GB_CONTROL_TYPE_GET_MANIFEST           0x04
+#define GB_CONTROL_TYPE_CONNECTED              0x05
+#define GB_CONTROL_TYPE_DISCONNECTED           0x06
+
+/* Control protocol manifest get size request has no payload*/
+struct gb_control_get_manifest_size_response {
+       __le16                  size;
+};
+
+/* Control protocol manifest get request has no payload */
+struct gb_control_get_manifest_response {
+       __u8                    data[0];
+};
+
+/* Control protocol [dis]connected request */
+struct gb_control_connected_request {
+       __le16                  cport_id;
+};
+
+struct gb_control_disconnected_request {
+       __le16                  cport_id;
+};
+/* Control protocol [dis]connected response has no payload */
+
 /* I2C */
 
 /* Version of the Greybus i2c protocol we support */
index 88a7a80568062c8f23e2f3bb6b4fd06b1bb9484b..9c566b237aba18f4c27e775da6e831874e331964 100644 (file)
@@ -13,6 +13,7 @@
 /* Greybus "public" definitions" */
 struct gb_interface {
        struct device dev;
+       struct gb_control *control;
 
        struct list_head bundles;
        struct list_head links; /* greybus_host_device->interfaces */