xref: /haiku/src/add-ons/kernel/busses/usb/xhci_rh.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2011, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  * 		Jian Chiang <j.jian.chiang@gmail.com>
8  */
9 
10 
11 #include "xhci.h"
12 
13 #define USB_MODULE_NAME "xhci roothub"
14 
15 static usb_device_descriptor sXHCIRootHubDevice =
16 {
17 	18,								// Descriptor length
18 	USB_DESCRIPTOR_DEVICE,			// Descriptor type
19 	0x300,							// USB 3.0
20 	0x09,							// Class (9 = Hub)
21 	0,								// Subclass
22 	3,								// Protocol
23 	9,								// Max packet size on endpoint 0
24 	0,								// Vendor ID
25 	0,								// Product ID
26 	0x300,							// Version
27 	1,								// Index of manufacturer string
28 	2,								// Index of product string
29 	0,								// Index of serial number string
30 	1								// Number of configurations
31 };
32 
33 
34 struct xhci_root_hub_configuration_s {
35 	usb_configuration_descriptor	configuration;
36 	usb_interface_descriptor		interface;
37 	usb_endpoint_descriptor			endpoint;
38 	usb_endpoint_ss_companion_descriptor endpoint_ss_companion;
39 	usb_hub_descriptor				hub;
40 } _PACKED;
41 
42 
43 static xhci_root_hub_configuration_s sXHCIRootHubConfig =
44 {
45 	{ // configuration descriptor
46 		9,								// Descriptor length
47 		USB_DESCRIPTOR_CONFIGURATION,	// Descriptor type
48 		sizeof(sXHCIRootHubConfig),		// Total length of configuration (including
49 										// interface, endpoint and hub descriptors)
50 		1,								// Number of interfaces
51 		1,								// Value of this configuration
52 		0,								// Index of configuration string
53 		0x40,							// Attributes (0x40 = self powered)
54 		0								// Max power (0, since self powered)
55 	},
56 
57 	{ // interface descriptor
58 		9,								// Descriptor length
59 		USB_DESCRIPTOR_INTERFACE,		// Descriptor type
60 		0,								// Interface number
61 		0,								// Alternate setting
62 		1,								// Number of endpoints
63 		0x09,							// Interface class (9 = Hub)
64 		0,								// Interface subclass
65 		0,								// Interface protocol
66 		0								// Index of interface string
67 	},
68 
69 	{ // endpoint descriptor
70 		7,								// Descriptor length
71 		USB_DESCRIPTOR_ENDPOINT,		// Descriptor type
72 		USB_REQTYPE_DEVICE_IN | 1,		// Endpoint address (first in IN endpoint)
73 		0x03,							// Attributes (0x03 = interrupt endpoint)
74 		2,								// Max packet size
75 		0xff							// Interval
76 	},
77 
78 	{ // endpoint companion descriptor
79 		7,
80 		USB_DESCRIPTOR_ENDPOINT_SS_COMPANION,
81 		0,
82 		0,
83 		0
84 	},
85 
86 	{ // hub descriptor
87 		9,								// Descriptor length (including
88 										// deprecated power control mask)
89 		USB_DESCRIPTOR_HUB,				// Descriptor type
90 		0x0f,							// Number of ports
91 		0x0000,							// Hub characteristics
92 		10,								// Power on to power good (in 2ms units)
93 		0,								// Maximum current (in mA)
94 		0x00,							// All ports are removable
95 		0xff							// Deprecated power control mask
96 	}
97 };
98 
99 
100 struct xhci_root_hub_string_s {
101 	uint8	length;
102 	uint8	descriptor_type;
103 	uint16	unicode_string[12];
104 } _PACKED;
105 
106 
107 static xhci_root_hub_string_s sXHCIRootHubStrings[3] = {
108 	{
109 		4,								// Descriptor length
110 		USB_DESCRIPTOR_STRING,			// Descriptor type
111 		{
112 			0x0409						// Supported language IDs (English US)
113 		}
114 	},
115 
116 	{
117 		22,								// Descriptor length
118 		USB_DESCRIPTOR_STRING,			// Descriptor type
119 		{
120 			'H', 'A', 'I', 'K', 'U',	// Characters
121 			' ', 'I', 'n', 'c', '.'
122 		}
123 	},
124 
125 	{
126 		26,								// Descriptor length
127 		USB_DESCRIPTOR_STRING,			// Descriptor type
128 		{
129 			'X', 'H', 'C', 'I', ' ',	// Characters
130 			'R', 'o', 'o', 't', 'H',
131 			'u', 'b'
132 		}
133 	}
134 };
135 
136 
137 XHCIRootHub::XHCIRootHub(Object *rootObject, int8 deviceAddress)
138 	:	Hub(rootObject, 0, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()),
139 			sXHCIRootHubDevice, deviceAddress, USB_SPEED_SUPERSPEED, true)
140 {
141 }
142 
143 
144 status_t
145 XHCIRootHub::ProcessTransfer(XHCI *xhci, Transfer *transfer)
146 {
147 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
148 		return B_ERROR;
149 
150 	usb_request_data *request = transfer->RequestData();
151 	TRACE_MODULE("request: %d\n", request->Request);
152 
153 	status_t status = B_TIMED_OUT;
154 	size_t actualLength = 0;
155 	switch (request->Request) {
156 		case USB_REQUEST_GET_STATUS: {
157 			if (request->Index == 0) {
158 				// get hub status
159 				actualLength = MIN(sizeof(usb_port_status),
160 					transfer->DataLength());
161 				// the hub reports whether the local power failed (bit 0)
162 				// and if there is a over-current condition (bit 1).
163 				// everything as 0 means all is ok.
164 				memset(transfer->Data(), 0, actualLength);
165 				status = B_OK;
166 				break;
167 			}
168 
169 			usb_port_status portStatus;
170 			if (xhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
171 				actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
172 				memcpy(transfer->Data(), (void *)&portStatus, actualLength);
173 				status = B_OK;
174 			}
175 
176 			break;
177 		}
178 
179 		case USB_REQUEST_SET_ADDRESS:
180 			if (request->Value >= 128) {
181 				status = B_TIMED_OUT;
182 				break;
183 			}
184 
185 			TRACE_MODULE("set address: %d\n", request->Value);
186 			status = B_OK;
187 			break;
188 
189 		case USB_REQUEST_GET_DESCRIPTOR:
190 			TRACE_MODULE("get descriptor: %d\n", request->Value >> 8);
191 
192 			switch (request->Value >> 8) {
193 				case USB_DESCRIPTOR_DEVICE: {
194 					actualLength = MIN(sizeof(usb_device_descriptor),
195 						transfer->DataLength());
196 					memcpy(transfer->Data(), (void *)&sXHCIRootHubDevice,
197 						actualLength);
198 					status = B_OK;
199 					break;
200 				}
201 
202 				case USB_DESCRIPTOR_CONFIGURATION: {
203 					actualLength = MIN(sizeof(xhci_root_hub_configuration_s),
204 						transfer->DataLength());
205 					sXHCIRootHubConfig.hub.num_ports = xhci->PortCount();
206 					memcpy(transfer->Data(), (void *)&sXHCIRootHubConfig,
207 						actualLength);
208 					status = B_OK;
209 					break;
210 				}
211 
212 				case USB_DESCRIPTOR_STRING: {
213 					uint8 index = request->Value & 0x00ff;
214 					if (index > 2)
215 						break;
216 
217 					actualLength = MIN(sXHCIRootHubStrings[index].length,
218 						transfer->DataLength());
219 					memcpy(transfer->Data(), (void *)&sXHCIRootHubStrings[index],
220 						actualLength);
221 					status = B_OK;
222 					break;
223 				}
224 
225 				case USB_DESCRIPTOR_HUB: {
226 					actualLength = MIN(sizeof(usb_hub_descriptor),
227 						transfer->DataLength());
228 					sXHCIRootHubConfig.hub.num_ports = xhci->PortCount();
229 					memcpy(transfer->Data(), (void *)&sXHCIRootHubConfig.hub,
230 						actualLength);
231 					status = B_OK;
232 					break;
233 				}
234 			}
235 			break;
236 
237 		case USB_REQUEST_SET_CONFIGURATION:
238 			status = B_OK;
239 			break;
240 
241 		case USB_REQUEST_CLEAR_FEATURE: {
242 			if (request->Index == 0) {
243 				// we don't support any hub changes
244 				TRACE_MODULE_ERROR("clear feature: no hub changes\n");
245 				break;
246 			}
247 
248 			TRACE_MODULE("clear feature: %d\n", request->Value);
249 			if (xhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
250 				status = B_OK;
251 			break;
252 		}
253 
254 		case USB_REQUEST_SET_FEATURE: {
255 			if (request->Index == 0) {
256 				// we don't support any hub changes
257 				TRACE_MODULE_ERROR("set feature: no hub changes\n");
258 				break;
259 			}
260 
261 			TRACE_MODULE("set feature: %d\n", request->Value);
262 			if (xhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
263 				status = B_OK;
264 			break;
265 		}
266 	}
267 
268 	transfer->Finished(status, actualLength);
269 	delete transfer;
270 	return B_OK;
271 }
272