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