diff options
Diffstat (limited to 'drivers/staging/greybus')
-rw-r--r-- | drivers/staging/greybus/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/greybus/control.c | 150 | ||||
-rw-r--r-- | drivers/staging/greybus/control.h | 27 | ||||
-rw-r--r-- | drivers/staging/greybus/core.c | 9 | ||||
-rw-r--r-- | drivers/staging/greybus/greybus.h | 1 | ||||
-rw-r--r-- | drivers/staging/greybus/greybus_protocols.h | 39 | ||||
-rw-r--r-- | drivers/staging/greybus/interface.h | 1 |
7 files changed, 228 insertions, 0 deletions
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index 1715f45..4f66ff3 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -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 index 0000000..c19814d --- /dev/null +++ b/drivers/staging/greybus/control.c @@ -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 index 0000000..6e41a2b --- /dev/null +++ b/drivers/staging/greybus/control.h @@ -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 */ diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index d4fffec..8d16e10 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -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(); diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 5c6f960..6874939 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -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" diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h index c64f6cb..9f9b722 100644 --- a/drivers/staging/greybus/greybus_protocols.h +++ b/drivers/staging/greybus/greybus_protocols.h @@ -52,6 +52,45 @@ #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 */ diff --git a/drivers/staging/greybus/interface.h b/drivers/staging/greybus/interface.h index 88a7a80..9c566b2 100644 --- a/drivers/staging/greybus/interface.h +++ b/drivers/staging/greybus/interface.h @@ -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 */ |