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 // some devices have bogus descriptors 190 if (speed == USB_SPEED_HIGHSPEED && maxPacketSize != 512) 191 maxPacketSize = 512; 192 193 Pipe::InitCommon(deviceAddress, endpointAddress, speed, direction, 194 maxPacketSize, interval, hubAddress, hubPort); 195 } 196 197 198 status_t 199 BulkPipe::QueueBulk(void *data, size_t dataLength, usb_callback_func callback, 200 void *callbackCookie) 201 { 202 if (dataLength > 0 && data == NULL) 203 return B_BAD_VALUE; 204 205 Transfer *transfer = new(std::nothrow) Transfer(this); 206 if (!transfer) 207 return B_NO_MEMORY; 208 209 transfer->SetData((uint8 *)data, dataLength); 210 transfer->SetCallback(callback, callbackCookie); 211 212 status_t result = GetBusManager()->SubmitTransfer(transfer); 213 if (result < B_OK) 214 delete transfer; 215 return result; 216 } 217 218 219 status_t 220 BulkPipe::QueueBulkV(iovec *vector, size_t vectorCount, 221 usb_callback_func callback, void *callbackCookie, bool physical) 222 { 223 if (vectorCount > 0 && vector == NULL) 224 return B_BAD_VALUE; 225 226 Transfer *transfer = new(std::nothrow) Transfer(this); 227 if (!transfer) 228 return B_NO_MEMORY; 229 230 transfer->SetPhysical(physical); 231 transfer->SetVector(vector, vectorCount); 232 transfer->SetCallback(callback, callbackCookie); 233 234 status_t result = GetBusManager()->SubmitTransfer(transfer); 235 if (result < B_OK) 236 delete transfer; 237 return result; 238 } 239 240 241 // 242 // #pragma mark - 243 // 244 245 246 IsochronousPipe::IsochronousPipe(Object *parent) 247 : Pipe(parent), 248 fMaxQueuedPackets(0), 249 fMaxBufferDuration(0), 250 fSampleSize(0) 251 { 252 } 253 254 255 status_t 256 IsochronousPipe::QueueIsochronous(void *data, size_t dataLength, 257 usb_iso_packet_descriptor *packetDesc, uint32 packetCount, 258 uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, 259 void *callbackCookie) 260 { 261 if ((dataLength > 0 && data == NULL) 262 || (packetCount > 0 && packetDesc == NULL)) 263 return B_BAD_VALUE; 264 265 usb_isochronous_data *isochronousData 266 = new(std::nothrow) usb_isochronous_data; 267 268 if (!isochronousData) 269 return B_NO_MEMORY; 270 271 isochronousData->packet_descriptors = packetDesc; 272 isochronousData->packet_count = packetCount; 273 isochronousData->starting_frame_number = startingFrameNumber; 274 isochronousData->flags = flags; 275 276 Transfer *transfer = new(std::nothrow) Transfer(this); 277 if (!transfer) { 278 delete isochronousData; 279 return B_NO_MEMORY; 280 } 281 282 transfer->SetData((uint8 *)data, dataLength); 283 transfer->SetCallback(callback, callbackCookie); 284 transfer->SetIsochronousData(isochronousData); 285 286 status_t result = GetBusManager()->SubmitTransfer(transfer); 287 if (result < B_OK) 288 delete transfer; 289 return result; 290 } 291 292 293 status_t 294 IsochronousPipe::SetPipePolicy(uint8 maxQueuedPackets, 295 uint16 maxBufferDurationMS, uint16 sampleSize) 296 { 297 if (maxQueuedPackets == fMaxQueuedPackets 298 || maxBufferDurationMS == fMaxBufferDuration 299 || sampleSize == fSampleSize) 300 return B_OK; 301 302 fMaxQueuedPackets = maxQueuedPackets; 303 fMaxBufferDuration = maxBufferDurationMS; 304 fSampleSize = sampleSize; 305 306 GetBusManager()->NotifyPipeChange(this, USB_CHANGE_PIPE_POLICY_CHANGED); 307 return B_OK; 308 } 309 310 311 status_t 312 IsochronousPipe::GetPipePolicy(uint8 *maxQueuedPackets, 313 uint16 *maxBufferDurationMS, uint16 *sampleSize) 314 { 315 if (maxQueuedPackets) 316 *maxQueuedPackets = fMaxQueuedPackets; 317 if (maxBufferDurationMS) 318 *maxBufferDurationMS = fMaxBufferDuration; 319 if (sampleSize) 320 *sampleSize = fSampleSize; 321 return B_OK; 322 } 323 324 325 // 326 // #pragma mark - 327 // 328 329 330 ControlPipe::ControlPipe(Object *parent) 331 : Pipe(parent), 332 fNotifySem(-1) 333 { 334 mutex_init(&fSendRequestLock, "control pipe send request"); 335 } 336 337 338 ControlPipe::~ControlPipe() 339 { 340 // We do this here in case a submitted request is still running. 341 PutUSBID(false); 342 ControlPipe::CancelQueuedTransfers(true); 343 WaitForUnbusy(); 344 345 if (fNotifySem >= 0) 346 delete_sem(fNotifySem); 347 mutex_lock(&fSendRequestLock); 348 mutex_destroy(&fSendRequestLock); 349 } 350 351 352 void 353 ControlPipe::InitCommon(int8 deviceAddress, uint8 endpointAddress, 354 usb_speed speed, pipeDirection direction, size_t maxPacketSize, 355 uint8 interval, int8 hubAddress, uint8 hubPort) 356 { 357 // The USB 2.0 spec section 5.5.3 gives fixed max packet sizes for the 358 // different speeds. The USB 3.1 specs defines the max packet size to a 359 // fixed 512 for control endpoints in 9.6.6. Some devices ignore these 360 // values and use bogus ones, so we restrict them here. 361 switch (speed) { 362 case USB_SPEED_LOWSPEED: 363 maxPacketSize = 8; 364 break; 365 case USB_SPEED_HIGHSPEED: 366 maxPacketSize = 64; 367 break; 368 case USB_SPEED_SUPERSPEED: 369 maxPacketSize = 512; 370 break; 371 372 default: 373 break; 374 } 375 376 Pipe::InitCommon(deviceAddress, endpointAddress, speed, direction, 377 maxPacketSize, interval, hubAddress, hubPort); 378 } 379 380 381 status_t 382 ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, 383 uint16 index, uint16 length, void *data, size_t dataLength, 384 size_t *actualLength) 385 { 386 status_t result = mutex_lock(&fSendRequestLock); 387 if (result != B_OK) 388 return result; 389 390 if (fNotifySem < 0) { 391 fNotifySem = create_sem(0, "usb send request notify"); 392 if (fNotifySem < 0) { 393 mutex_unlock(&fSendRequestLock); 394 return B_NO_MORE_SEMS; 395 } 396 } 397 398 result = QueueRequest(requestType, request, value, index, length, data, 399 dataLength, SendRequestCallback, this); 400 if (result < B_OK) { 401 mutex_unlock(&fSendRequestLock); 402 return result; 403 } 404 405 // The sem will be released unconditionally in the callback after the 406 // result data was filled in. Use a 2 seconds timeout for control transfers. 407 if (acquire_sem_etc(fNotifySem, 1, B_RELATIVE_TIMEOUT, 2000000) < B_OK) { 408 TRACE_ERROR("timeout waiting for queued request to complete\n"); 409 410 CancelQueuedTransfers(false); 411 412 // After the above cancel returns it is guaranteed that the callback 413 // has been invoked. Therefore we can simply grab that released 414 // semaphore again to clean up. 415 acquire_sem_etc(fNotifySem, 1, B_RELATIVE_TIMEOUT, 0); 416 417 if (actualLength) 418 *actualLength = 0; 419 420 mutex_unlock(&fSendRequestLock); 421 return B_TIMED_OUT; 422 } 423 424 if (actualLength) 425 *actualLength = fActualLength; 426 427 mutex_unlock(&fSendRequestLock); 428 return fTransferStatus; 429 } 430 431 432 void 433 ControlPipe::SendRequestCallback(void *cookie, status_t status, void *data, 434 size_t actualLength) 435 { 436 ControlPipe *pipe = (ControlPipe *)cookie; 437 pipe->fTransferStatus = status; 438 pipe->fActualLength = actualLength; 439 release_sem(pipe->fNotifySem); 440 } 441 442 443 status_t 444 ControlPipe::QueueRequest(uint8 requestType, uint8 request, uint16 value, 445 uint16 index, uint16 length, void *data, size_t dataLength, 446 usb_callback_func callback, void *callbackCookie) 447 { 448 if (dataLength > 0 && data == NULL) 449 return B_BAD_VALUE; 450 451 if (USBID() == UINT32_MAX) 452 return B_NO_INIT; 453 454 usb_request_data *requestData = new(std::nothrow) usb_request_data; 455 if (!requestData) 456 return B_NO_MEMORY; 457 458 requestData->RequestType = requestType; 459 requestData->Request = request; 460 requestData->Value = value; 461 requestData->Index = index; 462 requestData->Length = length; 463 464 Transfer *transfer = new(std::nothrow) Transfer(this); 465 if (!transfer) { 466 delete requestData; 467 return B_NO_MEMORY; 468 } 469 470 transfer->SetRequestData(requestData); 471 transfer->SetData((uint8 *)data, dataLength); 472 transfer->SetCallback(callback, callbackCookie); 473 474 status_t result = GetBusManager()->SubmitTransfer(transfer); 475 if (result < B_OK) 476 delete transfer; 477 return result; 478 } 479 480 481 status_t 482 ControlPipe::CancelQueuedTransfers(bool force) 483 { 484 if (force && fNotifySem >= 0) { 485 // There is likely a transfer currently running; we need to cancel it 486 // manually, as callbacks are not invoked when force-cancelling. 487 fTransferStatus = B_CANCELED; 488 fActualLength = 0; 489 release_sem_etc(fNotifySem, 1, B_RELEASE_IF_WAITING_ONLY); 490 } 491 492 return Pipe::CancelQueuedTransfers(force); 493 } 494