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
15static 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
34struct 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
43static 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		6,
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
100struct xhci_root_hub_string_s {
101	uint8	length;
102	uint8	descriptor_type;
103	uint16	unicode_string[12];
104} _PACKED;
105
106
107static 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
137XHCIRootHub::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
144status_t
145XHCIRootHub::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