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

Commit 27c11f8d authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: Allow f_rndis and f_gsi to coexist as modules"

parents d740f473 54f034f4
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -62,5 +62,8 @@ usb_f_ccid-y := f_ccid.o
obj-$(CONFIG_USB_F_CCID)	+= usb_f_ccid.o
usb_f_cdev-y			:= f_cdev.o
obj-$(CONFIG_USB_F_CDEV)	+= usb_f_cdev.o
usb_f_gsi-y			:= f_gsi.o rndis.o
usb_f_gsi-y			:= f_gsi.o
ifeq ($(CONFIG_USB_F_RNDIS),)
usb_f_gsi-y			+= rndis.o
endif
obj-$(CONFIG_USB_F_GSI)		+= usb_f_gsi.o
+67 −26
Original line number Diff line number Diff line
@@ -2038,20 +2038,47 @@ static void gsi_rndis_command_complete(struct usb_ep *ep,
		struct usb_request *req)
{
	struct f_gsi *gsi = req->context;
	rndis_init_msg_type *buf;
	int status;
	u32 MsgType;

	if (!req->buf || !gsi->params)
		return;

	MsgType = get_unaligned_le32((__le32 *)req->buf);

	/* intercept halt message to perform flow control */
	if (MsgType == RNDIS_MSG_HALT) {
		log_event_dbg("RNDIS_MSG_HALT, state:%d\n",
				gsi->params->state);
		if (gsi->params->state == RNDIS_DATA_INITIALIZED)
			gsi_rndis_flow_ctrl_enable(true, gsi->params);
		gsi->params->state = RNDIS_UNINITIALIZED;
		return;
	}

	status = rndis_msg_parser(gsi->params, (u8 *) req->buf);
	if (status < 0)
		log_event_err("RNDIS command error %d, %d/%d",
			status, req->actual, req->length);

	buf = (rndis_init_msg_type *)req->buf;
	if (le32_to_cpu(buf->MessageType) == RNDIS_MSG_INIT) {
	if (MsgType == RNDIS_MSG_INIT) {
		rndis_init_msg_type *buf = (rndis_init_msg_type *)req->buf;

		log_event_dbg("RNDIS host major:%d minor:%d version\n",
				le32_to_cpu(buf->MajorVersion),
				le32_to_cpu(buf->MinorVersion));

		/* honor host dl aggr size */
		gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
		log_event_dbg("RNDIS host dl_aggr_size:%d\n",
				gsi->params->dl_max_xfer_size);
		gsi->d_port.in_aggr_size = le32_to_cpu(buf->MaxTransferSize);
		log_event_dbg("RNDIS host DL MaxTransferSize:%d\n",
				le32_to_cpu(buf->MaxTransferSize));
	} else if (MsgType == RNDIS_MSG_SET) {
		rndis_set_msg_type *buf = (rndis_set_msg_type *)req->buf;

		if (le32_to_cpu(buf->OID) ==
				RNDIS_OID_GEN_CURRENT_PACKET_FILTER)
			gsi_rndis_flow_ctrl_enable(!(*gsi->params->filter),
					gsi->params);
	}
}

@@ -2182,13 +2209,37 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
			goto invalid;

		if (gsi->prot_id == IPA_USB_RNDIS) {
			rndis_init_cmplt_type *res;

			/* return the result */
			buf = rndis_get_next_response(gsi->params, &n);
			if (buf) {
			if (!buf)
				break;

			res = (rndis_init_cmplt_type *)buf;
			if (le32_to_cpu(res->MessageType) == RNDIS_MSG_INIT_C) {
				log_event_dbg("%s: max_pkt_per_xfer : %d",
					__func__, DEFAULT_MAX_PKT_PER_XFER);
				res->MaxPacketsPerTransfer =
					cpu_to_le32(DEFAULT_MAX_PKT_PER_XFER);

				res->MaxTransferSize = cpu_to_le32(
					le32_to_cpu(res->MaxTransferSize)
					* DEFAULT_MAX_PKT_PER_XFER);

				/* In case of aggregated packets QC device
				 * will request aliment to 4 (2^2).
				 */
				log_event_dbg("%s: pkt_alignment_factor : %d",
					__func__, DEFAULT_PKT_ALIGNMENT_FACTOR);
				res->PacketAlignmentFactor =
					cpu_to_le32(
						DEFAULT_PKT_ALIGNMENT_FACTOR);
			}

			memcpy(req->buf, buf, n);
			rndis_free_response(gsi->params, buf);
			value = n;
			}
			break;
		}

@@ -2545,8 +2596,11 @@ static void gsi_resume(struct usb_function *f)
	 */
	if (gsi->prot_id == IPA_USB_RNDIS &&
			!usb_gsi_remote_wakeup_allowed(f) &&
			gsi->host_supports_flow_control)
		rndis_flow_control(gsi->params, false);
			gsi->host_supports_flow_control && gsi->params) {
		if (gsi->params->state != RNDIS_DATA_INITIALIZED)
			gsi_rndis_flow_ctrl_enable(false, gsi->params);
		gsi->params->state = RNDIS_DATA_INITIALIZED;
	}

	post_event(&gsi->d_port, EVT_RESUMED);
	queue_delayed_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w, 0);
