Lines 980-1154
uhub_is_too_deep(struct usb_device *udev)
Link Here
|
980 |
break; |
980 |
break; |
981 |
} |
981 |
} |
982 |
return (0); |
982 |
return (0); |
983 |
} |
983 |
} |
984 |
|
984 |
|
985 |
/*------------------------------------------------------------------------* |
985 |
/*------------------------------------------------------------------------* |
986 |
* uhub_explore |
986 |
* uhub_explore |
987 |
* |
987 |
* |
988 |
* Returns: |
988 |
* Returns: |
989 |
* 0: Success |
989 |
* 0: Success |
990 |
* Else: Failure |
990 |
* Else: Failure |
991 |
*------------------------------------------------------------------------*/ |
991 |
*------------------------------------------------------------------------*/ |
992 |
static usb_error_t |
992 |
static usb_error_t |
993 |
uhub_explore(struct usb_device *udev) |
993 |
uhub_explore(struct usb_device *udev) |
994 |
{ |
994 |
{ |
995 |
struct usb_hub *hub; |
995 |
struct usb_hub *hub; |
996 |
struct uhub_softc *sc; |
996 |
struct uhub_softc *sc; |
997 |
struct usb_port *up; |
997 |
struct usb_port *up; |
998 |
usb_error_t err; |
998 |
usb_error_t err; |
999 |
uint8_t portno; |
999 |
uint8_t portno; |
1000 |
uint8_t x; |
1000 |
uint8_t x; |
1001 |
uint8_t do_unlock; |
1001 |
uint8_t do_unlock; |
1002 |
|
1002 |
|
1003 |
hub = udev->hub; |
1003 |
hub = udev->hub; |
1004 |
sc = hub->hubsoftc; |
1004 |
sc = hub->hubsoftc; |
1005 |
|
1005 |
|
1006 |
DPRINTFN(11, "udev=%p addr=%d\n", udev, udev->address); |
1006 |
DPRINTFN(11, "udev=%p addr=%d\n", udev, udev->address); |
1007 |
|
1007 |
|
1008 |
/* ignore devices that are too deep */ |
1008 |
/* ignore devices that are too deep */ |
1009 |
if (uhub_is_too_deep(udev)) |
1009 |
if (uhub_is_too_deep(udev)) |
1010 |
return (USB_ERR_TOO_DEEP); |
1010 |
return (USB_ERR_TOO_DEEP); |
1011 |
|
1011 |
|
1012 |
/* check if device is suspended */ |
1012 |
/* check if device is suspended */ |
1013 |
if (udev->flags.self_suspended) { |
1013 |
if (udev->flags.self_suspended) { |
1014 |
/* need to wait until the child signals resume */ |
1014 |
/* need to wait until the child signals resume */ |
1015 |
DPRINTF("Device is suspended!\n"); |
1015 |
DPRINTF("Device is suspended!\n"); |
1016 |
return (0); |
1016 |
return (0); |
1017 |
} |
1017 |
} |
1018 |
|
1018 |
|
1019 |
/* |
1019 |
/* |
1020 |
* Make sure we don't race against user-space applications |
1020 |
* Make sure we don't race against user-space applications |
1021 |
* like LibUSB: |
1021 |
* like LibUSB: |
1022 |
*/ |
1022 |
*/ |
1023 |
do_unlock = usbd_enum_lock(udev); |
1023 |
do_unlock = usbd_enum_lock(udev); |
1024 |
|
1024 |
|
|
|
1025 |
err = USB_ERR_NORMAL_COMPLETION; |
1025 |
for (x = 0; x != hub->nports; x++) { |
1026 |
for (x = 0; x != hub->nports; x++) { |
1026 |
up = hub->ports + x; |
1027 |
up = hub->ports + x; |
1027 |
portno = x + 1; |
1028 |
portno = x + 1; |
1028 |
|
1029 |
|
1029 |
err = uhub_read_port_status(sc, portno); |
1030 |
err = uhub_read_port_status(sc, portno); |
1030 |
if (err) { |
1031 |
if (err) { |
1031 |
/* most likely the HUB is gone */ |
1032 |
/* most likely the HUB is gone */ |
1032 |
break; |
1033 |
break; |
1033 |
} |
1034 |
} |
1034 |
if (sc->sc_st.port_change & UPS_C_OVERCURRENT_INDICATOR) { |
1035 |
if (sc->sc_st.port_change & UPS_C_OVERCURRENT_INDICATOR) { |
1035 |
DPRINTF("Overcurrent on port %u.\n", portno); |
1036 |
DPRINTF("Overcurrent on port %u.\n", portno); |
1036 |
err = usbd_req_clear_port_feature( |
1037 |
err = usbd_req_clear_port_feature( |
1037 |
udev, NULL, portno, UHF_C_PORT_OVER_CURRENT); |
1038 |
udev, NULL, portno, UHF_C_PORT_OVER_CURRENT); |
1038 |
if (err) { |
1039 |
if (err) { |
1039 |
/* most likely the HUB is gone */ |
1040 |
/* most likely the HUB is gone */ |
1040 |
break; |
1041 |
break; |
1041 |
} |
1042 |
} |
1042 |
} |
1043 |
} |
1043 |
if (!(sc->sc_flags & UHUB_FLAG_DID_EXPLORE)) { |
1044 |
if (!(sc->sc_flags & UHUB_FLAG_DID_EXPLORE)) { |
1044 |
/* |
1045 |
/* |
1045 |
* Fake a connect status change so that the |
1046 |
* Fake a connect status change so that the |
1046 |
* status gets checked initially! |
1047 |
* status gets checked initially! |
1047 |
*/ |
1048 |
*/ |
1048 |
sc->sc_st.port_change |= |
1049 |
sc->sc_st.port_change |= |
1049 |
UPS_C_CONNECT_STATUS; |
1050 |
UPS_C_CONNECT_STATUS; |
1050 |
} |
1051 |
} |
1051 |
if (sc->sc_st.port_change & UPS_C_PORT_ENABLED) { |
1052 |
if (sc->sc_st.port_change & UPS_C_PORT_ENABLED) { |
1052 |
err = usbd_req_clear_port_feature( |
1053 |
err = usbd_req_clear_port_feature( |
1053 |
udev, NULL, portno, UHF_C_PORT_ENABLE); |
1054 |
udev, NULL, portno, UHF_C_PORT_ENABLE); |
1054 |
if (err) { |
1055 |
if (err) { |
1055 |
/* most likely the HUB is gone */ |
1056 |
/* most likely the HUB is gone */ |
1056 |
break; |
1057 |
break; |
1057 |
} |
1058 |
} |
1058 |
if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) { |
1059 |
if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) { |
1059 |
/* |
1060 |
/* |
1060 |
* Ignore the port error if the device |
1061 |
* Ignore the port error if the device |
1061 |
* has vanished ! |
1062 |
* has vanished ! |
1062 |
*/ |
1063 |
*/ |
1063 |
} else if (sc->sc_st.port_status & UPS_PORT_ENABLED) { |
1064 |
} else if (sc->sc_st.port_status & UPS_PORT_ENABLED) { |
1064 |
DPRINTFN(0, "illegal enable change, " |
1065 |
DPRINTFN(0, "illegal enable change, " |
1065 |
"port %d\n", portno); |
1066 |
"port %d\n", portno); |
1066 |
} else { |
1067 |
} else { |
1067 |
if (up->restartcnt == USB_RESTART_MAX) { |
1068 |
if (up->restartcnt == USB_RESTART_MAX) { |
1068 |
/* XXX could try another speed ? */ |
1069 |
/* XXX could try another speed ? */ |
1069 |
DPRINTFN(0, "port error, giving up " |
1070 |
DPRINTFN(0, "port error, giving up " |
1070 |
"port %d\n", portno); |
1071 |
"port %d\n", portno); |
1071 |
} else { |
1072 |
} else { |
1072 |
sc->sc_st.port_change |= |
1073 |
sc->sc_st.port_change |= |
1073 |
UPS_C_CONNECT_STATUS; |
1074 |
UPS_C_CONNECT_STATUS; |
1074 |
up->restartcnt++; |
1075 |
up->restartcnt++; |
1075 |
} |
1076 |
} |
1076 |
} |
1077 |
} |
1077 |
} |
1078 |
} |
1078 |
if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) { |
1079 |
if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) { |
1079 |
err = uhub_reattach_port(sc, portno); |
1080 |
err = uhub_reattach_port(sc, portno); |
1080 |
if (err) { |
1081 |
if (err) { |
1081 |
/* most likely the HUB is gone */ |
1082 |
/* most likely the HUB is gone */ |
1082 |
break; |
1083 |
break; |
1083 |
} |
1084 |
} |
1084 |
} |
1085 |
} |
1085 |
if (sc->sc_st.port_change & (UPS_C_SUSPEND | |
1086 |
if (sc->sc_st.port_change & (UPS_C_SUSPEND | |
1086 |
UPS_C_PORT_LINK_STATE)) { |
1087 |
UPS_C_PORT_LINK_STATE)) { |
1087 |
err = uhub_suspend_resume_port(sc, portno); |
1088 |
err = uhub_suspend_resume_port(sc, portno); |
1088 |
if (err) { |
1089 |
if (err) { |
1089 |
/* most likely the HUB is gone */ |
1090 |
/* most likely the HUB is gone */ |
1090 |
break; |
1091 |
break; |
1091 |
} |
1092 |
} |
1092 |
} |
1093 |
} |
1093 |
err = uhub_explore_sub(sc, up); |
1094 |
err = uhub_explore_sub(sc, up); |
1094 |
if (err) { |
1095 |
if (err) { |
1095 |
/* no device(s) present */ |
1096 |
/* no device(s) present */ |
1096 |
continue; |
1097 |
continue; |
1097 |
} |
1098 |
} |
1098 |
/* explore succeeded - reset restart counter */ |
1099 |
/* explore succeeded - reset restart counter */ |
1099 |
up->restartcnt = 0; |
1100 |
up->restartcnt = 0; |
1100 |
} |
1101 |
} |
1101 |
|
1102 |
|
1102 |
if (do_unlock) |
1103 |
if (do_unlock) |
1103 |
usbd_enum_unlock(udev); |
1104 |
usbd_enum_unlock(udev); |
1104 |
|
1105 |
|
1105 |
/* initial status checked */ |
1106 |
/* initial status checked */ |
1106 |
sc->sc_flags |= UHUB_FLAG_DID_EXPLORE; |
1107 |
sc->sc_flags |= UHUB_FLAG_DID_EXPLORE; |
1107 |
|
1108 |
|
1108 |
/* return success */ |
1109 |
/* return success */ |
1109 |
return (USB_ERR_NORMAL_COMPLETION); |
1110 |
return (err); |
1110 |
} |
1111 |
} |
1111 |
|
1112 |
|
1112 |
int |
1113 |
int |
1113 |
uhub_probe(device_t dev) |
1114 |
uhub_probe(device_t dev) |
1114 |
{ |
1115 |
{ |
1115 |
struct usb_attach_arg *uaa = device_get_ivars(dev); |
1116 |
struct usb_attach_arg *uaa = device_get_ivars(dev); |
1116 |
|
1117 |
|
1117 |
if (uaa->usb_mode != USB_MODE_HOST) |
1118 |
if (uaa->usb_mode != USB_MODE_HOST) |
1118 |
return (ENXIO); |
1119 |
return (ENXIO); |
1119 |
|
1120 |
|
1120 |
/* |
1121 |
/* |
1121 |
* The subclass for USB HUBs is currently ignored because it |
1122 |
* The subclass for USB HUBs is currently ignored because it |
1122 |
* is 0 for some and 1 for others. |
1123 |
* is 0 for some and 1 for others. |
1123 |
*/ |
1124 |
*/ |
1124 |
if (uaa->info.bConfigIndex == 0 && |
1125 |
if (uaa->info.bConfigIndex == 0 && |
1125 |
uaa->info.bDeviceClass == UDCLASS_HUB) |
1126 |
uaa->info.bDeviceClass == UDCLASS_HUB) |
1126 |
return (BUS_PROBE_DEFAULT); |
1127 |
return (BUS_PROBE_DEFAULT); |
1127 |
|
1128 |
|
1128 |
return (ENXIO); |
1129 |
return (ENXIO); |
1129 |
} |
1130 |
} |
1130 |
|
1131 |
|
1131 |
/* NOTE: The information returned by this function can be wrong. */ |
1132 |
/* NOTE: The information returned by this function can be wrong. */ |
1132 |
usb_error_t |
1133 |
usb_error_t |
1133 |
uhub_query_info(struct usb_device *udev, uint8_t *pnports, uint8_t *ptt) |
1134 |
uhub_query_info(struct usb_device *udev, uint8_t *pnports, uint8_t *ptt) |
1134 |
{ |
1135 |
{ |
1135 |
struct usb_hub_descriptor hubdesc20; |
1136 |
struct usb_hub_descriptor hubdesc20; |
1136 |
struct usb_hub_ss_descriptor hubdesc30; |
1137 |
struct usb_hub_ss_descriptor hubdesc30; |
1137 |
usb_error_t err; |
1138 |
usb_error_t err; |
1138 |
uint8_t nports; |
1139 |
uint8_t nports; |
1139 |
uint8_t tt; |
1140 |
uint8_t tt; |
1140 |
|
1141 |
|
1141 |
if (udev->ddesc.bDeviceClass != UDCLASS_HUB) |
1142 |
if (udev->ddesc.bDeviceClass != UDCLASS_HUB) |
1142 |
return (USB_ERR_INVAL); |
1143 |
return (USB_ERR_INVAL); |
1143 |
|
1144 |
|
1144 |
nports = 0; |
1145 |
nports = 0; |
1145 |
tt = 0; |
1146 |
tt = 0; |
1146 |
|
1147 |
|
1147 |
switch (udev->speed) { |
1148 |
switch (udev->speed) { |
1148 |
case USB_SPEED_LOW: |
1149 |
case USB_SPEED_LOW: |
1149 |
case USB_SPEED_FULL: |
1150 |
case USB_SPEED_FULL: |
1150 |
case USB_SPEED_HIGH: |
1151 |
case USB_SPEED_HIGH: |
1151 |
/* assuming that there is one port */ |
1152 |
/* assuming that there is one port */ |
1152 |
err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1); |
1153 |
err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1); |
1153 |
if (err) { |
1154 |
if (err) { |
1154 |
DPRINTFN(0, "getting USB 2.0 HUB descriptor failed," |
1155 |
DPRINTFN(0, "getting USB 2.0 HUB descriptor failed," |