1 /* 2 * Copyright 2003-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 "usb_p.h" 11 #include <stdio.h> 12 13 14 Hub::Hub(Object *parent, int8 hubAddress, uint8 hubPort, 15 usb_device_descriptor &desc, int8 deviceAddress, usb_speed speed, 16 bool isRootHub) 17 : Device(parent, hubAddress, hubPort, desc, deviceAddress, speed, 18 isRootHub), 19 fInterruptPipe(NULL) 20 { 21 TRACE(("USB Hub %d: creating hub\n", DeviceAddress())); 22 23 memset(&fHubDescriptor, 0, sizeof(fHubDescriptor)); 24 for (int32 i = 0; i < USB_MAX_PORT_COUNT; i++) 25 fChildren[i] = NULL; 26 27 if (!fInitOK) { 28 TRACE_ERROR(("USB Hub %d: device failed to initialize\n", DeviceAddress())); 29 return; 30 } 31 32 // Set to false again for the hub init. 33 fInitOK = false; 34 35 if (fDeviceDescriptor.device_class != 9) { 36 TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress())); 37 return; 38 } 39 40 TRACE(("USB Hub %d: Getting hub descriptor...\n", DeviceAddress())); 41 size_t actualLength; 42 status_t status = GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0, 43 (void *)&fHubDescriptor, sizeof(usb_hub_descriptor), &actualLength); 44 45 // we need at least 8 bytes 46 if (status < B_OK || actualLength < 8) { 47 TRACE_ERROR(("USB Hub %d: Error getting hub descriptor\n", DeviceAddress())); 48 return; 49 } 50 51 TRACE(("USB Hub %d: hub descriptor (%ld bytes):\n", DeviceAddress(), actualLength)); 52 TRACE(("\tlength:..............%d\n", fHubDescriptor.length)); 53 TRACE(("\tdescriptor_type:.....0x%02x\n", fHubDescriptor.descriptor_type)); 54 TRACE(("\tnum_ports:...........%d\n", fHubDescriptor.num_ports)); 55 TRACE(("\tcharacteristics:.....0x%04x\n", fHubDescriptor.characteristics)); 56 TRACE(("\tpower_on_to_power_g:.%d\n", fHubDescriptor.power_on_to_power_good)); 57 TRACE(("\tdevice_removeable:...0x%02x\n", fHubDescriptor.device_removeable)); 58 TRACE(("\tpower_control_mask:..0x%02x\n", fHubDescriptor.power_control_mask)); 59 60 if (fHubDescriptor.num_ports > USB_MAX_PORT_COUNT) { 61 TRACE_ERROR(("USB Hub %d: hub supports more ports than we do (%d vs. %d)\n", 62 DeviceAddress(), fHubDescriptor.num_ports, USB_MAX_PORT_COUNT)); 63 fHubDescriptor.num_ports = USB_MAX_PORT_COUNT; 64 } 65 66 usb_interface_list *list = Configuration()->interface; 67 Object *object = GetStack()->GetObject(list->active->endpoint[0].handle); 68 if (object && (object->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0) { 69 fInterruptPipe = (InterruptPipe *)object; 70 fInterruptPipe->QueueInterrupt(fInterruptStatus, 71 sizeof(fInterruptStatus), InterruptCallback, this); 72 } else { 73 TRACE_ERROR(("USB Hub %d: no interrupt pipe found\n", DeviceAddress())); 74 } 75 76 // Wait some time before powering up the ports 77 if (!isRootHub) 78 snooze(USB_DELAY_HUB_POWER_UP); 79 80 // Enable port power on all ports 81 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 82 status = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 83 USB_REQUEST_SET_FEATURE, PORT_POWER, i + 1, 0, NULL, 0, NULL); 84 85 if (status < B_OK) 86 TRACE_ERROR(("USB Hub %d: power up failed on port %ld\n", DeviceAddress(), i)); 87 } 88 89 // Wait for power to stabilize 90 snooze(fHubDescriptor.power_on_to_power_good * 2000); 91 92 fInitOK = true; 93 TRACE(("USB Hub %d: initialised ok\n", DeviceAddress())); 94 } 95 96 97 Hub::~Hub() 98 { 99 delete fInterruptPipe; 100 } 101 102 103 status_t 104 Hub::Changed(change_item **changeList, bool added) 105 { 106 status_t result = Device::Changed(changeList, added); 107 if (added || result < B_OK) 108 return result; 109 110 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 111 if (fChildren[i] == NULL) 112 continue; 113 114 fChildren[i]->Changed(changeList, false); 115 fChildren[i] = NULL; 116 } 117 118 return B_OK; 119 } 120 121 122 status_t 123 Hub::UpdatePortStatus(uint8 index) 124 { 125 // get the current port status 126 size_t actualLength = 0; 127 status_t result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN, 128 USB_REQUEST_GET_STATUS, 0, index + 1, 4, (void *)&fPortStatus[index], 129 4, &actualLength); 130 131 if (result < B_OK || actualLength < 4) { 132 TRACE_ERROR(("USB Hub %d: error updating port status\n", DeviceAddress())); 133 return B_ERROR; 134 } 135 136 return B_OK; 137 } 138 139 140 status_t 141 Hub::ResetPort(uint8 index) 142 { 143 status_t result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 144 USB_REQUEST_SET_FEATURE, PORT_RESET, index + 1, 0, NULL, 0, NULL); 145 146 if (result < B_OK) 147 return result; 148 149 for (int32 i = 0; i < 10; i++) { 150 snooze(USB_DELAY_PORT_RESET); 151 152 result = UpdatePortStatus(index); 153 if (result < B_OK) 154 return result; 155 156 if (fPortStatus[index].change & C_PORT_RESET) { 157 // reset is done 158 break; 159 } 160 } 161 162 if ((fPortStatus[index].change & C_PORT_RESET) == 0) { 163 TRACE_ERROR(("USB Hub %d: port %d won't reset\n", DeviceAddress(), index)); 164 return B_ERROR; 165 } 166 167 // clear the reset change 168 result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 169 USB_REQUEST_CLEAR_FEATURE, C_PORT_RESET, index + 1, 0, NULL, 0, NULL); 170 if (result < B_OK) 171 return result; 172 173 // wait for reset recovery 174 snooze(USB_DELAY_PORT_RESET_RECOVERY); 175 TRACE(("USB Hub %d: port %d was reset successfully\n", DeviceAddress(), index)); 176 return B_OK; 177 } 178 179 180 status_t 181 Hub::DisablePort(uint8 index) 182 { 183 return DefaultPipe()->SendRequest(USB_REQTYPE_CLASS 184 | USB_REQTYPE_OTHER_OUT, USB_REQUEST_CLEAR_FEATURE, PORT_ENABLE, 185 index + 1, 0, NULL, 0, NULL); 186 } 187 188 189 190 void 191 Hub::Explore(change_item **changeList) 192 { 193 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 194 status_t result = UpdatePortStatus(i); 195 if (result < B_OK) 196 continue; 197 198 #ifdef TRACE_USB 199 if (fPortStatus[i].change) { 200 TRACE(("USB Hub %d: port %ld: status: 0x%04x; change: 0x%04x\n", DeviceAddress(), i, fPortStatus[i].status, fPortStatus[i].change)); 201 TRACE(("USB Hub %d: device at port %ld: 0x%08lx\n", DeviceAddress(), i, fChildren[i])); 202 } 203 #endif 204 205 if (fPortStatus[i].change & PORT_STATUS_CONNECTION) { 206 // clear status change 207 DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 208 USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1, 209 0, NULL, 0, NULL); 210 211 if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { 212 // new device attached! 213 TRACE(("USB Hub %d: new device connected\n", DeviceAddress())); 214 215 // wait some time for the device to power up 216 snooze(USB_DELAY_DEVICE_POWER_UP); 217 218 // reset the port, this will also enable it 219 result = ResetPort(i); 220 if (result < B_OK) { 221 TRACE_ERROR(("USB Hub %d: resetting port %ld failed\n", DeviceAddress(), i)); 222 continue; 223 } 224 225 result = UpdatePortStatus(i); 226 if (result < B_OK) 227 continue; 228 229 if ((fPortStatus[i].status & PORT_STATUS_CONNECTION) == 0) { 230 // device has vanished after reset, ignore 231 TRACE(("USB Hub %d: device disappeared on reset\n", DeviceAddress())); 232 continue; 233 } 234 235 if (fChildren[i]) { 236 TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress())); 237 fChildren[i]->Changed(changeList, false); 238 fChildren[i] = NULL; 239 } 240 241 usb_speed speed = USB_SPEED_FULLSPEED; 242 if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) 243 speed = USB_SPEED_LOWSPEED; 244 if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED) 245 speed = USB_SPEED_HIGHSPEED; 246 247 // either let the device inherit our addresses (if we are 248 // already potentially using a transaction translator) or set 249 // ourselfs as the hub when we might become the transaction 250 // translator for the device. 251 int8 hubAddress = HubAddress(); 252 uint8 hubPort = HubPort(); 253 if (Speed() == USB_SPEED_HIGHSPEED) { 254 hubAddress = DeviceAddress(); 255 hubPort = i + 1; 256 } 257 258 Device *newDevice = GetBusManager()->AllocateDevice(this, 259 hubAddress, hubPort, speed); 260 261 if (newDevice) { 262 newDevice->Changed(changeList, true); 263 fChildren[i] = newDevice; 264 } else { 265 // the device failed to setup correctly, disable the port 266 // so that the device doesn't get in the way of future 267 // addressing. 268 DisablePort(i); 269 } 270 } else { 271 // Device removed... 272 TRACE(("USB Hub %d: device removed\n", DeviceAddress())); 273 if (fChildren[i]) { 274 TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); 275 fChildren[i]->Changed(changeList, false); 276 fChildren[i] = NULL; 277 } 278 } 279 } 280 281 // other port changes we do not really handle, report and clear them 282 if (fPortStatus[i].change & PORT_STATUS_ENABLE) { 283 TRACE_ERROR(("USB Hub %d: port %ld %sabled\n", DeviceAddress(), i, (fPortStatus[i].status & PORT_STATUS_ENABLE) ? "en" : "dis")); 284 DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 285 USB_REQUEST_CLEAR_FEATURE, C_PORT_ENABLE, i + 1, 286 0, NULL, 0, NULL); 287 } 288 289 if (fPortStatus[i].change & PORT_STATUS_SUSPEND) { 290 TRACE_ERROR(("USB Hub %d: port %ld is %ssuspended\n", DeviceAddress(), i, (fPortStatus[i].status & PORT_STATUS_SUSPEND) ? "" : "not ")); 291 DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 292 USB_REQUEST_CLEAR_FEATURE, C_PORT_SUSPEND, i + 1, 293 0, NULL, 0, NULL); 294 } 295 296 if (fPortStatus[i].change & PORT_STATUS_OVER_CURRENT) { 297 TRACE_ERROR(("USB Hub %d: port %ld is %sin an over current state\n", DeviceAddress(), i, (fPortStatus[i].status & PORT_STATUS_OVER_CURRENT) ? "" : "not ")); 298 DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 299 USB_REQUEST_CLEAR_FEATURE, C_PORT_OVER_CURRENT, i + 1, 300 0, NULL, 0, NULL); 301 } 302 303 if (fPortStatus[i].change & PORT_RESET) { 304 TRACE_ERROR(("USB Hub %d: port %ld was reset\n", DeviceAddress(), i)); 305 DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 306 USB_REQUEST_CLEAR_FEATURE, C_PORT_RESET, i + 1, 307 0, NULL, 0, NULL); 308 } 309 } 310 311 // explore down the tree if we have hubs connected 312 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 313 if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0) 314 continue; 315 316 ((Hub *)fChildren[i])->Explore(changeList); 317 } 318 } 319 320 321 void 322 Hub::InterruptCallback(void *cookie, status_t status, void *data, 323 size_t actualLength) 324 { 325 TRACE(("USB Hub %d: interrupt callback!\n", ((Hub *)data)->DeviceAddress())); 326 } 327 328 329 status_t 330 Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, 331 void *data, size_t dataLength, size_t *actualLength) 332 { 333 return DefaultPipe()->SendRequest( 334 USB_REQTYPE_DEVICE_IN | USB_REQTYPE_CLASS, // type 335 USB_REQUEST_GET_DESCRIPTOR, // request 336 (descriptorType << 8) | index, // value 337 languageID, // index 338 dataLength, // length 339 data, // buffer 340 dataLength, // buffer length 341 actualLength); // actual length 342 } 343 344 345 status_t 346 Hub::ReportDevice(usb_support_descriptor *supportDescriptors, 347 uint32 supportDescriptorCount, const usb_notify_hooks *hooks, 348 usb_driver_cookie **cookies, bool added, bool recursive) 349 { 350 TRACE(("USB Hub %d: reporting hub\n", DeviceAddress())); 351 352 // Report ourselfs first 353 status_t result = Device::ReportDevice(supportDescriptors, 354 supportDescriptorCount, hooks, cookies, added, recursive); 355 356 if (!recursive) 357 return result; 358 359 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 360 if (!fChildren[i]) 361 continue; 362 363 if (fChildren[i]->ReportDevice(supportDescriptors, 364 supportDescriptorCount, hooks, cookies, added, true) == B_OK) 365 result = B_OK; 366 } 367 368 return result; 369 } 370 371 372 status_t 373 Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize, 374 Device *device) 375 { 376 status_t result = Device::BuildDeviceName(string, index, bufferSize, device); 377 if (result < B_OK) { 378 // recursion to parent failed, we're at the root(hub) 379 int32 managerIndex = GetStack()->IndexOfBusManager(GetBusManager()); 380 *index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex); 381 } 382 383 if (!device) { 384 // no device was specified - report the hub 385 *index += snprintf(string + *index, bufferSize - *index, "/hub"); 386 } else { 387 // find out where the requested device sitts 388 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 389 if (fChildren[i] == device) { 390 *index += snprintf(string + *index, bufferSize - *index, "/%ld", i); 391 break; 392 } 393 } 394 } 395 396 return B_OK; 397 } 398