VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/Device/vboxrwr.cpp@ 34545

Last change on this file since 34545 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/*++
2
3Copyright (c) 2000 Microsoft Corporation
4
5Module Name:
6
7 vboxrwr.cpp
8
9Abstract:
10
11 This file has routines to perform reads and writes.
12 The read and writes are for bulk transfers.
13
14Environment:
15
16 Kernel mode
17
18Notes:
19
20 Copyright (c) 2000 Microsoft Corporation.
21 All Rights Reserved.
22
23--*/
24
25#include "vboxusb.h"
26#include "vboxpnp.h"
27#include "vboxpwr.h"
28#include "vboxdev.h"
29#include "vboxrwr.h"
30#include <VBox/log.h>
31#include <iprt/assert.h>
32
33
34PVBOXUSB_PIPE_CONTEXT
35VBoxUSB_PipeWithName(
36 IN PDEVICE_OBJECT DeviceObject,
37 IN PUNICODE_STRING FileName
38 )
39/*++
40
41Routine Description:
42
43 This routine will pass the string pipe name and
44 fetch the pipe number.
45
46Arguments:
47
48 DeviceObject - pointer to DeviceObject
49 FileName - string pipe name
50
51Return Value:
52
53 The device extension maintains a pipe context for
54 the pipes on 82930 board.
55 This routine returns the pointer to this context in
56 the device extension for the "FileName" pipe.
57
58--*/
59{
60 LONG ix;
61 ULONG uval;
62 ULONG nameLength;
63 ULONG umultiplier;
64 PDEVICE_EXTENSION deviceExtension;
65 PVBOXUSB_PIPE_CONTEXT pipeContext;
66
67 //
68 // initialize variables
69 //
70 pipeContext = NULL;
71 //
72 // typedef WCHAR *PWSTR;
73 //
74 nameLength = (FileName->Length / sizeof(WCHAR));
75 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
76
77 dprintf(("VBoxUSB_PipeWithName - begins\n"));
78
79 if(nameLength != 0) {
80
81 dprintf(("Filename = %ws nameLength = %d\n", FileName->Buffer, nameLength));
82
83 //
84 // Parse the pipe#
85 //
86 ix = nameLength - 1;
87
88 // if last char isn't digit, decrement it.
89 while((ix > -1) &&
90 ((FileName->Buffer[ix] < (WCHAR) '0') ||
91 (FileName->Buffer[ix] > (WCHAR) '9'))) {
92
93 ix--;
94 }
95
96 if(ix > -1) {
97
98 uval = 0;
99 umultiplier = 1;
100
101 // traversing least to most significant digits.
102
103 while((ix > -1) &&
104 (FileName->Buffer[ix] >= (WCHAR) '0') &&
105 (FileName->Buffer[ix] <= (WCHAR) '9')) {
106
107 uval += (umultiplier *
108 (ULONG) (FileName->Buffer[ix] - (WCHAR) '0'));
109
110 ix--;
111 umultiplier *= 10;
112 }
113
114 if(uval < 6 && deviceExtension->PipeContext) {
115
116 pipeContext = &deviceExtension->PipeContext[uval];
117 }
118 }
119 }
120
121 dprintf(("VBoxUSB_PipeWithName - ends\n"));
122
123 return pipeContext;
124}
125
126NTSTATUS
127VBoxUSB_DispatchReadWrite(
128 IN PDEVICE_OBJECT DeviceObject,
129 IN PIRP Irp
130 )
131/*++
132
133Routine Description:
134
135 Dispatch routine for read and write.
136 This routine creates a VBOXUSB_RW_CONTEXT for a read/write.
137 This read/write is performed in stages of VBoxUSB_MAX_TRANSFER_SIZE.
138 once a stage of transfer is complete, then the irp is circulated again,
139 until the requested length of transfer is performed.
140
141Arguments:
142
143 DeviceObject - pointer to device object
144 Irp - I/O request packet
145
146Return Value:
147
148 NT status value
149
150--*/
151{
152 PMDL mdl;
153 PURB urb;
154 ULONG totalLength;
155 ULONG stageLength;
156 ULONG urbFlags;
157 BOOLEAN read;
158 NTSTATUS ntStatus;
159 ULONG_PTR virtualAddress;
160 PFILE_OBJECT fileObject;
161 PDEVICE_EXTENSION deviceExtension;
162 PIO_STACK_LOCATION irpStack;
163 PIO_STACK_LOCATION nextStack;
164 PVBOXUSB_RW_CONTEXT rwContext;
165 PUSBD_PIPE_INFORMATION pipeInformation;
166
167 //
168 // initialize variables
169 //
170 urb = NULL;
171 mdl = NULL;
172 rwContext = NULL;
173 totalLength = 0;
174 irpStack = IoGetCurrentIrpStackLocation(Irp);
175 fileObject = irpStack->FileObject;
176 read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
177 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
178
179 dprintf(("VBoxUSB_DispatchReadWrite - begins\n"));
180
181 if(deviceExtension->DeviceState != Working) {
182
183 dprintf(("Invalid device state\n"));
184
185 ntStatus = STATUS_INVALID_DEVICE_STATE;
186 goto VBoxUSB_DispatchReadWrite_Exit;
187 }
188
189 //
190 // It is true that the client driver cancelled the selective suspend
191 // request in the dispatch routine for create Irps.
192 // But there is no guarantee that it has indeed completed.
193 // so wait on the NoIdleReqPendEvent and proceed only if this event
194 // is signalled.
195 //
196 dprintf(("Waiting on the IdleReqPendEvent\n"));
197
198 //
199 // make sure that the selective suspend request has been completed.
200 //
201
202 if(deviceExtension->SSEnable) {
203
204 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
205 Executive,
206 KernelMode,
207 FALSE,
208 NULL);
209 }
210
211 if(fileObject && fileObject->FsContext) {
212
213 pipeInformation = (PUSBD_PIPE_INFORMATION)fileObject->FsContext;
214
215 if((UsbdPipeTypeBulk != pipeInformation->PipeType) &&
216 (UsbdPipeTypeInterrupt != pipeInformation->PipeType)) {
217
218 dprintf(("Usbd pipe type is not bulk or interrupt\n"));
219
220 ntStatus = STATUS_INVALID_HANDLE;
221 goto VBoxUSB_DispatchReadWrite_Exit;
222 }
223 }
224 else {
225
226 dprintf(("Invalid handle\n"));
227
228 ntStatus = STATUS_INVALID_HANDLE;
229 goto VBoxUSB_DispatchReadWrite_Exit;
230 }
231
232 rwContext = (PVBOXUSB_RW_CONTEXT)
233 ExAllocatePool(NonPagedPool,
234 sizeof(VBOXUSB_RW_CONTEXT));
235
236 if(rwContext == NULL) {
237
238 dprintf(("Failed to alloc mem for rwContext\n"));
239
240 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
241 goto VBoxUSB_DispatchReadWrite_Exit;
242 }
243
244 if(Irp->MdlAddress) {
245
246 totalLength = MmGetMdlByteCount(Irp->MdlAddress);
247 }
248
249 if(totalLength > VBOXUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {
250
251 dprintf(("Transfer length > circular buffer\n"));
252
253 ntStatus = STATUS_INVALID_PARAMETER;
254
255 ExFreePool(rwContext);
256
257 goto VBoxUSB_DispatchReadWrite_Exit;
258 }
259
260 if(totalLength == 0) {
261
262 dprintf(("Transfer data length = 0\n"));
263
264 ntStatus = STATUS_SUCCESS;
265
266 ExFreePool(rwContext);
267
268 goto VBoxUSB_DispatchReadWrite_Exit;
269 }
270
271 urbFlags = USBD_SHORT_TRANSFER_OK;
272 virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
273
274 if(read) {
275
276 urbFlags |= USBD_TRANSFER_DIRECTION_IN;
277 dprintf(("Read operation\n"));
278 }
279 else {
280
281 urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
282 dprintf(("Write operation\n"));
283 }
284
285 //
286 // the transfer request is for totalLength.
287 // we can perform a max of VBoxUSB_MAX_TRANSFER_SIZE
288 // in each stage.
289 //
290 if(totalLength > VBOXUSB_MAX_TRANSFER_SIZE) {
291
292 stageLength = VBOXUSB_MAX_TRANSFER_SIZE;
293 }
294 else {
295
296 stageLength = totalLength;
297 }
298
299 mdl = IoAllocateMdl((PVOID) virtualAddress,
300 totalLength,
301 FALSE,
302 FALSE,
303 NULL);
304
305 if(mdl == NULL) {
306
307 dprintf(("Failed to alloc mem for mdl\n"));
308
309 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
310
311 ExFreePool(rwContext);
312
313 goto VBoxUSB_DispatchReadWrite_Exit;
314 }
315
316 //
317 // map the portion of user-buffer described by an mdl to another mdl
318 //
319 IoBuildPartialMdl(Irp->MdlAddress,
320 mdl,
321 (PVOID) virtualAddress,
322 stageLength);
323
324 urb = (PURB)ExAllocatePool(NonPagedPool,sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
325
326 if(urb == NULL) {
327
328 dprintf(("Failed to alloc mem for urb\n"));
329
330 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
331
332 ExFreePool(rwContext);
333 IoFreeMdl(mdl);
334
335 goto VBoxUSB_DispatchReadWrite_Exit;
336 }
337
338 UsbBuildInterruptOrBulkTransferRequest(
339 urb,
340 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
341 pipeInformation->PipeHandle,
342 NULL,
343 mdl,
344 stageLength,
345 urbFlags,
346 NULL);
347
348 //
349 // set VBOXUSB_RW_CONTEXT parameters.
350 //
351
352 rwContext->Urb = urb;
353 rwContext->Mdl = mdl;
354 rwContext->Length = totalLength - stageLength;
355 rwContext->Numxfer = 0;
356 rwContext->VirtualAddress = virtualAddress + stageLength;
357 rwContext->DeviceExtension = deviceExtension;
358
359 //
360 // use the original read/write irp as an internal device control irp
361 //
362
363 nextStack = IoGetNextIrpStackLocation(Irp);
364 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
365 nextStack->Parameters.Others.Argument1 = (PVOID) urb;
366 nextStack->Parameters.DeviceIoControl.IoControlCode =
367 IOCTL_INTERNAL_USB_SUBMIT_URB;
368
369 IoSetCompletionRoutine(Irp,
370 (PIO_COMPLETION_ROUTINE)VBoxUSB_ReadWriteCompletion,
371 rwContext,
372 TRUE,
373 TRUE,
374 TRUE);
375
376 //
377 // since we return STATUS_PENDING call IoMarkIrpPending.
378 // This is the boiler plate code.
379 // This may cause extra overhead of an APC for the Irp completion
380 // but this is the correct thing to do.
381 //
382
383 IoMarkIrpPending(Irp);
384
385 dprintf(("VBoxUSB_DispatchReadWrite::"));
386 VBoxUSB_IoIncrement(deviceExtension);
387
388 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
389 Irp);
390
391 if(!NT_SUCCESS(ntStatus)) {
392
393 dprintf(("IoCallDriver fails with status %X\n", ntStatus));
394
395 //
396 // if the device was yanked out, then the pipeInformation
397 // field is invalid.
398 // similarly if the request was cancelled, then we need not
399 // invoked reset pipe/device.
400 //
401 if((ntStatus != STATUS_CANCELLED) &&
402 (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {
403
404 ntStatus = VBoxUSB_ResetPipe(DeviceObject,
405 pipeInformation->PipeHandle);
406
407 if(!NT_SUCCESS(ntStatus)) {
408
409 dprintf(("VBoxUSB_ResetPipe failed\n"));
410
411 ntStatus = VBoxUSB_ResetDevice(DeviceObject);
412 }
413 }
414 else {
415
416 dprintf(("ntStatus is STATUS_CANCELLED or "
417 "STATUS_DEVICE_NOT_CONNECTED\n"));
418 }
419 }
420
421 //
422 // we return STATUS_PENDING and not the status returned by the lower layer.
423 //
424 return STATUS_PENDING;
425
426VBoxUSB_DispatchReadWrite_Exit:
427
428 Irp->IoStatus.Status = ntStatus;
429 Irp->IoStatus.Information = 0;
430
431 IoCompleteRequest(Irp, IO_NO_INCREMENT);
432
433 dprintf(("VBoxUSB_DispatchReadWrite - ends\n"));
434
435 return ntStatus;
436}
437
438NTSTATUS
439VBoxUSB_ReadWriteCompletion(
440 IN PDEVICE_OBJECT DeviceObject,
441 IN PIRP Irp,
442 IN PVOID Context
443 )
444/*++
445
446Routine Description:
447
448 This is the completion routine for reads/writes
449 If the irp completes with success, we check if we
450 need to recirculate this irp for another stage of
451 transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED.
452 if the irp completes in error, free all memory allocs and
453 return the status.
454
455Arguments:
456
457 DeviceObject - pointer to device object
458 Irp - I/O request packet
459 Context - context passed to the completion routine.
460
461Return Value:
462
463 NT status value
464
465--*/
466{
467 ULONG stageLength;
468 NTSTATUS ntStatus;
469 PIO_STACK_LOCATION nextStack;
470 PVBOXUSB_RW_CONTEXT rwContext;
471
472 //
473 // initialize variables
474 //
475 rwContext = (PVBOXUSB_RW_CONTEXT) Context;
476 ntStatus = Irp->IoStatus.Status;
477
478 UNREFERENCED_PARAMETER(DeviceObject);
479 dprintf(("VBoxUSB_ReadWriteCompletion - begins\n"));
480
481 //
482 // successfully performed a stageLength of transfer.
483 // check if we need to recirculate the irp.
484 //
485 if(NT_SUCCESS(ntStatus)) {
486
487 if(rwContext) {
488
489 rwContext->Numxfer +=
490 rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
491
492 if(rwContext->Length) {
493
494 //
495 // another stage transfer
496 //
497 dprintf(("Another stage transfer...\n"));
498
499 if(rwContext->Length > VBOXUSB_MAX_TRANSFER_SIZE) {
500
501 stageLength = VBOXUSB_MAX_TRANSFER_SIZE;
502 }
503 else {
504
505 stageLength = rwContext->Length;
506 }
507
508 // the source MDL is not mapped and so when the lower driver
509 // calls MmGetSystemAddressForMdl(Safe) on Urb->Mdl (target Mdl),
510 // system PTEs are used.
511 // IoFreeMdl calls MmPrepareMdlForReuse to release PTEs (unlock
512 // VA address before freeing any Mdl
513 // Rather than calling IoFreeMdl and IoAllocateMdl each time,
514 // just call MmPrepareMdlForReuse
515 // Not calling MmPrepareMdlForReuse will leak system PTEs
516 //
517 MmPrepareMdlForReuse(rwContext->Mdl);
518
519 IoBuildPartialMdl(Irp->MdlAddress,
520 rwContext->Mdl,
521 (PVOID) rwContext->VirtualAddress,
522 stageLength);
523
524 //
525 // reinitialize the urb
526 //
527 rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength
528 = stageLength;
529 rwContext->VirtualAddress += stageLength;
530 rwContext->Length -= stageLength;
531
532 nextStack = IoGetNextIrpStackLocation(Irp);
533 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
534 nextStack->Parameters.Others.Argument1 = rwContext->Urb;
535 nextStack->Parameters.DeviceIoControl.IoControlCode =
536 IOCTL_INTERNAL_USB_SUBMIT_URB;
537
538 IoSetCompletionRoutine(Irp,
539 VBoxUSB_ReadWriteCompletion,
540 rwContext,
541 TRUE,
542 TRUE,
543 TRUE);
544
545 IoCallDriver(rwContext->DeviceExtension->TopOfStackDeviceObject,
546 Irp);
547
548 return STATUS_MORE_PROCESSING_REQUIRED;
549 }
550 else {
551
552 //
553 // this is the last transfer
554 //
555
556 Irp->IoStatus.Information = rwContext->Numxfer;
557 }
558 }
559 }
560 else {
561
562 dprintf(("ReadWriteCompletion - failed with status = %X\n", ntStatus));
563 }
564
565 if(rwContext) {
566
567 //
568 // dump rwContext
569 //
570 dprintf(("rwContext->Urb = %X\n",
571 rwContext->Urb));
572 dprintf(("rwContext->Mdl = %X\n",
573 rwContext->Mdl));
574 dprintf(("rwContext->Length = %d\n",
575 rwContext->Length));
576 dprintf(("rwContext->Numxfer = %d\n",
577 rwContext->Numxfer));
578 dprintf(("rwContext->VirtualAddress = %X\n",
579 rwContext->VirtualAddress));
580 dprintf(("rwContext->DeviceExtension = %X\n",
581 rwContext->DeviceExtension));
582
583 dprintf(("VBoxUSB_ReadWriteCompletion::"));
584 VBoxUSB_IoDecrement(rwContext->DeviceExtension);
585
586 ExFreePool(rwContext->Urb);
587 IoFreeMdl(rwContext->Mdl);
588 ExFreePool(rwContext);
589 }
590
591 dprintf(("VBoxUSB_ReadWriteCompletion - ends\n"));
592
593 return ntStatus;
594}
595
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette