View | Details | Raw Unified | Return to bug 237666 | Differences between
and this patch

Collapse All | Expand All

(-)sys/dev/usb/usb_hub.c (-1 / +2 lines)
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,"

Return to bug 237666