@@ -2831,8 +2885,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
		info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
		info.notify_buf_len = sizeof(struct usb_cdc_notification);

		params = rndis_register(gsi_rndis_response_available, gsi,
				gsi_rndis_flow_ctrl_enable);
		params = rndis_register(gsi_rndis_response_available, gsi);
		if (IS_ERR(params))
			goto fail;

@@ -2855,18 +2908,6 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
				gsi->manufacturer))
			goto dereg_rndis;

		log_event_dbg("%s: max_pkt_per_xfer : %d", __func__,
					DEFAULT_MAX_PKT_PER_XFER);
		rndis_set_max_pkt_xfer(gsi->params, DEFAULT_MAX_PKT_PER_XFER);

		/* In case of aggregated packets QC device will request
		 * aliment to 4 (2^2).
		 */
		log_event_dbg("%s: pkt_alignment_factor : %d", __func__,
					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.
+1 −16
Original line number Diff line number Diff line
@@ -66,8 +66,6 @@
 *   - MS-Windows drivers sometimes emit undocumented requests.
 */

#define RNDIS_UL_MAX_PKT_PER_XFER	3

struct f_rndis {
	struct gether			port;
	u8				ctrl_id, data_id;
@@ -673,7 +671,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
	struct usb_string	*us;
	int			status;
	struct usb_ep		*ep;
	unsigned int		max;

	struct f_rndis_opts *rndis_opts;

@@ -799,11 +796,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)

	rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
	rndis_set_host_mac(rndis->params, rndis->ethaddr);
	max = gether_get_ul_max_pkts_per_xfer(rndis_opts->net);
	if (!max)
		max = RNDIS_UL_MAX_PKT_PER_XFER;

	rndis_set_max_pkt_xfer(rndis->params, max);

	if (rndis->manufacturer && rndis->vendorID &&
			rndis_set_param_vendor(rndis->params, rndis->vendorID,
@@ -884,10 +876,6 @@ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass);
/* f_rndis_opts_protocol */
USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol);

/* f_rndis_opts_ul_max_pkt_per_xfer */
USB_ETHER_CONFIGFS_ITEM_ATTR_UL_MAX_PKT_PER_XFER(rndis);


static struct configfs_attribute *rndis_attrs[] = {
	&rndis_opts_attr_dev_addr,
	&rndis_opts_attr_host_addr,
@@ -896,7 +884,6 @@ static struct configfs_attribute *rndis_attrs[] = {
	&rndis_opts_attr_class,
	&rndis_opts_attr_subclass,
	&rndis_opts_attr_protocol,
	&rndis_opts_attr_ul_max_pkt_per_xfer,
	NULL,
};

@@ -1018,8 +1005,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
	rndis->port.wrap = rndis_add_header;
	rndis->port.unwrap = rndis_rm_hdr;
	if (!gether_get_ul_max_pkts_per_xfer(opts->net))
		rndis->port.ul_max_pkts_per_xfer = RNDIS_UL_MAX_PKT_PER_XFER;

	rndis->port.func.name = "rndis";
	/* descriptors are per-instance copies */
@@ -1030,7 +1015,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
	rndis->port.func.disable = rndis_disable;
	rndis->port.func.free_func = rndis_free;

	params = rndis_register(rndis_response_available, rndis, NULL);
	params = rndis_register(rndis_response_available, rndis);
	if (IS_ERR(params)) {
		kfree(rndis);
		return ERR_CAST(params);
+34 −150
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@

#include "rndis.h"


/* The driver for your USB chip needs to support ep0 OUT to work with
 * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
 *
@@ -522,11 +523,14 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
		 */
		retval = 0;
		if (*params->filter) {
			pr_debug("%s(): disable flow control\n", __func__);
			rndis_flow_control(params, false);
			params->state = RNDIS_DATA_INITIALIZED;
			netif_carrier_on(params->dev);
			if (netif_running(params->dev))
				netif_wake_queue(params->dev);
		} else {
			pr_err("%s(): enable flow control\n", __func__);
			rndis_flow_control(params, true);
			params->state = RNDIS_INITIALIZED;
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
		}
		break;

@@ -570,13 +574,13 @@ static int rndis_init_response(struct rndis_params *params,
	resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
	resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
	resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
		(params->dev->mtu
	resp->MaxPacketsPerTransfer = cpu_to_le32(1);
	resp->MaxTransferSize = cpu_to_le32(
		  params->dev->mtu
		+ sizeof(struct ethhdr)
		+ sizeof(struct rndis_packet_msg_type)
		+ 22));
	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
		+ 22);
	resp->PacketAlignmentFactor = cpu_to_le32(0);
	resp->AFListOffset = cpu_to_le32(0);
	resp->AFListSize = cpu_to_le32(0);

@@ -803,34 +807,19 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
	/* For USB: responses may take up to 10 seconds */
	switch (MsgType) {
	case RNDIS_MSG_INIT:
		pr_debug("%s: RNDIS_MSG_INIT\n", __func__);
		tmp++; /* to get RequestID */
		params->host_rndis_major_ver = get_unaligned_le32(tmp++);
		params->host_rndis_minor_ver = get_unaligned_le32(tmp++);
		params->dl_max_xfer_size = get_unaligned_le32(tmp++);

		pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n",
					__func__, params->host_rndis_major_ver,
					params->host_rndis_minor_ver);
		pr_debug("%s(): DL Max Transfer size:%x\n",
				__func__, params->dl_max_xfer_size);
		pr_debug("%s: RNDIS_MSG_INIT\n",
			__func__);
		params->state = RNDIS_INITIALIZED;
		return rndis_init_response(params, (rndis_init_msg_type *)buf);

	case RNDIS_MSG_HALT:
		pr_debug("%s: RNDIS_MSG_HALT\n",
			__func__);
		if (params->state == RNDIS_DATA_INITIALIZED) {
			if (params->flow_ctrl_enable) {
				params->flow_ctrl_enable(true, params);
			} else {
		params->state = RNDIS_UNINITIALIZED;
		if (params->dev) {
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
		}
			}
			params->state = RNDIS_UNINITIALIZED;
		}
		return 0;

	case RNDIS_MSG_QUERY:
@@ -884,8 +873,7 @@ static inline void rndis_put_nr(int nr)
	ida_simple_remove(&rndis_ida, nr);
}

struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
	void (*flow_ctrl_enable)(bool enable, struct rndis_params *params))
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
{
	struct rndis_params *params;
	int i;
@@ -929,7 +917,6 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
	params->state = RNDIS_UNINITIALIZED;
	params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
	params->resp_avail = resp_avail;
	params->flow_ctrl_enable = flow_ctrl_enable;
	params->v = v;
	INIT_LIST_HEAD(&params->resp_queue);
	pr_debug("%s: configNr = %d\n", __func__, i);
@@ -1006,56 +993,6 @@ int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed)
}
EXPORT_SYMBOL_GPL(rndis_set_param_medium);

