1 #ifndef _USBHUB_H
2 #define _USBHUB_H
3 
4 /** @file
5  *
6  * USB hubs
7  *
8  */
9 
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 
12 #include <ipxe/usb.h>
13 #include <ipxe/list.h>
14 #include <ipxe/process.h>
15 
16 /** Request recipient is a port */
17 #define USB_HUB_RECIP_PORT ( 3 << 0 )
18 
19 /** A basic USB hub descriptor */
20 struct usb_hub_descriptor_basic {
21 	/** Descriptor header */
22 	struct usb_descriptor_header header;
23 	/** Number of ports */
24 	uint8_t ports;
25 	/** Characteristics */
26 	uint16_t characteristics;
27 	/** Power-on delay (in 2ms intervals */
28 	uint8_t delay;
29 	/** Controller current (in mA) */
30 	uint8_t current;
31 } __attribute__ (( packed ));
32 
33 /** A basic USB hub descriptor */
34 #define USB_HUB_DESCRIPTOR 41
35 
36 /** An enhanced USB hub descriptor */
37 struct usb_hub_descriptor_enhanced {
38 	/** Basic USB hub descriptor */
39 	struct usb_hub_descriptor_basic basic;
40 	/** Header decode latency */
41 	uint8_t latency;
42 	/** Maximum delay */
43 	uint16_t delay;
44 	/** Removable device bitmask */
45 	uint16_t removable;
46 } __attribute__ (( packed ));
47 
48 /** An enhanced USB hub descriptor */
49 #define USB_HUB_DESCRIPTOR_ENHANCED 42
50 
51 /** A USB hub descriptor */
52 union usb_hub_descriptor {
53 	/** Descriptor header */
54 	struct usb_descriptor_header header;
55 	/** Basic hub descriptor */
56 	struct usb_hub_descriptor_basic basic;
57 	/** Enhanced hub descriptor */
58 	struct usb_hub_descriptor_enhanced enhanced;
59 } __attribute__ (( packed ));
60 
61 /** Port status */
62 struct usb_hub_port_status {
63 	/** Current status */
64 	uint16_t current;
65 	/** Changed status */
66 	uint16_t changed;
67 } __attribute__ (( packed ));
68 
69 /** Current connect status feature */
70 #define USB_HUB_PORT_CONNECTION 0
71 
72 /** Port enabled/disabled feature */
73 #define USB_HUB_PORT_ENABLE 1
74 
75 /** Port reset feature */
76 #define USB_HUB_PORT_RESET 4
77 
78 /** Port power feature */
79 #define USB_HUB_PORT_POWER 8
80 
81 /** Low-speed device attached */
82 #define USB_HUB_PORT_LOW_SPEED 9
83 
84 /** High-speed device attached */
85 #define USB_HUB_PORT_HIGH_SPEED 10
86 
87 /** Connect status changed */
88 #define USB_HUB_C_PORT_CONNECTION 16
89 
90 /** Port enable/disable changed */
91 #define	USB_HUB_C_PORT_ENABLE 17
92 
93 /** Suspend changed */
94 #define USB_HUB_C_PORT_SUSPEND 18
95 
96 /** Over-current indicator changed */
97 #define USB_HUB_C_PORT_OVER_CURRENT 19
98 
99 /** Reset changed */
100 #define USB_HUB_C_PORT_RESET 20
101 
102 /** Link state changed */
103 #define USB_HUB_C_PORT_LINK_STATE 25
104 
105 /** Configuration error */
106 #define USB_HUB_C_PORT_CONFIG_ERROR 26
107 
108 /** Calculate feature from change bit number */
109 #define USB_HUB_C_FEATURE( bit ) ( 16 + (bit) )
110 
111 /** USB features */
112 #define USB_HUB_FEATURES						\
113 	( ( 1 << USB_HUB_C_PORT_CONNECTION ) |				\
114 	  ( 1 << USB_HUB_C_PORT_ENABLE ) |				\
115 	  ( 1 << USB_HUB_C_PORT_SUSPEND ) |				\
116 	  ( 1 << USB_HUB_C_PORT_OVER_CURRENT ) |			\
117 	  ( 1 << USB_HUB_C_PORT_RESET ) )
118 
119 /** USB features for enhanced hubs */
120 #define USB_HUB_FEATURES_ENHANCED					\
121 	( ( 1 << USB_HUB_C_PORT_CONNECTION ) |				\
122 	  ( 1 << USB_HUB_C_PORT_OVER_CURRENT ) |			\
123 	  ( 1 << USB_HUB_C_PORT_RESET ) |				\
124 	  ( 1 << USB_HUB_C_PORT_LINK_STATE ) |				\
125 	  ( 1 << USB_HUB_C_PORT_CONFIG_ERROR ) )
126 
127 /** Set hub depth */
128 #define USB_HUB_SET_HUB_DEPTH						\
129 	( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE |		\
130 	  USB_REQUEST_TYPE ( 12 ) )
131 
132 /** Clear transaction translator buffer */
133 #define USB_HUB_CLEAR_TT_BUFFER						\
134 	( USB_DIR_OUT | USB_TYPE_CLASS | USB_HUB_RECIP_PORT |		\
135 	  USB_REQUEST_TYPE ( 8 ) )
136 
137 /**
138  * Get hub descriptor
139  *
140  * @v usb		USB device
141  * @v enhanced		Hub is an enhanced hub
142  * @v data		Hub descriptor to fill in
143  * @ret rc		Return status code
144  */
145 static inline __attribute__ (( always_inline )) int
usb_hub_get_descriptor(struct usb_device * usb,int enhanced,union usb_hub_descriptor * data)146 usb_hub_get_descriptor ( struct usb_device *usb, int enhanced,
147 			 union usb_hub_descriptor *data ) {
148 	unsigned int desc;
149 	size_t len;
150 
151 	/* Determine descriptor type and length */
152 	desc = ( enhanced ? USB_HUB_DESCRIPTOR_ENHANCED : USB_HUB_DESCRIPTOR );
153 	len = ( enhanced ? sizeof ( data->enhanced ) : sizeof ( data->basic ) );
154 
155 	return usb_get_descriptor ( usb, USB_TYPE_CLASS, desc, 0, 0,
156 				    &data->header, len );
157 }
158 
159 /**
160  * Get port status
161  *
162  * @v usb		USB device
163  * @v port		Port address
164  * @v status		Port status descriptor to fill in
165  * @ret rc		Return status code
166  */
167 static inline __attribute__ (( always_inline )) int
usb_hub_get_port_status(struct usb_device * usb,unsigned int port,struct usb_hub_port_status * status)168 usb_hub_get_port_status ( struct usb_device *usb, unsigned int port,
169 			  struct usb_hub_port_status *status ) {
170 
171 	return usb_get_status ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
172 				port, status, sizeof ( *status ) );
173 }
174 
175 /**
176  * Clear port feature
177  *
178  * @v usb		USB device
179  * @v port		Port address
180  * @v feature		Feature to clear
181  * @v index		Index (when clearing a port indicator)
182  * @ret rc		Return status code
183  */
184 static inline __attribute__ (( always_inline )) int
usb_hub_clear_port_feature(struct usb_device * usb,unsigned int port,unsigned int feature,unsigned int index)185 usb_hub_clear_port_feature ( struct usb_device *usb, unsigned int port,
186 			     unsigned int feature, unsigned int index ) {
187 
188 	return usb_clear_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
189 				   feature, ( ( index << 8 ) | port ) );
190 }
191 
192 /**
193  * Set port feature
194  *
195  * @v usb		USB device
196  * @v port		Port address
197  * @v feature		Feature to clear
198  * @v index		Index (when clearing a port indicator)
199  * @ret rc		Return status code
200  */
201 static inline __attribute__ (( always_inline )) int
usb_hub_set_port_feature(struct usb_device * usb,unsigned int port,unsigned int feature,unsigned int index)202 usb_hub_set_port_feature ( struct usb_device *usb, unsigned int port,
203 			   unsigned int feature, unsigned int index ) {
204 
205 	return usb_set_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
206 				 feature, ( ( index << 8 ) | port ) );
207 }
208 
209 /**
210  * Set hub depth
211  *
212  * @v usb		USB device
213  * @v depth		Hub depth
214  * @ret rc		Return status code
215  */
216 static inline __attribute__ (( always_inline )) int
usb_hub_set_hub_depth(struct usb_device * usb,unsigned int depth)217 usb_hub_set_hub_depth ( struct usb_device *usb, unsigned int depth ) {
218 
219 	return usb_control ( usb, USB_HUB_SET_HUB_DEPTH, depth, 0, NULL, 0 );
220 }
221 
222 /**
223  * Clear transaction translator buffer
224  *
225  * @v usb		USB device
226  * @v device		Device address
227  * @v endpoint		Endpoint address
228  * @v attributes	Endpoint attributes
229  * @v tt_port		Transaction translator port (or 1 for single-TT hubs)
230  * @ret rc		Return status code
231  */
232 static inline __attribute__ (( always_inline )) int
usb_hub_clear_tt_buffer(struct usb_device * usb,unsigned int device,unsigned int endpoint,unsigned int attributes,unsigned int tt_port)233 usb_hub_clear_tt_buffer ( struct usb_device *usb, unsigned int device,
234 			  unsigned int endpoint, unsigned int attributes,
235 			  unsigned int tt_port ) {
236 	unsigned int value;
237 
238 	/* Calculate value */
239 	value = ( ( ( endpoint & USB_ENDPOINT_MAX ) << 0 ) | ( device << 4 ) |
240 		  ( ( attributes & USB_ENDPOINT_ATTR_TYPE_MASK ) << 11 ) |
241 		  ( ( endpoint & USB_ENDPOINT_IN ) << 8 ) );
242 
243 	return usb_control ( usb, USB_HUB_CLEAR_TT_BUFFER, value,
244 			     tt_port, NULL, 0 );
245 }
246 
247 /** Transaction translator port value for single-TT hubs */
248 #define USB_HUB_TT_SINGLE 1
249 
250 /** A USB hub device */
251 struct usb_hub_device {
252 	/** Name */
253 	const char *name;
254 	/** USB device */
255 	struct usb_device *usb;
256 	/** USB hub */
257 	struct usb_hub *hub;
258 	/** Features */
259 	unsigned int features;
260 	/** Flags */
261 	unsigned int flags;
262 
263 	/** Interrupt endpoint */
264 	struct usb_endpoint intr;
265 	/** Interrupt endpoint refill process */
266 	struct process refill;
267 };
268 
269 /** Hub requires additional settling delay */
270 #define USB_HUB_SLOW_START 0x0001
271 
272 /** Additional setting delay for out-of-spec hubs */
273 #define USB_HUB_SLOW_START_DELAY_MS 500
274 
275 /** Interrupt ring fill level
276  *
277  * This is a policy decision.
278  */
279 #define USB_HUB_INTR_FILL 4
280 
281 /** Maximum time to wait for port to become enabled
282  *
283  * This is a policy decision.
284  */
285 #define USB_HUB_ENABLE_MAX_WAIT_MS 100
286 
287 #endif /* _USBHUB_H */
288