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