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