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