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