Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 489895b1 authored by Vamsi Krishna's avatar Vamsi Krishna Committed by Stephen Boyd
Browse files

usb: gadget: android: Add NCM function to android composition



NCM function allows remote networking over USB. Add ncm support
to android usb composition.

Change-Id: Ica0a03c1bb3575466dc856850c7589b3be7e2489
Signed-off-by: default avatarVamsi Krishna <vskrishn@codeaurora.org>
parent 57d86afe
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@
#include "u_uac1.c"
#include "f_uac1.c"
#endif
#include "f_ncm.c"

MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -896,7 +897,108 @@ static struct android_usb_function gps_function = {
	.bind_config	= gps_function_bind_config,
};

/* ncm */
struct ncm_function_config {
	u8      ethaddr[ETH_ALEN];
	struct eth_dev *dev;
};
static int
ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *c)
{
	f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL);
	if (!f->config)
		return -ENOMEM;

	return 0;
}

static void ncm_function_cleanup(struct android_usb_function *f)
{
	kfree(f->config);
	f->config = NULL;
}

static int
ncm_function_bind_config(struct android_usb_function *f,
				struct usb_configuration *c)
{
	struct ncm_function_config *ncm = f->config;
	int ret;
	struct eth_dev *dev;

	if (!ncm) {
		pr_err("%s: ncm config is null\n", __func__);
		return -EINVAL;
	}

	pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
		ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
		ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);

	dev = gether_setup_name(c->cdev->gadget, ncm->ethaddr, "ncm");
	if (IS_ERR(dev)) {
		ret = PTR_ERR(dev);
		pr_err("%s: gether setup failed err:%d\n", __func__, ret);
		return ret;
	}
	ncm->dev = dev;

	ret = ncm_bind_config(c, ncm->ethaddr, dev);
	if (ret) {
		pr_err("%s: ncm bind config failed err:%d", __func__, ret);
		gether_cleanup(dev);
		return ret;
	}

	return ret;
}

static void ncm_function_unbind_config(struct android_usb_function *f,
						struct usb_configuration *c)
{
	struct ncm_function_config *ncm = f->config;
	gether_cleanup(ncm->dev);
}

static ssize_t ncm_ethaddr_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct android_usb_function *f = dev_get_drvdata(dev);
	struct ncm_function_config *ncm = f->config;
	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
		ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
		ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
}

static ssize_t ncm_ethaddr_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct android_usb_function *f = dev_get_drvdata(dev);
	struct ncm_function_config *ncm = f->config;

	if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
		    (int *)&ncm->ethaddr[0], (int *)&ncm->ethaddr[1],
		    (int *)&ncm->ethaddr[2], (int *)&ncm->ethaddr[3],
		    (int *)&ncm->ethaddr[4], (int *)&ncm->ethaddr[5]) == 6)
		return size;
	return -EINVAL;
}

static DEVICE_ATTR(ncm_ethaddr, S_IRUGO | S_IWUSR, ncm_ethaddr_show,
					       ncm_ethaddr_store);
static struct device_attribute *ncm_function_attributes[] = {
	&dev_attr_ncm_ethaddr,
	NULL
};

static struct android_usb_function ncm_function = {
	.name		= "ncm",
	.init		= ncm_function_init,
	.cleanup	= ncm_function_cleanup,
	.bind_config	= ncm_function_bind_config,
	.unbind_config	= ncm_function_unbind_config,
	.attributes	= ncm_function_attributes,
};
/* ecm transport string */
static char ecm_transports[MAX_XPORT_STR_LEN];

@@ -1971,6 +2073,7 @@ static struct android_usb_function *supported_functions[] = {
	&rndis_function,
	&rndis_qc_function,
	&ecm_function,
	&ncm_function,
	&mass_storage_function,
	&accessory_function,
#ifdef CONFIG_SND_PCM
+38 −23
Original line number Diff line number Diff line
@@ -24,6 +24,21 @@

#include "u_ether.h"

#undef DBG
#undef VDBG
#undef ERROR
#undef INFO

#define DBG(d, fmt, args...) \
	dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) \
	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
