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