status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION);
switch (speed) { case USB_SPEED_HIGH:
status |= USB_PORT_STAT_HIGH_SPEED; break; case USB_SPEED_LOW:
status |= USB_PORT_STAT_LOW_SPEED; break; default: break;
}
spin_lock_irqsave(&vhci->lock, flags); if (!HCD_HW_ACCESSIBLE(hcd)) {
usbip_dbg_vhci_rh("hw accessible flag not on?\n"); goto done;
}
/* check pseudo status register for each port */ for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { if ((vhci_hcd->port_status[rhport] & PORT_C_MASK)) { /* The status of a port has been changed, */
usbip_dbg_vhci_rh("port %d status changed\n", rhport);
/* store old status and compare now and old later */ if (usbip_dbg_flag_vhci_rh) { if (!invalid_rhport)
memcpy(prev_port_status, vhci_hcd->port_status, sizeof(prev_port_status));
}
switch (typeReq) { case ClearHubFeature:
usbip_dbg_vhci_rh(" ClearHubFeature\n"); break; case ClearPortFeature: if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
} switch (wValue) { case USB_PORT_FEAT_SUSPEND: if (hcd->speed >= HCD_USB3) {
pr_err(" ClearPortFeature: USB_PORT_FEAT_SUSPEND req not " "supported for USB 3.0 roothub\n"); goto error;
}
usbip_dbg_vhci_rh( " ClearPortFeature: USB_PORT_FEAT_SUSPEND\n"); if (vhci_hcd->port_status[rhport] & USB_PORT_STAT_SUSPEND) { /* 20msec signaling */
vhci_hcd->resuming = 1;
vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
} break; case USB_PORT_FEAT_POWER:
usbip_dbg_vhci_rh( " ClearPortFeature: USB_PORT_FEAT_POWER\n"); if (hcd->speed >= HCD_USB3)
vhci_hcd->port_status[rhport] &= ~USB_SS_PORT_STAT_POWER; else
vhci_hcd->port_status[rhport] &= ~USB_PORT_STAT_POWER; break; default:
usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
wValue); if (wValue >= 32) goto error;
vhci_hcd->port_status[rhport] &= ~(1 << wValue); break;
} break; case GetHubDescriptor:
usbip_dbg_vhci_rh(" GetHubDescriptor\n"); if (hcd->speed >= HCD_USB3 &&
(wLength < USB_DT_SS_HUB_SIZE ||
wValue != (USB_DT_SS_HUB << 8))) {
pr_err("Wrong hub descriptor type for USB 3.0 roothub.\n"); goto error;
} if (hcd->speed >= HCD_USB3)
ss_hub_descriptor((struct usb_hub_descriptor *) buf); else
hub_descriptor((struct usb_hub_descriptor *) buf); break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: if (hcd->speed < HCD_USB3) goto error;
if ((wValue >> 8) != USB_DT_BOS) goto error;
memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc));
retval = sizeof(usb3_bos_desc); break; case GetHubStatus:
usbip_dbg_vhci_rh(" GetHubStatus\n");
*(__le32 *) buf = cpu_to_le32(0); break; case GetPortStatus:
usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex);
retval = -EPIPE; goto error;
}
/* we do not care about resume. */
/* whoever resets or resumes must GetPortStatus to *completeit!!
*/ if (vhci_hcd->resuming && time_after(jiffies, vhci_hcd->re_timeout)) {
vhci_hcd->port_status[rhport] |= (1 << USB_PORT_FEAT_C_SUSPEND);
vhci_hcd->port_status[rhport] &= ~(1 << USB_PORT_FEAT_SUSPEND);
vhci_hcd->resuming = 0;
vhci_hcd->re_timeout = 0;
}
usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
((u16 *)buf)[1]); break; case SetHubFeature:
usbip_dbg_vhci_rh(" SetHubFeature\n");
retval = -EPIPE; break; case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_LINK_STATE:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_LINK_STATE\n"); if (hcd->speed < HCD_USB3) {
pr_err("USB_PORT_FEAT_LINK_STATE req not " "supported for USB 2.0 roothub\n"); goto error;
} /* *Sincethisisdummywedon'thaveanactuallinkso *thereisnothingtodofortheSET_LINK_STATEcmd
*/ break; case USB_PORT_FEAT_U1_TIMEOUT:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n");
fallthrough; case USB_PORT_FEAT_U2_TIMEOUT:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); /* TODO: add suspend/resume support! */ if (hcd->speed < HCD_USB3) {
pr_err("USB_PORT_FEAT_U1/2_TIMEOUT req not " "supported for USB 2.0 roothub\n"); goto error;
} break; case USB_PORT_FEAT_SUSPEND:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); /* Applicable only for USB2.0 hub */ if (hcd->speed >= HCD_USB3) {
pr_err("USB_PORT_FEAT_SUSPEND req not " "supported for USB 3.0 roothub\n"); goto error;
}
if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
}
vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; break; case USB_PORT_FEAT_POWER:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_POWER\n"); if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
} if (hcd->speed >= HCD_USB3)
vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; else
vhci_hcd->port_status[rhport] |= USB_PORT_STAT_POWER; break; case USB_PORT_FEAT_BH_PORT_RESET:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
} /* Applicable only for USB3.0 hub */ if (hcd->speed < HCD_USB3) {
pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " "supported for USB 2.0 roothub\n"); goto error;
}
fallthrough; case USB_PORT_FEAT_RESET:
usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_RESET\n"); if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
} /* if it's already enabled, disable */ if (hcd->speed >= HCD_USB3) {
vhci_hcd->port_status[rhport] = 0;
vhci_hcd->port_status[rhport] =
(USB_SS_PORT_STAT_POWER |
USB_PORT_STAT_CONNECTION |
USB_PORT_STAT_RESET);
} elseif (vhci_hcd->port_status[rhport] & USB_PORT_STAT_ENABLE) {
vhci_hcd->port_status[rhport] &= ~(USB_PORT_STAT_ENABLE
| USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED);
}
/* 50msec reset signaling */
vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
fallthrough; default:
usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
wValue); if (invalid_rhport) {
pr_err("invalid port number %d\n", wIndex); goto error;
} if (wValue >= 32) goto error; if (hcd->speed >= HCD_USB3) { if ((vhci_hcd->port_status[rhport] &
USB_SS_PORT_STAT_POWER) != 0) {
vhci_hcd->port_status[rhport] |= (1 << wValue);
}
} else if ((vhci_hcd->port_status[rhport] &
USB_PORT_STAT_POWER) != 0) {
vhci_hcd->port_status[rhport] |= (1 << wValue);
}
} break; case GetPortErrorCount:
usbip_dbg_vhci_rh(" GetPortErrorCount\n"); if (hcd->speed < HCD_USB3) {
pr_err("GetPortErrorCount req not " "supported for USB 2.0 roothub\n"); goto error;
} /* We'll always return 0 since this is a dummy hub */
*(__le32 *) buf = cpu_to_le32(0); break; case SetHubDepth:
usbip_dbg_vhci_rh(" SetHubDepth\n"); if (hcd->speed < HCD_USB3) {
pr_err("SetHubDepth req not supported for " "USB 2.0 roothub\n"); goto error;
} break; default:
pr_err("default hub control req: %04x v%04x i%04x l%d\n",
typeReq, wValue, wIndex, wLength);
error: /* "protocol stall" on error */
retval = -EPIPE;
}
if (usbip_dbg_flag_vhci_rh) {
pr_debug("port %d\n", rhport); /* Only dump valid port status */ if (!invalid_rhport) {
dump_port_status_diff(prev_port_status[rhport],
vhci_hcd->port_status[rhport],
hcd->speed >= HCD_USB3);
}
}
usbip_dbg_vhci_rh(" bye\n");
if (type != PIPE_CONTROL || !ctrlreq) {
dev_err(dev, "invalid request to devnum 0\n");
ret = -EINVAL; goto no_need_xmit;
}
old = vdev->udev; switch (ctrlreq->bRequest) { case USB_REQ_SET_ADDRESS: /* set_address may come when a device is reset */
dev_info(dev, "SetAddress Request (%d) to port %d\n",
ctrlreq->wValue, vdev->rhport);
if (urb->status == -EINPROGRESS) { /* This request is successfully completed. */ /* If not -EINPROGRESS, possibly unlinked. */
urb->status = 0;
}
goto no_need_xmit;
case USB_REQ_GET_DESCRIPTOR: if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8))
usbip_dbg_vhci_hc( "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n");
priv = urb->hcpriv; if (!priv) { /* URB was never linked! or will be soon given back by
* vhci_rx. */
spin_unlock_irqrestore(&vhci->lock, flags); return -EIDRM;
}
{ int ret = 0;
ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) {
spin_unlock_irqrestore(&vhci->lock, flags); return ret;
}
}
/* 1. remove the userland interface of vhci_hcd */
id = hcd_name_to_id(hcd_name(hcd)); if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
vhci_finish_attr_group();
}
/* 2. shutdown all the ports of vhci_hcd */ for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
/* Change a group of bulk endpoints to support multiple stream IDs */ staticint vhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsignedint num_eps, unsignedint num_streams, gfp_t mem_flags)
{
dev_dbg(&hcd->self.root_hub->dev, "vhci_alloc_streams not implemented\n"); return0;
}
/* Reverts a group of bulk endpoints back to not using stream IDs. */ staticint vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsignedint num_eps,
gfp_t mem_flags)
{
dev_dbg(&hcd->self.root_hub->dev, "vhci_free_streams not implemented\n"); return0;
}
/* what should happen for USB/IP under suspend/resume? */ staticint vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
{ struct usb_hcd *hcd; struct vhci *vhci; int rhport; int connected = 0; int ret = 0; unsignedlong flags;
dev_dbg(&pdev->dev, "%s\n", __func__);
hcd = platform_get_drvdata(pdev); if (!hcd) return0;
for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { if (vhci->vhci_hcd_hs->port_status[rhport] &
USB_PORT_STAT_CONNECTION)
connected += 1;
if (vhci->vhci_hcd_ss->port_status[rhport] &
USB_PORT_STAT_CONNECTION)
connected += 1;
}
spin_unlock_irqrestore(&vhci->lock, flags);
if (connected > 0) {
dev_info(&pdev->dev, "We have %d active connection%s. Do not suspend.\n",
connected, str_plural(connected));
ret = -EBUSY;
} else {
dev_info(&pdev->dev, "suspend vhci_hcd");
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.