diff options
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 18 | ||||
| -rw-r--r-- | drivers/usb/gadget/tcm_usb_gadget.c | 54 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-omap.c | 18 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 44 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 11 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 6 | ||||
| -rw-r--r-- | drivers/usb/serial/metro-usb.c | 8 | ||||
| -rw-r--r-- | drivers/usb/serial/option.c | 26 | 
9 files changed, 124 insertions, 63 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8fd398dffce..ee469274a3f 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -500,6 +500,8 @@ retry:  			goto retry;  		}  		if (!desc->reslength) { /* zero length read */ +			dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); +			clear_bit(WDM_READ, &desc->flags);  			spin_unlock_irq(&desc->iuspin);  			goto retry;  		} diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 25a7422ee65..8fb484984c8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub)  static int hub_port_reset(struct usb_hub *hub, int port1,  			struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive state? */ -static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus) +/* Is a USB 3.0 port in the Inactive or Complinance Mode state? + * Port worm reset is required to recover + */ +static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)  {  	return hub_is_superspeed(hub->hdev) && -		(portstatus & USB_PORT_STAT_LINK_STATE) == -		USB_SS_PORT_LS_SS_INACTIVE; +		(((portstatus & USB_PORT_STAT_LINK_STATE) == +		  USB_SS_PORT_LS_SS_INACTIVE) || +		 ((portstatus & USB_PORT_STAT_LINK_STATE) == +		  USB_SS_PORT_LS_COMP_MOD)) ;  }  static int hub_port_wait_reset(struct usb_hub *hub, int port1, @@ -2365,7 +2369,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,  			 *  			 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752  			 */ -			if (hub_port_inactive(hub, portstatus)) { +			if (hub_port_warm_reset_required(hub, portstatus)) {  				int ret;  				if ((portchange & USB_PORT_STAT_C_CONNECTION)) @@ -4408,9 +4412,7 @@ static void hub_events(void)  			/* Warm reset a USB3 protocol port if it's in  			 * SS.Inactive state.  			 */ -			if (hub_is_superspeed(hub->hdev) && -				(portstatus & USB_PORT_STAT_LINK_STATE) -					== USB_SS_PORT_LS_SS_INACTIVE) { +			if (hub_port_warm_reset_required(hub, portstatus)) {  				dev_dbg(hub_dev, "warm reset port %d\n", i);  				hub_port_reset(hub, i, NULL,  						HUB_BH_RESET_TIME, true); diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index c46439c8dd7..5444866e13e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -294,7 +294,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd)  		pr_err("%s(%d)\n", __func__, __LINE__);  	wait_for_completion(&cmd->write_complete); -	transport_generic_process_write(se_cmd); +	target_execute_cmd(se_cmd);  cleanup:  	return ret;  } @@ -725,7 +725,7 @@ static int uasp_send_write_request(struct usbg_cmd *cmd)  	}  	wait_for_completion(&cmd->write_complete); -	transport_generic_process_write(se_cmd); +	target_execute_cmd(se_cmd);  cleanup:  	return ret;  } @@ -1065,16 +1065,20 @@ static void usbg_cmd_work(struct work_struct *work)  				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,  				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,  				cmd->prio_attr, cmd->sense_iu.sense); - -		transport_send_check_condition_and_sense(se_cmd, -				TCM_UNSUPPORTED_SCSI_OPCODE, 1); -		usbg_cleanup_cmd(cmd); -		return; +		goto out;  	} -	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, +	if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,  			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, -			0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); +			0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0) +		goto out; + +	return; + +out: +	transport_send_check_condition_and_sense(se_cmd, +			TCM_UNSUPPORTED_SCSI_OPCODE, 1); +	usbg_cleanup_cmd(cmd);  }  static int usbg_submit_command(struct f_uas *fu, @@ -1177,16 +1181,20 @@ static void bot_cmd_work(struct work_struct *work)  				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,  				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,  				cmd->prio_attr, cmd->sense_iu.sense); - -		transport_send_check_condition_and_sense(se_cmd, -				TCM_UNSUPPORTED_SCSI_OPCODE, 1); -		usbg_cleanup_cmd(cmd); -		return; +		goto out;  	} -	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, +	if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,  			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, -			cmd->data_len, cmd->prio_attr, dir, 0); +			cmd->data_len, cmd->prio_attr, dir, 0) < 0) +		goto out; + +	return; + +out: +	transport_send_check_condition_and_sense(se_cmd, +				TCM_UNSUPPORTED_SCSI_OPCODE, 1); +	usbg_cleanup_cmd(cmd);  }  static int bot_submit_command(struct f_uas *fu, @@ -1400,19 +1408,6 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)  	return 1;  } -static int usbg_new_cmd(struct se_cmd *se_cmd) -{ -	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, -			se_cmd); -	int ret; - -	ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); -	if (ret) -		return ret; - -	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); -} -  static void usbg_cmd_release(struct kref *ref)  {  	struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, @@ -1902,7 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = {  	.tpg_alloc_fabric_acl		= usbg_alloc_fabric_acl,  	.tpg_release_fabric_acl		= usbg_release_fabric_acl,  	.tpg_get_inst_index		= usbg_tpg_get_inst_index, -	.new_cmd_map			= usbg_new_cmd,  	.release_cmd			= usbg_release_cmd,  	.shutdown_session		= usbg_shutdown_session,  	.close_session			= usbg_close_session, diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 17cfb8a1131..c30435499a0 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -281,14 +281,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  		}  	} +	/* Hold PHYs in reset while initializing EHCI controller */  	if (pdata->phy_reset) {  		if (gpio_is_valid(pdata->reset_gpio_port[0])) -			gpio_request_one(pdata->reset_gpio_port[0], -					 GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); +			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);  		if (gpio_is_valid(pdata->reset_gpio_port[1])) -			gpio_request_one(pdata->reset_gpio_port[1], -					 GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); +			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);  		/* Hold the PHY in RESET for enough time till DIR is high */  		udelay(10); @@ -330,6 +329,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  	omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);  	ehci_reset(omap_ehci); +	ret = usb_add_hcd(hcd, irq, IRQF_SHARED); +	if (ret) { +		dev_err(dev, "failed to add hcd with err %d\n", ret); +		goto err_add_hcd; +	}  	if (pdata->phy_reset) {  		/* Hold the PHY in RESET for enough time till @@ -344,12 +348,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);  	} -	ret = usb_add_hcd(hcd, irq, IRQF_SHARED); -	if (ret) { -		dev_err(dev, "failed to add hcd with err %d\n", ret); -		goto err_add_hcd; -	} -  	/* root ports should always stay powered */  	ehci_port_power(omap_ehci, 1); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 2732ef660c5..7b01094d799 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,  	}  } +/* Updates Link Status for super Speed port */ +static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +{ +	u32 pls = status_reg & PORT_PLS_MASK; + +	/* resume state is a xHCI internal state. +	 * Do not report it to usb core. +	 */ +	if (pls == XDEV_RESUME) +		return; + +	/* When the CAS bit is set then warm reset +	 * should be performed on port +	 */ +	if (status_reg & PORT_CAS) { +		/* The CAS bit can be set while the port is +		 * in any link state. +		 * Only roothubs have CAS bit, so we +		 * pretend to be in compliance mode +		 * unless we're already in compliance +		 * or the inactive state. +		 */ +		if (pls != USB_SS_PORT_LS_COMP_MOD && +		    pls != USB_SS_PORT_LS_SS_INACTIVE) { +			pls = USB_SS_PORT_LS_COMP_MOD; +		} +		/* Return also connection bit - +		 * hub state machine resets port +		 * when this bit is set. +		 */ +		pls |= USB_PORT_STAT_CONNECTION; +	} +	/* update status field */ +	*status |= pls; +} +  int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		u16 wIndex, char *buf, u16 wLength)  { @@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			else  				status |= USB_PORT_STAT_POWER;  		} -		/* Port Link State */ +		/* Update Port Link State for super speed ports*/  		if (hcd->speed == HCD_USB3) { -			/* resume state is a xHCI internal state. -			 * Do not report it to usb core. -			 */ -			if ((temp & PORT_PLS_MASK) != XDEV_RESUME) -				status |= (temp & PORT_PLS_MASK); +			xhci_hub_report_link_state(&status, temp);  		}  		if (bus_state->port_c_suspend & (1 << wIndex))  			status |= 1 << USB_PORT_FEAT_C_SUSPEND; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 23b4aefd103..8275645889d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,  	num_trbs_free_temp = ep_ring->num_trbs_free;  	dequeue_temp = ep_ring->dequeue; +	/* If we get two back-to-back stalls, and the first stalled transfer +	 * ends just before a link TRB, the dequeue pointer will be left on +	 * the link TRB by the code in the while loop.  So we have to update +	 * the dequeue pointer one segment further, or we'll jump off +	 * the segment into la-la-land. +	 */ +	if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { +		ep_ring->deq_seg = ep_ring->deq_seg->next; +		ep_ring->dequeue = ep_ring->deq_seg->trbs; +	} +  	while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {  		/* We have more usable TRBs */  		ep_ring->num_trbs_free++; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index de3d6e3e57b..55c0785810c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -341,7 +341,11 @@ struct xhci_op_regs {  #define PORT_PLC	(1 << 22)  /* port configure error change - port failed to configure its link partner */  #define PORT_CEC	(1 << 23) -/* bit 24 reserved */ +/* Cold Attach Status - xHC can set this bit to report device attached during + * Sx state. Warm port reset should be perfomed to clear this bit and move port + * to connected state. + */ +#define PORT_CAS	(1 << 24)  /* wake on connect (enable) */  #define PORT_WKCONN_E	(1 << 25)  /* wake on disconnect (enable) */ diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 81423f7361d..d47eb06fe46 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)  	metro_priv->throttled = 0;  	spin_unlock_irqrestore(&metro_priv->lock, flags); -	/* -	 * Force low_latency on so that our tty_push actually forces the data -	 * through, otherwise it is scheduled, and with high data rates (like -	 * with OHCI) data can get lost. -	 */ -	if (tty) -		tty->low_latency = 1; -  	/* Clear the urb pipe. */  	usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index adf8ce72be5..417ab1b0aa3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb);  /* MediaTek products */  #define MEDIATEK_VENDOR_ID			0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM		0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM		0x00a5 +#define MEDIATEK_PRODUCT_DC_5COM		0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM		0x7101 +#define MEDIATEK_PRODUCT_7208_2COM		0x7102 +#define MEDIATEK_PRODUCT_FP_1COM		0x0003 +#define MEDIATEK_PRODUCT_FP_2COM		0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM		0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM		0x0033  /* Cellient products */  #define CELLIENT_VENDOR_ID			0x2692 @@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = {  	.reserved = BIT(1),  }; +static const struct option_blacklist_info net_intf2_blacklist = { +	.reserved = BIT(2), +}; +  static const struct option_blacklist_info net_intf3_blacklist = {  	.reserved = BIT(3),  }; @@ -1099,6 +1112,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), +		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,  	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, @@ -1240,6 +1255,17 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) },        /* MediaTek MT6276M modem & app port */ +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },  	{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },  	{ } /* Terminating entry */  };  | 
