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;
3822002cf4SAugustin Cavalier usb_endpoint_ss_companion_descriptor endpoint_ss_companion;
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
79*edd8e471SX512 6,
8022002cf4SAugustin Cavalier USB_DESCRIPTOR_ENDPOINT_SS_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
XHCIRootHub(Object * rootObject,int8 deviceAddress)137d6e4f54fSJérôme Duval XHCIRootHub::XHCIRootHub(Object *rootObject, int8 deviceAddress)
138d6e4f54fSJérôme Duval : Hub(rootObject, 0, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()),
1396e2bbbb1SAugustin 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
ProcessTransfer(XHCI * xhci,Transfer * transfer)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