#define ERROR(d, fmt, args...) \
	dev_err(&(d)->gadget->dev , fmt , ## args)
#define WARNING(d, fmt, args...) \
	dev_warn(&(d)->gadget->dev , fmt , ## args)
#define INFO(d, fmt, args...) \
	dev_info(&(d)->gadget->dev , fmt , ## args)
/*
 * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
 * NCM is intended to be used with high-speed network attachments.
@@ -125,7 +140,7 @@ static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
#define NCM_STATUS_INTERVAL_MS		32
#define NCM_STATUS_BYTECOUNT		16	/* 8 byte header + data */

static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
static struct usb_interface_assoc_descriptor ncm_iad_desc = {
	.bLength =		sizeof ncm_iad_desc,
	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,

@@ -139,7 +154,7 @@ static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {

/* interface descriptor: */

static struct usb_interface_descriptor ncm_control_intf __initdata = {
static struct usb_interface_descriptor ncm_control_intf = {
	.bLength =		sizeof ncm_control_intf,
	.bDescriptorType =	USB_DT_INTERFACE,

@@ -151,7 +166,7 @@ static struct usb_interface_descriptor ncm_control_intf __initdata = {
	/* .iInterface = DYNAMIC */
};

static struct usb_cdc_header_desc ncm_header_desc __initdata = {
static struct usb_cdc_header_desc ncm_header_desc = {
	.bLength =		sizeof ncm_header_desc,
	.bDescriptorType =	USB_DT_CS_INTERFACE,
	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -159,7 +174,7 @@ static struct usb_cdc_header_desc ncm_header_desc __initdata = {
	.bcdCDC =		cpu_to_le16(0x0110),
};

static struct usb_cdc_union_desc ncm_union_desc __initdata = {
static struct usb_cdc_union_desc ncm_union_desc = {
	.bLength =		sizeof(ncm_union_desc),
	.bDescriptorType =	USB_DT_CS_INTERFACE,
	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
@@ -167,8 +182,8 @@ static struct usb_cdc_union_desc ncm_union_desc __initdata = {
	/* .bSlaveInterface0 =	DYNAMIC */
};

static struct usb_cdc_ether_desc ecm_desc __initdata = {
	.bLength =		sizeof ecm_desc,
static struct usb_cdc_ether_desc necm_desc = {
	.bLength =		sizeof necm_desc,
	.bDescriptorType =	USB_DT_CS_INTERFACE,
	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,

@@ -182,7 +197,7 @@ static struct usb_cdc_ether_desc ecm_desc __initdata = {

#define NCAPS	(USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)

static struct usb_cdc_ncm_desc ncm_desc __initdata = {
static struct usb_cdc_ncm_desc ncm_desc = {
	.bLength =		sizeof ncm_desc,
	.bDescriptorType =	USB_DT_CS_INTERFACE,
	.bDescriptorSubType =	USB_CDC_NCM_TYPE,
@@ -194,7 +209,7 @@ static struct usb_cdc_ncm_desc ncm_desc __initdata = {

/* the default data interface has no endpoints ... */

static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
static struct usb_interface_descriptor ncm_data_nop_intf = {
	.bLength =		sizeof ncm_data_nop_intf,
	.bDescriptorType =	USB_DT_INTERFACE,

@@ -209,7 +224,7 @@ static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {

/* ... but the "real" data interface has two bulk endpoints */

static struct usb_interface_descriptor ncm_data_intf __initdata = {
static struct usb_interface_descriptor ncm_data_intf = {
	.bLength =		sizeof ncm_data_intf,
	.bDescriptorType =	USB_DT_INTERFACE,

@@ -224,7 +239,7 @@ static struct usb_interface_descriptor ncm_data_intf __initdata = {

/* full speed support: */

static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -234,7 +249,7 @@ static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
	.bInterval =		NCM_STATUS_INTERVAL_MS,
};

static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_in_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -242,7 +257,7 @@ static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
};

static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
static struct usb_endpoint_descriptor fs_ncm_out_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -250,13 +265,13 @@ static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
};

static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
static struct usb_descriptor_header *ncm_fs_function[] = {
	(struct usb_descriptor_header *) &ncm_iad_desc,
	/* CDC NCM control descriptors */
	(struct usb_descriptor_header *) &ncm_control_intf,
	(struct usb_descriptor_header *) &ncm_header_desc,
	(struct usb_descriptor_header *) &ncm_union_desc,
	(struct usb_descriptor_header *) &ecm_desc,
	(struct usb_descriptor_header *) &necm_desc,
	(struct usb_descriptor_header *) &ncm_desc,
	(struct usb_descriptor_header *) &fs_ncm_notify_desc,
	/* data interface, altsettings 0 and 1 */
@@ -269,7 +284,7 @@ static struct usb_descriptor_header *ncm_fs_function[] __initdata = {

/* high speed support: */

static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -278,7 +293,7 @@ static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
	.wMaxPacketSize =	cpu_to_le16(NCM_STATUS_BYTECOUNT),
	.bInterval =		USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS),
};
static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_in_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -287,7 +302,7 @@ static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
	.wMaxPacketSize =	cpu_to_le16(512),
};

static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
static struct usb_endpoint_descriptor hs_ncm_out_desc = {
	.bLength =		USB_DT_ENDPOINT_SIZE,
	.bDescriptorType =	USB_DT_ENDPOINT,

@@ -296,13 +311,13 @@ static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
	.wMaxPacketSize =	cpu_to_le16(512),
};

static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
static struct usb_descriptor_header *ncm_hs_function[] = {
	(struct usb_descriptor_header *) &ncm_iad_desc,
	/* CDC NCM control descriptors */
	(struct usb_descriptor_header *) &ncm_control_intf,
	(struct usb_descriptor_header *) &ncm_header_desc,
	(struct usb_descriptor_header *) &ncm_union_desc,
	(struct usb_descriptor_header *) &ecm_desc,
	(struct usb_descriptor_header *) &necm_desc,
	(struct usb_descriptor_header *) &ncm_desc,
	(struct usb_descriptor_header *) &hs_ncm_notify_desc,
	/* data interface, altsettings 0 and 1 */
@@ -317,7 +332,7 @@ static struct usb_descriptor_header *ncm_hs_function[] __initdata = {

#define STRING_CTRL_IDX	0
#define STRING_MAC_IDX	1
#define STRING_DATA_IDX	2
#define NCM_STRING_DATA_IDX	2
#define STRING_IAD_IDX	3

static struct usb_string ncm_string_defs[] = {
@@ -1152,7 +1167,7 @@ static void ncm_close(struct gether *geth)

/* ethernet function driver setup/binding */

static int __init
static int
ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
@@ -1287,7 +1302,7 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
 * Caller must have called @gether_setup().  Caller is also responsible
 * for calling @gether_cleanup() before module unload.
 */
int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		struct eth_dev *dev)
{
	struct f_ncm	*ncm;
@@ -1307,7 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
		ncm_data_nop_intf.iInterface = status;
		ncm_data_intf.iInterface = status;

		ecm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id;
		necm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id;
		ncm_iad_desc.iFunction = ncm_string_defs[STRING_IAD_IDX].id;
	}