void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer)
{
	pr_debug("%s:\n", __func__);

	params->max_pkt_per_xfer = max_pkt_per_xfer;
}

/**
 * rndis_flow_control: enable/disable flow control with USB RNDIS interface
 * params - RNDIS network parameter
 * enable_flow_control - true: perform flow control, false: disable flow control
 *
 * In hw accelerated mode, this function triggers functionality to start/stop
 * endless transfers, otherwise it enables/disables RNDIS network interface.
 */
void rndis_flow_control(struct rndis_params *params, bool enable_flow_control)
{
	if (!params) {
		pr_err("%s: failed, params NULL\n", __func__);
		return;
	}

	pr_debug("%s(): params->state:%x\n", __func__, params->state);

	if (enable_flow_control) {
		if (params->state == RNDIS_DATA_INITIALIZED) {
			if (params->flow_ctrl_enable) {
				params->flow_ctrl_enable(enable_flow_control,
								params);
			} else {
				netif_carrier_off(params->dev);
				netif_stop_queue(params->dev);
			}
		}
		params->state = RNDIS_INITIALIZED;
	} else {
		if (params->state != RNDIS_DATA_INITIALIZED) {
			if (params->flow_ctrl_enable) {
				params->flow_ctrl_enable(enable_flow_control,
								params);
			} else {
				netif_carrier_on(params->dev);
				if (netif_running(params->dev))
					netif_wake_queue(params->dev);
			}
		}
		params->state = RNDIS_DATA_INITIALIZED;
	}
}

