1 /* 2 * Copyright 2004-2020, 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_private.h" 11 12 13 Pipe::Pipe(Object *parent) 14 : Object(parent), 15 fDataToggle(false), 16 fControllerCookie(NULL) 17 { 18 // all other init is to be done in InitCommon() 19 } 20 21 22 Pipe::~Pipe() 23 { 24 PutUSBID(); 25 26 CancelQueuedTransfers(true); 27 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); 28 } 29 30 31 void 32 Pipe::InitCommon(int8 deviceAddress, uint8 endpointAddress, usb_speed speed, 33 pipeDirection direction, size_t maxPacketSize, uint8 interval, 34 int8 hubAddress, uint8 hubPort) 35 { 36 fDeviceAddress = deviceAddress; 37 fEndpointAddress = endpointAddress; 38 fSpeed = speed; 39 fDirection = direction; 40 fMaxPacketSize = maxPacketSize; 41 fInterval = interval; 42 fHubAddress = hubAddress; 43 fHubPort = hubPort; 44 45 fMaxBurst = 0; 46 fBytesPerInterval = 0; 47 48 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_CREATED); 49 } 50 51 52 void 53 Pipe::InitSuperSpeed(uint8 maxBurst, uint16 bytesPerInterval) 54 { 55 fMaxBurst = maxBurst; 56 fBytesPerInterval = bytesPerInterval; 57 } 58 59 60 void 61 Pipe::SetHubInfo(int8 address, uint8 port) 62 { 63 fHubAddress = address; 64 fHubPort = port; 65 } 66 67 68 status_t 69 Pipe::SubmitTransfer(Transfer *transfer) 70 { 71 // ToDo: keep track of all submited transfers to be able to cancel them 72 return GetBusManager()->SubmitTransfer(transfer); 73 } 74 75 76 status_t 77 Pipe::CancelQueuedTransfers(bool force) 78 { 79 return GetBusManager()->CancelQueuedTransfers(this, force); 80 } 81 82 83 status_t 84 Pipe::SetFeature(uint16 selector) 85 { 86 TRACE("set feature %u\n", selector); 87 Device *device = (Device *)Parent(); 88 if (device->InitCheck() != B_OK) 89 return B_NO_INIT; 90 91 return device->DefaultPipe()->SendRequest( 92 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 93 USB_REQUEST_SET_FEATURE, 94 selector, 95 fEndpointAddress | (fDirection == In ? USB_ENDPOINT_ADDR_DIR_IN 96 : USB_ENDPOINT_ADDR_DIR_OUT), 97 0, 98 NULL, 99 0, 100 NULL); 101 } 102 103 104 status_t 105 Pipe::ClearFeature(uint16 selector) 106 { 107 Device *device = (Device *)Parent(); 108 if (device->InitCheck() != B_OK) 109 return B_NO_INIT; 110 111 // clearing a stalled condition resets the data toggle 112 if (selector == USB_FEATURE_ENDPOINT_HALT) 113 SetDataToggle(false); 114 115 TRACE("clear feature %u\n", selector); 116 return device->DefaultPipe()->SendRequest( 117 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 118 USB_REQUEST_CLEAR_FEATURE, 119 selector, 120 fEndpointAddress | (fDirection == In ? USB_ENDPOINT_ADDR_DIR_IN 121 : USB_ENDPOINT_ADDR_DIR_OUT), 122 0, 123 NULL, 124 0, 125 NULL); 126 } 127 128 129 status_t 130 Pipe::GetStatus(uint16 *status) 131 { 132 TRACE("get status\n"); 133 Device *device = (Device *)Parent(); 134 if (device->InitCheck() != B_OK) 135 return B_NO_INIT; 136 137 return device->DefaultPipe()->SendRequest( 138 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_IN, 139 USB_REQUEST_GET_STATUS, 140 0, 141 fEndpointAddress | (fDirection == In ? USB_ENDPOINT_ADDR_DIR_IN 142 : USB_ENDPOINT_ADDR_DIR_OUT), 143 2, 144 (void *)status, 145 2, 146 NULL); 147 } 148 149 150 // 151 // #pragma mark - 152 // 153 154 155 InterruptPipe::InterruptPipe(Object *parent) 156 : Pipe(parent) 157 { 158 } 159 160 161 status_t 162 InterruptPipe::QueueInterrupt(void *data, size_t dataLength, 163 usb_callback_func callback, void *callbackCookie) 164 { 165 if (dataLength > 0 && data == NULL) 166 return B_BAD_VALUE; 167 168 Transfer *transfer = new(std::nothrow) Transfer(this); 169 if (!transfer) 170 return B_NO_MEMORY; 171 172 transfer->SetData((uint8 *)data, dataLength); 173 transfer->SetCallback(callback, callbackCookie); 174 175 status_t result = GetBusManager()->SubmitTransfer(transfer); 176 if (result < B_OK) 177 delete transfer; 178 return result; 179 } 180 181 182 // 183 // #pragma mark - 184 // 185 186 187 BulkPipe::BulkPipe(Object *parent) 188 : Pipe(parent) 189 { 190 } 191 192 193 void 194 BulkPipe::InitCommon(int8 deviceAddress, uint8 endpointAddress, 195 usb_speed speed, pipeDirection direction, size_t maxPacketSize, 196 uint8 interval, int8 hubAddress, uint8 hubPort) 197 { 198 // some devices have bogus descriptors 199 if (speed == USB_SPEED_HIGHSPEED && maxPacketSize != 512) 200 maxPacketSize = 512; 201 202 Pipe::InitCommon(deviceAddress, endpointAddress, speed, direction, 203 maxPacketSize, interval, hubAddress, hubPort); 204 } 205 206 207 status_t 208 BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, 209 void *callbackCookie) 210 { 211 if (dataLength > 0 && data == NULL) 212 return B_BAD_VALUE; 213 214 Transfer *transfer = new(std::nothrow) Transfer(this); 215 if (!transfer) 216 return B_NO_MEMORY; 217 218 transfer->SetData((uint8 *)data, dataLength); 219 transfer->SetCallback(callback, callbackCookie); 220 221 status_t result = GetBusManager()->SubmitTransfer(transfer); 222 if (result < B_OK) 223 delete transfer; 224 return result; 225 } 226 227 228 status_t 229 BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, 230 usb_callback_func callback, void *callbackCookie, bool physical) 231 { 232 if (vectorCount > 0 && vector == NULL) 233 return B_BAD_VALUE; 234 235 Transfer *transfer = new(std::nothrow) Transfer(this); 236 if (!transfer) 237 return B_NO_MEMORY; 238 239 transfer->SetPhysical(physical); 240 transfer->SetVector(vector, vectorCount); 241 transfer->SetCallback(callback, callbackCookie); 242 243 status_t result = GetBusManager()->SubmitTransfer(transfer); 244 if (result < B_OK) 245 delete transfer; 246 return result; 247 } 248 249 250 // 251 // #pragma mark - 252 // 253 254 255 IsochronousPipe::IsochronousPipe(Object *parent) 256 : Pipe(parent), 257 fMaxQueuedPackets(0), 258 fMaxBufferDuration(0), 259 fSampleSize(0) 260 { 261 } 262 263 264 status_t 265 IsochronousPipe::QueueIsochronous(void *data, size_t dataLength, 266 usb_iso_packet_descriptor *packetDesc, uint32 packetCount, 267 uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, 268 void *callbackCookie) 269 { 270 if ((dataLength > 0 && data == NULL) 271 || (packetCount > 0 && packetDesc == NULL)) 272 return B_BAD_VALUE; 273 274 usb_isochronous_data *isochronousData 275 = new(std::nothrow) usb_isochronous_data; 276 277 if (!isochronousData) 278 return B_NO_MEMORY; 279 280 isochronousData->packet_descriptors = packetDesc; 281 isochronousData->packet_count = packetCount; 282 isochronousData->starting_frame_number = startingFrameNumber; 283 isochronousData->flags = flags; 284 285 Transfer *transfer = new(std::nothrow) Transfer(this); 286 if (!transfer) { 287 delete isochronousData; 288 return B_NO_MEMORY; 289 } 290 291 transfer->SetData((uint8 *)data, dataLength); 292 transfer->SetCallback(callback, callbackCookie); 293 transfer->SetIsochronousData(isochronousData); 294 295 status_t result = GetBusManager()->SubmitTransfer(transfer); 296 if (result < B_OK) 297 delete transfer; 298 return result; 299 } 300 301 302 status_t 303 IsochronousPipe::SetPipePolicy(uint8 maxQueuedPackets, 304 uint16 maxBufferDurationMS, uint16 sampleSize) 305 { 306 if (maxQueuedPackets == fMaxQueuedPackets 307 || maxBufferDurationMS == fMaxBufferDuration 308 || sampleSize == fSampleSize) 309 return B_OK; 310 311 fMaxQueuedPackets = maxQueuedPackets; 312 fMaxBufferDuration = maxBufferDurationMS; 313 fSampleSize = sampleSize; 314 315 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_PIPE_POLICY_CHANGED); 316 return B_OK; 317 } 318 319 320 status_t 321 IsochronousPipe::GetPipePolicy(uint8 *maxQueuedPackets, 322 uint16 *maxBufferDurationMS, uint16 *sampleSize) 323 { 324 if (maxQueuedPackets) 325 *maxQueuedPackets = fMaxQueuedPackets; 326 if (maxBufferDurationMS) 327 *maxBufferDurationMS = fMaxBufferDuration; 328 if (sampleSize) 329 *sampleSize = fSampleSize; 330 return B_OK; 331 } 332 333 334 // 335 // #pragma mark - 336 // 337 338 339 ControlPipe::ControlPipe(Object *parent) 340 : Pipe(parent), 341 fNotifySem(-1) 342 { 343 mutex_init(&fSendRequestLock, "control pipe send request"); 344 } 345 346 347 ControlPipe::~ControlPipe() 348 { 349 if (fNotifySem >= 0) 350 delete_sem(fNotifySem); 351 mutex_lock(&fSendRequestLock); 352 mutex_destroy(&fSendRequestLock); 353 } 354 355 356 void 357 ControlPipe::InitCommon(int8 deviceAddress, uint8 endpointAddress, 358 usb_speed speed, pipeDirection direction, size_t maxPacketSize, 359 uint8 interval, int8 hubAddress, uint8 hubPort) 360 { 361 // The USB 2.0 spec section 5.5.3 gives fixed max packet sizes for the 362 // different speeds. The USB 3.1 specs defines the max packet size to a 363 // fixed 512 for control endpoints in 9.6.6. Some devices ignore these 364 // values and use bogus ones, so we restrict them here. 365 switch (speed) { 366 case USB_SPEED_LOWSPEED: 367 maxPacketSize = 8; 368 break; 369 case USB_SPEED_HIGHSPEED: 370 maxPacketSize = 64; 371 break; 372 case USB_SPEED_SUPERSPEED: 373 maxPacketSize = 512; 374 break; 375 376 default: 377 break; 378 } 379 380 Pipe::InitCommon(deviceAddress, endpointAddress, speed, direction, 381 maxPacketSize, interval, hubAddress, hubPort); 382 } 383 384 385 status_t 386 ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, 387 uint16 index, uint16 length, void *data, size_t dataLength, 388 size_t *actualLength) 389 { 390 status_t result = mutex_lock(&fSendRequestLock); 391 if (result != B_OK) 392 return result; 393 394 if (fNotifySem < 0) { 395 fNotifySem = create_sem(0, "usb send request notify"); 396 if (fNotifySem < 0) { 397 mutex_unlock(&fSendRequestLock); 398 return B_NO_MORE_SEMS; 399 } 400 } 401 402 result = QueueRequest(requestType, request, value, index, length, data, 403 dataLength, SendRequestCallback, this); 404 if (result < B_OK) { 405 mutex_unlock(&fSendRequestLock); 406 return result; 407 } 408 409 // The sem will be released unconditionally in the callback after the 410 // result data was filled in. Use a 2 seconds timeout for control transfers. 411 if (acquire_sem_etc(fNotifySem, 1, B_RELATIVE_TIMEOUT, 2000000) < B_OK) { 412 TRACE_ERROR("timeout waiting for queued request to complete\n"); 413 414 CancelQueuedTransfers(false); 415 416 // After the above cancel returns it is guaranteed that the callback 417 // has been invoked. Therefore we can simply grab that released 418 // semaphore again to clean up. 419 acquire_sem_etc(fNotifySem, 1, B_RELATIVE_TIMEOUT, 0); 420 421 if (actualLength) 422 *actualLength = 0; 423 424 mutex_unlock(&fSendRequestLock); 425 return B_TIMED_OUT; 426 } 427 428 if (actualLength) 429 *actualLength = fActualLength; 430 431 mutex_unlock(&fSendRequestLock); 432 return fTransferStatus; 433 } 434 435 436 void 437 ControlPipe::SendRequestCallback(void *cookie, status_t status, void *data, 438 size_t actualLength) 439 { 440 ControlPipe *pipe = (ControlPipe *)cookie; 441 pipe->fTransferStatus = status; 442 pipe->fActualLength = actualLength; 443 release_sem(pipe->fNotifySem); 444 } 445 446 447 status_t 448 ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 449 uint16 index, uint16 length, void *data, size_t dataLength, 450 usb_callback_func callback, void *callbackCookie) 451 { 452 if (dataLength > 0 && data == NULL) 453 return B_BAD_VALUE; 454 455 usb_request_data *requestData = new(std::nothrow) usb_request_data; 456 if (!requestData) 457 return B_NO_MEMORY; 458 459 requestData->RequestType = requestType; 460 requestData->Request = request; 461 requestData->Value = value; 462 requestData->Index = index; 463 requestData->Length = length; 464 465 Transfer *transfer = new(std::nothrow) Transfer(this); 466 if (!transfer) { 467 delete requestData; 468 return B_NO_MEMORY; 469 } 470 471 transfer->SetRequestData(requestData); 472 transfer->SetData((uint8 *)data, dataLength); 473 transfer->SetCallback(callback, callbackCookie); 474 475 status_t result = GetBusManager()->SubmitTransfer(transfer); 476 if (result < B_OK) 477 delete transfer; 478 return result; 479 } 480