mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
- Try to fix support for USB 3.0 HUBs.
- Try to fix support for USB 3.0 suspend and resume. MFC after: 1 week
This commit is contained in:
parent
ab71f27172
commit
4131f6fb60
5 changed files with 79 additions and 20 deletions
|
|
@ -2211,9 +2211,10 @@ xhci_configure_device(struct usb_device *udev)
|
|||
struct usb_device *hubdev;
|
||||
uint32_t temp;
|
||||
uint32_t route;
|
||||
uint32_t rh_port;
|
||||
uint8_t is_hub;
|
||||
uint8_t index;
|
||||
uint8_t rh_port;
|
||||
uint8_t depth;
|
||||
|
||||
index = udev->controller_slot_id;
|
||||
|
||||
|
|
@ -2235,6 +2236,8 @@ xhci_configure_device(struct usb_device *udev)
|
|||
if (hubdev->parent_hub == NULL)
|
||||
break;
|
||||
|
||||
depth = hubdev->parent_hub->depth;
|
||||
|
||||
/*
|
||||
* NOTE: HS/FS/LS devices and the SS root HUB can have
|
||||
* more than 15 ports
|
||||
|
|
@ -2242,17 +2245,18 @@ xhci_configure_device(struct usb_device *udev)
|
|||
|
||||
rh_port = hubdev->port_no;
|
||||
|
||||
if (hubdev->parent_hub->parent_hub == NULL)
|
||||
if (depth == 0)
|
||||
break;
|
||||
|
||||
route *= 16;
|
||||
|
||||
if (rh_port > 15)
|
||||
route |= 15;
|
||||
else
|
||||
route |= rh_port;
|
||||
rh_port = 15;
|
||||
|
||||
if (depth < 6)
|
||||
route |= rh_port << (4 * (depth - 1));
|
||||
}
|
||||
|
||||
DPRINTF("Route=0x%08x\n", route);
|
||||
|
||||
temp = XHCI_SCTX_0_ROUTE_SET(route);
|
||||
|
||||
switch (sc->sc_hw.devs[index].state) {
|
||||
|
|
@ -3063,6 +3067,7 @@ xhci_roothub_exec(struct usb_device *udev,
|
|||
case UHF_C_PORT_CONFIG_ERROR:
|
||||
XWRITE4(sc, oper, port, v | XHCI_PS_CEC);
|
||||
break;
|
||||
case UHF_C_PORT_SUSPEND:
|
||||
case UHF_C_PORT_LINK_STATE:
|
||||
XWRITE4(sc, oper, port, v | XHCI_PS_PLC);
|
||||
break;
|
||||
|
|
@ -3190,7 +3195,7 @@ xhci_roothub_exec(struct usb_device *udev,
|
|||
if (v & XHCI_PS_PR)
|
||||
i |= UPS_RESET;
|
||||
if (v & XHCI_PS_PP)
|
||||
i |= UPS_PORT_POWER;
|
||||
i |= UPS_PORT_POWER_SS;
|
||||
USETW(sc->sc_hub_desc.ps.wPortStatus, i);
|
||||
|
||||
i = 0;
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ struct usb_port_status {
|
|||
#define UPS_PORT_LS_LOOPBACK 0x0B
|
||||
#define UPS_PORT_LS_RESUME 0x0F
|
||||
#define UPS_PORT_POWER 0x0100
|
||||
#define UPS_PORT_POWER_SS 0x0200 /* super-speed only */
|
||||
#define UPS_LOW_SPEED 0x0200
|
||||
#define UPS_HIGH_SPEED 0x0400
|
||||
#define UPS_OTHER_SPEED 0x0600 /* currently FreeBSD specific */
|
||||
|
|
|
|||
|
|
@ -369,10 +369,25 @@ repeat:
|
|||
}
|
||||
/* check if there is no power on the port and print a warning */
|
||||
|
||||
if (!(sc->sc_st.port_status & UPS_PORT_POWER)) {
|
||||
DPRINTF("WARNING: strange, connected port %d "
|
||||
"has no power\n", portno);
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_HIGH:
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
if (!(sc->sc_st.port_status & UPS_PORT_POWER)) {
|
||||
DPRINTF("WARNING: strange, connected port %d "
|
||||
"has no power\n", portno);
|
||||
}
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
if (!(sc->sc_st.port_status & UPS_PORT_POWER_SS)) {
|
||||
DPRINTF("WARNING: strange, connected port %d "
|
||||
"has no power\n", portno);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if the device is in Host Mode */
|
||||
|
||||
if (!(sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)) {
|
||||
|
|
@ -611,6 +626,7 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
|
|||
switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
|
||||
case UPS_PORT_LS_U0:
|
||||
case UPS_PORT_LS_U1:
|
||||
case UPS_PORT_LS_U2:
|
||||
case UPS_PORT_LS_RESUME:
|
||||
is_suspend = 0;
|
||||
break;
|
||||
|
|
@ -632,8 +648,7 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
|
|||
*/
|
||||
if (is_suspend == 0)
|
||||
usb_dev_resume_peer(child);
|
||||
else if ((child->flags.usb_mode == USB_MODE_DEVICE) ||
|
||||
(usb_device_20_compatible(child) == 0))
|
||||
else if (child->flags.usb_mode == USB_MODE_DEVICE)
|
||||
usb_dev_suspend_peer(child);
|
||||
}
|
||||
done:
|
||||
|
|
@ -2064,7 +2079,6 @@ usb_peer_should_wakeup(struct usb_device *udev)
|
|||
(udev->pwr_save.write_refs != 0) ||
|
||||
((udev->pwr_save.read_refs != 0) &&
|
||||
(udev->flags.usb_mode == USB_MODE_HOST) &&
|
||||
(usb_device_20_compatible(udev) != 0) &&
|
||||
(usb_peer_can_wakeup(udev) == 0)));
|
||||
}
|
||||
|
||||
|
|
@ -2244,6 +2258,14 @@ usb_dev_resume_peer(struct usb_device *udev)
|
|||
DPRINTFN(0, "Resuming port failed\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* resume current port (Valid in Host and Device Mode) */
|
||||
err = usbd_req_set_port_link_state(udev->parent_hub,
|
||||
NULL, udev->port_no, UPS_PORT_LS_U0);
|
||||
if (err) {
|
||||
DPRINTFN(0, "Resuming port failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* resume settle time */
|
||||
|
|
@ -2285,8 +2307,7 @@ usb_dev_resume_peer(struct usb_device *udev)
|
|||
usbd_sr_unlock(udev);
|
||||
|
||||
/* check if peer has wakeup capability */
|
||||
if (usb_peer_can_wakeup(udev) &&
|
||||
usb_device_20_compatible(udev)) {
|
||||
if (usb_peer_can_wakeup(udev)) {
|
||||
/* clear remote wakeup */
|
||||
err = usbd_req_clear_device_feature(udev,
|
||||
NULL, UF_DEVICE_REMOTE_WAKEUP);
|
||||
|
|
@ -2347,8 +2368,7 @@ repeat:
|
|||
}
|
||||
}
|
||||
|
||||
if (usb_peer_can_wakeup(udev) &&
|
||||
usb_device_20_compatible(udev)) {
|
||||
if (usb_peer_can_wakeup(udev)) {
|
||||
/*
|
||||
* This request needs to be done before we set
|
||||
* "udev->flags.self_suspended":
|
||||
|
|
@ -2380,8 +2400,7 @@ repeat:
|
|||
USB_BUS_UNLOCK(udev->bus);
|
||||
|
||||
if (err != 0) {
|
||||
if (usb_peer_can_wakeup(udev) &&
|
||||
usb_device_20_compatible(udev)) {
|
||||
if (usb_peer_can_wakeup(udev)) {
|
||||
/* allow device to do remote wakeup */
|
||||
err = usbd_req_clear_device_feature(udev,
|
||||
NULL, UF_DEVICE_REMOTE_WAKEUP);
|
||||
|
|
@ -2437,6 +2456,14 @@ repeat:
|
|||
DPRINTFN(0, "Suspending port failed\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* suspend current port */
|
||||
err = usbd_req_set_port_link_state(udev->parent_hub,
|
||||
NULL, udev->port_no, UPS_PORT_LS_U3);
|
||||
if (err) {
|
||||
DPRINTFN(0, "Suspending port failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
udev = udev->parent_hub;
|
||||
|
|
|
|||
|
|
@ -2164,3 +2164,27 @@ usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
|
|||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(udev, mtx, &req, 0));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usbd_req_set_port_link_state
|
||||
*
|
||||
* USB 3.0 specific request
|
||||
*
|
||||
* Returns:
|
||||
* 0: Success
|
||||
* Else: Failure
|
||||
*------------------------------------------------------------------------*/
|
||||
usb_error_t
|
||||
usbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx,
|
||||
uint8_t port, uint8_t link_state)
|
||||
{
|
||||
struct usb_device_request req;
|
||||
|
||||
req.bmRequestType = UT_WRITE_CLASS_OTHER;
|
||||
req.bRequest = UR_SET_FEATURE;
|
||||
USETW(req.wValue, UHF_PORT_LINK_STATE);
|
||||
req.wIndex[0] = port;
|
||||
req.wIndex[1] = link_state;
|
||||
USETW(req.wLength, 0);
|
||||
return (usbd_do_request(udev, mtx, &req, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,5 +89,7 @@ usb_error_t usbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
|
|||
uint8_t port);
|
||||
usb_error_t usbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
|
||||
uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint);
|
||||
usb_error_t usbd_req_set_port_link_state(struct usb_device *udev,
|
||||
struct mtx *mtx, uint8_t port, uint8_t link_state);
|
||||
|
||||
#endif /* _USB_REQUEST_H_ */
|
||||
|
|
|
|||
Loading…
Reference in a new issue