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