void rndis_add_hdr(struct sk_buff *skb)
{
	struct rndis_packet_msg_type *header;
@@ -1122,82 +1059,29 @@ int rndis_rm_hdr(struct gether *port,
			struct sk_buff *skb,
			struct sk_buff_head *list)
{
	while (skb->len) {
		struct rndis_packet_msg_type *hdr;
		struct sk_buff          *skb2;
		u32             msg_len, data_offset, data_len;

		/* some rndis hosts send extra byte to avoid zlp, ignore it */
		if (skb->len == 1) {
			dev_kfree_skb_any(skb);
			return 0;
		}
	/* tmp points to a struct rndis_packet_msg_type */
	__le32 *tmp = (void *)skb->data;

		if (skb->len < sizeof(*hdr)) {
			pr_err("invalid rndis pkt: skblen:%u hdr_len:%lu\n",
					skb->len, sizeof(*hdr));
	/* MessageType, MessageLength */
	if (cpu_to_le32(RNDIS_MSG_PACKET)
			!= get_unaligned(tmp++)) {
		dev_kfree_skb_any(skb);
		return -EINVAL;
	}
	tmp++;

		hdr = (void *)skb->data;
		msg_len = le32_to_cpu(hdr->MessageLength);
		data_offset = le32_to_cpu(hdr->DataOffset);
		data_len = le32_to_cpu(hdr->DataLength);

		if (skb->len < msg_len ||
				((data_offset + data_len + 8) > msg_len)) {
			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
					le32_to_cpu(hdr->MessageType), msg_len,
					data_offset, data_len, skb->len);
	/* DataOffset, DataLength */
	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
		dev_kfree_skb_any(skb);
		return -EOVERFLOW;
	}
		if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) {
			pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
					le32_to_cpu(hdr->MessageType), msg_len,
					data_offset, data_len, skb->len);
			dev_kfree_skb_any(skb);
			return -EINVAL;
		}

		skb_pull(skb, data_offset + 8);

		if (msg_len == skb->len) {
			skb_trim(skb, data_len);
			break;
		}

		skb2 = skb_clone(skb, GFP_ATOMIC);
		if (!skb2) {
			pr_err("%s:skb clone failed\n", __func__);
			dev_kfree_skb_any(skb);
			return -ENOMEM;
		}

		skb_pull(skb, msg_len - sizeof(*hdr));
		skb_trim(skb2, data_len);
		skb_queue_tail(list, skb2);
	}
	skb_trim(skb, get_unaligned_le32(tmp++));

	skb_queue_tail(list, skb);
	return 0;
}
EXPORT_SYMBOL_GPL(rndis_rm_hdr);

void rndis_set_pkt_alignment_factor(struct rndis_params *params,
		u8 pkt_alignment_factor)
{
	pr_debug("%s:\n", __func__);

	if (!params) {
		pr_err("%s: failed, params NULL\n", __func__);
		return;
	}

	params->pkt_alignment_factor = pkt_alignment_factor;
}

#ifdef CONFIG_USB_GADGET_DEBUG_FILES

static int rndis_proc_show(struct seq_file *m, void *v)
+1 −14
Original line number Diff line number Diff line
@@ -170,24 +170,15 @@ typedef struct rndis_params {
	struct net_device	*dev;

	u32			vendorID;
	u8			max_pkt_per_xfer;
	u32			host_rndis_major_ver;
	u32			host_rndis_minor_ver;
	u32			dl_max_xfer_size;
	const char		*vendorDescr;
	u8			pkt_alignment_factor;
	void			(*resp_avail)(void *v);
	void			(*flow_ctrl_enable)(bool enable,
			struct rndis_params *params);

	void			*v;
	struct list_head	resp_queue;
} rndis_params;

/* RNDIS Message parser and other useless functions */
int  rndis_msg_parser(struct rndis_params *params, u8 *buf);
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
	void (*flow_ctrl_enable)(bool enable, struct rndis_params *params));
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v);
void rndis_deregister(struct rndis_params *params);
int  rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
			 u16 *cdc_filter);
@@ -195,7 +186,6 @@ int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
			    const char *vendorDescr);
int  rndis_set_param_medium(struct rndis_params *params, u32 medium,
			     u32 speed);
void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer);
void rndis_add_hdr(struct sk_buff *skb);
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
			struct sk_buff_head *list);
@@ -207,8 +197,5 @@ int rndis_signal_connect(struct rndis_params *params);
int  rndis_signal_disconnect(struct rndis_params *params);
int  rndis_state(struct rndis_params *params);
extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr);
void rndis_flow_control(struct rndis_params *params, bool enable_flow_control);
void rndis_set_pkt_alignment_factor(struct rndis_params *params,
		u8 pkt_alignment_factor);

#endif  /* _LINUX_RNDIS_H */
Loading