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

Commit 46fed0a5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files


Pull USB fixes from Greg Kroah-Hartman:
 "Here are a bunch of USB fixes for your 3.8-rc3 tree.  They all either
  fix problems that have been reported (like the xhci/hub changes) or
  add new device ids to existing drivers.

  Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org&gt;">

* tag 'usb-3.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (39 commits)
  usb: ftdi_sio: Crucible Technologies COMET Caller ID - pid added
  usb: host: ohci-tmio: fix compile warning
  USB: Add device quirk for Microsoft VX700 webcam
  USB: ehci-fsl: fix regression on mpc5121e
  usb: chipidea: Allow disabling streaming not only in udc mode
  USB: fsl-mph-dr-of: fix regression on mpc5121e
  USB: select USB_ARCH_HAS_EHCI for MXS
  USB: hub: handle claim of enabled remote wakeup after reset
  USB: cdc-acm: Add support for "PSC Scanning, Magellan 800i"
  USB: option: add Nexpring NP10T terminal id
  USB: option: add Telekom Speedstick LTE II
  USB: option: blacklist network interface on ZTE MF880
  usb: imx21-hcd: Include missing linux/module.h
  USB: option: Add new MEDIATEK PID support
  USB: ehci: make debug port in-use detection functional again
  USB: usbtest: fix test number in log message
  xhci: Avoid "dead ports", add roothub port polling.
  USB: Handle warm reset failure on empty port.
  USB: Ignore port state until reset completes.
  USB: Increase reset timeout.
  ...
parents 3441f0d2 8cf65dc3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ config USB_ARCH_HAS_EHCI
	default y if ARCH_W90X900
	default y if ARCH_W90X900
	default y if ARCH_AT91
	default y if ARCH_AT91
	default y if ARCH_MXC
	default y if ARCH_MXC
	default y if ARCH_MXS
	default y if ARCH_OMAP3
	default y if ARCH_OMAP3
	default y if ARCH_CNS3XXX
	default y if ARCH_CNS3XXX
	default y if ARCH_VT8500
	default y if ARCH_VT8500
+3 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,9 @@ static int host_start(struct ci13xxx *ci)
	else
	else
		ci->hcd = hcd;
		ci->hcd = hcd;


	if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);

	return ret;
	return ret;
}
}


+3 −0
Original line number Original line Diff line number Diff line
@@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = {
	{ USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
	{ USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
	.driver_info = NO_UNION_NORMAL,
	.driver_info = NO_UNION_NORMAL,
	},
	},
	{ USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
	.driver_info = NO_UNION_NORMAL,
	},
	{ USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
	{ USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
	.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
	.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
	},
	},
+96 −24
Original line number Original line Diff line number Diff line
@@ -877,6 +877,60 @@ static int hub_hub_status(struct usb_hub *hub,
	return ret;
	return ret;
}
}


static int hub_set_port_link_state(struct usb_hub *hub, int port1,
			unsigned int link_status)
{
	return set_port_feature(hub->hdev,
			port1 | (link_status << 3),
			USB_PORT_FEAT_LINK_STATE);
}

/*
 * If USB 3.0 ports are placed into the Disabled state, they will no longer
 * detect any device connects or disconnects.  This is generally not what the
 * USB core wants, since it expects a disabled port to produce a port status
 * change event when a new device connects.
 *
 * Instead, set the link state to Disabled, wait for the link to settle into
 * that state, clear any change bits, and then put the port into the RxDetect
 * state.
 */
static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
{
	int ret;
	int total_time;
	u16 portchange, portstatus;

	if (!hub_is_superspeed(hub->hdev))
		return -EINVAL;

	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
	if (ret) {
		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
				port1, ret);
		return ret;
	}

	/* Wait for the link to enter the disabled state. */
	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
		ret = hub_port_status(hub, port1, &portstatus, &portchange);
		if (ret < 0)
			return ret;

		if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
				USB_SS_PORT_LS_SS_DISABLED)
			break;
		if (total_time >= HUB_DEBOUNCE_TIMEOUT)
			break;
		msleep(HUB_DEBOUNCE_STEP);
	}
	if (total_time >= HUB_DEBOUNCE_TIMEOUT)
		dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n",
				port1, total_time);

	return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);
}

