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

Commit d5e10846 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: f_fs: Add support for SuperSpeed Mode"

parents 34704e73 f4f64b3f
Loading
Loading
Loading
Loading
+133 −41
Original line number Diff line number Diff line
@@ -197,13 +197,17 @@ struct ffs_data {
	 * Real descriptors are 16 bytes after raw_descs (so you need
	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
	 * first full speed descriptor).  raw_descs_length and
	 * raw_fs_descs_length do not have those 16 bytes added.
	 * raw_fs_hs_descs_length do not have those 16 bytes added.
	 * ss_desc are 8 bytes (ss_magic + count) pass the hs_descs
	 */
	const void			*raw_descs;
	unsigned			raw_descs_length;
	unsigned			raw_fs_descs_length;
	unsigned			raw_fs_hs_descs_length;
	unsigned			raw_ss_descs_offset;
	unsigned			raw_ss_descs_length;
	unsigned			fs_descs_count;
	unsigned			hs_descs_count;
	unsigned			ss_descs_count;

	unsigned short			strings_count;
	unsigned short			interfaces_count;
@@ -301,8 +305,8 @@ struct ffs_ep {
	struct usb_ep			*ep;	/* P: ffs->eps_lock */
	struct usb_request		*req;	/* P: epfile->mutex */

	/* [0]: full speed, [1]: high speed */
	struct usb_endpoint_descriptor	*descs[2];
	/* [0]: full speed, [1]: high speed, [2]: super speed */
	struct usb_endpoint_descriptor	*descs[3];

	u8				num;

@@ -757,7 +761,7 @@ static ssize_t ffs_epfile_io(struct file *file,
	char *data = NULL;
	ssize_t ret;
	int halt;
	int buffer_len = !read ? len : round_up(len, 512);
	int buffer_len = !read ? len : round_up(len, 1024);

	pr_debug("%s: len %d, buffer_len %d, read %d\n", __func__, len, buffer_len, read);

@@ -1365,9 +1369,12 @@ static void ffs_data_reset(struct ffs_data *ffs)
	ffs->stringtabs = NULL;

	ffs->raw_descs_length = 0;
	ffs->raw_fs_descs_length = 0;
	ffs->raw_fs_hs_descs_length = 0;
	ffs->raw_ss_descs_offset = 0;
	ffs->raw_ss_descs_length = 0;
	ffs->fs_descs_count = 0;
	ffs->hs_descs_count = 0;
	ffs->ss_descs_count = 0;

	ffs->strings_count = 0;
	ffs->interfaces_count = 0;
@@ -1575,7 +1582,15 @@ static int ffs_func_eps_enable(struct ffs_function *func)
	spin_lock_irqsave(&func->ffs->eps_lock, flags);
	do {
		struct usb_endpoint_descriptor *ds;
		int desc_idx = ffs->gadget->speed == USB_SPEED_HIGH ? 1 : 0;
		int desc_idx;

		if (ffs->gadget->speed == USB_SPEED_SUPER)
			desc_idx = 2;
		else if (ffs->gadget->speed == USB_SPEED_HIGH)
			desc_idx = 1;
		else
			desc_idx = 0;

		ds = ep->descs[desc_idx];
		if (!ds) {
			ret = -EINVAL;
@@ -1715,6 +1730,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
	}
		break;

	case USB_DT_SS_ENDPOINT_COMP:
		pr_vdebug("EP SS companion descriptor\n");
		if (length != sizeof(struct usb_ss_ep_comp_descriptor))
			goto inv_length;
		break;

	case USB_DT_OTHER_SPEED_CONFIG:
	case USB_DT_INTERFACE_POWER:
	case USB_DT_DEBUG:
@@ -1825,8 +1846,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
static int __ffs_data_got_descs(struct ffs_data *ffs,
				char *const _data, size_t len)
{
	unsigned fs_count, hs_count;
	int fs_len, ret = -EINVAL;
	unsigned fs_count, hs_count, ss_count = 0;
	int fs_len, hs_len, ss_len, ss_magic, ret = -EINVAL;
	char *data = _data;

	ENTER();
@@ -1837,9 +1858,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
	fs_count = get_unaligned_le32(data +  8);
	hs_count = get_unaligned_le32(data + 12);

	if (!fs_count && !hs_count)
		goto einval;

	data += 16;
	len  -= 16;

@@ -1858,22 +1876,58 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
	}

	if (likely(hs_count)) {
		ret = ffs_do_descs(hs_count, data, len,
		hs_len = ffs_do_descs(hs_count, data, len,
				   __ffs_data_do_entity, ffs);
		if (unlikely(ret < 0))
		if (unlikely(hs_len < 0)) {
			ret = hs_len;
			goto error;
		}
	} else {
		hs_len = 0;
	}

	if ((len >= hs_len + 8)) {
		/* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
		ss_magic = get_unaligned_le32(data + hs_len);
		if (ss_magic != FUNCTIONFS_SS_DESC_MAGIC)
			goto einval;

		ss_count = get_unaligned_le32(data + hs_len + 4);
		data += hs_len + 8;
		len  -= hs_len + 8;
	} else {
		data += hs_len;
		len  -= hs_len;
	}

	if (!fs_count && !hs_count && !ss_count)
		goto einval;

	if (ss_count) {
		ss_len = ffs_do_descs(ss_count, data, len,
				   __ffs_data_do_entity, ffs);
		if (unlikely(ss_len < 0)) {
			ret = ss_len;
			goto error;
		}
		ret = ss_len;
	} else {
		ss_len = 0;
		ret = 0;
	}

	if (unlikely(len != ret))
		goto einval;

	ffs->raw_fs_descs_length = fs_len;
	ffs->raw_descs_length    = fs_len + ret;
	ffs->raw_fs_hs_descs_length	 = fs_len + hs_len;
	ffs->raw_ss_descs_length	 = ss_len;
	ffs->raw_descs_length		 = ffs->raw_fs_hs_descs_length + ss_len;
	ffs->raw_descs			 = _data;
	ffs->fs_descs_count		 = fs_count;
	ffs->hs_descs_count		 = hs_count;
	ffs->ss_descs_count		 = ss_count;
	if (ffs->ss_descs_count)
		ffs->raw_ss_descs_offset = 16 + ffs->raw_fs_hs_descs_length + 8;

	return 0;

@@ -2097,16 +2151,23 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
	 * If hs_descriptors is not NULL then we are reading hs
	 * descriptors now
	 */
	const int isHS = func->function.hs_descriptors != NULL;
	unsigned idx;
	const int is_hs = func->function.hs_descriptors != NULL;
	const int is_ss = func->function.ss_descriptors != NULL;
	unsigned ep_desc_id, idx;

	if (type != FFS_DESCRIPTOR)
		return 0;

	if (isHS)
	if (is_ss) {
		func->function.ss_descriptors[(long)valuep] = desc;
		ep_desc_id = 2;
	} else if (is_hs) {
		func->function.hs_descriptors[(long)valuep] = desc;
	else
		ep_desc_id = 1;
	} else {
		func->function.fs_descriptors[(long)valuep]    = desc;
		ep_desc_id = 0;
	}

	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
		return 0;
@@ -2114,13 +2175,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
	ffs_ep = func->eps + idx;

	if (unlikely(ffs_ep->descs[isHS])) {
	if (unlikely(ffs_ep->descs[ep_desc_id])) {
		pr_vdebug("two %sspeed descriptors for EP %d\n",
			  isHS ? "high" : "full",
			  is_ss ? "super" : "high/full",
			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
		return -EINVAL;
	}
	ffs_ep->descs[isHS] = ds;
	ffs_ep->descs[ep_desc_id] = ds;

	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
	if (ffs_ep->ep) {
@@ -2215,8 +2276,10 @@ static int ffs_func_bind(struct usb_configuration *c,
	const int full = !!func->ffs->fs_descs_count;
	const int high = gadget_is_dualspeed(func->gadget) &&
		func->ffs->hs_descs_count;
	const int super = gadget_is_superspeed(func->gadget) &&
		func->ffs->ss_descs_count;

	int ret;
	int fs_len, hs_len, ret;

	/* Make it a single chunk, less management later on */
	struct {
@@ -2225,15 +2288,16 @@ static int ffs_func_bind(struct usb_configuration *c,
			*fs_descs[full ? ffs->fs_descs_count + 1 : 0];
		struct usb_descriptor_header
			*hs_descs[high ? ffs->hs_descs_count + 1 : 0];
		struct usb_descriptor_header
			*ss_descs[super ? ffs->ss_descs_count + 1 : 0];
		short inums[ffs->interfaces_count];
		char raw_descs[high ? ffs->raw_descs_length
				    : ffs->raw_fs_descs_length];
		char raw_descs[ffs->raw_descs_length];
	} *data;

	ENTER();

	/* Only high speed but not supported by gadget? */
	if (unlikely(!(full | high)))
	/* Only high/super speed but not supported by gadget? */
	if (unlikely(!(full | high | super)))
		return -ENOTSUPP;

	/* Allocate */
@@ -2243,7 +2307,15 @@ static int ffs_func_bind(struct usb_configuration *c,

	/* Zero */
	memset(data->eps, 0, sizeof data->eps);
	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
	/* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */
	memcpy(data->raw_descs, ffs->raw_descs + 16,
				ffs->raw_fs_hs_descs_length);
	/* Copy SS descriptors */
	if (func->ffs->ss_descs_count)
		memcpy(data->raw_descs + ffs->raw_fs_hs_descs_length,
			ffs->raw_descs + ffs->raw_ss_descs_offset,
			ffs->raw_ss_descs_length);

	memset(data->inums, 0xff, sizeof data->inums);
	for (ret = ffs->eps_count; ret; --ret)
		data->eps[ret].num = -1;
@@ -2259,23 +2331,42 @@ static int ffs_func_bind(struct usb_configuration *c,
	 */
	if (likely(full)) {
		func->function.fs_descriptors = data->fs_descs;
		ret = ffs_do_descs(ffs->fs_descs_count,
		fs_len = ffs_do_descs(ffs->fs_descs_count,
				   data->raw_descs,
				   sizeof data->raw_descs,
				   sizeof(data->raw_descs),
				   __ffs_func_bind_do_descs, func);
		if (unlikely(ret < 0))
		if (unlikely(fs_len < 0)) {
			ret = fs_len;
			goto error;
		}
	} else {
		ret = 0;
		fs_len = 0;
	}

	if (likely(high)) {
		func->function.hs_descriptors = data->hs_descs;
		ret = ffs_do_descs(ffs->hs_descs_count,
				   data->raw_descs + ret,
				   (sizeof data->raw_descs) - ret,
		hs_len = ffs_do_descs(ffs->hs_descs_count,
				   data->raw_descs + fs_len,
				   (sizeof(data->raw_descs)) - fs_len,
				   __ffs_func_bind_do_descs, func);
		if (unlikely(hs_len < 0)) {
			ret = hs_len;
			goto error;
		}
	} else {
		hs_len = 0;
	}

	if (likely(super)) {
		func->function.ss_descriptors = data->ss_descs;
		ret = ffs_do_descs(ffs->ss_descs_count,
				   data->raw_descs + fs_len + hs_len,
				   (sizeof(data->raw_descs)) - fs_len - hs_len,
				   __ffs_func_bind_do_descs, func);
		if (unlikely(ret < 0))
			goto error;
	}


	/*
	 * Now handle interface numbers allocation and interface and
@@ -2283,8 +2374,9 @@ static int ffs_func_bind(struct usb_configuration *c,
	 * now.
	 */
	ret = ffs_do_descs(ffs->fs_descs_count +
			   (high ? ffs->hs_descs_count : 0),
			   data->raw_descs, sizeof data->raw_descs,
			   (high ? ffs->hs_descs_count : 0) +
			   (super ? ffs->ss_descs_count : 0),
			   data->raw_descs, sizeof(data->raw_descs),
			   __ffs_func_bind_do_nums, func);
	if (unlikely(ret < 0))
		goto error;
+5 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ enum {
	FUNCTIONFS_STRINGS_MAGIC     = 2
};

#define FUNCTIONFS_SS_DESC_MAGIC 0x0055DE5C

#ifndef __KERNEL__

@@ -50,7 +51,11 @@ struct usb_functionfs_descs_head {
 * |  12 | hs_count  | LE32         | number of high-speed descriptors     |
 * |  16 | fs_descrs | Descriptor[] | list of full-speed descriptors       |
 * |     | hs_descrs | Descriptor[] | list of high-speed descriptors       |
 * |     | ss_magic  | LE32         | FUNCTIONFS_SS_DESC_MAGIC             |
 * |     | ss_count  | LE32         | number of super-speed descriptors    |
 * |     | ss_descrs | Descriptor[] | list of super-speed descriptors      |
 *
 * ss_magic: if present then it implies that SS_DESCs are also present
 * descs are just valid USB descriptors and have the following format:
 *
 * | off | name            | type | description              |