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 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
43struct 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
52static 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
109struct xhci_root_hub_string_s {
110	uint8	length;
111	uint8	descriptor_type;
112	uint16	unicode_string[12];
113} _PACKED;
114
115
116static 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
146XHCIRootHub::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
153status_t
154XHCIRootHub::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