Browse Source

[usb] Try multiple USB device configurations

Iterate over a USB device's available configurations until we find one
for which we have working drivers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
a60f2ddfeb
2 changed files with 137 additions and 72 deletions
  1. 134
    69
      src/drivers/bus/usb.c
  2. 3
    3
      src/include/ipxe/usb.h

+ 134
- 69
src/drivers/bus/usb.c View File

@@ -831,7 +831,7 @@ usb_probe_all ( struct usb_device *usb,
831 831
 		func->dev.desc.vendor = le16_to_cpu ( usb->device.vendor );
832 832
 		func->dev.desc.device = le16_to_cpu ( usb->device.product );
833 833
 		snprintf ( func->dev.name, sizeof ( func->dev.name ),
834
-			   "%s-%d", usb->name, first );
834
+			   "%s-%d.%d", usb->name, config->config, first );
835 835
 		INIT_LIST_HEAD ( &func->dev.children );
836 836
 		func->dev.parent = bus->dev;
837 837
 
@@ -905,6 +905,133 @@ static void usb_remove_all ( struct usb_device *usb ) {
905 905
 	}
906 906
 }
907 907
 
908
+/**
909
+ * Select USB device configuration
910
+ *
911
+ * @v usb		USB device
912
+ * @v index		Configuration index
913
+ * @ret rc		Return status code
914
+ */
915
+static int usb_configure ( struct usb_device *usb, unsigned int index ) {
916
+	struct usb_configuration_descriptor partial;
917
+	struct usb_configuration_descriptor *config;
918
+	size_t len;
919
+	int rc;
920
+
921
+	/* Read first part of configuration descriptor to get size */
922
+	if ( ( rc = usb_get_config_descriptor ( usb, index, &partial,
923
+						sizeof ( partial ) ) ) != 0 ) {
924
+		DBGC ( usb, "USB %s could not get configuration descriptor %d: "
925
+		       "%s\n", usb->name, index, strerror ( rc ) );
926
+		goto err_get_partial;
927
+	}
928
+	len = le16_to_cpu ( partial.len );
929
+	if ( len < sizeof ( partial ) ) {
930
+		DBGC ( usb, "USB %s underlength configuraton descriptor %d\n",
931
+		       usb->name, index );
932
+		rc = -EINVAL;
933
+		goto err_partial_len;
934
+	}
935
+
936
+	/* Allocate buffer for whole configuration descriptor */
937
+	config = malloc ( len );
938
+	if ( ! config ) {
939
+		rc = -ENOMEM;
940
+		goto err_alloc_config;
941
+	}
942
+
943
+	/* Read whole configuration descriptor */
944
+	if ( ( rc = usb_get_config_descriptor ( usb, index, config,
945
+						len ) ) != 0 ) {
946
+		DBGC ( usb, "USB %s could not get configuration descriptor %d: "
947
+		       "%s\n", usb->name, index, strerror ( rc ) );
948
+		goto err_get_config_descriptor;
949
+	}
950
+	if ( config->len != partial.len ) {
951
+		DBGC ( usb, "USB %s bad configuration descriptor %d length\n",
952
+		       usb->name, index );
953
+		rc = -EINVAL;
954
+		goto err_config_len;
955
+	}
956
+
957
+	/* Set configuration */
958
+	if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){
959
+		DBGC ( usb, "USB %s could not set configuration %d: %s\n",
960
+		       usb->name, config->config, strerror ( rc ) );
961
+		goto err_set_configuration;
962
+	}
963
+
964
+	/* Probe USB device drivers */
965
+	usb_probe_all ( usb, config );
966
+
967
+	/* Free configuration descriptor */
968
+	free ( config );
969
+
970
+	return 0;
971
+
972
+	usb_remove_all ( usb );
973
+	usb_set_configuration ( usb, 0 );
974
+ err_set_configuration:
975
+ err_config_len:
976
+ err_get_config_descriptor:
977
+	free ( config );
978
+ err_alloc_config:
979
+ err_partial_len:
980
+ err_get_partial:
981
+	return rc;
982
+}
983
+
984
+/**
985
+ * Clear USB device configuration
986
+ *
987
+ * @v usb		USB device
988
+ */
989
+static void usb_deconfigure ( struct usb_device *usb ) {
990
+	unsigned int i;
991
+
992
+	/* Remove device drivers */
993
+	usb_remove_all ( usb );
994
+
995
+	/* Sanity checks */
996
+	for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++){
997
+		if ( i != USB_ENDPOINT_IDX ( USB_EP0_ADDRESS ) )
998
+			assert ( usb->ep[i] == NULL );
999
+	}
1000
+
1001
+	/* Clear device configuration */
1002
+	usb_set_configuration ( usb, 0 );
1003
+}
1004
+
1005
+/**
1006
+ * Find and select a supported USB device configuration
1007
+ *
1008
+ * @v usb		USB device
1009
+ * @ret rc		Return status code
1010
+ */
1011
+static int usb_configure_any ( struct usb_device *usb ) {
1012
+	unsigned int index;
1013
+	int rc = -ENOENT;
1014
+
1015
+	/* Attempt all configuration indexes */
1016
+	for ( index = 0 ; index < usb->device.configurations ; index++ ) {
1017
+
1018
+		/* Attempt this configuration index */
1019
+		if ( ( rc = usb_configure ( usb, index ) ) != 0 )
1020
+			continue;
1021
+
1022
+		/* If we have no drivers, then try the next configuration */
1023
+		if ( list_empty ( &usb->functions ) ) {
1024
+			rc = -ENOTSUP;
1025
+			usb_deconfigure ( usb );
1026
+			continue;
1027
+		}
1028
+
1029
+		return 0;
1030
+	}
1031
+
1032
+	return rc;
1033
+}
1034
+
908 1035
 /******************************************************************************
909 1036
  *
910 1037
  * USB device
@@ -948,11 +1075,8 @@ static int register_usb ( struct usb_device *usb ) {
948 1075
 	struct usb_port *port = usb->port;
949 1076
 	struct usb_hub *hub = port->hub;
950 1077
 	struct usb_bus *bus = hub->bus;
951
-	struct usb_configuration_descriptor partial;
952
-	struct usb_configuration_descriptor *config;
953 1078
 	unsigned int protocol;
954 1079
 	size_t mtu;
955
-	size_t len;
956 1080
 	int rc;
957 1081
 
958 1082
 	/* Add to port */
