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

Commit 58f78dbf authored by Vamsi Krishna Samavedam's avatar Vamsi Krishna Samavedam
Browse files

usb: gadget: Add support for different rndis usbif class codes

RNDIS (Remote NDIS) is supported using many combinations of class,
subclass and protocol. Enhance the current implementation to allow
dynamically choosing one of the combinations. Currently, Windows7/
Windows10 automatically loads RNDIS drivers for class drivers which
represents MISC_ACTIVE_SYNC, MISC_RNDIS_OVER_ETHERNET and
WIRELESS_CONTROLLER_REMOTE_NDIS. All the codes listed below are from
http://www.usb.org/developers/defined_class

 and its unknown why windows
loads rndis class driver for some of them.  Note that, Windows loads
NDIS6 stack automatically for MISC_RNDIS_OVER_ETHERNET. Windows loads
NDIS5 stack for MISC_ACTIVE_SYNC and WIRELESS_CONTROLLER_REMOTE_NDIS.
For other class codes, NDIS stack can be installed using customized INF
file but that defeats the purpose as its expected to load drivers
automatically for known class drivers published by usbif.  Linux rndis
host driver supports MISC_ACTIVE_SYNC and WIRELESS_CONTROLLER_REMOTE_NDIS
as of now.

rndis_class_id - usb class/subclass/protocol
 1	- 	WIRELESS_CONTROLLER_REMOTE_NDIS (0xE0/0x1/0x3)
 2	-	MISC_ACTIVE_SYNC(0xEF/0x1/0x1)
 3	-	MISC_RNDIS_OVER_ETHERNET(0xEF/0x4/0x1)
 4	-	MISC_RNDIS_OVER_WIFI(0xEF/0x4/0x2)
 5	-	MISC_RNDIS_OVER_WIMAX(0xEF/0x4/0x3)
 6	-	MISC_RNDIS_OVER_WWAN(0xEF/0x4/0x4)
 7	-	MISC_RNDIS_FOR_IPV4(0xEF/0x4/0x5)
 8	-	MISC_RNDIS_FOR_IPV6(0xEF/0x4/0x6)
 9	-	MISC_RNDIS_FOR_GPRS(0xEF/0x4/0x7)

Example: to select MISC_RNDIS_OVER_ETHERNET use following command:

echo 3 > /config/usb_gadget/g1/functions/gsi.rndis/rndis_class_id

Change-Id: Ic650867b3038556d055c4449372103564ae95a11
Signed-off-by: default avatarVamsi Krishna Samavedam <vskrishn@codeaurora.org>
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent d91ef6f6
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -2507,6 +2507,10 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
	struct f_gsi *gsi = func_to_gsi(f);
	struct rndis_params *params;
	int status;
	__u8  class;
	__u8  subclass;
	__u8  proto;


	if (gsi->prot_id == IPA_USB_RMNET ||
		gsi->prot_id == IPA_USB_DIAG)
@@ -2588,6 +2592,80 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
					DEFAULT_PKT_ALIGNMENT_FACTOR);
		rndis_set_pkt_alignment_factor(gsi->params,
					DEFAULT_PKT_ALIGNMENT_FACTOR);

		/* Windows7/Windows10 automatically loads RNDIS drivers for
		 * class drivers which represents MISC_ACTIVE_SYNC,
		 * MISC_RNDIS_OVER_ETHERNET & WIRELESS_CONTROLLER_REMOTE_NDIS.
		 * All the codes listed below are from
		 * http://www.usb.org/developers/defined_class and its unknown
		 * why windows loads rndis class driver for some of them.
		 * Note that, Windows loads NDIS6 stack automatically for
		 * MISC_RNDIS_OVER_ETHERNET. Windows loads NDIS5 stack for
		 * MISC_ACTIVE_SYNC and WIRELESS_CONTROLLER_REMOTE_NDIS.
		 * For other class codes, NDIS stack can be selected using
		 * customized INF file but that defeats the purpose as its
		 * expected to load drivers automatically for known class
		 * drivers published by usbif.
		 * Linux rndis host driver supports MISC_ACTIVE_SYNC and
		 * WIRELESS_CONTROLLER_REMOTE_NDIS as of now.
		 */
		switch (gsi->rndis_id) {
		default:
			/* fall throug */
		case WIRELESS_CONTROLLER_REMOTE_NDIS:
			class = USB_CLASS_WIRELESS_CONTROLLER;
			subclass = 0x01;
			proto = 0x03;
			break;
		case MISC_ACTIVE_SYNC:
			class = USB_CLASS_MISC;
			subclass = 0x01;
			proto = 0x01;
			break;
		case MISC_RNDIS_OVER_ETHERNET:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x01;
			break;
		case MISC_RNDIS_OVER_WIFI:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x02;
			break;
		case MISC_RNDIS_OVER_WIMAX:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x03;
			break;
		case MISC_RNDIS_OVER_WWAN:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x04;
			break;
		case MISC_RNDIS_FOR_IPV4:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x05;
			break;
		case MISC_RNDIS_FOR_IPV6:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x06;
			break;
		case MISC_RNDIS_FOR_GPRS:
			class = USB_CLASS_MISC;
			subclass = 0x04;
			proto = 0x07;
			break;
		}

		info.iad_desc->bFunctionClass = class;
		info.iad_desc->bFunctionSubClass = subclass;
		info.iad_desc->bFunctionProtocol = proto;
		info.ctrl_desc->bInterfaceClass = class;
		info.ctrl_desc->bInterfaceSubClass = subclass;
		info.ctrl_desc->bInterfaceProtocol = proto;

		break;
	case IPA_USB_MBIM:
		info.string_defs = mbim_gsi_string_defs;
