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
15 static 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
34 struct 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
43 static 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
100 struct xhci_root_hub_string_s {
101 uint8 length;
102 uint8 descriptor_type;
103 uint16 unicode_string[12];
104 } _PACKED;
105
106
107 static 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
XHCIRootHub(Object * rootObject,int8 deviceAddress)137 XHCIRootHub::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
144 status_t
ProcessTransfer(XHCI * xhci,Transfer * transfer)145 XHCIRootHub::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