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