Currently, only the es2 hd controller is supported, which restrict the usage of greybus to few products.
This series intents to add a support of new hd controllers. The driver doesn't support any hardware. Actually, the controller is just a bridge between Greybus kernel and userspace. The real driver must be implemented in userspace. This give the ability to support any kind of transport layer (such as Bluetooth, WiFi, Ethernet).
The controller uses Generic Netlink. My original intent was to implement a TCP/IP controller but it was very slow, unstable. In addition, some features such as SVC or module discovery were to add to implement in kernel side. With the generic netlink controller, we can easily add support of new controller. It also helps to deal with all the project ARA legacy such as SVC.
I have started to implement an application which is able to emulate the SVC, a module (like gbsim but only support control and loopback protcols), TCP/IP, Bluetooth and UART. It is still under development but it was stable enough to test this series. The application can found here: https://github.com/anobli/gbridge
Alexandre Bailon (3): staging greybus: make cport_quiesce() method optional staging: greybus: Add Greybus netlink driver staging: greybus: netlink: Add a way to "hot remove" SVC
drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/connection.c | 3 + drivers/staging/greybus/gb_netlink.h | 38 ++++++ drivers/staging/greybus/netlink.c | 256 +++++++++++++++++++++++++++++++++++ 5 files changed, 308 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
The cport_quiesce() method is mandatory in the case of the es2 Greybus hd controller to shutdown the cports on the es2 controller. In order to add support of another controller which may not need to shutdown its cports, make the cport_quiesce() optional, and check if the controller implement it before to use it.
Signed-off-by: Alexandre Bailon abailon@baylibre.com --- drivers/staging/greybus/connection.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 1bf0ee4..2cf6464 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -366,6 +366,9 @@ static int gb_connection_hd_cport_quiesce(struct gb_connection *connection) if (connection->mode_switch) peer_space += sizeof(struct gb_operation_msg_hdr);
+ if (!hd->driver->cport_quiesce) + return 0; + ret = hd->driver->cport_quiesce(hd, connection->hd_cport_id, peer_space, GB_CONNECTION_CPORT_QUIESCE_TIMEOUT);
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Signed-off-by: Alexandre Bailon abailon@baylibre.com --- drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/gb_netlink.h | 37 ++++++ drivers/staging/greybus/netlink.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index 50de2d7..f9f3526 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -27,6 +27,15 @@ config GREYBUS_ES2 To compile this code as a module, chose M here: the module will be called gb-es2.ko
+config GREYBUS_NETLINK + tristate "Greybus netlink host controller" + ---help--- + Select this option if you want to implement a Greybus + "host controller" in userspace. + + To compile this code as a module, chose M here: the module + will be called gb-netlink.ko + config GREYBUS_AUDIO tristate "Greybus Audio Class driver" depends on SOUND diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index b26b9a3..d057f1d 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -20,8 +20,10 @@ ccflags-y += -I$(src)
# Greybus Host controller drivers gb-es2-y := es2.o +gb-netlink-y := netlink.o
obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o +obj-$(CONFIG_GREYBUS_NETLINK) += gb-netlink.o
# Greybus class drivers gb-bootrom-y := bootrom.o diff --git a/drivers/staging/greybus/gb_netlink.h b/drivers/staging/greybus/gb_netlink.h new file mode 100644 index 0000000..4af6fe5 --- /dev/null +++ b/drivers/staging/greybus/gb_netlink.h @@ -0,0 +1,37 @@ +/* + * Greybus Netlink driver for userspace controller + * + * Copyright (c) 2017 BayLibre SAS + * + * Released under the GPLv2 only. + */ + +#ifndef __GB_NETLINK_H +#define __GB_NETLINK_H + +/* Maximum packet size */ +#define GB_NETLINK_MTU 2048 +/* Maximum number of Cports */ +#define GB_NETLINK_NUM_CPORT 32 + +#define GB_NL_NAME "GREYBUS" +#define GB_NL_PID 1 + +enum { + GB_NL_A_UNSPEC, + GB_NL_A_DATA, + GB_NL_A_CPORT, + __GB_NL_A_MAX, +}; + +#define GB_NL_A_MAX (__GB_NL_A_MAX - 1) + +enum { + GB_NL_C_UNSPEC, + GB_NL_C_MSG, + __GB_NL_C_MAX, +}; + +#define GB_NL_C_MAX (__GB_NL_C_MAX - 1) + +#endif /* __GB_NETLINK_H */ diff --git a/drivers/staging/greybus/netlink.c b/drivers/staging/greybus/netlink.c new file mode 100644 index 0000000..84f3018 --- /dev/null +++ b/drivers/staging/greybus/netlink.c @@ -0,0 +1,221 @@ +/* + * Greybus Netlink driver for userspace controller + * + * Copyright (c) 2017 BayLibre SAS + * + * Released under the GPLv2 only. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <net/genetlink.h> + +#include "greybus.h" +#include "gb_netlink.h" + +static dev_t major_dev; +static struct class *gb_nl_class; +static struct genl_family gb_nl_family; +static struct gb_host_device *gb_nl_hd; + +#define VERSION_NR 1 + +#define DEVICE_NAME "gb_netlink" +#define CLASS_NAME "gb_netlink" + +static int gb_netlink_msg(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *na; + u16 cport_id; + void *data; + + if (!info) + return -EPROTO; + + na = info->attrs[GB_NL_A_CPORT]; + if (!na) { + dev_err(&gb_nl_hd->dev, + "Received message without cport id attribute\n"); + return -EPROTO; + } + + cport_id = nla_get_u32(na); + if (!cport_id_valid(gb_nl_hd, cport_id)) { + dev_err(&gb_nl_hd->dev, "invalid cport id %u received", + cport_id); + return -EINVAL; + } + + na = info->attrs[GB_NL_A_DATA]; + if (!na) { + dev_err(&gb_nl_hd->dev, + "Received message without data attribute\n"); + return -EPROTO; + } + + data = nla_data(na); + if (!data) { + dev_err(&gb_nl_hd->dev, + "Received message without data\n"); + return -EINVAL; + } + + greybus_data_rcvd(gb_nl_hd, cport_id, data, nla_len(na)); + + return 0; +} + +static struct nla_policy gb_nl_policy[GB_NL_A_MAX + 1] = { + [GB_NL_A_DATA] = { .type = NLA_BINARY, .len = GB_NETLINK_MTU }, + [GB_NL_A_CPORT] = { .type = NLA_U16}, +}; + +static struct genl_ops gb_nl_ops[] = { + { + .cmd = GB_NL_C_MSG, + .policy = gb_nl_policy, + .doit = gb_netlink_msg, + }, +}; + +static struct genl_family gb_nl_family = { + .hdrsize = 0, + .name = GB_NL_NAME, + .version = VERSION_NR, + .maxattr = GB_NL_A_MAX, + .ops = gb_nl_ops, + .n_ops = ARRAY_SIZE(gb_nl_ops), +}; + +static int message_send(struct gb_host_device *hd, u16 cport_id, + struct gb_message *message, gfp_t gfp_mask) +{ + struct nl_msg *nl_msg; + struct sk_buff *skb; + int retval = -ENOMEM; + + skb = genlmsg_new(sizeof(*message->header) + sizeof(u32) + + message->payload_size, GFP_KERNEL); + if (!skb) + goto err_out; + + nl_msg = genlmsg_put(skb, GB_NL_PID, 0, + &gb_nl_family, 0, GB_NL_C_MSG); + if (!nl_msg) + goto err_free; + + retval = nla_put_u32(skb, GB_NL_A_CPORT, cport_id); + if (retval) + goto err_cancel; + + retval = nla_put(skb, GB_NL_A_DATA, + sizeof(*message->header) + message->payload_size, + message->header); + if (retval) + goto err_cancel; + + genlmsg_end(skb, nl_msg); + + retval = genlmsg_unicast(&init_net, skb, GB_NL_PID); + if (retval) + goto err_cancel; + + greybus_message_sent(hd, message, 0); + + return 0; + +err_cancel: + genlmsg_cancel(skb, nl_msg); +err_free: + nlmsg_free(skb); +err_out: + return retval; +} + +static void message_cancel(struct gb_message *message) +{ +} + +static struct gb_hd_driver tcpip_driver = { + .message_send = message_send, + .message_cancel = message_cancel, +}; + +static void __exit gb_netlink_exit(void) +{ + if (!gb_nl_hd) + return; + + gb_hd_del(gb_nl_hd); + gb_hd_put(gb_nl_hd); + + gb_nl_hd = NULL; + + unregister_chrdev_region(major_dev, 1); + device_destroy(gb_nl_class, major_dev); + class_destroy(gb_nl_class); + + genl_unregister_family(&gb_nl_family); +} + +static int __init gb_netlink_init(void) +{ + int retval; + struct device *dev; + struct gb_host_device *gb_nl_hd; + + retval = genl_register_family(&gb_nl_family); + if (retval) + return retval; + + retval = alloc_chrdev_region(&major_dev, 0, 1, DEVICE_NAME); + if (retval) + goto err_genl_unregister; + + gb_nl_class = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(gb_nl_class)) { + retval = PTR_ERR(gb_nl_class); + goto err_chrdev_unregister; + } + + dev = device_create(gb_nl_class, NULL, major_dev, NULL, DEVICE_NAME); + if (IS_ERR(dev)) { + retval = PTR_ERR(dev); + goto err_class_destroy; + } + + gb_nl_hd = gb_hd_create(&tcpip_driver, dev, GB_NETLINK_MTU, + GB_NETLINK_NUM_CPORT); + if (IS_ERR(gb_nl_hd)) { + retval = PTR_ERR(gb_nl_hd); + goto err_device_destroy; + } + + retval = gb_hd_add(gb_nl_hd); + if (retval) + goto err_gb_hd_del; + + return 0; + +err_gb_hd_del: + gb_hd_del(gb_nl_hd); + gb_hd_put(gb_nl_hd); +err_device_destroy: + device_destroy(gb_nl_class, major_dev); +err_chrdev_unregister: + unregister_chrdev_region(major_dev, 1); +err_class_destroy: + class_destroy(gb_nl_class); +err_genl_unregister: + genl_unregister_family(&gb_nl_family); + + return retval; +} + +module_init(gb_netlink_init); +module_exit(gb_netlink_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexandre Bailon abailon@baylibre.com");
Currently, there is no way to remove the SVC. It was fine because the SVC was tied the es2 controller, and so removing the es2 controller device was removing the SVC. But the case of netlink, the SVC is emulated in userspace and it may be stopped or restarted. But because on the next run, it won't be reinitialized by Greybus, the SVC won't do its job and Greybus won't work. Add a netlink operation to remove the SVC, which will remove the hd driver, and then register it again.
Signed-off-by: Alexandre Bailon abailon@baylibre.com --- drivers/staging/greybus/gb_netlink.h | 1 + drivers/staging/greybus/netlink.c | 63 ++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/greybus/gb_netlink.h b/drivers/staging/greybus/gb_netlink.h index 4af6fe5..3a6335b 100644 --- a/drivers/staging/greybus/gb_netlink.h +++ b/drivers/staging/greybus/gb_netlink.h @@ -29,6 +29,7 @@ enum { enum { GB_NL_C_UNSPEC, GB_NL_C_MSG, + GB_NL_C_HD_RESET, __GB_NL_C_MAX, };
diff --git a/drivers/staging/greybus/netlink.c b/drivers/staging/greybus/netlink.c index 84f3018..ddf2f98 100644 --- a/drivers/staging/greybus/netlink.c +++ b/drivers/staging/greybus/netlink.c @@ -25,6 +25,9 @@ static struct gb_host_device *gb_nl_hd; #define DEVICE_NAME "gb_netlink" #define CLASS_NAME "gb_netlink"
+static int _gb_netlink_init(struct device *dev); +static void _gb_netlink_exit(void); + static int gb_netlink_msg(struct sk_buff *skb, struct genl_info *info) { struct nlattr *na; @@ -67,6 +70,18 @@ static int gb_netlink_msg(struct sk_buff *skb, struct genl_info *info) return 0; }
+static int gb_netlink_hd_reset(struct sk_buff *skb, struct genl_info *info) +{ + struct device *dev; + struct gb_host_device *hd = gb_nl_hd; + + dev = hd->dev.parent; + _gb_netlink_exit(); + _gb_netlink_init(dev); + + return 0; +} + static struct nla_policy gb_nl_policy[GB_NL_A_MAX + 1] = { [GB_NL_A_DATA] = { .type = NLA_BINARY, .len = GB_NETLINK_MTU }, [GB_NL_A_CPORT] = { .type = NLA_U16}, @@ -78,6 +93,10 @@ static struct genl_ops gb_nl_ops[] = { .policy = gb_nl_policy, .doit = gb_netlink_msg, }, + { + .cmd = GB_NL_C_HD_RESET, + .doit = gb_netlink_hd_reset, + }, };
static struct genl_family gb_nl_family = { @@ -143,7 +162,7 @@ static struct gb_hd_driver tcpip_driver = { .message_cancel = message_cancel, };
-static void __exit gb_netlink_exit(void) +static void _gb_netlink_exit(void) { if (!gb_nl_hd) return; @@ -152,6 +171,11 @@ static void __exit gb_netlink_exit(void) gb_hd_put(gb_nl_hd);
gb_nl_hd = NULL; +} + +static void __exit gb_netlink_exit(void) +{ + _gb_netlink_exit();
unregister_chrdev_region(major_dev, 1); device_destroy(gb_nl_class, major_dev); @@ -160,11 +184,32 @@ static void __exit gb_netlink_exit(void) genl_unregister_family(&gb_nl_family); }
+static int _gb_netlink_init(struct device *dev) +{ + int retval; + + gb_nl_hd = gb_hd_create(&tcpip_driver, dev, GB_NETLINK_MTU, + GB_NETLINK_NUM_CPORT); + if (IS_ERR(gb_nl_hd)) + return PTR_ERR(gb_nl_hd); + + retval = gb_hd_add(gb_nl_hd); + if (retval) + goto err_gb_hd_del; + + return 0; + +err_gb_hd_del: + gb_hd_del(gb_nl_hd); + gb_hd_put(gb_nl_hd); + + return retval; +} + static int __init gb_netlink_init(void) { int retval; struct device *dev; - struct gb_host_device *gb_nl_hd;
retval = genl_register_family(&gb_nl_family); if (retval) @@ -186,22 +231,12 @@ static int __init gb_netlink_init(void) goto err_class_destroy; }
- gb_nl_hd = gb_hd_create(&tcpip_driver, dev, GB_NETLINK_MTU, - GB_NETLINK_NUM_CPORT); - if (IS_ERR(gb_nl_hd)) { - retval = PTR_ERR(gb_nl_hd); - goto err_device_destroy; - } - - retval = gb_hd_add(gb_nl_hd); + retval = _gb_netlink_init(dev); if (retval) - goto err_gb_hd_del; + goto err_device_destroy;
return 0;
-err_gb_hd_del: - gb_hd_del(gb_nl_hd); - gb_hd_put(gb_nl_hd); err_device_destroy: device_destroy(gb_nl_class, major_dev); err_chrdev_unregister:
On 03/26/2017 12:58 PM, Alexandre Bailon wrote:
Currently, only the es2 hd controller is supported, which restrict the usage of greybus to few products.
This series intents to add a support of new hd controllers. The driver doesn't support any hardware. Actually, the controller is just a bridge between Greybus kernel and userspace. The real driver must be implemented in userspace. This give the ability to support any kind of transport layer (such as Bluetooth, WiFi, Ethernet).
The controller uses Generic Netlink. My original intent was to implement a TCP/IP controller but it was very slow, unstable. In addition, some features such as SVC or module discovery were to add to implement in kernel side. With the generic netlink controller, we can easily add support of new controller. It also helps to deal with all the project ARA legacy such as SVC.
I have started to implement an application which is able to emulate the SVC, a module (like gbsim but only support control and loopback protcols), TCP/IP, Bluetooth and UART. It is still under development but it was stable enough to test this series. The application can found here: https://github.com/anobli/gbridge
I'm not going to comment on the actual patch itself, but I do want to say that I'm very happy to see progress on making Gerybus generic to any transport.
On Sun, Mar 26, 2017 at 06:58:24PM +0200, Alexandre Bailon wrote:
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Very cool stuff, any hints on how to use this over netlink? Will the network developers get mad at this as an abuse of the transport?
Signed-off-by: Alexandre Bailon abailon@baylibre.com
drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/gb_netlink.h | 37 ++++++ drivers/staging/greybus/netlink.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index 50de2d7..f9f3526 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -27,6 +27,15 @@ config GREYBUS_ES2 To compile this code as a module, chose M here: the module will be called gb-es2.ko +config GREYBUS_NETLINK
- tristate "Greybus netlink host controller"
- ---help---
Select this option if you want to implement a Greybus
"host controller" in userspace.
To compile this code as a module, chose M here: the module
will be called gb-netlink.ko
Doesn't this need to depend on netlink to build properly?
thanks,
greg k-h
On Sun, Mar 26, 2017 at 06:58:24PM +0200, Alexandre Bailon wrote:
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Signed-off-by: Alexandre Bailon abailon@baylibre.com
drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/gb_netlink.h | 37 ++++++ drivers/staging/greybus/netlink.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index 50de2d7..f9f3526 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -27,6 +27,15 @@ config GREYBUS_ES2 To compile this code as a module, chose M here: the module will be called gb-es2.ko +config GREYBUS_NETLINK
- tristate "Greybus netlink host controller"
- ---help---
Select this option if you want to implement a Greybus
"host controller" in userspace.
To compile this code as a module, chose M here: the module
will be called gb-netlink.ko
config GREYBUS_AUDIO tristate "Greybus Audio Class driver" depends on SOUND diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index b26b9a3..d057f1d 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -20,8 +20,10 @@ ccflags-y += -I$(src) # Greybus Host controller drivers gb-es2-y := es2.o +gb-netlink-y := netlink.o obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o +obj-$(CONFIG_GREYBUS_NETLINK) += gb-netlink.o # Greybus class drivers gb-bootrom-y := bootrom.o diff --git a/drivers/staging/greybus/gb_netlink.h b/drivers/staging/greybus/gb_netlink.h new file mode 100644 index 0000000..4af6fe5 --- /dev/null +++ b/drivers/staging/greybus/gb_netlink.h @@ -0,0 +1,37 @@ +/*
- Greybus Netlink driver for userspace controller
- Copyright (c) 2017 BayLibre SAS
- Released under the GPLv2 only.
- */
+#ifndef __GB_NETLINK_H +#define __GB_NETLINK_H
+/* Maximum packet size */ +#define GB_NETLINK_MTU 2048 +/* Maximum number of Cports */ +#define GB_NETLINK_NUM_CPORT 32
+#define GB_NL_NAME "GREYBUS" +#define GB_NL_PID 1
+enum {
- GB_NL_A_UNSPEC,
- GB_NL_A_DATA,
- GB_NL_A_CPORT,
- __GB_NL_A_MAX,
+};
+#define GB_NL_A_MAX (__GB_NL_A_MAX - 1)
+enum {
- GB_NL_C_UNSPEC,
- GB_NL_C_MSG,
- __GB_NL_C_MAX,
+};
+#define GB_NL_C_MAX (__GB_NL_C_MAX - 1)
+#endif /* __GB_NETLINK_H */ diff --git a/drivers/staging/greybus/netlink.c b/drivers/staging/greybus/netlink.c new file mode 100644 index 0000000..84f3018 --- /dev/null +++ b/drivers/staging/greybus/netlink.c @@ -0,0 +1,221 @@ +/*
- Greybus Netlink driver for userspace controller
- Copyright (c) 2017 BayLibre SAS
- Released under the GPLv2 only.
- */
+#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <net/genetlink.h>
+#include "greybus.h" +#include "gb_netlink.h"
+static dev_t major_dev; +static struct class *gb_nl_class; +static struct genl_family gb_nl_family; +static struct gb_host_device *gb_nl_hd;
+#define VERSION_NR 1
+#define DEVICE_NAME "gb_netlink" +#define CLASS_NAME "gb_netlink"
+static int gb_netlink_msg(struct sk_buff *skb, struct genl_info *info) +{
- struct nlattr *na;
- u16 cport_id;
- void *data;
- if (!info)
return -EPROTO;
- na = info->attrs[GB_NL_A_CPORT];
- if (!na) {
dev_err(&gb_nl_hd->dev,
"Received message without cport id attribute\n");
return -EPROTO;
- }
- cport_id = nla_get_u32(na);
- if (!cport_id_valid(gb_nl_hd, cport_id)) {
dev_err(&gb_nl_hd->dev, "invalid cport id %u received",
cport_id);
return -EINVAL;
- }
- na = info->attrs[GB_NL_A_DATA];
- if (!na) {
dev_err(&gb_nl_hd->dev,
"Received message without data attribute\n");
return -EPROTO;
- }
- data = nla_data(na);
- if (!data) {
dev_err(&gb_nl_hd->dev,
"Received message without data\n");
return -EINVAL;
- }
- greybus_data_rcvd(gb_nl_hd, cport_id, data, nla_len(na));
- return 0;
+}
+static struct nla_policy gb_nl_policy[GB_NL_A_MAX + 1] = {
- [GB_NL_A_DATA] = { .type = NLA_BINARY, .len = GB_NETLINK_MTU },
- [GB_NL_A_CPORT] = { .type = NLA_U16},
+};
+static struct genl_ops gb_nl_ops[] = {
- {
.cmd = GB_NL_C_MSG,
.policy = gb_nl_policy,
.doit = gb_netlink_msg,
- },
+};
+static struct genl_family gb_nl_family = {
- .hdrsize = 0,
- .name = GB_NL_NAME,
- .version = VERSION_NR,
- .maxattr = GB_NL_A_MAX,
- .ops = gb_nl_ops,
- .n_ops = ARRAY_SIZE(gb_nl_ops),
+};
+static int message_send(struct gb_host_device *hd, u16 cport_id,
struct gb_message *message, gfp_t gfp_mask)
+{
- struct nl_msg *nl_msg;
- struct sk_buff *skb;
- int retval = -ENOMEM;
- skb = genlmsg_new(sizeof(*message->header) + sizeof(u32) +
message->payload_size, GFP_KERNEL);
- if (!skb)
goto err_out;
- nl_msg = genlmsg_put(skb, GB_NL_PID, 0,
&gb_nl_family, 0, GB_NL_C_MSG);
- if (!nl_msg)
goto err_free;
- retval = nla_put_u32(skb, GB_NL_A_CPORT, cport_id);
- if (retval)
goto err_cancel;
- retval = nla_put(skb, GB_NL_A_DATA,
sizeof(*message->header) + message->payload_size,
message->header);
- if (retval)
goto err_cancel;
- genlmsg_end(skb, nl_msg);
- retval = genlmsg_unicast(&init_net, skb, GB_NL_PID);
- if (retval)
goto err_cancel;
- greybus_message_sent(hd, message, 0);
- return 0;
+err_cancel:
- genlmsg_cancel(skb, nl_msg);
+err_free:
- nlmsg_free(skb);
+err_out:
- return retval;
+}
+static void message_cancel(struct gb_message *message) +{ +}
+static struct gb_hd_driver tcpip_driver = {
- .message_send = message_send,
- .message_cancel = message_cancel,
+};
+static void __exit gb_netlink_exit(void) +{
- if (!gb_nl_hd)
return;
- gb_hd_del(gb_nl_hd);
- gb_hd_put(gb_nl_hd);
- gb_nl_hd = NULL;
- unregister_chrdev_region(major_dev, 1);
- device_destroy(gb_nl_class, major_dev);
- class_destroy(gb_nl_class);
- genl_unregister_family(&gb_nl_family);
+}
+static int __init gb_netlink_init(void) +{
- int retval;
- struct device *dev;
- struct gb_host_device *gb_nl_hd;
- retval = genl_register_family(&gb_nl_family);
- if (retval)
return retval;
- retval = alloc_chrdev_region(&major_dev, 0, 1, DEVICE_NAME);
- if (retval)
goto err_genl_unregister;
- gb_nl_class = class_create(THIS_MODULE, CLASS_NAME);
- if (IS_ERR(gb_nl_class)) {
retval = PTR_ERR(gb_nl_class);
goto err_chrdev_unregister;
- }
- dev = device_create(gb_nl_class, NULL, major_dev, NULL, DEVICE_NAME);
- if (IS_ERR(dev)) {
retval = PTR_ERR(dev);
goto err_class_destroy;
- }
What do you do with this character device? Can you just use a misc device instead?
thanks,
greg k-h
On 04/18/2017 01:59 PM, Greg KH wrote:
On Sun, Mar 26, 2017 at 06:58:24PM +0200, Alexandre Bailon wrote:
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Very cool stuff, any hints on how to use this over netlink? Will the network developers get mad at this as an abuse of the transport?
Currently, I haven't documented anything. The only hint I can gives is to take a look https://github.com/anobli/gbridge/blob/master/controllers/gb_netlink.c, which is source code of gbridge that deals with generic netlink. I think I should have a least documented the data format generic netlink operations.
I'm not sure to understand your point about the abuse of the transport.
Signed-off-by: Alexandre Bailon abailon@baylibre.com
drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/gb_netlink.h | 37 ++++++ drivers/staging/greybus/netlink.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index 50de2d7..f9f3526 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -27,6 +27,15 @@ config GREYBUS_ES2 To compile this code as a module, chose M here: the module will be called gb-es2.ko +config GREYBUS_NETLINK
- tristate "Greybus netlink host controller"
- ---help---
Select this option if you want to implement a Greybus
"host controller" in userspace.
To compile this code as a module, chose M here: the module
will be called gb-netlink.ko
Doesn't this need to depend on netlink to build properly?
I think so. I will check.
thanks,
greg k-h
Thanks, Alexandre
On 04/18/2017 02:01 PM, Greg KH wrote:
On Sun, Mar 26, 2017 at 06:58:24PM +0200, Alexandre Bailon wrote:
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Signed-off-by: Alexandre Bailon abailon@baylibre.com
drivers/staging/greybus/Kconfig | 9 ++ drivers/staging/greybus/Makefile | 2 + drivers/staging/greybus/gb_netlink.h | 37 ++++++ drivers/staging/greybus/netlink.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 drivers/staging/greybus/gb_netlink.h create mode 100644 drivers/staging/greybus/netlink.c
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig index 50de2d7..f9f3526 100644 --- a/drivers/staging/greybus/Kconfig +++ b/drivers/staging/greybus/Kconfig @@ -27,6 +27,15 @@ config GREYBUS_ES2 To compile this code as a module, chose M here: the module will be called gb-es2.ko +config GREYBUS_NETLINK
- tristate "Greybus netlink host controller"
- ---help---
Select this option if you want to implement a Greybus
"host controller" in userspace.
To compile this code as a module, chose M here: the module
will be called gb-netlink.ko
- config GREYBUS_AUDIO tristate "Greybus Audio Class driver" depends on SOUND
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index b26b9a3..d057f1d 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -20,8 +20,10 @@ ccflags-y += -I$(src) # Greybus Host controller drivers gb-es2-y := es2.o +gb-netlink-y := netlink.o obj-$(CONFIG_GREYBUS_ES2) += gb-es2.o +obj-$(CONFIG_GREYBUS_NETLINK) += gb-netlink.o # Greybus class drivers gb-bootrom-y := bootrom.o diff --git a/drivers/staging/greybus/gb_netlink.h b/drivers/staging/greybus/gb_netlink.h new file mode 100644 index 0000000..4af6fe5 --- /dev/null +++ b/drivers/staging/greybus/gb_netlink.h @@ -0,0 +1,37 @@ +/*
- Greybus Netlink driver for userspace controller
- Copyright (c) 2017 BayLibre SAS
- Released under the GPLv2 only.
- */
+#ifndef __GB_NETLINK_H +#define __GB_NETLINK_H
+/* Maximum packet size */ +#define GB_NETLINK_MTU 2048 +/* Maximum number of Cports */ +#define GB_NETLINK_NUM_CPORT 32
+#define GB_NL_NAME "GREYBUS" +#define GB_NL_PID 1
+enum {
- GB_NL_A_UNSPEC,
- GB_NL_A_DATA,
- GB_NL_A_CPORT,
- __GB_NL_A_MAX,
+};
+#define GB_NL_A_MAX (__GB_NL_A_MAX - 1)
+enum {
- GB_NL_C_UNSPEC,
- GB_NL_C_MSG,
- __GB_NL_C_MAX,
+};
+#define GB_NL_C_MAX (__GB_NL_C_MAX - 1)
+#endif /* __GB_NETLINK_H */ diff --git a/drivers/staging/greybus/netlink.c b/drivers/staging/greybus/netlink.c new file mode 100644 index 0000000..84f3018 --- /dev/null +++ b/drivers/staging/greybus/netlink.c @@ -0,0 +1,221 @@ +/*
- Greybus Netlink driver for userspace controller
- Copyright (c) 2017 BayLibre SAS
- Released under the GPLv2 only.
- */
+#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <net/genetlink.h>
+#include "greybus.h" +#include "gb_netlink.h"
+static dev_t major_dev; +static struct class *gb_nl_class; +static struct genl_family gb_nl_family; +static struct gb_host_device *gb_nl_hd;
+#define VERSION_NR 1
+#define DEVICE_NAME "gb_netlink" +#define CLASS_NAME "gb_netlink"
+static int gb_netlink_msg(struct sk_buff *skb, struct genl_info *info) +{
- struct nlattr *na;
- u16 cport_id;
- void *data;
- if (!info)
return -EPROTO;
- na = info->attrs[GB_NL_A_CPORT];
- if (!na) {
dev_err(&gb_nl_hd->dev,
"Received message without cport id attribute\n");
return -EPROTO;
- }
- cport_id = nla_get_u32(na);
- if (!cport_id_valid(gb_nl_hd, cport_id)) {
dev_err(&gb_nl_hd->dev, "invalid cport id %u received",
cport_id);
return -EINVAL;
- }
- na = info->attrs[GB_NL_A_DATA];
- if (!na) {
dev_err(&gb_nl_hd->dev,
"Received message without data attribute\n");
return -EPROTO;
- }
- data = nla_data(na);
- if (!data) {
dev_err(&gb_nl_hd->dev,
"Received message without data\n");
return -EINVAL;
- }
- greybus_data_rcvd(gb_nl_hd, cport_id, data, nla_len(na));
- return 0;
+}
+static struct nla_policy gb_nl_policy[GB_NL_A_MAX + 1] = {
- [GB_NL_A_DATA] = { .type = NLA_BINARY, .len = GB_NETLINK_MTU },
- [GB_NL_A_CPORT] = { .type = NLA_U16},
+};
+static struct genl_ops gb_nl_ops[] = {
- {
.cmd = GB_NL_C_MSG,
.policy = gb_nl_policy,
.doit = gb_netlink_msg,
- },
+};
+static struct genl_family gb_nl_family = {
- .hdrsize = 0,
- .name = GB_NL_NAME,
- .version = VERSION_NR,
- .maxattr = GB_NL_A_MAX,
- .ops = gb_nl_ops,
- .n_ops = ARRAY_SIZE(gb_nl_ops),
+};
+static int message_send(struct gb_host_device *hd, u16 cport_id,
struct gb_message *message, gfp_t gfp_mask)
+{
- struct nl_msg *nl_msg;
- struct sk_buff *skb;
- int retval = -ENOMEM;
- skb = genlmsg_new(sizeof(*message->header) + sizeof(u32) +
message->payload_size, GFP_KERNEL);
- if (!skb)
goto err_out;
- nl_msg = genlmsg_put(skb, GB_NL_PID, 0,
&gb_nl_family, 0, GB_NL_C_MSG);
- if (!nl_msg)
goto err_free;
- retval = nla_put_u32(skb, GB_NL_A_CPORT, cport_id);
- if (retval)
goto err_cancel;
- retval = nla_put(skb, GB_NL_A_DATA,
sizeof(*message->header) + message->payload_size,
message->header);
- if (retval)
goto err_cancel;
- genlmsg_end(skb, nl_msg);
- retval = genlmsg_unicast(&init_net, skb, GB_NL_PID);
- if (retval)
goto err_cancel;
- greybus_message_sent(hd, message, 0);
- return 0;
+err_cancel:
- genlmsg_cancel(skb, nl_msg);
+err_free:
- nlmsg_free(skb);
+err_out:
- return retval;
+}
+static void message_cancel(struct gb_message *message) +{ +}
+static struct gb_hd_driver tcpip_driver = {
- .message_send = message_send,
- .message_cancel = message_cancel,
+};
+static void __exit gb_netlink_exit(void) +{
- if (!gb_nl_hd)
return;
- gb_hd_del(gb_nl_hd);
- gb_hd_put(gb_nl_hd);
- gb_nl_hd = NULL;
- unregister_chrdev_region(major_dev, 1);
- device_destroy(gb_nl_class, major_dev);
- class_destroy(gb_nl_class);
- genl_unregister_family(&gb_nl_family);
+}
+static int __init gb_netlink_init(void) +{
- int retval;
- struct device *dev;
- struct gb_host_device *gb_nl_hd;
- retval = genl_register_family(&gb_nl_family);
- if (retval)
return retval;
- retval = alloc_chrdev_region(&major_dev, 0, 1, DEVICE_NAME);
- if (retval)
goto err_genl_unregister;
- gb_nl_class = class_create(THIS_MODULE, CLASS_NAME);
- if (IS_ERR(gb_nl_class)) {
retval = PTR_ERR(gb_nl_class);
goto err_chrdev_unregister;
- }
- dev = device_create(gb_nl_class, NULL, major_dev, NULL, DEVICE_NAME);
- if (IS_ERR(dev)) {
retval = PTR_ERR(dev);
goto err_class_destroy;
- }
What do you do with this character device? Can you just use a misc device instead?
I'm doing nothing with the character device. Actually, I just need to have a parent device for greybus. I will take a look to the misc device.
thanks,
greg k-h
Thanks, Alexandre
On Fri, May 05, 2017 at 11:43:28AM +0200, Alexandre Bailon wrote:
- dev = device_create(gb_nl_class, NULL, major_dev, NULL, DEVICE_NAME);
- if (IS_ERR(dev)) {
retval = PTR_ERR(dev);
goto err_class_destroy;
- }
What do you do with this character device? Can you just use a misc device instead?
I'm doing nothing with the character device. Actually, I just need to have a parent device for greybus. I will take a look to the misc device.
Hm, how about just a dummy "virtual" device instead? That will be "cleaner" and will not burn a character device node for no reason.
thanks,
greg k-h
On Fri, May 05, 2017 at 11:38:38AM +0200, Alexandre Bailon wrote:
On 04/18/2017 01:59 PM, Greg KH wrote:
On Sun, Mar 26, 2017 at 06:58:24PM +0200, Alexandre Bailon wrote:
Currently, the only hd controller supported by Greybus is the es2 controller which only support is mainly a bridge between USB and UniPro. In order to use Greybus on devices that do not support UniPro, add a the Greybus netlink hd controller.
By using Generic Netlink, userspace can act as a bridge between Greybus and any kind of bus supported by the platform (e.g. Bluetooth). In addition, this add an easy way to implement some component such as SVC which is required by Greybus though it may not be available on every platforms.
Very cool stuff, any hints on how to use this over netlink? Will the network developers get mad at this as an abuse of the transport?
Currently, I haven't documented anything. The only hint I can gives is to take a look https://github.com/anobli/gbridge/blob/master/controllers/gb_netlink.c, which is source code of gbridge that deals with generic netlink. I think I should have a least documented the data format generic netlink operations.
I'm not sure to understand your point about the abuse of the transport.
I am not familiar if the network developers like people adding new users of the transport. For some reason I didn't think they did, but I might be totally wrong and thinking of something else.
To compile this code as a module, chose M here: the module
will be called gb-netlink.ko
Doesn't this need to depend on netlink to build properly?
I think so. I will check.
Thanks, I'll wait for your new versions :)
greg k-h