diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 374 |
1 files changed, 185 insertions, 189 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e492bca74425..782ce2e31c7f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -4413,66 +4413,15 @@ hub_power_remaining (struct usb_hub *hub) | |||
4413 | return remaining; | 4413 | return remaining; |
4414 | } | 4414 | } |
4415 | 4415 | ||
4416 | /* Handle physical or logical connection change events. | 4416 | static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, |
4417 | * This routine is called when: | 4417 | u16 portchange) |
4418 | * a port connection-change occurs; | ||
4419 | * a port enable-change occurs (often caused by EMI); | ||
4420 | * usb_reset_and_verify_device() encounters changed descriptors (as from | ||
4421 | * a firmware download) | ||
4422 | * caller already locked the hub | ||
4423 | */ | ||
4424 | static void hub_port_connect_change(struct usb_hub *hub, int port1, | ||
4425 | u16 portstatus, u16 portchange) | ||
4426 | { | 4418 | { |
4419 | int status, i; | ||
4420 | unsigned unit_load; | ||
4427 | struct usb_device *hdev = hub->hdev; | 4421 | struct usb_device *hdev = hub->hdev; |
4428 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); | 4422 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); |
4429 | struct usb_port *port_dev = hub->ports[port1 - 1]; | 4423 | struct usb_port *port_dev = hub->ports[port1 - 1]; |
4430 | struct usb_device *udev; | 4424 | struct usb_device *udev = port_dev->child; |
4431 | int status, i; | ||
4432 | unsigned unit_load; | ||
4433 | |||
4434 | dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", | ||
4435 | portstatus, portchange, portspeed(hub, portstatus)); | ||
4436 | |||
4437 | if (hub->has_indicators) { | ||
4438 | set_port_led(hub, port1, HUB_LED_AUTO); | ||
4439 | hub->indicator[port1-1] = INDICATOR_AUTO; | ||
4440 | } | ||
4441 | |||
4442 | #ifdef CONFIG_USB_OTG | ||
4443 | /* during HNP, don't repeat the debounce */ | ||
4444 | if (hdev->bus->is_b_host) | ||
4445 | portchange &= ~(USB_PORT_STAT_C_CONNECTION | | ||
4446 | USB_PORT_STAT_C_ENABLE); | ||
4447 | #endif | ||
4448 | |||
4449 | /* Try to resuscitate an existing device */ | ||
4450 | udev = port_dev->child; | ||
4451 | if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && | ||
4452 | udev->state != USB_STATE_NOTATTACHED) { | ||
4453 | usb_lock_device(udev); | ||
4454 | if (portstatus & USB_PORT_STAT_ENABLE) { | ||
4455 | status = 0; /* Nothing to do */ | ||
4456 | |||
4457 | #ifdef CONFIG_PM_RUNTIME | ||
4458 | } else if (udev->state == USB_STATE_SUSPENDED && | ||
4459 | udev->persist_enabled) { | ||
4460 | /* For a suspended device, treat this as a | ||
4461 | * remote wakeup event. | ||
4462 | */ | ||
4463 | status = usb_remote_wakeup(udev); | ||
4464 | #endif | ||
4465 | |||
4466 | } else { | ||
4467 | status = -ENODEV; /* Don't resuscitate */ | ||
4468 | } | ||
4469 | usb_unlock_device(udev); | ||
4470 | |||
4471 | if (status == 0) { | ||
4472 | clear_bit(port1, hub->change_bits); | ||
4473 | return; | ||
4474 | } | ||
4475 | } | ||
4476 | 4425 | ||
4477 | /* Disconnect any existing devices under this port */ | 4426 | /* Disconnect any existing devices under this port */ |
4478 | if (udev) { | 4427 | if (udev) { |
@@ -4481,7 +4430,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, | |||
4481 | usb_phy_notify_disconnect(hcd->phy, udev->speed); | 4430 | usb_phy_notify_disconnect(hcd->phy, udev->speed); |
4482 | usb_disconnect(&port_dev->child); | 4431 | usb_disconnect(&port_dev->child); |
4483 | } | 4432 | } |
4484 | clear_bit(port1, hub->change_bits); | ||
4485 | 4433 | ||
4486 | /* We can forget about a "removed" device when there's a physical | 4434 | /* We can forget about a "removed" device when there's a physical |
4487 | * disconnect or the connect status changes. | 4435 | * disconnect or the connect status changes. |
@@ -4663,6 +4611,65 @@ done: | |||
4663 | hub_port_disable(hub, port1, 1); | 4611 | hub_port_disable(hub, port1, 1); |
4664 | if (hcd->driver->relinquish_port && !hub->hdev->parent) | 4612 | if (hcd->driver->relinquish_port && !hub->hdev->parent) |
4665 | hcd->driver->relinquish_port(hcd, port1); | 4613 | hcd->driver->relinquish_port(hcd, port1); |
4614 | |||
4615 | } | ||
4616 | |||
4617 | /* Handle physical or logical connection change events. | ||
4618 | * This routine is called when: | ||
4619 | * a port connection-change occurs; | ||
4620 | * a port enable-change occurs (often caused by EMI); | ||
4621 | * usb_reset_and_verify_device() encounters changed descriptors (as from | ||
4622 | * a firmware download) | ||
4623 | * caller already locked the hub | ||
4624 | */ | ||
4625 | static void hub_port_connect_change(struct usb_hub *hub, int port1, | ||
4626 | u16 portstatus, u16 portchange) | ||
4627 | { | ||
4628 | struct usb_port *port_dev = hub->ports[port1 - 1]; | ||
4629 | struct usb_device *udev = port_dev->child; | ||
4630 | int status = -ENODEV; | ||
4631 | |||
4632 | dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, | ||
4633 | portchange, portspeed(hub, portstatus)); | ||
4634 | |||
4635 | if (hub->has_indicators) { | ||
4636 | set_port_led(hub, port1, HUB_LED_AUTO); | ||
4637 | hub->indicator[port1-1] = INDICATOR_AUTO; | ||
4638 | } | ||
4639 | |||
4640 | #ifdef CONFIG_USB_OTG | ||
4641 | /* during HNP, don't repeat the debounce */ | ||
4642 | if (hub->hdev->bus->is_b_host) | ||
4643 | portchange &= ~(USB_PORT_STAT_C_CONNECTION | | ||
4644 | USB_PORT_STAT_C_ENABLE); | ||
4645 | #endif | ||
4646 | |||
4647 | /* Try to resuscitate an existing device */ | ||
4648 | if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && | ||
4649 | udev->state != USB_STATE_NOTATTACHED) { | ||
4650 | if (portstatus & USB_PORT_STAT_ENABLE) { | ||
4651 | status = 0; /* Nothing to do */ | ||
4652 | #ifdef CONFIG_PM_RUNTIME | ||
4653 | } else if (udev->state == USB_STATE_SUSPENDED && | ||
4654 | udev->persist_enabled) { | ||
4655 | /* For a suspended device, treat this as a | ||
4656 | * remote wakeup event. | ||
4657 | */ | ||
4658 | usb_lock_device(udev); | ||
4659 | status = usb_remote_wakeup(udev); | ||
4660 | usb_unlock_device(udev); | ||
4661 | #endif | ||
4662 | } else { | ||
4663 | /* Don't resuscitate */; | ||
4664 | } | ||
4665 | |||
4666 | } | ||
4667 | clear_bit(port1, hub->change_bits); | ||
4668 | |||
4669 | if (status == 0) | ||
4670 | return; | ||
4671 | |||
4672 | hub_port_connect(hub, port1, portstatus, portchange); | ||
4666 | } | 4673 | } |
4667 | 4674 | ||
4668 | /* Returns 1 if there was a remote wakeup and a connect status change. */ | 4675 | /* Returns 1 if there was a remote wakeup and a connect status change. */ |
@@ -4705,6 +4712,121 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, | |||
4705 | return connect_change; | 4712 | return connect_change; |
4706 | } | 4713 | } |
4707 | 4714 | ||
4715 | static void port_event(struct usb_hub *hub, int port1) | ||
4716 | { | ||
4717 | int connect_change, reset_device = 0; | ||
4718 | struct usb_port *port_dev = hub->ports[port1 - 1]; | ||
4719 | struct usb_device *udev = port_dev->child; | ||
4720 | struct usb_device *hdev = hub->hdev; | ||
4721 | u16 portstatus, portchange; | ||
4722 | |||
4723 | connect_change = test_bit(port1, hub->change_bits); | ||
4724 | clear_bit(port1, hub->event_bits); | ||
4725 | clear_bit(port1, hub->wakeup_bits); | ||
4726 | |||
4727 | if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) | ||
4728 | return; | ||
4729 | |||
4730 | if (portchange & USB_PORT_STAT_C_CONNECTION) { | ||
4731 | usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); | ||
4732 | connect_change = 1; | ||
4733 | } | ||
4734 | |||
4735 | if (portchange & USB_PORT_STAT_C_ENABLE) { | ||
4736 | if (!connect_change) | ||
4737 | dev_dbg(&port_dev->dev, "enable change, status %08x\n", | ||
4738 | portstatus); | ||
4739 | usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); | ||
4740 | |||
4741 | /* | ||
4742 | * EM interference sometimes causes badly shielded USB devices | ||
4743 | * to be shutdown by the hub, this hack enables them again. | ||
4744 | * Works at least with mouse driver. | ||
4745 | */ | ||
4746 | if (!(portstatus & USB_PORT_STAT_ENABLE) | ||
4747 | && !connect_change && udev) { | ||
4748 | dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); | ||
4749 | connect_change = 1; | ||
4750 | } | ||
4751 | } | ||
4752 | |||
4753 | if (portchange & USB_PORT_STAT_C_OVERCURRENT) { | ||
4754 | u16 status = 0, unused; | ||
4755 | |||
4756 | dev_dbg(&port_dev->dev, "over-current change\n"); | ||
4757 | usb_clear_port_feature(hdev, port1, | ||
4758 | USB_PORT_FEAT_C_OVER_CURRENT); | ||
4759 | msleep(100); /* Cool down */ | ||
4760 | hub_power_on(hub, true); | ||
4761 | hub_port_status(hub, port1, &status, &unused); | ||
4762 | if (status & USB_PORT_STAT_OVERCURRENT) | ||
4763 | dev_err(&port_dev->dev, "over-current condition\n"); | ||
4764 | } | ||
4765 | |||
4766 | if (portchange & USB_PORT_STAT_C_RESET) { | ||
4767 | dev_dbg(&port_dev->dev, "reset change\n"); | ||
4768 | usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); | ||
4769 | } | ||
4770 | if ((portchange & USB_PORT_STAT_C_BH_RESET) | ||
4771 | && hub_is_superspeed(hdev)) { | ||
4772 | dev_dbg(&port_dev->dev, "warm reset change\n"); | ||
4773 | usb_clear_port_feature(hdev, port1, | ||
4774 | USB_PORT_FEAT_C_BH_PORT_RESET); | ||
4775 | } | ||
4776 | if (portchange & USB_PORT_STAT_C_LINK_STATE) { | ||
4777 | dev_dbg(&port_dev->dev, "link state change\n"); | ||
4778 | usb_clear_port_feature(hdev, port1, | ||
4779 | USB_PORT_FEAT_C_PORT_LINK_STATE); | ||
4780 | } | ||
4781 | if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { | ||
4782 | dev_warn(&port_dev->dev, "config error\n"); | ||
4783 | usb_clear_port_feature(hdev, port1, | ||
4784 | USB_PORT_FEAT_C_PORT_CONFIG_ERROR); | ||
4785 | } | ||
4786 | |||
4787 | if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange)) | ||
4788 | connect_change = 1; | ||
4789 | |||
4790 | /* | ||
4791 | * Warm reset a USB3 protocol port if it's in | ||
4792 | * SS.Inactive state. | ||
4793 | */ | ||
4794 | if (hub_port_warm_reset_required(hub, portstatus)) { | ||
4795 | dev_dbg(&port_dev->dev, "do warm reset\n"); | ||
4796 | if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) | ||
4797 | || udev->state == USB_STATE_NOTATTACHED) { | ||
4798 | if (hub_port_reset(hub, port1, NULL, | ||
4799 | HUB_BH_RESET_TIME, true) < 0) | ||
4800 | hub_port_disable(hub, port1, 1); | ||
4801 | } else | ||
4802 | reset_device = 1; | ||
4803 | } | ||
4804 | |||
4805 | /* | ||
4806 | * On disconnect USB3 protocol ports transit from U0 to | ||
4807 | * SS.Inactive to Rx.Detect. If this happens a warm- | ||
4808 | * reset is not needed, but a (re)connect may happen | ||
4809 | * before khubd runs and sees the disconnect, and the | ||
4810 | * device may be an unknown state. | ||
4811 | * | ||
4812 | * If the port went through SS.Inactive without khubd | ||
4813 | * seeing it the C_LINK_STATE change flag will be set, | ||
4814 | * and we reset the dev to put it in a known state. | ||
4815 | */ | ||
4816 | if (reset_device || (udev && hub_is_superspeed(hub->hdev) | ||
4817 | && (portchange & USB_PORT_STAT_C_LINK_STATE) | ||
4818 | && (portstatus & USB_PORT_STAT_CONNECTION))) { | ||
4819 | usb_lock_device(udev); | ||
4820 | usb_reset_device(udev); | ||
4821 | usb_unlock_device(udev); | ||
4822 | connect_change = 0; | ||
4823 | } | ||
4824 | |||
4825 | if (connect_change) | ||
4826 | hub_port_connect_change(hub, port1, portstatus, portchange); | ||
4827 | } | ||
4828 | |||
4829 | |||
4708 | static void hub_events(void) | 4830 | static void hub_events(void) |
4709 | { | 4831 | { |
4710 | struct list_head *tmp; | 4832 | struct list_head *tmp; |
@@ -4714,10 +4836,7 @@ static void hub_events(void) | |||
4714 | struct device *hub_dev; | 4836 | struct device *hub_dev; |
4715 | u16 hubstatus; | 4837 | u16 hubstatus; |
4716 | u16 hubchange; | 4838 | u16 hubchange; |
4717 | u16 portstatus; | ||
4718 | u16 portchange; | ||
4719 | int i, ret; | 4839 | int i, ret; |
4720 | int connect_change, wakeup_change; | ||
4721 | 4840 | ||
4722 | /* | 4841 | /* |
4723 | * We restart the list every time to avoid a deadlock with | 4842 | * We restart the list every time to avoid a deadlock with |
@@ -4791,135 +4910,12 @@ static void hub_events(void) | |||
4791 | 4910 | ||
4792 | /* deal with port status changes */ | 4911 | /* deal with port status changes */ |
4793 | for (i = 1; i <= hdev->maxchild; i++) { | 4912 | for (i = 1; i <= hdev->maxchild; i++) { |
4794 | struct usb_port *port_dev = hub->ports[i - 1]; | 4913 | if (!test_bit(i, hub->busy_bits) |
4795 | struct usb_device *udev = port_dev->child; | 4914 | && (test_bit(i, hub->event_bits) |
4796 | 4915 | || test_bit(i, hub->change_bits) | |
4797 | if (test_bit(i, hub->busy_bits)) | 4916 | || test_bit(i, hub->wakeup_bits))) |
4798 | continue; | 4917 | port_event(hub, i); |
4799 | connect_change = test_bit(i, hub->change_bits); | 4918 | } |
4800 | wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); | ||
4801 | if (!test_and_clear_bit(i, hub->event_bits) && | ||
4802 | !connect_change && !wakeup_change) | ||
4803 | continue; | ||
4804 | |||
4805 | ret = hub_port_status(hub, i, | ||
4806 | &portstatus, &portchange); | ||
4807 | if (ret < 0) | ||
4808 | continue; | ||
4809 | |||
4810 | if (portchange & USB_PORT_STAT_C_CONNECTION) { | ||
4811 | usb_clear_port_feature(hdev, i, | ||
4812 | USB_PORT_FEAT_C_CONNECTION); | ||
4813 | connect_change = 1; | ||
4814 | } | ||
4815 | |||
4816 | if (portchange & USB_PORT_STAT_C_ENABLE) { | ||
4817 | if (!connect_change) | ||
4818 | dev_dbg(&port_dev->dev, | ||
4819 | "enable change, status %08x\n", | ||
4820 | portstatus); | ||
4821 | usb_clear_port_feature(hdev, i, | ||
4822 | USB_PORT_FEAT_C_ENABLE); | ||
4823 | |||
4824 | /* | ||
4825 | * EM interference sometimes causes badly | ||
4826 | * shielded USB devices to be shutdown by | ||
4827 | * the hub, this hack enables them again. | ||
4828 | * Works at least with mouse driver. | ||
4829 | */ | ||
4830 | if (!(portstatus & USB_PORT_STAT_ENABLE) | ||
4831 | && !connect_change && udev) { | ||
4832 | dev_err(&port_dev->dev, | ||
4833 | "disabled by hub (EMI?), re-enabling...\n"); | ||
4834 | connect_change = 1; | ||
4835 | } | ||
4836 | } | ||
4837 | |||
4838 | if (hub_handle_remote_wakeup(hub, i, | ||
4839 | portstatus, portchange)) | ||
4840 | connect_change = 1; | ||
4841 | |||
4842 | if (portchange & USB_PORT_STAT_C_OVERCURRENT) { | ||
4843 | u16 status = 0; | ||
4844 | u16 unused; | ||
4845 | |||
4846 | dev_dbg(&port_dev->dev, "over-current change\n"); | ||
4847 | usb_clear_port_feature(hdev, i, | ||
4848 | USB_PORT_FEAT_C_OVER_CURRENT); | ||
4849 | msleep(100); /* Cool down */ | ||
4850 | hub_power_on(hub, true); | ||
4851 | hub_port_status(hub, i, &status, &unused); | ||
4852 | if (status & USB_PORT_STAT_OVERCURRENT) | ||
4853 | dev_err(&port_dev->dev, | ||
4854 | "over-current condition\n"); | ||
4855 | } | ||
4856 | |||
4857 | if (portchange & USB_PORT_STAT_C_RESET) { | ||
4858 | dev_dbg(&port_dev->dev, "reset change\n"); | ||
4859 | usb_clear_port_feature(hdev, i, | ||
4860 | USB_PORT_FEAT_C_RESET); | ||
4861 | } | ||
4862 | if ((portchange & USB_PORT_STAT_C_BH_RESET) && | ||
4863 | hub_is_superspeed(hub->hdev)) { | ||
4864 | dev_dbg(&port_dev->dev, "warm reset change\n"); | ||
4865 | usb_clear_port_feature(hdev, i, | ||
4866 | USB_PORT_FEAT_C_BH_PORT_RESET); | ||
4867 | } | ||
4868 | if (portchange & USB_PORT_STAT_C_LINK_STATE) { | ||
4869 | usb_clear_port_feature(hub->hdev, i, | ||
4870 | USB_PORT_FEAT_C_PORT_LINK_STATE); | ||
4871 | } | ||
4872 | if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { | ||
4873 | dev_warn(&port_dev->dev, "config error\n"); | ||
4874 | usb_clear_port_feature(hub->hdev, i, | ||
4875 | USB_PORT_FEAT_C_PORT_CONFIG_ERROR); | ||
4876 | } | ||
4877 | |||
4878 | /* Warm reset a USB3 protocol port if it's in | ||
4879 | * SS.Inactive state. | ||
4880 | */ | ||
4881 | if (hub_port_warm_reset_required(hub, portstatus)) { | ||
4882 | int status; | ||
4883 | |||
4884 | dev_dbg(&port_dev->dev, "warm reset\n"); | ||
4885 | if (!udev || | ||
4886 | !(portstatus & USB_PORT_STAT_CONNECTION) || | ||
4887 | udev->state == USB_STATE_NOTATTACHED) { | ||
4888 | status = hub_port_reset(hub, i, | ||
4889 | NULL, HUB_BH_RESET_TIME, | ||
4890 | true); | ||
4891 | if (status < 0) | ||
4892 | hub_port_disable(hub, i, 1); | ||
4893 | } else { | ||
4894 | usb_lock_device(udev); | ||
4895 | status = usb_reset_device(udev); | ||
4896 | usb_unlock_device(udev); | ||
4897 | connect_change = 0; | ||
4898 | } | ||
4899 | /* | ||
4900 | * On disconnect USB3 protocol ports transit from U0 to | ||
4901 | * SS.Inactive to Rx.Detect. If this happens a warm- | ||
4902 | * reset is not needed, but a (re)connect may happen | ||
4903 | * before khubd runs and sees the disconnect, and the | ||
4904 | * device may be an unknown state. | ||
4905 | * | ||
4906 | * If the port went through SS.Inactive without khubd | ||
4907 | * seeing it the C_LINK_STATE change flag will be set, | ||
4908 | * and we reset the dev to put it in a known state. | ||
4909 | */ | ||
4910 | } else if (udev && hub_is_superspeed(hub->hdev) && | ||
4911 | (portchange & USB_PORT_STAT_C_LINK_STATE) && | ||
4912 | (portstatus & USB_PORT_STAT_CONNECTION)) { | ||
4913 | usb_lock_device(udev); | ||
4914 | usb_reset_device(udev); | ||
4915 | usb_unlock_device(udev); | ||
4916 | connect_change = 0; | ||
4917 | } | ||
4918 | |||
4919 | if (connect_change) | ||
4920 | hub_port_connect_change(hub, i, | ||
4921 | portstatus, portchange); | ||
4922 | } /* end for i */ | ||
4923 | 4919 | ||
4924 | /* deal with hub status changes */ | 4920 | /* deal with hub status changes */ |
4925 | if (test_and_clear_bit(0, hub->event_bits) == 0) | 4921 | if (test_and_clear_bit(0, hub->event_bits) == 0) |