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