/* * Find the peer port either via explicit platform firmware "location" * data, the peer hcd for root hubs, or the upstream peer relationship * for all other hubs. */ static void find_and_link_peer(struct usb_hub *hub, int port1) { struct usb_port *port_dev = hub->ports[port1 - 1], *peer; struct usb_device *hdev = hub->hdev; struct usb_device *peer_hdev; struct usb_hub *peer_hub; /* * If location data is available then we can only peer this port * by a location match, not the default peer (lest we create a * situation where we need to go back and undo a default peering * when the port is later peered by location data) */ if (port_dev->location) { /* we link the peer in match_location() if found */ usb_for_each_dev(port_dev, match_location); return; } else if (!hdev->parent) { struct usb_hcd *hcd = bus_to_hcd(hdev->bus); struct usb_hcd *peer_hcd = hcd->shared_hcd; if (!peer_hcd) return; peer_hdev = peer_hcd->self.root_hub; } else { struct usb_port *upstream; struct usb_device *parent = hdev->parent; struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); if (!parent_hub) return; upstream = parent_hub->ports[hdev->portnum - 1]; if (!upstream || !upstream->peer) return; peer_hdev = upstream->peer->child; } peer_hub = usb_hub_to_struct_hub(peer_hdev); if (!peer_hub || port1 > peer_hdev->maxchild) return; /* * we found a valid default peer, last check is to make sure it * does not have location data */ peer = peer_hub->ports[port1 - 1]; if (peer && peer->location == 0) link_peers_report(port_dev, peer); }
static int usb_port_runtime_resume(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; usb_autopm_get_interface(intf); set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, port1, true); if (port_dev->child && !retval) { /* * Attempt to wait for usb hub port to be reconnected in order * to make the resume procedure successful. The device may have * disconnected while the port was powered off, so ignore the * return status. */ retval = hub_port_debounce_be_connected(hub, port1); if (retval < 0) dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", retval); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); retval = 0; } clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); return retval; }
static int usb_port_runtime_suspend(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL) return -EAGAIN; usb_autopm_get_interface(intf); set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); return retval; }
/** * usb_acpi_set_power_state - control usb port's power via acpi power * resource * @hdev: USB device belonging to the usb hub * @index: port index based zero * @enable: power state expected to be set * * Notice to use usb_acpi_power_manageable() to check whether the usb port * has acpi power resource before invoking this function. * * Returns 0 on success, else negative errno. */ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable) { struct usb_hub *hub = usb_hub_to_struct_hub(hdev); struct usb_port *port_dev; acpi_handle port_handle; unsigned char state; int port1 = index + 1; int error = -EINVAL; if (!hub) return -ENODEV; port_dev = hub->ports[port1 - 1]; port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1); if (!port_handle) return error; if (enable) state = ACPI_STATE_D0; else state = ACPI_STATE_D3_COLD; error = acpi_bus_set_power(port_handle, state); if (!error) dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable); else dev_dbg(&port_dev->dev, "acpi: power failed to be set\n"); return error; }
/* * For each usb hub device in the system check to see if it is in the * peer domain of the given port_dev, and if it is check to see if it * has a port that matches the given port by location */ static int match_location(struct usb_device *peer_hdev, void *p) { int port1; struct usb_hcd *hcd, *peer_hcd; struct usb_port *port_dev = p, *peer; struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev); struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent); if (!peer_hub) return 0; hcd = bus_to_hcd(hdev->bus); peer_hcd = bus_to_hcd(peer_hdev->bus); /* peer_hcd is provisional until we verify it against the known peer */ if (peer_hcd != hcd->shared_hcd) return 0; for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) { peer = peer_hub->ports[port1 - 1]; if (peer && peer->location == port_dev->location) { link_peers_report(port_dev, peer); return 1; /* done */ } } return 0; }
static int usb_port_runtime_resume(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); struct usb_device *udev = port_dev->child; struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; if (hub->in_reset) { set_bit(port1, hub->power_bits); return 0; } /* * Power on our usb3 peer before this usb2 port to prevent a usb3 * device from degrading to its usb2 connection */ if (!port_dev->is_superspeed && peer) pm_runtime_get_sync(&peer->dev); usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, true); msleep(hub_power_on_good_delay(hub)); if (udev && !retval) { /* * Attempt to wait for usb hub port to be reconnected in order * to make the resume procedure successful. The device may have * disconnected while the port was powered off, so ignore the * return status. */ retval = hub_port_debounce_be_connected(hub, port1); if (retval < 0) dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", retval); retval = 0; /* Force the child awake to revalidate after the power loss. */ if (!test_and_set_bit(port1, hub->child_usage_bits)) { pm_runtime_get_noresume(&port_dev->dev); pm_request_resume(&udev->dev); } } usb_autopm_put_interface(intf); return retval; }
int mtk_is_hub_active(void){ struct usb_hcd *hcd = xhci_to_hcd(mtk_xhci); struct usb_device *rhdev = hcd->self.root_hub; struct usb_hub *hub = usb_hub_to_struct_hub(rhdev); bool ret = true; spin_lock_irq(mtk_hub_event_lock); if((mtk_ep_count == 0) && (list_empty(&hub->event_list) == 1) && (atomic_read(&(hub->kref.refcount)) == 1)){ ret = false; } spin_unlock_irq(mtk_hub_event_lock); return ret; }
static int usb_acpi_check_port_connect_type(struct usb_device *hdev, acpi_handle handle, int port1) { enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct usb_hub *hub = usb_hub_to_struct_hub(hdev); struct acpi_pld_info *pld; union acpi_object *upc; acpi_status status; int ret = 0; if (!hub) return 0; /* * According to ACPI Spec 9.13. PLD indicates whether usb port is * user visible and _UPC indicates whether it is connectable. If * the port was visible and connectable, it could be freely connected * and disconnected with USB devices. If no visible and connectable, * a usb device is directly hard-wired to the port. If no visible and * no connectable, the port would be not used. */ status = acpi_get_physical_device_location(handle, &pld); if (ACPI_FAILURE(status)) return -ENODEV; status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); upc = buffer.pointer; if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4) { ret = -EINVAL; goto out; } if (upc->package.elements[0].integer.value) if (pld->user_visible) connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG; else connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED; else if (!pld->user_visible) connect_type = USB_PORT_NOT_USED; hub->ports[port1 - 1]->connect_type = connect_type; out: ACPI_FREE(pld); kfree(upc); return ret; }
static int usb_port_runtime_suspend(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); struct usb_port *peer = port_dev->peer; int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; if (hub->in_reset) return -EBUSY; if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL) return -EAGAIN; if (usb_port_block_power_off) return -EBUSY; usb_autopm_get_interface(intf); retval = usb_hub_set_port_power(hdev, hub, port1, false); usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); if (!port_dev->is_superspeed) usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); usb_autopm_put_interface(intf); /* * Our peer usb3 port may now be able to suspend, so * asynchronously queue a suspend request to observe that this * usb2 port is now off. */ if (!port_dev->is_superspeed && peer) pm_runtime_put(&peer->dev); return retval; }
static int usb_port_runtime_resume(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); struct usb_hub *hub = usb_hub_to_struct_hub(hdev); int port1 = port_dev->portnum; int retval; if (!hub) return -EINVAL; usb_autopm_get_interface(intf); set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, hub, port1, true); if (port_dev->child && !retval) { /* * Wait for usb hub port to be reconnected in order to make * the resume procedure successful. */ retval = hub_port_debounce_be_connected(hub, port1); if (retval < 0) { dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", retval); goto out; } usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); /* Set return value to 0 if debounce successful */ retval = 0; } out: clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); return retval; }
static int single_step_get_dev_desc(struct usb_hcd *hcd, u8 port) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct urb *urb; struct usb_device *hdev; struct usb_device *udev = NULL; struct usb_hub *hub = NULL; struct usb_ctrlrequest setup_packet; char data_buffer[USB_DT_DEVICE_SIZE]; int ret = 0; xhci_info(xhci, "Testing SINGLE_STEP_GET_DEV_DESC\n"); hdev = hcd->self.root_hub; if (!hdev) { xhci_err(xhci, "EHSET: root_hub pointer is NULL\n"); ret = -EPIPE; goto error; } hub = usb_hub_to_struct_hub(hdev); if (hub == NULL) { xhci_err(xhci, "EHSET: hub pointer is NULL\n"); ret = -EPIPE; goto error; } if (hub->ports[port]->child != NULL) udev = hub->ports[port]->child; if (!udev) { xhci_err(xhci, "EHSET: device available is NOT found\n"); ret = -EPIPE; goto error; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { xhci_err(xhci, "urb : get alloc failed\n"); ret = -ENOMEM; goto error; } setup_packet.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR; setup_packet.wValue = (USB_DT_DEVICE << 8); setup_packet.wIndex = 0; setup_packet.wLength = USB_DT_DEVICE_SIZE; urb->dev = udev; urb->hcpriv = udev->ep0.hcpriv; urb->setup_packet = (unsigned char *)&setup_packet; urb->transfer_buffer = data_buffer; urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; urb->actual_length = 0; urb->transfer_flags = URB_DIR_IN | URB_HCD_DRIVER_TEST; urb->pipe = usb_rcvctrlpipe(udev, 0); urb->ep = usb_pipe_endpoint(udev, urb->pipe); if (!urb->ep) { xhci_err(xhci, "urb->ep is NULL\n"); ret = -ENOENT; goto error_urb_ep; } urb->setup_dma = dma_map_single( hcd->self.controller, urb->setup_packet, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); if (dma_mapping_error(hcd->self.controller, urb->setup_dma)) { xhci_err(xhci, "setup : dma_map_single failed\n"); ret = -EBUSY; goto error_setup_dma; } urb->transfer_dma = dma_map_single( hcd->self.controller, urb->transfer_buffer, urb->transfer_buffer_length, DMA_TO_DEVICE); if (dma_mapping_error(hcd->self.controller, urb->transfer_dma)) { xhci_err(xhci, "xfer : dma_map_single failed\n"); ret = -EBUSY; goto error_xfer_dma; } ret = xhci_urb_enqueue_single_step(hcd, urb, GFP_ATOMIC, 1); dma_unmap_single(hcd->self.controller, urb->transfer_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); error_xfer_dma: dma_unmap_single(hcd->self.controller, urb->setup_dma, sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); error_setup_dma: error_urb_ep: usb_free_urb(urb); error: return ret; }
static struct acpi_device *usb_acpi_find_companion(struct device *dev) { int port1; struct usb_device *udev; acpi_handle *parent_handle; /* * In the ACPI DSDT table, only usb root hub and usb ports are * acpi device nodes. The hierarchy like following. * Device (EHC1) * Device (HUBN) * Device (PR01) * Device (PR11) * Device (PR12) * Device (PR13) * ... * So all binding process is divided into two parts. binding * root hub and usb ports. */ if (is_usb_device(dev)) { udev = to_usb_device(dev); port1 = udev->portnum; if (udev->parent) { struct usb_hub *hub; hub = usb_hub_to_struct_hub(udev->parent); /* * According usb port's connect type to set usb device's * removability. */ switch (hub->ports[port1 - 1]->connect_type) { case USB_PORT_CONNECT_TYPE_HOT_PLUG: udev->removable = USB_DEVICE_REMOVABLE; break; case USB_PORT_CONNECT_TYPE_HARD_WIRED: udev->removable = USB_DEVICE_FIXED; break; default: udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN; break; } return NULL; } /* root hub's parent is the usb hcd. */ return acpi_find_child_device(ACPI_COMPANION(dev->parent), port1, false); } else if (is_usb_port(dev)) { struct usb_port *port_dev = to_usb_port(dev); struct acpi_device *adev = NULL; /* Get the struct usb_device point of port's hub */ udev = to_usb_device(dev->parent->parent); port1 = port_dev->portnum; /* * The root hub ports' parent is the root hub. The non-root-hub * ports' parent is the parent hub port which the hub is * connected to. */ if (!udev->parent) { struct usb_hcd *hcd = bus_to_hcd(udev->bus); int raw; raw = usb_hcd_find_raw_port_number(hcd, port1); adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), raw, false); if (!adev) return NULL; } else { parent_handle = usb_get_hub_port_acpi_handle(udev->parent, udev->portnum); if (!parent_handle) return NULL; acpi_bus_get_device(parent_handle, &adev); adev = acpi_find_child_device(adev, port1, false); if (!adev) return NULL; } usb_acpi_check_port_connect_type(udev, adev->handle, port1); return adev; } return NULL; }