@@ -3086,6 +3164,43 @@ static struct config_item_type gsi_func_type = {
	.ct_owner	= THIS_MODULE,
};

static ssize_t gsi_rndis_class_id_show(struct config_item *item, char *page)
{
	struct f_gsi *gsi = to_gsi_opts(item)->gsi;

	return snprintf(page, PAGE_SIZE, "%d\n", gsi->rndis_id);
}

static ssize_t gsi_rndis_class_id_store(struct config_item *item,
			const char *page, size_t len)
{
	struct f_gsi *gsi = to_gsi_opts(item)->gsi;
	u8 id;

	if (kstrtou8(page, 0, &id))
		return -EINVAL;

	if (id > RNDIS_ID_UNKNOWN && id < RNDIS_ID_MAX)
		gsi->rndis_id = id;
	else
		return -EINVAL;

	return len;
}
CONFIGFS_ATTR(gsi_, rndis_class_id);

static struct configfs_attribute *gsi_rndis_attrs[] = {
	&gsi_attr_info,
	&gsi_attr_rndis_class_id,
	NULL,
};

static struct config_item_type gsi_func_rndis_type = {
	.ct_item_ops	= &gsi_item_ops,
	.ct_attrs	= gsi_rndis_attrs,
	.ct_owner	= THIS_MODULE,
};

static void gsi_inst_clean(struct gsi_opts *opts)
{
	if (opts->gsi->c_port.ctrl_device.fops)
@@ -3127,6 +3242,10 @@ static int gsi_set_inst_name(struct usb_function_instance *fi,
	}
	mutex_unlock(&inst_status[prot_id].gsi_lock);

	if (prot_id == IPA_USB_RNDIS)
		config_group_init_type_name(&opts->func_inst.group, "",
					    &gsi_func_rndis_type);

	gsi = gsi_function_init(prot_id);
	if (IS_ERR(gsi))
		return PTR_ERR(gsi);
+15 −0
Original line number Diff line number Diff line
@@ -122,6 +122,20 @@ enum gsi_ctrl_notify_state {
	GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE,
};

enum rndis_class_id {
	RNDIS_ID_UNKNOWN,
	WIRELESS_CONTROLLER_REMOTE_NDIS,
	MISC_ACTIVE_SYNC,
	MISC_RNDIS_OVER_ETHERNET,
	MISC_RNDIS_OVER_WIFI,
	MISC_RNDIS_OVER_WIMAX,
	MISC_RNDIS_OVER_WWAN,
	MISC_RNDIS_FOR_IPV4,
	MISC_RNDIS_FOR_IPV6,
	MISC_RNDIS_FOR_GPRS,
	RNDIS_ID_MAX,
};

#define MAXQUEUELEN 128
struct event_queue {
	u8 event[MAXQUEUELEN];
@@ -258,6 +272,7 @@ struct f_gsi {
	struct rndis_params *params;
	atomic_t connected;
	bool data_interface_up;
	enum rndis_class_id rndis_id;

	const struct usb_endpoint_descriptor *in_ep_desc_backup;
	const struct usb_endpoint_descriptor *out_ep_desc_backup;