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@xxxxxxxxxxxx> > --- > 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 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel