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