[greybus-dev][PATCH 2/3] staging: greybus: Add Greybus netlink driver

Alexandre Bailon abailon at baylibre.com
Fri May 5 09:43:28 UTC 2017



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 at 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


More information about the devel mailing list