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