USB fixes for 3.13-rc3
Here are a bunch of USB fixes for 3.13-rc3. Nothing major, but we seem to have an argument about a XHCI fix, so I'm not including a revert that Sarah requested, because that breaks a USB network driver, and I can't revert the USB network driver fix without reintroducing other bugs that it fixed. So as it is, everything should now be working. Worse case, I can revert the XHCI fix before 3.13-final is out, but it seems to work well here with my testing, so all should be good. Other than that, some driver updates based on reports. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlKiEuYACgkQMUfUDdst+ymE8ACgnDT8s4FtrYfoyOo5K4TVTRaZ S2wAn3+Xa2TX1Sym+ltJry7N1jRnY2Qy =JUaB -----END PGP SIGNATURE----- Merge tag 'usb-3.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a bunch of USB fixes for 3.13-rc3. Nothing major, but we seem to have an argument about a XHCI fix, so I'm not including a revert that Sarah requested, because that breaks a USB network driver, and I can't revert the USB network driver fix without reintroducing other bugs that it fixed. So as it is, everything should now be working. Worse case, I can revert the XHCI fix before 3.13-final is out, but it seems to work well here with my testing, so all should be good. Other than that, some driver updates based on reports" * tag 'usb-3.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (40 commits) usb: hub: Use correct reset for wedged USB3 devices that are NOTATTACHED usb: ohci-pxa27x: include linux/dma-mapping.h USB: cdc-acm: Added support for the Lenovo RD02-D400 USB Modem usb: tools: fix a regression issue that gcc can't link to pthread USB: switch maintainership of chipidea to Peter USB: pl2303: fixed handling of CS5 setting USB: ftdi_sio: fixed handling of unsupported CSIZE setting USB: mos7840: correct handling of CS5 setting USB: spcp8x5: correct handling of CS5 setting usb: wusbcore: fix deadlock in wusbhc_gtk_rekey usb: wusbcore: do device lookup while holding the hc mutex usb: wusbcore: send keepalives to unauthenticated devices USB: option: support new huawei devices USB: serial: option: blacklist interface 1 for Huawei E173s-6 usb: xhci: Link TRB must not occur within a USB payload burst usb: gadget: f_mass_storage: call try_to_freeze only when its safe usb: gadget: tcm_usb_gadget: mark bot_cleanup_old_alt static usb: gadget: ffs: fix sparse warning usb: gadget: zero: module parameters can be static usb: gadget: storage: fix sparse warning ...
This commit is contained in:
		
				commit
				
					
						b19d69c72d
					
				
			
		
					 36 changed files with 472 additions and 266 deletions
				
			
		| 
						 | 
				
			
			@ -2138,7 +2138,8 @@ S:	Maintained
 | 
			
		|||
F:	Documentation/zh_CN/
 | 
			
		||||
 | 
			
		||||
CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
 | 
			
		||||
M:	Alexander Shishkin <alexander.shishkin@linux.intel.com>
 | 
			
		||||
M:	Peter Chen <Peter.Chen@freescale.com>
 | 
			
		||||
T:	git://github.com/hzpeterchen/linux-usb.git
 | 
			
		||||
L:	linux-usb@vger.kernel.org
 | 
			
		||||
S:	Maintained
 | 
			
		||||
F:	drivers/usb/chipidea/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1515,6 +1515,8 @@ static int acm_reset_resume(struct usb_interface *intf)
 | 
			
		|||
 | 
			
		||||
