1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** \file 18 This file consists of implementation of class AndroidUsbPipeFileObject that 19 encapsulates a common extension for pipe file objects. 20 */ 21 #pragma data_seg() 22 #pragma code_seg() 23 24 #include "precomp.h" 25 #include "android_usb_pipe_file_object.h" 26 27 #pragma data_seg() 28 #pragma code_seg("PAGE") 29 30 AndroidUsbPipeFileObject::AndroidUsbPipeFileObject( 31 AndroidUsbDeviceObject* dev_obj, 32 WDFFILEOBJECT wdf_fo, 33 WDFUSBPIPE wdf_pipe_obj) 34 : AndroidUsbFileObject(AndroidUsbFileObjectTypePipe, dev_obj, wdf_fo), 35 wdf_pipe_(wdf_pipe_obj) { 36 ASSERT_IRQL_PASSIVE(); 37 ASSERT(NULL != wdf_pipe_obj); 38 } 39 40 #pragma code_seg() 41 42 AndroidUsbPipeFileObject::~AndroidUsbPipeFileObject() { 43 ASSERT_IRQL_LOW_OR_DISPATCH(); 44 } 45 46 #pragma code_seg("PAGE") 47 48 NTSTATUS AndroidUsbPipeFileObject::InitializePipe( 49 const WDF_USB_PIPE_INFORMATION* pipe_info) { 50 ASSERT_IRQL_LOW(); 51 ASSERT(IsPipeAttached()); 52 if (!IsPipeAttached()) 53 return STATUS_INTERNAL_ERROR; 54 55 // Initialize base class 56 NTSTATUS status = AndroidUsbFileObject::Initialize(); 57 ASSERT(NT_SUCCESS(status)); 58 if (!NT_SUCCESS(status)) 59 return status; 60 61 // Save pipe information 62 pipe_information_ = *pipe_info; 63 64 // We will provide size check ourselves (less surprizes always better) 65 WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(wdf_pipe()); 66 67 GoogleDbgPrint("\n===== File %p for %s pipe. max_transfer_size = %X, max_packet_size = %X", 68 this, is_input_pipe() ? "read" : "write", 69 max_transfer_size(), max_packet_size()); 70 return STATUS_SUCCESS; 71 } 72 73 #pragma code_seg() 74 75 void AndroidUsbPipeFileObject::OnEvtIoRead(WDFREQUEST request, 76 size_t length) { 77 ASSERT_IRQL_LOW_OR_DISPATCH(); 78 79 // Make sure that this is an input pipe 80 if (is_output_pipe()) { 81 GoogleDbgPrint("\n!!!! Attempt to read from output pipe %p", this); 82 WdfRequestComplete(request, STATUS_ACCESS_DENIED); 83 return; 84 } 85 86 // Make sure zero length I/O doesn't go through 87 if (0 == length) { 88 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); 89 return; 90 } 91 92 // Get MDL for this request. 93 PMDL request_mdl = NULL; 94 NTSTATUS status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl); 95 ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); 96 if (NT_SUCCESS(status)) { 97 CommonBulkReadWrite(request, 98 request_mdl, 99 static_cast<ULONG>(length), 100 true, 101 0, 102 false); 103 } else { 104 WdfRequestComplete(request, status); 105 } 106 } 107 108 void AndroidUsbPipeFileObject::OnEvtIoWrite(WDFREQUEST request, 109 size_t length) { 110 111 // Make sure that this is an output pipe 112 if (is_input_pipe()) { 113 GoogleDbgPrint("\n!!!! Attempt to write to input pipe %p", this); 114 WdfRequestComplete(request, STATUS_ACCESS_DENIED); 115 return; 116 } 117 118 // Make sure zero length I/O doesn't go through 119 if (0 == length) { 120 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); 121 return; 122 } 123 124 // Get MDL for this request. 125 PMDL request_mdl = NULL; 126 NTSTATUS status = WdfRequestRetrieveInputWdmMdl(request, &request_mdl); 127 ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); 128 if (NT_SUCCESS(status)) { 129 CommonBulkReadWrite(request, 130 request_mdl, 131 static_cast<ULONG>(length), 132 false, 133 0, 134 false); 135 } else { 136 WdfRequestComplete(request, status); 137 } 138 } 139 140 void AndroidUsbPipeFileObject::OnEvtIoDeviceControl(WDFREQUEST request, 141 size_t output_buf_len, 142 size_t input_buf_len, 143 ULONG ioctl_code) { 144 ASSERT_IRQL_LOW_OR_DISPATCH(); 145 146 switch (ioctl_code) { 147 case ADB_IOCTL_GET_ENDPOINT_INFORMATION: 148 OnCtlGetEndpointInformation(request, output_buf_len); 149 break; 150 151 case ADB_IOCTL_BULK_READ: 152 OnCtlBulkRead(request, output_buf_len, input_buf_len); 153 break; 154 155 case ADB_IOCTL_BULK_WRITE: 156 OnCtlBulkWrite(request, output_buf_len, input_buf_len); 157 break; 158 159 default: 160 AndroidUsbFileObject::OnEvtIoDeviceControl(request, 161 output_buf_len, 162 input_buf_len, 163 ioctl_code); 164 break; 165 } 166 } 167 168 void AndroidUsbPipeFileObject::OnCtlGetEndpointInformation( 169 WDFREQUEST request, 170 size_t output_buf_len) { 171 ASSERT_IRQL_LOW_OR_DISPATCH(); 172 173 // Verify output buffer 174 if (output_buf_len < sizeof(AdbEndpointInformation)) { 175 WdfRequestCompleteWithInformation(request, 176 STATUS_BUFFER_TOO_SMALL, 177 sizeof(AdbEndpointInformation)); 178 return; 179 } 180 181 // Get the output buffer 182 NTSTATUS status; 183 AdbEndpointInformation* ret_info = 184 reinterpret_cast<AdbEndpointInformation*>(OutAddress(request, &status)); 185 ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); 186 if (!NT_SUCCESS(status)) { 187 WdfRequestComplete(request, status); 188 return; 189 } 190 191 // Copy endpoint info to the output 192 ret_info->max_packet_size = pipe_information_.MaximumPacketSize; 193 ret_info->endpoint_address = pipe_information_.EndpointAddress; 194 ret_info->polling_interval = pipe_information_.Interval; 195 ret_info->setting_index = pipe_information_.SettingIndex; 196 ret_info->endpoint_type = 197 static_cast<AdbEndpointType>(pipe_information_.PipeType); 198 ret_info->max_transfer_size = pipe_information_.MaximumTransferSize; 199 200 WdfRequestCompleteWithInformation(request, 201 STATUS_SUCCESS, 202 sizeof(AdbEndpointInformation)); 203 } 204 205 void AndroidUsbPipeFileObject::OnCtlBulkRead(WDFREQUEST request, 206 size_t output_buf_len, 207 size_t input_buf_len) { 208 ASSERT_IRQL_LOW_OR_DISPATCH(); 209 210 // Make sure that this is an input pipe 211 if (is_output_pipe()) { 212 GoogleDbgPrint("\n!!!! Attempt to IOCTL read from output pipe %p", this); 213 WdfRequestComplete(request, STATUS_ACCESS_DENIED); 214 return; 215 } 216 217 // Make sure zero length I/O doesn't go through 218 if (0 == output_buf_len) { 219 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); 220 return; 221 } 222 223 // Verify buffers 224 ASSERT(input_buf_len >= sizeof(AdbBulkTransfer)); 225 if (input_buf_len < sizeof(AdbBulkTransfer)) { 226 WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); 227 return; 228 } 229 230 // Get the input buffer 231 NTSTATUS status; 232 AdbBulkTransfer* transfer_param = 233 reinterpret_cast<AdbBulkTransfer*>(InAddress(request, &status)); 234 ASSERT(NT_SUCCESS(status) && (NULL != transfer_param)); 235 if (!NT_SUCCESS(status)) { 236 WdfRequestComplete(request, status); 237 return; 238 } 239 240 // Get MDL for this request. 241 PMDL request_mdl = NULL; 242 status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl); 243 ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); 244 if (NT_SUCCESS(status)) { 245 // Perform the read 246 CommonBulkReadWrite(request, 247 request_mdl, 248 static_cast<ULONG>(output_buf_len), 249 true, 250 transfer_param->time_out, 251 true); 252 } else { 253 WdfRequestComplete(request, status); 254 } 255 } 256 257 void AndroidUsbPipeFileObject::OnCtlBulkWrite(WDFREQUEST request, 258 size_t output_buf_len, 259 size_t input_buf_len) { 260 ASSERT_IRQL_LOW_OR_DISPATCH(); 261 262 // Make sure that this is an output pipe 263 if (is_input_pipe()) { 264 GoogleDbgPrint("\n!!!! Attempt to IOCTL write to input pipe %p", this); 265 WdfRequestComplete(request, STATUS_ACCESS_DENIED); 266 return; 267 } 268 269 // Verify buffers 270 ASSERT(input_buf_len >= sizeof(AdbBulkTransfer)); 271 // Output buffer points to ULONG that receives number of transferred bytes 272 ASSERT(output_buf_len >= sizeof(ULONG)); 273 if ((input_buf_len < sizeof(AdbBulkTransfer)) || 274 (output_buf_len < sizeof(ULONG))) { 275 WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); 276 return; 277 } 278 279 // Get the input buffer 280 NTSTATUS status = STATUS_SUCCESS; 281 AdbBulkTransfer* transfer_param = 282 reinterpret_cast<AdbBulkTransfer*>(InAddress(request, &status)); 283 ASSERT(NT_SUCCESS(status) && (NULL != transfer_param)); 284 if (!NT_SUCCESS(status)) { 285 WdfRequestComplete(request, status); 286 return; 287 } 288 289 // Get the output buffer 290 ULONG* ret_transfer = 291 reinterpret_cast<ULONG*>(OutAddress(request, &status)); 292 ASSERT(NT_SUCCESS(status) && (NULL != ret_transfer)); 293 if (!NT_SUCCESS(status)) { 294 WdfRequestComplete(request, status); 295 return; 296 } 297 298 // Cache these param to prevent us from sudden change after we've chacked it. 299 // This is common practice in protecting ourselves from malicious code: 300 // 1. Never trust anything that comes from the User Mode. 301 // 2. Never assume that anything that User Mode buffer has will remain 302 // unchanged. 303 void* transfer_buffer = transfer_param->GetWriteBuffer(); 304 ULONG transfer_size = transfer_param->transfer_size; 305 306 // Make sure zero length I/O doesn't go through 307 if (0 == transfer_size) { 308 *ret_transfer = 0; 309 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, sizeof(ULONG)); 310 return; 311 } 312 313 // Make sure that buffer is not NULL 314 ASSERT(NULL != transfer_buffer); 315 if (NULL == transfer_buffer) { 316 WdfRequestComplete(request, STATUS_INVALID_PARAMETER); 317 return; 318 } 319 320 // At this point we are ready to build MDL for the user buffer. 321 PMDL write_mdl = 322 IoAllocateMdl(transfer_buffer, transfer_size, FALSE, FALSE, NULL); 323 ASSERT(NULL != write_mdl); 324 if (NULL == write_mdl) { 325 WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); 326 return; 327 } 328 329 // Now we need to probe/lock this mdl 330 __try { 331 MmProbeAndLockPages(write_mdl, 332 WdfRequestGetRequestorMode(request), 333 IoReadAccess); 334 status = STATUS_SUCCESS; 335 } __except (EXCEPTION_EXECUTE_HANDLER) { 336 status = GetExceptionCode(); 337 ASSERTMSG("\n!!!!! AndroidUsbPipeFileObject::OnCtlBulkWrite exception", 338 false); 339 } 340 341 if (!NT_SUCCESS(status)) { 342 IoFreeMdl(write_mdl); 343 WdfRequestComplete(request, status); 344 return; 345 } 346 347 // Perform the write 348 status = CommonBulkReadWrite(request, 349 write_mdl, 350 transfer_size, 351 false, 352 transfer_param->time_out, 353 true); 354 if (!NT_SUCCESS(status)) { 355 // If CommonBulkReadWrite failed we need to unlock and free MDL here 356 MmUnlockPages(write_mdl); 357 IoFreeMdl(write_mdl); 358 } 359 } 360 361 NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite( 362 WDFREQUEST request, 363 PMDL transfer_mdl, 364 ULONG length, 365 bool is_read, 366 ULONG time_out, 367 bool is_ioctl) { 368 ASSERT_IRQL_LOW_OR_DISPATCH(); 369 370 ASSERT(IsPipeAttached()); 371 if (!IsPipeAttached()) { 372 WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); 373 return STATUS_INVALID_DEVICE_STATE; 374 } 375 376 // Quick access check. Might be redundant though... 377 ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe())); 378 if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) { 379 WdfRequestComplete(request, STATUS_ACCESS_DENIED); 380 return STATUS_ACCESS_DENIED; 381 } 382 383 // Set URB flags 384 ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ? 385 USBD_TRANSFER_DIRECTION_IN : 386 USBD_TRANSFER_DIRECTION_OUT); 387 388 // Calculate transfer length for this stage. 389 ULONG stage_len = 390 (length > GetTransferGranularity()) ? GetTransferGranularity() : length; 391 392 // Get virtual address that we're gonna use in the transfer. 393 // We rely here on the fact that we're in the context of the calling thread. 394 void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl); 395 396 // Allocate our private MDL for this address which we will use for the transfer 397 PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL); 398 ASSERT(NULL != new_mdl); 399 if (NULL == new_mdl) { 400 WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); 401 return STATUS_INSUFFICIENT_RESOURCES; 402 } 403 404 // Map the portion of user buffer that we're going to transfer at this stage 405 // to our mdl. 406 IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len); 407 408 // Allocate memory for URB and associate it with this request 409 WDF_OBJECT_ATTRIBUTES mem_attrib; 410 WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib); 411 mem_attrib.ParentObject = request; 412 413 WDFMEMORY urb_mem = NULL; 414 PURB urb = NULL; 415 NTSTATUS status = 416 WdfMemoryCreate(&mem_attrib, 417 NonPagedPool, 418 GANDR_POOL_TAG_BULKRW_URB, 419 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 420 &urb_mem, 421 reinterpret_cast<PVOID*>(&urb)); 422 ASSERT(NT_SUCCESS(status) && (NULL != urb)); 423 if (!NT_SUCCESS(status)) { 424 IoFreeMdl(new_mdl); 425 WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); 426 return STATUS_INSUFFICIENT_RESOURCES; 427 } 428 429 // Get USB pipe handle for our pipe and initialize transfer request for it 430 USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe(); 431 ASSERT(NULL != usbd_pipe_hndl); 432 if (NULL == usbd_pipe_hndl) { 433 IoFreeMdl(new_mdl); 434 WdfRequestComplete(request, STATUS_INTERNAL_ERROR); 435 return STATUS_INTERNAL_ERROR; 436 } 437 438 // Initialize URB with request information 439 UsbBuildInterruptOrBulkTransferRequest( 440 urb, 441 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), 442 usbd_pipe_hndl, 443 NULL, 444 new_mdl, 445 stage_len, 446 urb_flags, 447 NULL); 448 449 // Build transfer request 450 status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), 451 request, 452 urb_mem, 453 NULL); 454 ASSERT(NT_SUCCESS(status)); 455 if (!NT_SUCCESS(status)) { 456 IoFreeMdl(new_mdl); 457 WdfRequestComplete(request, status); 458 return status; 459 } 460 461 // Initialize our request context. 462 AndroidUsbWdfRequestContext* context = 463 GetAndroidUsbWdfRequestContext(request); 464 ASSERT(NULL != context); 465 if (NULL == context) { 466 IoFreeMdl(new_mdl); 467 WdfRequestComplete(request, STATUS_INTERNAL_ERROR); 468 return STATUS_INTERNAL_ERROR; 469 } 470 471 context->object_type = AndroidUsbWdfObjectTypeRequest; 472 context->urb_mem = urb_mem; 473 context->transfer_mdl = transfer_mdl; 474 context->mdl = new_mdl; 475 context->length = length; 476 context->transfer_size = stage_len; 477 context->num_xfer = 0; 478 context->virtual_address = virtual_address; 479 context->is_read = is_read; 480 context->initial_time_out = time_out; 481 context->is_ioctl = is_ioctl; 482 483 // Set our completion routine 484 WdfRequestSetCompletionRoutine(request, 485 CommonReadWriteCompletionEntry, 486 this); 487 488 // Init send options (our timeout goes here) 489 WDF_REQUEST_SEND_OPTIONS send_options; 490 if (0 != time_out) { 491 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT); 492 WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out)); 493 } 494 495 // Timestamp first WdfRequestSend 496 KeQuerySystemTime(&context->sent_at); 497 498 // Send request asynchronously. 499 if (WdfRequestSend(request, wdf_pipe_io_target(), 500 (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) { 501 return STATUS_SUCCESS; 502 } 503 504 // Something went wrong here 505 status = WdfRequestGetStatus(request); 506 ASSERT(!NT_SUCCESS(status)); 507 GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X", 508 is_read, status); 509 WdfRequestCompleteWithInformation(request, status, 0); 510 511 return status; 512 } 513 514 void AndroidUsbPipeFileObject::OnCommonReadWriteCompletion( 515 WDFREQUEST request, 516 PWDF_REQUEST_COMPLETION_PARAMS completion_params, 517 AndroidUsbWdfRequestContext* context) { 518 ASSERT_IRQL_LOW_OR_DISPATCH(); 519 520 NTSTATUS status = completion_params->IoStatus.Status; 521 if (!NT_SUCCESS(status)){ 522 GoogleDbgPrint("\n========== Request completed with failure: %X", status); 523 IoFreeMdl(context->mdl); 524 // If this was IOCTL-originated write we must unlock and free 525 // our transfer MDL. 526 if (context->is_ioctl && !context->is_read) { 527 MmUnlockPages(context->transfer_mdl); 528 IoFreeMdl(context->transfer_mdl); 529 } 530 WdfRequestComplete(request, status); 531 return; 532 } 533 534 // Get our URB buffer 535 PURB urb 536 = reinterpret_cast<PURB>(WdfMemoryGetBuffer(context->urb_mem, NULL)); 537 ASSERT(NULL != urb); 538 539 // Lets see how much has been transfered and update our counters accordingly 540 ULONG bytes_transfered = 541 urb->UrbBulkOrInterruptTransfer.TransferBufferLength; 542 // We expect writes to transfer entire packet 543 ASSERT((bytes_transfered == context->transfer_size) || context->is_read); 544 context->num_xfer += bytes_transfered; 545 context->length -= bytes_transfered; 546 547 // Is there anything left to transfer? Now, by the protocol we should 548 // successfuly complete partial reads, instead of waiting on full set 549 // of requested bytes being accumulated in the read buffer. 550 if ((0 == context->length) || context->is_read) { 551 status = STATUS_SUCCESS; 552 553 // This was the last transfer 554 if (context->is_ioctl && !context->is_read) { 555 // For IOCTL-originated writes we have to return transfer size through 556 // the IOCTL's output buffer. 557 ULONG* ret_transfer = 558 reinterpret_cast<ULONG*>(OutAddress(request, NULL)); 559 ASSERT(NULL != ret_transfer); 560 if (NULL != ret_transfer) 561 *ret_transfer = context->num_xfer; 562 WdfRequestSetInformation(request, sizeof(ULONG)); 563 564 // We also must unlock / free transfer MDL 565 MmUnlockPages(context->transfer_mdl); 566 IoFreeMdl(context->transfer_mdl); 567 } else { 568 // For other requests we report transfer size through the request I/O 569 // completion status. 570 WdfRequestSetInformation(request, context->num_xfer); 571 } 572 IoFreeMdl(context->mdl); 573 WdfRequestComplete(request, status); 574 return; 575 } 576 577 // There are something left for the transfer. Prepare for it. 578 // Required to free any mapping made on the partial MDL and 579 // reset internal MDL state. 580 MmPrepareMdlForReuse(context->mdl); 581 582 // Update our virtual address 583 context->virtual_address = 584 reinterpret_cast<char*>(context->virtual_address) + bytes_transfered; 585 586 // Calculate size of this transfer 587 ULONG stage_len = 588 (context->length > GetTransferGranularity()) ? GetTransferGranularity() : 589 context->length; 590 591 IoBuildPartialMdl(context->transfer_mdl, 592 context->mdl, 593 context->virtual_address, 594 stage_len); 595 596 // Reinitialize the urb and context 597 urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stage_len; 598 context->transfer_size = stage_len; 599 600 // Format the request to send a URB to a USB pipe. 601 status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), 602 request, 603 context->urb_mem, 604 NULL); 605 ASSERT(NT_SUCCESS(status)); 606 if (!NT_SUCCESS(status)) { 607 if (context->is_ioctl && !context->is_read) { 608 MmUnlockPages(context->transfer_mdl); 609 IoFreeMdl(context->transfer_mdl); 610 } 611 IoFreeMdl(context->mdl); 612 WdfRequestComplete(request, status); 613 return; 614 } 615 616 // Reset the completion routine 617 WdfRequestSetCompletionRoutine(request, 618 CommonReadWriteCompletionEntry, 619 this); 620 621 // Send the request asynchronously. 622 if (!WdfRequestSend(request, wdf_pipe_io_target(), WDF_NO_SEND_OPTIONS)) { 623 if (context->is_ioctl && !context->is_read) { 624 MmUnlockPages(context->transfer_mdl); 625 IoFreeMdl(context->transfer_mdl); 626 } 627 status = WdfRequestGetStatus(request); 628 IoFreeMdl(context->mdl); 629 WdfRequestComplete(request, status); 630 } 631 } 632 633 NTSTATUS AndroidUsbPipeFileObject::ResetPipe() { 634 ASSERT_IRQL_PASSIVE(); 635 636 // This routine synchronously submits a URB_FUNCTION_RESET_PIPE 637 // request down the stack. 638 NTSTATUS status = WdfUsbTargetPipeAbortSynchronously(wdf_pipe(), 639 WDF_NO_HANDLE, 640 NULL); 641 if (NT_SUCCESS(status)) { 642 status = WdfUsbTargetPipeResetSynchronously(wdf_pipe(), 643 WDF_NO_HANDLE, 644 NULL); 645 if (!NT_SUCCESS(status)) 646 GoogleDbgPrint("\n!!!!! AndroidUsbPipeFileObject::ResetPipe failed %X", status); 647 } else { 648 GoogleDbgPrint("\n!!!!! WdfUsbTargetPipeAbortSynchronously failed %X", status); 649 } 650 651 return status; 652 } 653 654 NTSTATUS AndroidUsbPipeFileObject::QueueResetPipePassiveCallback() { 655 ASSERT_IRQL_LOW_OR_DISPATCH(); 656 657 // Initialize workitem 658 WDF_OBJECT_ATTRIBUTES attr; 659 WDF_OBJECT_ATTRIBUTES_INIT(&attr); 660 WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attr, AndroidUsbWorkitemContext); 661 attr.ParentObject = wdf_device(); 662 663 WDFWORKITEM wdf_work_item = NULL; 664 WDF_WORKITEM_CONFIG workitem_config; 665 WDF_WORKITEM_CONFIG_INIT(&workitem_config, ResetPipePassiveCallbackEntry); 666 NTSTATUS status = WdfWorkItemCreate(&workitem_config, 667 &attr, 668 &wdf_work_item); 669 ASSERT(NT_SUCCESS(status) && (NULL != wdf_work_item)); 670 if (!NT_SUCCESS(status)) 671 return status; 672 673 // Initialize our extension to work item 674 AndroidUsbWorkitemContext* context = 675 GetAndroidUsbWorkitemContext(wdf_work_item); 676 ASSERT(NULL != context); 677 if (NULL == context) { 678 WdfObjectDelete(wdf_work_item); 679 return STATUS_INTERNAL_ERROR; 680 } 681 682 context->object_type = AndroidUsbWdfObjectTypeWorkitem; 683 context->pipe_file_ext = this; 684 685 // Enqueue this work item. 686 WdfWorkItemEnqueue(wdf_work_item); 687 688 return STATUS_SUCCESS; 689 } 690 691 void AndroidUsbPipeFileObject::CommonReadWriteCompletionEntry( 692 WDFREQUEST request, 693 WDFIOTARGET wdf_target, 694 PWDF_REQUEST_COMPLETION_PARAMS completion_params, 695 WDFCONTEXT completion_context) { 696 ASSERT_IRQL_LOW_OR_DISPATCH(); 697 698 AndroidUsbWdfRequestContext* 699 context = GetAndroidUsbWdfRequestContext(request); 700 ASSERT((NULL != context) && (AndroidUsbWdfObjectTypeRequest == context->object_type)); 701 702 AndroidUsbPipeFileObject* pipe_file_ext = 703 reinterpret_cast<AndroidUsbPipeFileObject*>(completion_context); 704 ASSERT((NULL != pipe_file_ext) && 705 (pipe_file_ext->wdf_pipe() == (WDFUSBPIPE)wdf_target)); 706 707 pipe_file_ext->OnCommonReadWriteCompletion(request, 708 completion_params, 709 context); 710 } 711 712 void AndroidUsbPipeFileObject::ResetPipePassiveCallbackEntry( 713 WDFWORKITEM wdf_work_item) { 714 ASSERT_IRQL_PASSIVE(); 715 716 AndroidUsbWorkitemContext* context = 717 GetAndroidUsbWorkitemContext(wdf_work_item); 718 ASSERT((NULL != context) && 719 (AndroidUsbWdfObjectTypeWorkitem == context->object_type)); 720 if ((NULL == context) || 721 (AndroidUsbWdfObjectTypeWorkitem != context->object_type)) { 722 WdfObjectDelete(wdf_work_item); 723 return; 724 } 725 726 // In the sample they reset the device if pipe reset failed 727 AndroidUsbDeviceObject* wdf_device_ext = 728 context->pipe_file_ext->device_object(); 729 730 NTSTATUS status = context->pipe_file_ext->ResetPipe(); 731 if (!NT_SUCCESS(status)) 732 status = wdf_device_ext->ResetDevice(); 733 734 WdfObjectDelete(wdf_work_item); 735 } 736 737 #pragma data_seg() 738 #pragma code_seg() 739