@@ -1040,65 +1164,14 @@ static int register_usb ( struct usb_device *usb ) {
1040 1164
 	       usb_bcd ( le16_to_cpu ( usb->device.protocol ) ),
1041 1165
 	       usb_speed_name ( port->speed ), usb->control.mtu );
1042 1166
 
1043
-	/* Read first part of configuration descriptor to get size */
1044
-	if ( ( rc = usb_get_config_descriptor ( usb, 0, &partial,
1045
-						sizeof ( partial ) ) ) != 0 ) {
1046
-		DBGC ( usb, "USB %s could not get configuration descriptor: "
1047
-		       "%s\n", usb->name, strerror ( rc ) );
1048
-		goto err_get_partial;
1049
-	}
1050
-	len = le16_to_cpu ( partial.len );
1051
-	if ( len < sizeof ( partial ) ) {
1052
-		DBGC ( usb, "USB %s underlength configuraton descriptor\n",
1053
-		       usb->name );
1054
-		rc = -EINVAL;
1055
-		goto err_partial_len;
1056
-	}
1057
-
1058
-	/* Allocate buffer for whole configuration descriptor */
1059
-	config = malloc ( len );
1060
-	if ( ! config ) {
1061
-		rc = -ENOMEM;
1062
-		goto err_alloc_config;
1063
-	}
1064
-
1065
-	/* Read whole configuration descriptor */
1066
-	if ( ( rc = usb_get_config_descriptor ( usb, 0, config, len ) ) != 0 ) {
1067
-		DBGC ( usb, "USB %s could not get configuration descriptor: "
1068
-		       "%s\n", usb->name, strerror ( rc ) );
1069
-		goto err_get_config_descriptor;
1070
-	}
1071
-	if ( config->len != partial.len ) {
1072
-		DBGC ( usb, "USB %s bad configuration descriptor length\n",
1073
-		       usb->name );
1074
-		rc = -EINVAL;
1075
-		goto err_config_len;
1076
-	}
1077
-
1078
-	/* Set configuration */
1079
-	if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){
1080
-		DBGC ( usb, "USB %s could not set configuration %#02x: %s\n",
1081
-		       usb->name, config->config, strerror ( rc ) );
1082
-		goto err_set_configuration;
1083
-	}
1084
-
1085
-	/* Probe USB device drivers */
1086
-	usb_probe_all ( usb, config );
1087
-
1088
-	/* Free configuration descriptor */
1089
-	free ( config );
1167
+	/* Configure device */
1168
+	if ( ( rc = usb_configure_any ( usb ) ) != 0 )
1169
+		goto err_configure_any;
1090 1170
 