static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{
{
	struct usb_device *hdev = hub->hdev;
	struct usb_device *hdev = hub->hdev;
@@ -885,8 +939,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
	if (hub->ports[port1 - 1]->child && set_state)
	if (hub->ports[port1 - 1]->child && set_state)
		usb_set_device_state(hub->ports[port1 - 1]->child,
		usb_set_device_state(hub->ports[port1 - 1]->child,
				USB_STATE_NOTATTACHED);
				USB_STATE_NOTATTACHED);
	if (!hub->error && !hub_is_superspeed(hub->hdev))
	if (!hub->error) {
		ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
		if (hub_is_superspeed(hub->hdev))
			ret = hub_usb3_port_disable(hub, port1);
		else
			ret = clear_port_feature(hdev, port1,
					USB_PORT_FEAT_ENABLE);
	}
	if (ret)
	if (ret)
		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
				port1, ret);
				port1, ret);
@@ -2440,7 +2499,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#define HUB_SHORT_RESET_TIME	10
#define HUB_SHORT_RESET_TIME	10
#define HUB_BH_RESET_TIME	50
#define HUB_BH_RESET_TIME	50
#define HUB_LONG_RESET_TIME	200
#define HUB_LONG_RESET_TIME	200
#define HUB_RESET_TIMEOUT	500
#define HUB_RESET_TIMEOUT	800


static int hub_port_reset(struct usb_hub *hub, int port1,
static int hub_port_reset(struct usb_hub *hub, int port1,
			struct usb_device *udev, unsigned int delay, bool warm);
			struct usb_device *udev, unsigned int delay, bool warm);
@@ -2475,6 +2534,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;


		/* The port state is unknown until the reset completes. */
		if ((portstatus & USB_PORT_STAT_RESET))
			goto delay;

		/*
		/*
		 * Some buggy devices require a warm reset to be issued even
		 * Some buggy devices require a warm reset to be issued even
		 * when the port appears not to be connected.
		 * when the port appears not to be connected.
@@ -2520,11 +2583,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
			if ((portchange & USB_PORT_STAT_C_CONNECTION))
			if ((portchange & USB_PORT_STAT_C_CONNECTION))
				return -ENOTCONN;
				return -ENOTCONN;


			/* if we`ve finished resetting, then break out of
			if ((portstatus & USB_PORT_STAT_ENABLE)) {
			 * the loop
			 */
			if (!(portstatus & USB_PORT_STAT_RESET) &&
			    (portstatus & USB_PORT_STAT_ENABLE)) {
				if (hub_is_wusb(hub))
				if (hub_is_wusb(hub))
					udev->speed = USB_SPEED_WIRELESS;
					udev->speed = USB_SPEED_WIRELESS;
				else if (hub_is_superspeed(hub->hdev))
				else if (hub_is_superspeed(hub->hdev))
@@ -2538,10 +2597,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
				return 0;
				return 0;
			}
			}
		} else {
		} else {
			if (portchange & USB_PORT_STAT_C_BH_RESET)
			if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
					hub_port_warm_reset_required(hub,
						portstatus))
				return -ENOTCONN;

			return 0;
			return 0;
		}
		}


delay:
		/* switch to the long delay after two short delay failures */
		/* switch to the long delay after two short delay failures */
		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
			delay = HUB_LONG_RESET_TIME;
			delay = HUB_LONG_RESET_TIME;
