1 /*
2 * Copyright 2004-2006, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 * Niels S. Reedijk
8 */
9
10 #include "uhci.h"
11
12 #define USB_MODULE_NAME "uhci roothub"
13
14 static usb_device_descriptor sUHCIRootHubDevice =
15 {
16 18, // Descriptor length
17 USB_DESCRIPTOR_DEVICE, // Descriptor type
18 0x110, // USB 1.1
19 0x09, // Class (9 = Hub)
20 0, // Subclass
21 0, // Protocol
22 64, // Max packet size on endpoint 0
23 0, // Vendor ID
24 0, // Product ID
25 0x110, // Version
26 1, // Index of manufacturer string
27 2, // Index of product string
28 0, // Index of serial number string
29 1 // Number of configurations
30 };
31
32
33 struct uhci_root_hub_configuration_s {
34 usb_configuration_descriptor configuration;
35 usb_interface_descriptor interface;
36 usb_endpoint_descriptor endpoint;
37 usb_hub_descriptor hub;
38 } _PACKED;
39
40
41 static uhci_root_hub_configuration_s sUHCIRootHubConfig =
42 {
43 { // configuration descriptor
44 9, // Descriptor length
45 USB_DESCRIPTOR_CONFIGURATION, // Descriptor type
46 34, // Total length of configuration (including
47 // interface, endpoint and hub descriptors)
48 1, // Number of interfaces
49 1, // Value of this configuration
50 0, // Index of configuration string
51 0x40, // Attributes (0x40 = self powered)
52 0 // Max power (0, since self powered)
53 },
54
55 { // interface descriptor
56 9, // Descriptor length
57 USB_DESCRIPTOR_INTERFACE, // Descriptor type
58 0, // Interface number
59 0, // Alternate setting
60 1, // Number of endpoints
61 0x09, // Interface class (9 = Hub)
62 0, // Interface subclass
63 0, // Interface protocol
64 0 // Index of interface string
65 },
66
67 { // endpoint descriptor
68 7, // Descriptor length
69 USB_DESCRIPTOR_ENDPOINT, // Descriptor type
70 USB_REQTYPE_DEVICE_IN | 1, // Endpoint address (first in IN endpoint)
71 0x03, // Attributes (0x03 = interrupt endpoint)
72 8, // Max packet size
73 0xff // Interval
74 },
75
76 { // hub descriptor
77 9, // Descriptor length (including
78 // deprecated power control mask)
79 USB_DESCRIPTOR_HUB, // Descriptor type
80 2, // Number of ports
81 0x0000, // Hub characteristics
82 0, // Power on to power good (in 2ms units)
83 0, // Maximum current (in mA)
84 0x00, // Both ports are removable
85 0xff // Depricated power control mask
86 }
87 };
88
89
90 struct uhci_root_hub_string_s {
91 uint8 length;
92 uint8 descriptor_type;
93 uint16 unicode_string[12];
94 } _PACKED;
95
96
97 static uhci_root_hub_string_s sUHCIRootHubStrings[3] = {
98 {
99 4, // Descriptor length
100 USB_DESCRIPTOR_STRING, // Descriptor type
101 {
102 0x0409 // Supported language IDs (English US)
103 }
104 },
105
106 {
107 22, // Descriptor length
108 USB_DESCRIPTOR_STRING, // Descriptor type
109 {
110 'H', 'A', 'I', 'K', 'U', // Characters
111 ' ', 'I', 'n', 'c', '.'
112 }
113 },
114
115 {
116 26, // Descriptor length
117 USB_DESCRIPTOR_STRING, // Descriptor type
118 {
119 'U', 'H', 'C', 'I', ' ', // Characters
120 'R', 'o', 'o', 't', 'H',
121 'u', 'b'
122 }
123 }
124 };
125
126
UHCIRootHub(Object * rootObject,int8 deviceAddress)127 UHCIRootHub::UHCIRootHub(Object *rootObject, int8 deviceAddress)
128 : Hub(rootObject, 0, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()),
129 sUHCIRootHubDevice, deviceAddress, USB_SPEED_FULLSPEED, true)
130 {
131 }
132
133
134 status_t
ProcessTransfer(UHCI * uhci,Transfer * transfer)135 UHCIRootHub::ProcessTransfer(UHCI *uhci, Transfer *transfer)
136 {
137 if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
138 return B_ERROR;
139
140 usb_request_data *request = transfer->RequestData();
141 TRACE_MODULE("request: %d\n", request->Request);
142
143 status_t status = B_TIMED_OUT;
144 size_t actualLength = 0;
145 switch (request->Request) {
146 case USB_REQUEST_GET_STATUS: {
147 if (request->Index == 0) {
148 // get hub status
149 actualLength = MIN(sizeof(usb_port_status),
150 transfer->DataLength());
151 // the hub reports whether the local power failed (bit 0)
152 // and if there is a over-current condition (bit 1).
153 // everything as 0 means all is ok.
154 memset(transfer->Data(), 0, actualLength);
155 status = B_OK;
156 break;
157 }
158
159 usb_port_status portStatus;
160 if (uhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
161 actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
162 memcpy(transfer->Data(), (void *)&portStatus, actualLength);
163 status = B_OK;
164 }
165
166 break;
167 }
168
169 case USB_REQUEST_SET_ADDRESS:
170 if (request->Value >= 128) {
171 status = B_TIMED_OUT;
172 break;
173 }
174
175 TRACE_MODULE("set address: %d\n", request->Value);
176 status = B_OK;
177 break;
178
179 case USB_REQUEST_GET_DESCRIPTOR:
180 TRACE_MODULE("get descriptor: %d\n", request->Value >> 8);
181
182 switch (request->Value >> 8) {
183 case USB_DESCRIPTOR_DEVICE: {
184 actualLength = MIN(sizeof(usb_device_descriptor),
185 transfer->DataLength());
186 memcpy(transfer->Data(), (void *)&sUHCIRootHubDevice,
187 actualLength);
188 status = B_OK;
189 break;
190 }
191
192 case USB_DESCRIPTOR_CONFIGURATION: {
193 actualLength = MIN(sizeof(uhci_root_hub_configuration_s),
194 transfer->DataLength());
195 memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig,
196 actualLength);
197 status = B_OK;
198 break;
199 }
200
201 case USB_DESCRIPTOR_STRING: {
202 uint8 index = request->Value & 0x00ff;
203 if (index > 2)
204 break;
205
206 actualLength = MIN(sUHCIRootHubStrings[index].length,
207 transfer->DataLength());
208 memcpy(transfer->Data(), (void *)&sUHCIRootHubStrings[index],
209 actualLength);
210 status = B_OK;
211 break;
212 }
213
214 case USB_DESCRIPTOR_HUB: {
215 actualLength = MIN(sizeof(usb_hub_descriptor),
216 transfer->DataLength());
217 memcpy(transfer->Data(), (void *)&sUHCIRootHubConfig.hub,
218 actualLength);
219 status = B_OK;
220 break;
221 }
222 }
223 break;
224
225 case USB_REQUEST_SET_CONFIGURATION:
226 status = B_OK;
227 break;
228
229 case USB_REQUEST_CLEAR_FEATURE: {
230 if (request->Index == 0) {
231 // we don't support any hub changes
232 TRACE_MODULE_ERROR("clear feature: no hub changes\n");
233 break;
234 }
235
236 TRACE_MODULE("clear feature: %d\n", request->Value);
237 if (uhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
238 status = B_OK;
239 break;
240 }
241
242 case USB_REQUEST_SET_FEATURE: {
243 if (request->Index == 0) {
244 // we don't support any hub changes
245 TRACE_MODULE_ERROR("set feature: no hub changes\n");
246 break;
247 }
248
249 TRACE_MODULE("set feature: %d\n", request->Value);
250 if (uhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
251 status = B_OK;
252 break;
253 }
254 }
255
256 transfer->Finished(status, actualLength);
257 delete transfer;
258 return B_OK;
259 }
260