1091 1171
 	return 0;
1092 1172
 
1093
-	usb_remove_all ( usb );
1094
-	usb_set_configuration ( usb, 0 );
1095
- err_set_configuration:
1096
- err_config_len:
1097
- err_get_config_descriptor:
1098
-	free ( config );
1099
- err_alloc_config:
1100
- err_partial_len:
1101
- err_get_partial:
1173
+	usb_deconfigure ( usb );
1174
+ err_configure_any:
1102 1175
  err_get_device_descriptor:
1103 1176
  err_mtu:
1104 1177
  err_get_mtu:
@@ -1126,20 +1199,12 @@ static void unregister_usb ( struct usb_device *usb ) {
1126 1199
 	struct usb_hub *hub = port->hub;
1127 1200
 	struct io_buffer *iobuf;
1128 1201
 	struct io_buffer *tmp;
1129
-	unsigned int i;
1130
-
1131
-	/* Remove device drivers */
1132
-	usb_remove_all ( usb );
1133 1202
 
1134 1203
 	/* Sanity checks */
1135
-	for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++){
1136
-		if ( i != USB_ENDPOINT_IDX ( USB_EP0_ADDRESS ) )
1137
-			assert ( usb->ep[i] == NULL );
1138
-	}
1139 1204
 	assert ( port->usb == usb );
1140 1205
 
1141 1206
 	/* Clear device configuration */
1142
-	usb_set_configuration ( usb, 0 );
1207
+	usb_deconfigure ( usb );
1143 1208
 
1144 1209
 	/* Close control endpoint */
1145 1210
 	usb_endpoint_close ( &usb->control );

+ 3
- 3
src/include/ipxe/usb.h View File

@@ -1034,13 +1034,13 @@ usb_get_config_descriptor ( struct usb_device *usb, unsigned int index,
1034 1034
  * Set USB configuration
1035 1035
  *
1036 1036
  * @v usb		USB device
1037
- * @v config		Configuration value
1037
+ * @v index		Configuration index
1038 1038
  * @ret rc		Return status code
1039 1039
  */
1040 1040
 static inline __attribute__ (( always_inline )) int
1041
-usb_set_configuration ( struct usb_device *usb, unsigned int config ) {
1041
+usb_set_configuration ( struct usb_device *usb, unsigned int index ) {
1042 1042
 
1043
-	return usb_control ( usb, USB_SET_CONFIGURATION, config, 0, NULL, 0 );
1043
+	return usb_control ( usb, USB_SET_CONFIGURATION, index, 0, NULL, 0 );
1044 1044
 }
1045 1045
 
1046 1046
 /**

Loading…
Cancel
Save