@@ -2565,14 +2629,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
			msleep(10 + 40);
			msleep(10 + 40);
			update_devnum(udev, 0);
			update_devnum(udev, 0);
			hcd = bus_to_hcd(udev->bus);
			hcd = bus_to_hcd(udev->bus);
			if (hcd->driver->reset_device) {
			/* The xHC may think the device is already reset,
				*status = hcd->driver->reset_device(hcd, udev);
			 * so ignore the status.
				if (*status < 0) {
			 */
					dev_err(&udev->dev, "Cannot reset "
			if (hcd->driver->reset_device)
							"HCD device state\n");
				hcd->driver->reset_device(hcd, udev);
					break;
				}
			}
		}
		}
		/* FALL THROUGH */
		/* FALL THROUGH */
	case -ENOTCONN:
	case -ENOTCONN:
@@ -2580,16 +2641,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
		clear_port_feature(hub->hdev,
		clear_port_feature(hub->hdev,
				port1, USB_PORT_FEAT_C_RESET);
				port1, USB_PORT_FEAT_C_RESET);
		/* FIXME need disconnect() for NOTATTACHED device */
		/* FIXME need disconnect() for NOTATTACHED device */
		if (warm) {
		if (hub_is_superspeed(hub->hdev)) {
			clear_port_feature(hub->hdev, port1,
			clear_port_feature(hub->hdev, port1,
					USB_PORT_FEAT_C_BH_PORT_RESET);
					USB_PORT_FEAT_C_BH_PORT_RESET);
			clear_port_feature(hub->hdev, port1,
			clear_port_feature(hub->hdev, port1,
					USB_PORT_FEAT_C_PORT_LINK_STATE);
					USB_PORT_FEAT_C_PORT_LINK_STATE);
		} else {
		}
		if (!warm)
			usb_set_device_state(udev, *status
			usb_set_device_state(udev, *status
					? USB_STATE_NOTATTACHED
					? USB_STATE_NOTATTACHED
					: USB_STATE_DEFAULT);
					: USB_STATE_DEFAULT);
		}
		break;
		break;
	}
	}
}
}
@@ -2939,7 +3000,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
static int finish_port_resume(struct usb_device *udev)
static int finish_port_resume(struct usb_device *udev)
{
{
	int	status = 0;
	int	status = 0;
	u16	devstatus;
	u16	devstatus = 0;


	/* caller owns the udev device lock */
	/* caller owns the udev device lock */
	dev_dbg(&udev->dev, "%s\n",
	dev_dbg(&udev->dev, "%s\n",
@@ -2984,7 +3045,13 @@ static int finish_port_resume(struct usb_device *udev)
	if (status) {
	if (status) {
		dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
		dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
				status);
				status);
	} else if (udev->actconfig) {
	/*
	 * There are a few quirky devices which violate the standard
	 * by claiming to have remote wakeup enabled after a reset,
	 * which crash if the feature is cleared, hence check for
	 * udev->reset_resume
	 */
	} else if (udev->actconfig && !udev->reset_resume) {
		le16_to_cpus(&devstatus);
		le16_to_cpus(&devstatus);
		if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
		if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
			status = usb_control_msg(udev,
			status = usb_control_msg(udev,
@@ -4638,9 +4705,14 @@ static void hub_events(void)
			 * SS.Inactive state.
			 * SS.Inactive state.
			 */
			 */
			if (hub_port_warm_reset_required(hub, portstatus)) {
			if (hub_port_warm_reset_required(hub, portstatus)) {
				int status;

				dev_dbg(hub_dev, "warm reset port %d\n", i);
				dev_dbg(hub_dev, "warm reset port %d\n", i);
				hub_port_reset(hub, i, NULL,
				status = hub_port_reset(hub, i, NULL,
						HUB_BH_RESET_TIME, true);
						HUB_BH_RESET_TIME, true);
				if (status < 0)
					hub_port_disable(hub, i, 1);
				connect_change = 0;
			}
			}


			if (connect_change)
			if (connect_change)
+3 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = {
	/* Creative SB Audigy 2 NX */
	/* Creative SB Audigy 2 NX */
	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },


	/* Microsoft LifeCam-VX700 v2.0 */
	{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },

	/* Logitech Quickcam Fusion */
	/* Logitech Quickcam Fusion */
	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },


Loading