static const struct usb_device_id acm_ids[] = {
 | 
			
		||||
	/* quirky and broken devices */
 | 
			
		||||
	{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */
 | 
			
		||||
	.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */
 | 
			
		||||
	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 | 
			
		||||
	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 | 
			
		||||
	},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4832,8 +4832,9 @@ static void hub_events(void)
 | 
			
		|||
					hub->ports[i - 1]->child;
 | 
			
		||||
 | 
			
		||||
				dev_dbg(hub_dev, "warm reset port %d\n", i);
 | 
			
		||||
				if (!udev || !(portstatus &
 | 
			
		||||
						USB_PORT_STAT_CONNECTION)) {
 | 
			
		||||
				if (!udev ||
 | 
			
		||||
				    !(portstatus & USB_PORT_STAT_CONNECTION) ||
 | 
			
		||||
				    udev->state == USB_STATE_NOTATTACHED) {
 | 
			
		||||
					status = hub_port_reset(hub, i,
 | 
			
		||||
							NULL, HUB_BH_RESET_TIME,
 | 
			
		||||
							true);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -459,6 +459,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
 | 
			
		|||
			dep = dwc3_wIndex_to_dep(dwc, wIndex);
 | 
			
		||||
			if (!dep)
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
 | 
			
		||||
				break;
 | 
			
		||||
			ret = __dwc3_gadget_ep_set_halt(dep, set);
 | 
			
		||||
			if (ret)
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1200,9 +1200,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
 | 
			
		|||
		else
 | 
			
		||||
			dep->flags |= DWC3_EP_STALL;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (dep->flags & DWC3_EP_WEDGE)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
 | 
			
		||||
			DWC3_DEPCMD_CLEARSTALL, ¶ms);
 | 
			
		||||
		if (ret)
 | 
			
		||||
| 
						 | 
				
			
			@ -1210,7 +1207,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
 | 
			
		|||
					value ? "set" : "clear",
 | 
			
		||||
					dep->name);
 | 
			
		||||
		else
 | 
			
		||||
			dep->flags &= ~DWC3_EP_STALL;
 | 
			
		||||
			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -682,6 +682,7 @@ config USB_CONFIGFS_PHONET
 | 
			
		|||
config USB_CONFIGFS_MASS_STORAGE
 | 
			
		||||
	boolean "Mass storage"
 | 
			
		||||
	depends on USB_CONFIGFS
 | 
			
		||||
	depends on BLOCK
 | 
			
		||||
	select USB_F_MASS_STORAGE
 | 
			
		||||
	help
 | 
			
		||||
	  The Mass Storage Gadget acts as a USB Mass Storage disk drive.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -593,6 +593,7 @@ static void reset_config(struct usb_composite_dev *cdev)
 | 
			
		|||
		bitmap_zero(f->endpoints, 32);
 | 
			
		||||
	}
 | 
			
		||||
	cdev->config = NULL;
 | 
			
		||||
	cdev->delayed_status = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_config(struct usb_composite_dev *cdev,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1304,7 +1304,7 @@ static struct ffs_data *ffs_data_new(void)
 | 
			
		|||
{
 | 
			
		||||
	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
 | 
			
		||||
	if (unlikely(!ffs))
 | 
			
		||||
		return 0;
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	ENTER();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -523,7 +523,7 @@ static int fsg_setup(struct usb_function *f,
 | 
			
		|||
		 */
 | 
			
		||||
		DBG(fsg, "bulk reset request\n");
 | 
			
		||||
		raise_exception(fsg->common, FSG_STATE_RESET);
 | 
			
		||||
		return DELAYED_STATUS;
 | 
			
		||||
		return USB_GADGET_DELAYED_STATUS;
 | 
			
		||||
 | 
			
		||||
	case US_BULK_GET_MAX_LUN:
 | 
			
		||||
		if (ctrl->bRequestType !=
 | 
			
		||||
| 
						 | 
				
			
			@ -602,12 +602,13 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sleep_thread(struct fsg_common *common)
 | 
			
		||||
static int sleep_thread(struct fsg_common *common, bool can_freeze)
 | 
			
		||||
{
 | 
			
		||||
	int	rc = 0;
 | 
			
		||||
 | 
			
		||||
	/* Wait until a signal arrives or we are woken up */
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if (can_freeze)
 | 
			
		||||
			try_to_freeze();
 | 
			
		||||
		set_current_state(TASK_INTERRUPTIBLE);
 | 
			
		||||
		if (signal_pending(current)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +683,7 @@ static int do_read(struct fsg_common *common)
 | 
			
		|||
		/* Wait for the next buffer to become available */
 | 
			
		||||
		bh = common->next_buffhd_to_fill;
 | 
			
		||||
		while (bh->state != BUF_STATE_EMPTY) {
 | 
			
		||||
			rc = sleep_thread(common);
 | 
			
		||||
			rc = sleep_thread(common, false);
 | 
			
		||||
			if (rc)
 | 
			
		||||
				return rc;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -937,7 +938,7 @@ static int do_write(struct fsg_common *common)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		/* Wait for something to happen */
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, false);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1504,7 +1505,7 @@ static int throw_away_data(struct fsg_common *common)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		/* Otherwise wait for something to happen */
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, true);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1625,7 +1626,7 @@ static int send_status(struct fsg_common *common)
 | 
			
		|||
	/* Wait for the next buffer to become available */
 | 
			
		||||
	bh = common->next_buffhd_to_fill;
 | 
			
		||||
	while (bh->state != BUF_STATE_EMPTY) {
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, true);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1828,7 +1829,7 @@ static int do_scsi_command(struct fsg_common *common)
 | 
			
		|||
	bh = common->next_buffhd_to_fill;
 | 
			
		||||
	common->next_buffhd_to_drain = bh;
 | 
			
		||||
	while (bh->state != BUF_STATE_EMPTY) {
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, true);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2174,7 +2175,7 @@ static int get_next_command(struct fsg_common *common)
 | 
			
		|||
	/* Wait for the next buffer to become available */
 | 
			
		||||
	bh = common->next_buffhd_to_fill;
 | 
			
		||||
	while (bh->state != BUF_STATE_EMPTY) {
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, true);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2193,7 +2194,7 @@ static int get_next_command(struct fsg_common *common)
 | 
			
		|||
 | 
			
		||||
	/* Wait for the CBW to arrive */
 | 
			
		||||
	while (bh->state != BUF_STATE_FULL) {
 | 
			
		||||
		rc = sleep_thread(common);
 | 
			
		||||
		rc = sleep_thread(common, true);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2379,7 +2380,7 @@ static void handle_exception(struct fsg_common *common)
 | 
			
		|||
			}
 | 
			
		||||
			if (num_active == 0)
 | 
			
		||||
				break;
 | 
			
		||||
			if (sleep_thread(common))
 | 
			
		||||
			if (sleep_thread(common, true))
 | 
			
		||||
				return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2516,7 +2517,7 @@ static int fsg_main_thread(void *common_)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		if (!common->running) {
 | 
			
		||||
			sleep_thread(common);
 | 
			
		||||
			sleep_thread(common, true);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3111,7 +3112,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		|||
					  fsg->common->can_stall);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
		fsg_common_set_inquiry_string(fsg->common, 0, 0);
 | 
			
		||||
		fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
 | 
			
		||||
		ret = fsg_common_run_thread(fsg->common);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#ifdef CONFIG_ARCH_PXA
 | 
			
		||||
#include <mach/pxa25x-udc.h>
 | 
			
		||||
#include <mach/hardware.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_LUBBOCK
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1180,6 +1180,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
 | 
			
		||||
static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * s3c_hsotg_process_control - process a control request
 | 
			
		||||
| 
						 | 
				
			
			@ -1221,6 +1222,7 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
 | 
			
		|||
	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
 | 
			
		||||
		switch (ctrl->bRequest) {
 | 
			
		||||
		case USB_REQ_SET_ADDRESS:
 | 
			
		||||
			s3c_hsotg_disconnect(hsotg);
 | 
			
		||||
			dcfg = readl(hsotg->regs + DCFG);
 | 
			
		||||
			dcfg &= ~DCFG_DevAddr_MASK;
 | 
			
		||||
			dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;
 | 
			
		||||
| 
						 | 
				
			
			@ -1245,7 +1247,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
 | 
			
		|||
	/* as a fallback, try delivering it to the driver to deal with */
 | 
			
		||||
 | 
			
		||||
	if (ret == 0 && hsotg->driver) {
 | 
			
		||||
		spin_unlock(&hsotg->lock);
 | 
			
		||||
		ret = hsotg->driver->setup(&hsotg->gadget, ctrl);
 | 
			
		||||
		spin_lock(&hsotg->lock);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1308,10 +1312,12 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_lock(&hsotg->lock);
 | 
			
		||||
	if (req->actual == 0)
 | 
			
		||||
		s3c_hsotg_enqueue_setup(hsotg);
 | 
			
		||||
	else
 | 
			
		||||
		s3c_hsotg_process_control(hsotg, req->buf);
 | 
			
		||||
	spin_unlock(&hsotg->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -2533,7 +2539,6 @@ irq_retry:
 | 
			
		|||
		writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS);
 | 
			
		||||
 | 
			
		||||
		call_gadget(hsotg, suspend);
 | 
			
		||||
		s3c_hsotg_disconnect(hsotg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (gintsts & GINTSTS_WkUpInt) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,10 +119,6 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
 | 
			
		|||
	return curlun->filp != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Big enough to hold our biggest descriptor */
 | 
			
		||||
#define EP0_BUFSIZE	256
 | 
			
		||||
#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */
 | 
			
		||||
 | 
			
		||||
/* Default size of buffer length. */
 | 
			
		||||
#define FSG_BUFLEN	((u32)16384)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -370,7 +370,7 @@ err:
 | 
			
		|||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bot_cleanup_old_alt(struct f_uas *fu)
 | 
			
		||||
static void bot_cleanup_old_alt(struct f_uas *fu)
 | 
			
		||||
{
 | 
			
		||||
	if (!(fu->flags & USBG_ENABLED))
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,17 +91,17 @@ static struct usb_zero_options gzero_options = {
 | 
			
		|||
 * functional coverage for the "USBCV" test harness from USB-IF.
 | 
			
		||||
 * It's always set if OTG mode is enabled.
 | 
			
		||||
 */
 | 
			
		||||
unsigned autoresume = DEFAULT_AUTORESUME;
 | 
			
		||||
static unsigned autoresume = DEFAULT_AUTORESUME;
 | 
			
		||||
module_param(autoresume, uint, S_IRUGO);
 | 
			
		||||
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
 | 
			
		||||
 | 
			
		||||
/* Maximum Autoresume time */
 | 
			
		||||
unsigned max_autoresume;
 | 
			
		||||
static unsigned max_autoresume;
 | 
			
		||||
module_param(max_autoresume, uint, S_IRUGO);
 | 
			
		||||
MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup");
 | 
			
		||||
 | 
			
		||||
/* Interval between two remote wakeups */
 | 
			
		||||
unsigned autoresume_interval_ms;
 | 
			
		||||
static unsigned autoresume_interval_ms;
 | 
			
		||||
module_param(autoresume_interval_ms, uint, S_IRUGO);
 | 
			
		||||
MODULE_PARM_DESC(autoresume_interval_ms,
 | 
			
		||||
		"milliseconds to increase successive wakeup delays");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2973,8 +2973,58 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		if (room_on_ring(xhci, ep_ring, num_trbs)) {
 | 
			
		||||
			union xhci_trb *trb = ep_ring->enqueue;
 | 
			
		||||
			unsigned int usable = ep_ring->enq_seg->trbs +
 | 
			
		||||
					TRBS_PER_SEGMENT - 1 - trb;
 | 
			
		||||
			u32 nop_cmd;
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * Section 4.11.7.1 TD Fragments states that a link
 | 
			
		||||
			 * TRB must only occur at the boundary between
 | 
			
		||||
			 * data bursts (eg 512 bytes for 480M).
 | 
			
		||||
			 * While it is possible to split a large fragment
 | 
			
		||||
			 * we don't know the size yet.
 | 
			
		||||
			 * Simplest solution is to fill the trb before the
 | 
			
		||||
			 * LINK with nop commands.
 | 
			
		||||
			 */
 | 
			
		||||
			if (num_trbs == 1 || num_trbs <= usable || usable == 0)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (ep_ring->type != TYPE_BULK)
 | 
			
		||||
				/*
 | 
			
		||||
				 * While isoc transfers might have a buffer that
 | 
			
		||||
				 * crosses a 64k boundary it is unlikely.
 | 
			
		||||
				 * Since we can't add NOPs without generating
 | 
			
		||||
				 * gaps in the traffic just hope it never
 | 
			
		||||
				 * happens at the end of the ring.
 | 
			
		||||
				 * This could be fixed by writing a LINK TRB
 | 
			
		||||
				 * instead of the first NOP - however the
 | 
			
		||||
				 * TRB_TYPE_LINK_LE32() calls would all need
 | 
			
		||||
				 * changing to check the ring length.
 | 
			
		||||
				 */
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (num_trbs >= TRBS_PER_SEGMENT) {
 | 
			
		||||
				xhci_err(xhci, "Too many fragments %d, max %d\n",
 | 
			
		||||
						num_trbs, TRBS_PER_SEGMENT - 1);
 | 
			
		||||
				return -ENOMEM;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) |
 | 
			
		||||
					ep_ring->cycle_state);
 | 
			
		||||
			ep_ring->num_trbs_free -= usable;
 | 
			
		||||
			do {
 | 
			
		||||
				trb->generic.field[0] = 0;
 | 
			
		||||
				trb->generic.field[1] = 0;
 | 
			
		||||
				trb->generic.field[2] = 0;
 | 
			
		||||
				trb->generic.field[3] = nop_cmd;
 | 
			
		||||
				trb++;
 | 
			
		||||
			} while (--usable);
 | 
			
		||||
			ep_ring->enqueue = trb;
 | 
			
		||||
			if (room_on_ring(xhci, ep_ring, num_trbs))
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ep_ring == xhci->cmd_ring) {
 | 
			
		||||
			xhci_err(xhci, "Do not support expand command ring\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1809,7 +1809,6 @@ static void musb_free(struct musb *musb)
 | 
			
		|||
			disable_irq_wake(musb->nIrq);
 | 
			
		||||
		free_irq(musb->nIrq, musb);
 | 
			
		||||
	}
 | 
			
		||||
	cancel_work_sync(&musb->irq_work);
 | 
			
		||||
 | 
			
		||||
	musb_host_free(musb);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1896,6 +1895,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 | 
			
		|||
	musb_platform_disable(musb);
 | 
			
		||||
	musb_generic_disable(musb);
 | 
			
		||||
 | 
			
		||||
	/* Init IRQ workqueue before request_irq */
 | 
			
		||||
	INIT_WORK(&musb->irq_work, musb_irq_work);
 | 
			
		||||
 | 
			
		||||
	/* setup musb parts of the core (especially endpoints) */
 | 
			
		||||
	status = musb_core_init(plat->config->multipoint
 | 
			
		||||
			? MUSB_CONTROLLER_MHDRC
 | 
			
		||||
| 
						 | 
				
			
			@ -1905,9 +1907,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 | 
			
		|||
 | 
			
		||||
	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
 | 
			
		||||
 | 
			
		||||
	/* Init IRQ workqueue before request_irq */
 | 
			
		||||
	INIT_WORK(&musb->irq_work, musb_irq_work);
 | 
			
		||||
 | 
			
		||||
	/* attach to the IRQ */
 | 
			
		||||
	if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {
 | 
			
		||||
		dev_err(dev, "request_irq %d failed!\n", nIrq);
 | 
			
		||||
| 
						 | 
				
			
			@ -1981,6 +1980,7 @@ fail4:
 | 
			
		|||
	musb_host_cleanup(musb);
 | 
			
		||||
 | 
			
		||||
fail3:
 | 
			
		||||
	cancel_work_sync(&musb->irq_work);
 | 
			
		||||
	if (musb->dma_controller)
 | 
			
		||||
		dma_controller_destroy(musb->dma_controller);
 | 
			
		||||
fail2_5:
 | 
			
		||||
| 
						 | 
				
			
			@ -2043,6 +2043,7 @@ static int musb_remove(struct platform_device *pdev)
 | 
			
		|||
	if (musb->dma_controller)
 | 
			
		||||
		dma_controller_destroy(musb->dma_controller);
 | 
			
		||||
 | 
			
		||||
	cancel_work_sync(&musb->irq_work);
 | 
			
		||||
	musb_free(musb);
 | 
			
		||||
	device_init_wakeup(dev, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ struct cppi41_dma_channel {
 | 
			
		|||
	u32 prog_len;
 | 
			
		||||
	u32 transferred;
 | 
			
		||||
	u32 packet_sz;
 | 
			
		||||
	struct list_head tx_check;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MUSB_DMA_NUM_CHANNELS 15
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,8 @@ struct cppi41_dma_controller {
 | 
			
		|||
	struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
 | 
			
		||||
	struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
 | 
			
		||||
	struct musb *musb;
 | 
			
		||||
	struct hrtimer early_tx;
 | 
			
		||||
	struct list_head early_tx_list;
 | 
			
		||||
	u32 rx_mode;
 | 
			
		||||
	u32 tx_mode;
 | 
			
		||||
	u32 auto_req;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,31 +99,27 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
 | 
			
		|||
	cppi41_channel->usb_toggle = toggle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cppi41_dma_callback(void *private_data)
 | 
			
		||||
static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
 | 
			
		||||
{
 | 
			
		||||
	u8		epnum = hw_ep->epnum;
 | 
			
		||||
	struct musb	*musb = hw_ep->musb;
 | 
			
		||||
	void __iomem	*epio = musb->endpoints[epnum].regs;
 | 
			
		||||
	u16		csr;
 | 
			
		||||
 | 
			
		||||
	csr = musb_readw(epio, MUSB_TXCSR);
 | 
			
		||||
	if (csr & MUSB_TXCSR_TXPKTRDY)
 | 
			
		||||
		return false;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cppi41_dma_callback(void *private_data);
 | 
			
		||||
 | 
			
		||||
static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
 | 
			
		||||
{
 | 
			
		||||
	struct dma_channel *channel = private_data;
 | 
			
		||||
	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
 | 
			
		||||
	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
 | 
			
		||||
	struct musb *musb = hw_ep->musb;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct dma_tx_state txstate;
 | 
			
		||||
	u32 transferred;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&musb->lock, flags);
 | 
			
		||||
 | 
			
		||||
	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
 | 
			
		||||
			&txstate);
 | 
			
		||||
	transferred = cppi41_channel->prog_len - txstate.residue;
 | 
			
		||||
	cppi41_channel->transferred += transferred;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
 | 
			
		||||
		hw_ep->epnum, cppi41_channel->transferred,
 | 
			
		||||
		cppi41_channel->total_len);
 | 
			
		||||
 | 
			
		||||
	update_rx_toggle(cppi41_channel);
 | 
			
		||||
 | 
			
		||||
	if (cppi41_channel->transferred == cppi41_channel->total_len ||
 | 
			
		||||
			transferred < cppi41_channel->packet_sz) {
 | 
			
		||||
	if (!cppi41_channel->prog_len) {
 | 
			
		||||
 | 
			
		||||
		/* done, complete */
 | 
			
		||||
		cppi41_channel->channel.actual_len =
 | 
			
		||||
| 
						 | 
				
			
			@ -150,13 +149,11 @@ static void cppi41_dma_callback(void *private_data)
 | 
			
		|||
				remain_bytes,
 | 
			
		||||
				direction,
 | 
			
		||||
				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 | 
			
		||||
		if (WARN_ON(!dma_desc)) {
 | 
			
		||||
			spin_unlock_irqrestore(&musb->lock, flags);
 | 
			
		||||
		if (WARN_ON(!dma_desc))
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dma_desc->callback = cppi41_dma_callback;
 | 
			
		||||
		dma_desc->callback_param = channel;
 | 
			
		||||
		dma_desc->callback_param = &cppi41_channel->channel;
 | 
			
		||||
		cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
 | 
			
		||||
		dma_async_issue_pending(dc);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,6 +163,117 @@ static void cppi41_dma_callback(void *private_data)
 | 
			
		|||
			musb_writew(epio, MUSB_RXCSR, csr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
 | 
			
		||||
{
 | 
			
		||||
	struct cppi41_dma_controller *controller;
 | 
			
		||||
	struct cppi41_dma_channel *cppi41_channel, *n;
 | 
			
		||||
	struct musb *musb;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	enum hrtimer_restart ret = HRTIMER_NORESTART;
 | 
			
		||||
 | 
			
		||||
	controller = container_of(timer, struct cppi41_dma_controller,
 | 
			
		||||
			early_tx);
 | 
			
		||||
	musb = controller->musb;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&musb->lock, flags);
 | 
			
		||||
	list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list,
 | 
			
		||||
			tx_check) {
 | 
			
		||||
		bool empty;
 | 
			
		||||
		struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
 | 
			
		||||
 | 
			
		||||
		empty = musb_is_tx_fifo_empty(hw_ep);
 | 
			
		||||
		if (empty) {
 | 
			
		||||
			list_del_init(&cppi41_channel->tx_check);
 | 
			
		||||
			cppi41_trans_done(cppi41_channel);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!list_empty(&controller->early_tx_list)) {
 | 
			
		||||
		ret = HRTIMER_RESTART;
 | 
			
		||||
		hrtimer_forward_now(&controller->early_tx,
 | 
			
		||||
				ktime_set(0, 150 * NSEC_PER_USEC));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&musb->lock, flags);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cppi41_dma_callback(void *private_data)
 | 
			
		||||
{
 | 
			
		||||
	struct dma_channel *channel = private_data;
 | 
			
		||||
	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
 | 
			
		||||
	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
 | 
			
		||||
	struct musb *musb = hw_ep->musb;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct dma_tx_state txstate;
 | 
			
		||||
	u32 transferred;
 | 
			
		||||
	bool empty;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&musb->lock, flags);
 | 
			
		||||
 | 
			
		||||
	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
 | 
			
		||||
			&txstate);
 | 
			
		||||
	transferred = cppi41_channel->prog_len - txstate.residue;
 | 
			
		||||
	cppi41_channel->transferred += transferred;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
 | 
			
		||||
		hw_ep->epnum, cppi41_channel->transferred,
 | 
			
		||||
		cppi41_channel->total_len);
 | 
			
		||||
 | 
			
		||||
	update_rx_toggle(cppi41_channel);
 | 
			
		||||
 | 
			
		||||
	if (cppi41_channel->transferred == cppi41_channel->total_len ||
 | 
			
		||||
			transferred < cppi41_channel->packet_sz)
 | 
			
		||||
		cppi41_channel->prog_len = 0;
 | 
			
		||||
 | 
			
		||||
	empty = musb_is_tx_fifo_empty(hw_ep);
 | 
			
		||||
	if (empty) {
 | 
			
		||||
		cppi41_trans_done(cppi41_channel);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct cppi41_dma_controller *controller;
 | 
			
		||||
		/*
 | 
			
		||||
		 * On AM335x it has been observed that the TX interrupt fires
 | 
			
		||||
		 * too early that means the TXFIFO is not yet empty but the DMA
 | 
			
		||||
		 * engine says that it is done with the transfer. We don't
 | 
			
		||||
		 * receive a FIFO empty interrupt so the only thing we can do is
 | 
			
		||||
		 * to poll for the bit. On HS it usually takes 2us, on FS around
 | 
			
		||||
		 * 110us - 150us depending on the transfer size.
 | 
			
		||||
		 * We spin on HS (no longer than than 25us and setup a timer on
 | 
			
		||||
		 * FS to check for the bit and complete the transfer.
 | 
			
		||||
		 */
 | 
			
		||||
		controller = cppi41_channel->controller;
 | 
			
		||||
 | 
			
		||||
		if (musb->g.speed == USB_SPEED_HIGH) {
 | 
			
		||||
			unsigned wait = 25;
 | 
			
		||||
 | 
			
		||||
			do {
 | 
			
		||||
				empty = musb_is_tx_fifo_empty(hw_ep);
 | 
			
		||||
				if (empty)
 | 
			
		||||
					break;
 | 
			
		||||
				wait--;
 | 
			
		||||
				if (!wait)
 | 
			
		||||
					break;
 | 
			
		||||
				udelay(1);
 | 
			
		||||
			} while (1);
 | 
			
		||||
 | 
			
		||||
			empty = musb_is_tx_fifo_empty(hw_ep);
 | 
			
		||||
			if (empty) {
 | 
			
		||||
				cppi41_trans_done(cppi41_channel);
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		list_add_tail(&cppi41_channel->tx_check,
 | 
			
		||||
				&controller->early_tx_list);
 | 
			
		||||
		if (!hrtimer_active(&controller->early_tx)) {
 | 
			
		||||
			hrtimer_start_range_ns(&controller->early_tx,
 | 
			
		||||
				ktime_set(0, 140 * NSEC_PER_USEC),
 | 
			
		||||
				40 * NSEC_PER_USEC,
 | 
			
		||||
				HRTIMER_MODE_REL);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	spin_unlock_irqrestore(&musb->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -364,6 +472,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
 | 
			
		|||
		WARN_ON(1);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (cppi41_channel->is_tx)
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* AM335x Advisory 1.0.13. No workaround for device RX mode */
 | 
			
		||||
| 
						 | 
				
			
			@ -388,6 +498,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
 | 
			
		|||
	if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	list_del_init(&cppi41_channel->tx_check);
 | 
			
		||||
	if (is_tx) {
 | 
			
		||||
		csr = musb_readw(epio, MUSB_TXCSR);
 | 
			
		||||
		csr &= ~MUSB_TXCSR_DMAENAB;
 | 
			
		||||
| 
						 | 
				
			
			@ -495,6 +606,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
 | 
			
		|||
		cppi41_channel->controller = controller;
 | 
			
		||||
		cppi41_channel->port_num = port;
 | 
			
		||||
		cppi41_channel->is_tx = is_tx;
 | 
			
		||||
		INIT_LIST_HEAD(&cppi41_channel->tx_check);
 | 
			
		||||
 | 
			
		||||
		musb_dma = &cppi41_channel->channel;
 | 
			
		||||
		musb_dma->private_data = cppi41_channel;
 | 
			
		||||
| 
						 | 
				
			
			@ -520,6 +632,7 @@ void dma_controller_destroy(struct dma_controller *c)
 | 
			
		|||
	struct cppi41_dma_controller *controller = container_of(c,
 | 
			
		||||
			struct cppi41_dma_controller, controller);
 | 
			
		||||
 | 
			
		||||
	hrtimer_cancel(&controller->early_tx);
 | 
			
		||||
	cppi41_dma_controller_stop(controller);
 | 
			
		||||
	kfree(controller);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -539,6 +652,9 @@ struct dma_controller *dma_controller_create(struct musb *musb,
 | 
			
		|||
	if (!controller)
 | 
			
		||||
		goto kzalloc_fail;
 | 
			
		||||
 | 
			
		||||
	hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 | 
			
		||||
	controller->early_tx.function = cppi41_recheck_tx_req;
 | 
			
		||||
	INIT_LIST_HEAD(&controller->early_tx_list);
 | 
			
		||||
	controller->musb = musb;
 | 
			
		||||
 | 
			
		||||
	controller->controller.channel_alloc = cppi41_dma_channel_allocate;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1796,7 +1796,11 @@ int musb_gadget_setup(struct musb *musb)
 | 
			
		|||
 | 
			
		||||
	/* this "gadget" abstracts/virtualizes the controller */
 | 
			
		||||
	musb->g.name = musb_driver_name;
 | 
			
		||||
#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)
 | 
			
		||||
	musb->g.is_otg = 1;
 | 
			
		||||
#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET)
 | 
			
		||||
	musb->g.is_otg = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	musb_g_init_endpoints(musb);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,8 +52,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
 | 
			
		|||
		return am_phy->id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
 | 
			
		||||
			USB_PHY_TYPE_USB2, 0, false);
 | 
			
		||||
	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,8 +65,6 @@ static int am335x_phy_probe(struct platform_device *pdev)
 | 
			
		|||
	platform_set_drvdata(pdev, am_phy);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int am335x_phy_remove(struct platform_device *pdev)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,8 +48,9 @@ void usb_nop_xceiv_register(void)
 | 
			
		|||
	if (pd)
 | 
			
		||||
		return;
 | 
			
		||||
	pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
 | 
			
		||||
	if (!pd) {
 | 
			
		||||
	if (IS_ERR(pd)) {
 | 
			
		||||
		pr_err("Unable to register generic usb transceiver\n");
 | 
			
		||||
		pd = NULL;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -150,10 +151,40 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 | 
			
		||||
		enum usb_phy_type type, u32 clk_rate, bool needs_vcc)
 | 
			
		||||
		struct usb_phy_gen_xceiv_platform_data *pdata)
 | 
			
		||||
{
 | 
			
		||||
	enum usb_phy_type type = USB_PHY_TYPE_USB2;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	u32 clk_rate = 0;
 | 
			
		||||
	bool needs_vcc = false;
 | 
			
		||||
 | 
			
		||||
	nop->reset_active_low = true;	/* default behaviour */
 | 
			
		||||
 | 
			
		||||
	if (dev->of_node) {
 | 
			
		||||
		struct device_node *node = dev->of_node;
 | 
			
		||||
		enum of_gpio_flags flags = 0;
 | 
			
		||||
 | 
			
		||||
		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
 | 
			
		||||
			clk_rate = 0;
 | 
			
		||||
 | 
			
		||||
		needs_vcc = of_property_read_bool(node, "vcc-supply");
 | 
			
		||||
		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
 | 
			
		||||
								0, &flags);
 | 
			
		||||
		if (nop->gpio_reset == -EPROBE_DEFER)
 | 
			
		||||
			return -EPROBE_DEFER;
 | 
			
		||||
 | 
			
		||||
		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
 | 
			
		||||
 | 
			
		||||
	} else if (pdata) {
 | 
			
		||||
		type = pdata->type;
 | 
			
		||||
		clk_rate = pdata->clk_rate;
 | 
			
		||||
		needs_vcc = pdata->needs_vcc;
 | 
			
		||||
		nop->gpio_reset = pdata->gpio_reset;
 | 
			
		||||
	} else {
 | 
			
		||||
		nop->gpio_reset = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
 | 
			
		||||
			GFP_KERNEL);
 | 
			
		||||
	if (!nop->phy.otg)
 | 
			
		||||
| 
						 | 
				
			
			@ -218,43 +249,14 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
 | 
			
		|||
static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &pdev->dev;
 | 
			
		||||
	struct usb_phy_gen_xceiv_platform_data *pdata =
 | 
			
		||||
			dev_get_platdata(&pdev->dev);
 | 
			
		||||
	struct usb_phy_gen_xceiv	*nop;
 | 
			
		||||
	enum usb_phy_type	type = USB_PHY_TYPE_USB2;
 | 
			
		||||
	int err;
 | 
			
		||||
	u32 clk_rate = 0;
 | 
			
		||||
	bool needs_vcc = false;
 | 
			
		||||
 | 
			
		||||
	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
 | 
			
		||||
	if (!nop)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	nop->reset_active_low = true;	/* default behaviour */
 | 
			
		||||
 | 
			
		||||
	if (dev->of_node) {
 | 
			
		||||
		struct device_node *node = dev->of_node;
 | 
			
		||||
		enum of_gpio_flags flags;
 | 
			
		||||
 | 
			
		||||
		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
 | 
			
		||||
			clk_rate = 0;
 | 
			
		||||
 | 
			
		||||
		needs_vcc = of_property_read_bool(node, "vcc-supply");
 | 
			
		||||
		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
 | 
			
		||||
								0, &flags);
 | 
			
		||||
		if (nop->gpio_reset == -EPROBE_DEFER)
 | 
			
		||||
			return -EPROBE_DEFER;
 | 
			
		||||
 | 
			
		||||
		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
 | 
			
		||||
 | 
			
		||||
	} else if (pdata) {
 | 
			
		||||
		type = pdata->type;
 | 
			
		||||
		clk_rate = pdata->clk_rate;
 | 
			
		||||
		needs_vcc = pdata->needs_vcc;
 | 
			
		||||
		nop->gpio_reset = pdata->gpio_reset;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc);
 | 
			
		||||
	err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -271,8 +273,6 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 | 
			
		|||
	platform_set_drvdata(pdev, nop);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
#ifndef _PHY_GENERIC_H_
 | 
			
		||||
#define _PHY_GENERIC_H_
 | 
			
		||||
 | 
			
		||||
#include <linux/usb/usb_phy_gen_xceiv.h>
 | 
			
		||||
 | 
			
		||||
struct usb_phy_gen_xceiv {
 | 
			
		||||
	struct usb_phy phy;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +16,6 @@ int usb_gen_phy_init(struct usb_phy *phy);
 | 
			
		|||
void usb_gen_phy_shutdown(struct usb_phy *phy);
 | 
			
		||||
 | 
			
		||||
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
 | 
			
		||||
		enum usb_phy_type type, u32 clk_rate, bool needs_vcc);
 | 
			
		||||
		struct usb_phy_gen_xceiv_platform_data *pdata);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,7 +164,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	mxs_phy->clk = clk;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, &mxs_phy->phy);
 | 
			
		||||
	platform_set_drvdata(pdev, mxs_phy);
 | 
			
		||||
 | 
			
		||||
	ret = usb_add_phy_dev(&mxs_phy->phy);
 | 
			
		||||
	if (ret)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,10 +107,10 @@ static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv)
 | 
			
		|||
	clk_prepare_enable(priv->clk);
 | 
			
		||||
 | 
			
		||||
	/* Set USB channels in the USBHS UGCTRL2 register */
 | 
			
		||||
	val = ioread32(priv->base);
 | 
			
		||||
	val = ioread32(priv->base + USBHS_UGCTRL2_REG);
 | 
			
		||||
	val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS);
 | 
			
		||||
	val |= priv->ugctrl2;
 | 
			
		||||
	iowrite32(val, priv->base);
 | 
			
		||||
	iowrite32(val, priv->base + USBHS_UGCTRL2_REG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Shutdown USB channels */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2123,6 +2123,20 @@ static void ftdi_set_termios(struct tty_struct *tty,
 | 
			
		|||
		termios->c_cflag |= CRTSCTS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * All FTDI UART chips are limited to CS7/8. We won't pretend to
 | 
			
		||||
	 * support CS5/6 and revert the CSIZE setting instead.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((C_CSIZE(tty) != CS8) && (C_CSIZE(tty) != CS7)) {
 | 
			
		||||
		dev_warn(ddev, "requested CSIZE setting not supported\n");
 | 
			
		||||
 | 
			
		||||
		termios->c_cflag &= ~CSIZE;
 | 
			
		||||
		if (old_termios)
 | 
			
		||||
			termios->c_cflag |= old_termios->c_cflag & CSIZE;
 | 
			
		||||
		else
 | 
			
		||||
			termios->c_cflag |= CS8;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cflag = termios->c_cflag;
 | 
			
		||||
 | 
			
		||||
	if (!old_termios)
 | 
			
		||||
| 
						 | 
				
			
			@ -2159,19 +2173,16 @@ no_skip:
 | 
			
		|||
	} else {
 | 
			
		||||
		urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;
 | 
			
		||||
	}
 | 
			
		||||
	if (cflag & CSIZE) {
 | 
			
		||||
	switch (cflag & CSIZE) {
 | 
			
		||||
	case CS7:
 | 
			
		||||
		urb_value |= 7;
 | 
			
		||||
		dev_dbg(ddev, "Setting CS7\n");
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
	case CS8:
 | 
			
		||||
		urb_value |= 8;
 | 
			
		||||
		dev_dbg(ddev, "Setting CS8\n");
 | 
			
		||||
		break;
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(ddev, "CSIZE was set but not CS7-CS8\n");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* This is needed by the break command since it uses the same command
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -173,16 +173,8 @@ retry:
 | 
			
		|||
		clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try sending off another urb, unless called from completion handler
 | 
			
		||||
	 * (in which case there will be no free urb or no data).
 | 
			
		||||
	 */
 | 
			
		||||
	if (mem_flags != GFP_ATOMIC)
 | 
			
		||||
		goto retry;
 | 
			
		||||
 | 
			
		||||
	clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	goto retry;	/* try sending off another urb */
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(usb_serial_generic_write_start);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
 | 
			
		|||
		return 0;
 | 
			
		||||
 | 
			
		||||
	count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
 | 
			
		||||
	result = usb_serial_generic_write_start(port, GFP_KERNEL);
 | 
			
		||||
	result = usb_serial_generic_write_start(port, GFP_ATOMIC);
 | 
			
		||||
	if (result)
 | 
			
		||||
		return result;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1813,7 +1813,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
 | 
			
		|||
	iflag = tty->termios.c_iflag;
 | 
			
		||||
 | 
			
		||||
	/* Change the number of bits */
 | 
			
		||||
	if (cflag & CSIZE) {
 | 
			
		||||
	switch (cflag & CSIZE) {
 | 
			
		||||
	case CS5:
 | 
			
		||||
		lData = LCR_BITS_5;
 | 
			
		||||
| 
						 | 
				
			
			@ -1826,12 +1825,13 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
 | 
			
		|||
	case CS7:
 | 
			
		||||
		lData = LCR_BITS_7;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
	case CS8:
 | 
			
		||||
		lData = LCR_BITS_8;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Change the Parity bit */
 | 
			
		||||
	if (cflag & PARENB) {
 | 
			
		||||
		if (cflag & PARODD) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,6 +85,7 @@ static void option_instat_callback(struct urb *urb);
 | 
			
		|||
#define HUAWEI_PRODUCT_K4505			0x1464
 | 
			
		||||
#define HUAWEI_PRODUCT_K3765			0x1465
 | 
			
		||||
#define HUAWEI_PRODUCT_K4605			0x14C6
 | 
			
		||||
#define HUAWEI_PRODUCT_E173S6			0x1C07
 | 
			
		||||
 | 
			
		||||
#define QUANTA_VENDOR_ID			0x0408
 | 
			
		||||
#define QUANTA_PRODUCT_Q101			0xEA02
 | 
			
		||||
| 
						 | 
				
			
			@ -572,6 +573,8 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
 | 
			
		||||
	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
 | 
			
		||||
		.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
 | 
			
		||||
	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
 | 
			
		||||
		.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
 | 
			
		||||
	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
 | 
			
		||||
		.driver_info = (kernel_ulong_t) &net_intf2_blacklist },
 | 
			
		||||
	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
 | 
			
		||||
| 
						 | 
				
			
			@ -634,6 +637,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			@ -688,6 +695,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			@ -742,6 +753,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			@ -796,6 +811,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			@ -850,6 +869,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			@ -904,6 +927,10 @@ static const struct usb_device_id option_ids[] = {
 | 
			
		|||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
 | 
			
		||||
	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -361,7 +361,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 | 
			
		|||
			    0, 0, buf, 7, 100);
 | 
			
		||||
	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 | 
			
		||||
 | 
			
		||||
	if (C_CSIZE(tty)) {
 | 
			
		||||
	switch (C_CSIZE(tty)) {
 | 
			
		||||
	case CS5:
 | 
			
		||||
		buf[6] = 5;
 | 
			
		||||
| 
						 | 
				
			
			@ -377,7 +376,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 | 
			
		|||
		buf[6] = 8;
 | 
			
		||||
	}
 | 
			
		||||
	dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* For reference buf[0]:buf[3] baud rate value */
 | 
			
		||||
	pl2303_encode_baudrate(tty, port, &buf[0]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -348,7 +348,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
 | 
			
		||||
	if (cflag & CSIZE) {
 | 
			
		||||
	switch (cflag & CSIZE) {
 | 
			
		||||
	case CS5:
 | 
			
		||||
		buf[1] |= SET_UART_FORMAT_SIZE_5;
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +363,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
 | 
			
		|||
		buf[1] |= SET_UART_FORMAT_SIZE_8;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set Stop bit2 : 0:1bit 1:2bit */
 | 
			
		||||
	buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 :
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,18 +97,12 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work);
 | 
			
		|||
 | 
			
		||||
static void wusb_dev_free(struct wusb_dev *wusb_dev)
 | 
			
		||||
{
 | 
			
		||||
	if (wusb_dev) {
 | 
			
		||||
		kfree(wusb_dev->set_gtk_req);
 | 
			
		||||
		usb_free_urb(wusb_dev->set_gtk_urb);
 | 
			
		||||
	kfree(wusb_dev);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
 | 
			
		||||
{
 | 
			
		||||
	struct wusb_dev *wusb_dev;
 | 
			
		||||
	struct urb *urb;
 | 
			
		||||
	struct usb_ctrlrequest *req;
 | 
			
		||||
 | 
			
		||||
	wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
 | 
			
		||||
	if (wusb_dev == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -118,22 +112,6 @@ static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
 | 
			
		|||
 | 
			
		||||
	INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
 | 
			
		||||
 | 
			
		||||
	urb = usb_alloc_urb(0, GFP_KERNEL);
 | 
			
		||||
	if (urb == NULL)
 | 
			
		||||
		goto err;
 | 
			
		||||
	wusb_dev->set_gtk_urb = urb;
 | 
			
		||||
 | 
			
		||||
	req = kmalloc(sizeof(*req), GFP_KERNEL);
 | 
			
		||||
	if (req == NULL)
 | 
			
		||||
		goto err;
 | 
			
		||||
	wusb_dev->set_gtk_req = req;
 | 
			
		||||
 | 
			
		||||
	req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
 | 
			
		||||
	req->bRequest = USB_REQ_SET_DESCRIPTOR;
 | 
			
		||||
	req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index);
 | 
			
		||||
	req->wIndex = 0;
 | 
			
		||||
	req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength);
 | 
			
		||||
 | 
			
		||||
	return wusb_dev;
 | 
			
		||||
err:
 | 
			
		||||
	wusb_dev_free(wusb_dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -411,9 +389,6 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
 | 
			
		|||
/*
 | 
			
		||||
 * Refresh the list of keep alives to emit in the MMC
 | 
			
		||||
 *
 | 
			
		||||
 * Some devices don't respond to keep alives unless they've been
 | 
			
		||||
 * authenticated, so skip unauthenticated devices.
 | 
			
		||||
 *
 | 
			
		||||
 * We only publish the first four devices that have a coming timeout
 | 
			
		||||
 * condition. Then when we are done processing those, we go for the
 | 
			
		||||
 * next ones. We ignore the ones that have timed out already (they'll
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +423,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
 | 
			
		|||
 | 
			
		||||
		if (wusb_dev == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated)
 | 
			
		||||
		if (wusb_dev->usb_dev == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -524,11 +499,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
 | 
			
		|||
 *
 | 
			
		||||
 * @wusbhc shall be referenced and unlocked
 | 
			
		||||
 */
 | 
			
		||||
static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
 | 
			
		||||
static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	struct wusb_dev *wusb_dev;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&wusbhc->mutex);
 | 
			
		||||
	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
 | 
			
		||||
	if (wusb_dev == NULL) {
 | 
			
		||||
		dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
 | 
			
		||||
			srcaddr);
 | 
			
		||||
	} else {
 | 
			
		||||
		wusb_dev->entry_ts = jiffies;
 | 
			
		||||
		__wusbhc_keep_alive(wusbhc);
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&wusbhc->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -582,14 +565,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
 | 
			
		|||
 *
 | 
			
		||||
 * @wusbhc shall be referenced and unlocked
 | 
			
		||||
 */
 | 
			
		||||
static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
 | 
			
		||||
static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = wusbhc->dev;
 | 
			
		||||
 | 
			
		||||
	dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr);
 | 
			
		||||
	struct wusb_dev *wusb_dev;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&wusbhc->mutex);
 | 
			
		||||
	__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx));
 | 
			
		||||
	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
 | 
			
		||||
	if (wusb_dev == NULL) {
 | 
			
		||||
		dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
 | 
			
		||||
			srcaddr);
 | 
			
		||||
	} else {
 | 
			
		||||
		dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
 | 
			
		||||
			wusb_dev->addr);
 | 
			
		||||
		__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
 | 
			
		||||
			wusb_dev->port_idx));
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&wusbhc->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -611,30 +602,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
 | 
			
		|||
		      struct wusb_dn_hdr *dn_hdr, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = wusbhc->dev;
 | 
			
		||||
	struct wusb_dev *wusb_dev;
 | 
			
		||||
 | 
			
		||||
	if (size < sizeof(struct wusb_dn_hdr)) {
 | 
			
		||||
		dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
 | 
			
		||||
			(int)size, (int)sizeof(struct wusb_dn_hdr));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
 | 
			
		||||
	if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) {
 | 
			
		||||
		dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n",
 | 
			
		||||
			dn_hdr->bType, srcaddr);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (dn_hdr->bType) {
 | 
			
		||||
	case WUSB_DN_CONNECT:
 | 
			
		||||
		wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
 | 
			
		||||
		break;
 | 
			
		||||
	case WUSB_DN_ALIVE:
 | 
			
		||||
		wusbhc_handle_dn_alive(wusbhc, wusb_dev);
 | 
			
		||||
		wusbhc_handle_dn_alive(wusbhc, srcaddr);
 | 
			
		||||
		break;
 | 
			
		||||
	case WUSB_DN_DISCONNECT:
 | 
			
		||||
		wusbhc_handle_dn_disconnect(wusbhc, wusb_dev);
 | 
			
		||||
		wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
 | 
			
		||||
		break;
 | 
			
		||||
	case WUSB_DN_MASAVAILCHANGED:
 | 
			
		||||
	case WUSB_DN_RWAKE:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,19 +29,16 @@
 | 
			
		|||
#include <linux/export.h>
 | 
			
		||||
#include "wusbhc.h"
 | 
			
		||||
 | 
			
		||||
static void wusbhc_set_gtk_callback(struct urb *urb);
 | 
			
		||||
static void wusbhc_gtk_rekey_done_work(struct work_struct *work);
 | 
			
		||||
static void wusbhc_gtk_rekey_work(struct work_struct *work);
 | 
			
		||||
 | 
			
		||||
int wusbhc_sec_create(struct wusbhc *wusbhc)
 | 
			
		||||
{
 | 
			
		||||
	wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data);
 | 
			
		||||
	wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
 | 
			
		||||
	wusbhc->gtk.descr.bReserved = 0;
 | 
			
		||||
	wusbhc->gtk_index = 0;
 | 
			
		||||
 | 
			
		||||
	wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
 | 
			
		||||
					   WUSB_KEY_INDEX_ORIGINATOR_HOST);
 | 
			
		||||
 | 
			
		||||
	INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work);
 | 
			
		||||
	INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +126,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc)
 | 
			
		|||
 */
 | 
			
		||||
void wusbhc_sec_stop(struct wusbhc *wusbhc)
 | 
			
		||||
{
 | 
			
		||||
	cancel_work_sync(&wusbhc->gtk_rekey_done_work);
 | 
			
		||||
	cancel_work_sync(&wusbhc->gtk_rekey_work);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -185,12 +182,14 @@ static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
 | 
			
		|||
static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_device *usb_dev = wusb_dev->usb_dev;
 | 
			
		||||
	u8 key_index = wusb_key_index(wusbhc->gtk_index,
 | 
			
		||||
		WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
 | 
			
		||||
 | 
			
		||||
	return usb_control_msg(
 | 
			
		||||
		usb_dev, usb_sndctrlpipe(usb_dev, 0),
 | 
			
		||||
		USB_REQ_SET_DESCRIPTOR,
 | 
			
		||||
		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
 | 
			
		||||
		USB_DT_KEY << 8 | wusbhc->gtk_index, 0,
 | 
			
		||||
		USB_DT_KEY << 8 | key_index, 0,
 | 
			
		||||
		&wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
 | 
			
		||||
		1000);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -520,24 +519,55 @@ error_kzalloc:
 | 
			
		|||
 * Once all connected and authenticated devices have received the new
 | 
			
		||||
 * GTK, switch the host to using it.
 | 
			
		||||
 */
 | 
			
		||||
static void wusbhc_gtk_rekey_done_work(struct work_struct *work)
 | 
			
		||||
static void wusbhc_gtk_rekey_work(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work);
 | 
			
		||||
	struct wusbhc *wusbhc = container_of(work,
 | 
			
		||||
					struct wusbhc, gtk_rekey_work);
 | 
			
		||||
	size_t key_size = sizeof(wusbhc->gtk.data);
 | 
			
		||||
	int port_idx;
 | 
			
		||||
	struct wusb_dev *wusb_dev, *wusb_dev_next;
 | 
			
		||||
	LIST_HEAD(rekey_list);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&wusbhc->mutex);
 | 
			
		||||
	/* generate the new key */
 | 
			
		||||
	wusbhc_generate_gtk(wusbhc);
 | 
			
		||||
	/* roll the gtk index. */
 | 
			
		||||
	wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Save all connected devices on a list while holding wusbhc->mutex and
 | 
			
		||||
	 * take a reference to each one.  Then submit the set key request to
 | 
			
		||||
	 * them after releasing the lock in order to avoid a deadlock.
 | 
			
		||||
	 */
 | 
			
		||||
	for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
 | 
			
		||||
		wusb_dev = wusbhc->port[port_idx].wusb_dev;
 | 
			
		||||
		if (!wusb_dev || !wusb_dev->usb_dev
 | 
			
		||||
			|| !wusb_dev->usb_dev->authenticated)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
	if (--wusbhc->pending_set_gtks == 0)
 | 
			
		||||
		wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size);
 | 
			
		||||
 | 
			
		||||
		wusb_dev_get(wusb_dev);
 | 
			
		||||
		list_add_tail(&wusb_dev->rekey_node, &rekey_list);
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&wusbhc->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wusbhc_set_gtk_callback(struct urb *urb)
 | 
			
		||||
{
 | 
			
		||||
	struct wusbhc *wusbhc = urb->context;
 | 
			
		||||
	/* Submit the rekey requests without holding wusbhc->mutex. */
 | 
			
		||||
	list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
 | 
			
		||||
		rekey_node) {
 | 
			
		||||
		list_del_init(&wusb_dev->rekey_node);
 | 
			
		||||
		dev_dbg(&wusb_dev->usb_dev->dev, "%s: rekey device at port %d\n",
 | 
			
		||||
			__func__, wusb_dev->port_idx);
 | 
			
		||||
 | 
			
		||||
	queue_work(wusbd, &wusbhc->gtk_rekey_done_work);
 | 
			
		||||
		if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
 | 
			
		||||
			dev_err(&wusb_dev->usb_dev->dev, "%s: rekey device at port %d failed\n",
 | 
			
		||||
				__func__, wusb_dev->port_idx);
 | 
			
		||||
		}
 | 
			
		||||
		wusb_dev_put(wusb_dev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Switch the host controller to use the new GTK. */
 | 
			
		||||
	mutex_lock(&wusbhc->mutex);
 | 
			
		||||
	wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
 | 
			
		||||
		&wusbhc->gtk.descr.bKeyData, key_size);
 | 
			
		||||
	mutex_unlock(&wusbhc->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -553,26 +583,12 @@ static void wusbhc_set_gtk_callback(struct urb *urb)
 | 
			
		|||
 */
 | 
			
		||||
void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
 | 
			
		||||
{
 | 
			
		||||
	static const size_t key_size = sizeof(wusbhc->gtk.data);
 | 
			
		||||
	int p;
 | 
			
		||||
 | 
			
		||||
	wusbhc_generate_gtk(wusbhc);
 | 
			
		||||
 | 
			
		||||
	for (p = 0; p < wusbhc->ports_max; p++) {
 | 
			
		||||
		struct wusb_dev *wusb_dev;
 | 
			
		||||
 | 
			
		||||
		wusb_dev = wusbhc->port[p].wusb_dev;
 | 
			
		||||
		if (!wusb_dev || !wusb_dev->usb_dev || !wusb_dev->usb_dev->authenticated)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev,
 | 
			
		||||
				     usb_sndctrlpipe(wusb_dev->usb_dev, 0),
 | 
			
		||||
				     (void *)wusb_dev->set_gtk_req,
 | 
			
		||||
				     &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
 | 
			
		||||
				     wusbhc_set_gtk_callback, wusbhc);
 | 
			
		||||
		if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0)
 | 
			
		||||
			wusbhc->pending_set_gtks++;
 | 
			
		||||
	}
 | 
			
		||||
	if (wusbhc->pending_set_gtks == 0)
 | 
			
		||||
		wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size);
 | 
			
		||||
	/*
 | 
			
		||||
	 * We need to submit a URB to the downstream WUSB devices in order to
 | 
			
		||||
	 * change the group key.  This can't be done while holding the
 | 
			
		||||
	 * wusbhc->mutex since that is also taken in the urb_enqueue routine
 | 
			
		||||
	 * and will cause a deadlock.  Instead, queue a work item to do
 | 
			
		||||
	 * it when the lock is not held
 | 
			
		||||
	 */
 | 
			
		||||
	queue_work(wusbd, &wusbhc->gtk_rekey_work);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,7 @@ struct wusb_dev {
 | 
			
		|||
	struct kref refcnt;
 | 
			
		||||
	struct wusbhc *wusbhc;
 | 
			
		||||
	struct list_head cack_node;	/* Connect-Ack list */
 | 
			
		||||
	struct list_head rekey_node;	/* GTK rekey list */
 | 
			
		||||
	u8 port_idx;
 | 
			
		||||
	u8 addr;
 | 
			
		||||
	u8 beacon_type:4;
 | 
			
		||||
| 
						 | 
				
			
			@ -107,8 +108,6 @@ struct wusb_dev {
 | 
			
		|||
	struct usb_wireless_cap_descriptor *wusb_cap_descr;
 | 
			
		||||
	struct uwb_mas_bm availability;
 | 
			
		||||
	struct work_struct devconnect_acked_work;
 | 
			
		||||
	struct urb *set_gtk_urb;
 | 
			
		||||
	struct usb_ctrlrequest *set_gtk_req;
 | 
			
		||||
	struct usb_device *usb_dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -296,8 +295,7 @@ struct wusbhc {
 | 
			
		|||
	} __attribute__((packed)) gtk;
 | 
			
		||||
	u8 gtk_index;
 | 
			
		||||
	u32 gtk_tkid;
 | 
			
		||||
	struct work_struct gtk_rekey_done_work;
 | 
			
		||||
	int pending_set_gtks;
 | 
			
		||||
	struct work_struct gtk_rekey_work;
 | 
			
		||||
 | 
			
		||||
	struct usb_encryption_descriptor *ccm1_etd;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1264,6 +1264,8 @@ typedef void (*usb_complete_t)(struct urb *);
 | 
			
		|||
 * @sg: scatter gather buffer list, the buffer size of each element in
 | 
			
		||||
 * 	the list (except the last) must be divisible by the endpoint's
 | 
			
		||||
 * 	max packet size if no_sg_constraint isn't set in 'struct usb_bus'
 | 
			
		||||
 * 	(FIXME: scatter-gather under xHCI is broken for periodic transfers.
 | 
			
		||||
 * 	Do not use urb->sg for interrupt endpoints for now, only bulk.)
 | 
			
		||||
 * @num_mapped_sgs: (internal) number of mapped sg entries
 | 
			
		||||
 * @num_sgs: number of entries in the sg list
 | 
			
		||||
 * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,6 +271,8 @@ static inline u8 wusb_key_index(int index, int type, int originator)
 | 
			
		|||
#define WUSB_KEY_INDEX_TYPE_GTK			2
 | 
			
		||||
#define WUSB_KEY_INDEX_ORIGINATOR_HOST		0
 | 
			
		||||
#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE	1
 | 
			
		||||
/* bits 0-3 used for the key index. */
 | 
			
		||||
#define WUSB_KEY_INDEX_MAX			15
 | 
			
		||||
 | 
			
		||||
/* A CCM Nonce, defined in WUSB1.0[6.4.1] */
 | 
			
		||||
struct aes_ccm_nonce {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,11 +3,12 @@
 | 
			
		|||
CC = $(CROSS_COMPILE)gcc
 | 
			
		||||
PTHREAD_LIBS = -lpthread
 | 
			
		||||
WARNINGS = -Wall -Wextra
 | 
			
		||||
CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include
 | 
			
		||||
CFLAGS = $(WARNINGS) -g -I../include
 | 
			
		||||
LDFLAGS = $(PTHREAD_LIBS)
 | 
			
		||||
 | 
			
		||||
all: testusb ffs-test
 | 
			
		||||
%: %.c
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ $^
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(RM) testusb ffs-test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue