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
AndroidUsbPipeFileObject(AndroidUsbDeviceObject * dev_obj,WDFFILEOBJECT wdf_fo,WDFUSBPIPE wdf_pipe_obj)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
~AndroidUsbPipeFileObject()42 AndroidUsbPipeFileObject::~AndroidUsbPipeFileObject() {
43 ASSERT_IRQL_LOW_OR_DISPATCH();
44 }
45
46 #pragma code_seg("PAGE")
47
InitializePipe(const WDF_USB_PIPE_INFORMATION * pipe_info)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
OnEvtIoRead(WDFREQUEST request,size_t length)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
OnEvtIoWrite(WDFREQUEST request,size_t length)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
OnEvtIoDeviceControl(WDFREQUEST request,size_t output_buf_len,size_t input_buf_len,ULONG ioctl_code)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
OnCtlGetEndpointInformation(WDFREQUEST request,size_t output_buf_len)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
OnCtlBulkRead(WDFREQUEST request,size_t output_buf_len,size_t input_buf_len)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
OnCtlBulkWrite(WDFREQUEST request,size_t output_buf_len,size_t input_buf_len)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
CommonBulkReadWrite(WDFREQUEST request,PMDL transfer_mdl,ULONG length,bool is_read,ULONG time_out,bool is_ioctl)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
OnCommonReadWriteCompletion(WDFREQUEST request,PWDF_REQUEST_COMPLETION_PARAMS completion_params,AndroidUsbWdfRequestContext * context)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
ResetPipe()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
QueueResetPipePassiveCallback()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
CommonReadWriteCompletionEntry(WDFREQUEST request,WDFIOTARGET wdf_target,PWDF_REQUEST_COMPLETION_PARAMS completion_params,WDFCONTEXT completion_context)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
ResetPipePassiveCallbackEntry(WDFWORKITEM wdf_work_item)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