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