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(BusManager *bus, Device *parent, usb_device_descriptor &desc, 15 int8 deviceAddress, bool lowSpeed) 16 : Device(bus, parent, desc, deviceAddress, lowSpeed) 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 = 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 = 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 = 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 = 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 if (DeviceAddress() > 1) 159 TRACE(("USB Hub (%d): port %d: status: 0x%04x; change: 0x%04x\n", DeviceAddress(), i, fPortStatus[i].status, fPortStatus[i].change)); 160 161 if (fPortStatus[i].change & PORT_STATUS_CONNECTION) { 162 if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { 163 // new device attached! 164 TRACE(("USB Hub: Explore(): New device connected\n")); 165 166 // wait some time for the device to power up 167 snooze(USB_DELAY_DEVICE_POWER_UP); 168 169 // reset the port, this will also enable it 170 result = ResetPort(i); 171 if (result < B_OK) 172 continue; 173 174 result = UpdatePortStatus(i); 175 if (result < B_OK) 176 continue; 177 178 if ((fPortStatus[i].status & PORT_STATUS_CONNECTION) == 0) { 179 // device has vanished after reset, ignore 180 continue; 181 } 182 183 Device *newDevice = fBus->AllocateNewDevice(this, 184 (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) > 0); 185 186 if (newDevice) { 187 fChildren[i] = newDevice; 188 GetStack()->NotifyDeviceChange(fChildren[i], true); 189 } else { 190 // the device failed to setup correctly, disable the port 191 // so that the device doesn't get in the way of future 192 // addressing. 193 SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 194 USB_REQUEST_CLEAR_FEATURE, PORT_ENABLE, i + 1, 195 0, NULL, 0, NULL); 196 } 197 } else { 198 // Device removed... 199 TRACE(("USB Hub Explore(): Device removed\n")); 200 if (fChildren[i]) { 201 GetStack()->NotifyDeviceChange(fChildren[i], false); 202 GetStack()->PutUSBID(fChildren[i]->USBID()); 203 delete fChildren[i]; 204 fChildren[i] = NULL; 205 } 206 } 207 208 // clear status change 209 SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_OUT, 210 USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1, 211 0, NULL, 0, NULL); 212 } 213 } 214 215 // explore down the tree if we have hubs connected 216 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 217 if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0) 218 continue; 219 220 ((Hub *)fChildren[i])->Explore(); 221 } 222 } 223 224 225 void 226 Hub::InterruptCallback(void *cookie, uint32 status, void *data, 227 uint32 actualLength) 228 { 229 TRACE(("USB Hub: interrupt callback!\n")); 230 } 231 232 233 status_t 234 Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, 235 void *data, size_t dataLength, size_t *actualLength) 236 { 237 return SendRequest( 238 USB_REQTYPE_DEVICE_IN | USB_REQTYPE_CLASS, // type 239 USB_REQUEST_GET_DESCRIPTOR, // request 240 (descriptorType << 8) | index, // value 241 languageID, // index 242 dataLength, // length 243 data, // buffer 244 dataLength, // buffer length 245 actualLength); // actual length 246 } 247 248 249 void 250 Hub::ReportDevice(usb_support_descriptor *supportDescriptors, 251 uint32 supportDescriptorCount, const usb_notify_hooks *hooks, bool added) 252 { 253 TRACE(("USB Hub ReportDevice\n")); 254 255 // Report ourselfs first 256 Device::ReportDevice(supportDescriptors, supportDescriptorCount, hooks, added); 257 258 // Then report all of our children 259 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 260 if (!fChildren[i]) 261 continue; 262 263 fChildren[i]->ReportDevice(supportDescriptors, 264 supportDescriptorCount, hooks, added); 265 } 266 } 267 268 269 status_t 270 Hub::BuildDeviceName(char *string, uint32 *index, size_t bufferSize, 271 Device *device) 272 { 273 status_t result = Device::BuildDeviceName(string, index, bufferSize, device); 274 if (result < B_OK) { 275 // recursion to parent failed, we're at the root(hub) 276 int32 managerIndex = GetStack()->IndexOfBusManager(Manager()); 277 *index += snprintf(string + *index, bufferSize - *index, "%ld", managerIndex); 278 } 279 280 if (!device) { 281 // no device was specified - report the hub 282 *index += snprintf(string + *index, bufferSize - *index, "/hub"); 283 } else { 284 // find out where the requested device sitts 285 for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { 286 if (fChildren[i] == device) { 287 *index += snprintf(string + *index, bufferSize - *index, "/%ld", i); 288 break; 289 } 290 } 291 } 292 293 return B_OK; 294 } 295