VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/Device/vboxpnp.cpp@ 36768

Last change on this file since 36768 was 33540, checked in by vboxsync, 15 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.0 KB
Line 
1/*++
2
3Copyright (c) 2000 Microsoft Corporation
4
5Module Name:
6
7 vboxpnp.c
8
9Abstract:
10
11 Bulk USB device driver for Intel 82930 USB test board
12 Plug and Play module.
13 This file contains routines to handle pnp requests.
14 These routines are not USB specific but is required
15 for every driver which conforms to the WDM model.
16
17Environment:
18
19 Kernel mode
20
21Notes:
22
23 Copyright (c) 2000 Microsoft Corporation.
24 All Rights Reserved.
25
26--*/
27
28#include "vboxusb.h"
29#include "vboxpnp.h"
30#include "vboxpwr.h"
31#include "vboxdev.h"
32#include "vboxrwr.h"
33#include <iprt/assert.h>
34
35NTSTATUS
36VBoxUSB_DispatchPnP(
37 IN PDEVICE_OBJECT DeviceObject,
38 IN PIRP Irp
39 )
40/*++
41
42Routine Description:
43
44 The plug and play dispatch routines.
45 Most of these requests the driver will completely ignore.
46 In all cases it must pass on the IRP to the lower driver.
47
48Arguments:
49
50 DeviceObject - pointer to a device object.
51
52 Irp - pointer to an I/O Request Packet.
53
54Return Value:
55
56 NT status value
57
58--*/
59{
60 PIO_STACK_LOCATION irpStack;
61 PDEVICE_EXTENSION deviceExtension;
62 NTSTATUS ntStatus;
63
64 //
65 // initialize variables
66 //
67
68 irpStack = IoGetCurrentIrpStackLocation(Irp);
69 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
70
71 //
72 // since the device is removed, fail the Irp.
73 //
74
75 if(Removed == deviceExtension->DeviceState) {
76
77 ntStatus = STATUS_DELETE_PENDING;
78
79 Irp->IoStatus.Status = ntStatus;
80 Irp->IoStatus.Information = 0;
81
82 IoCompleteRequest(Irp, IO_NO_INCREMENT);
83
84 return ntStatus;
85 }
86
87 dprintf(("///////////////////////////////////////////\n"));
88 dprintf(("VBoxUSB_DispatchPnP::"));
89 VBoxUSB_IoIncrement(deviceExtension);
90
91 if(irpStack->MinorFunction == IRP_MN_START_DEVICE) {
92
93 ASSERT(deviceExtension->IdleReqPend == 0);
94 }
95 else {
96
97 if(deviceExtension->SSEnable) {
98
99 CancelSelectSuspend(deviceExtension);
100 }
101 }
102
103 dprintf((PnPMinorFunctionString(irpStack->MinorFunction)));
104
105 switch(irpStack->MinorFunction) {
106
107 case IRP_MN_START_DEVICE:
108
109 ntStatus = HandleStartDevice(DeviceObject, Irp);
110
111 break;
112
113 case IRP_MN_QUERY_STOP_DEVICE:
114
115 //
116 // if we cannot stop the device, we fail the query stop irp
117 //
118
119 ntStatus = CanStopDevice(DeviceObject, Irp);
120
121 if(NT_SUCCESS(ntStatus)) {
122
123 ntStatus = HandleQueryStopDevice(DeviceObject, Irp);
124
125 return ntStatus;
126 }
127 break;
128
129 case IRP_MN_CANCEL_STOP_DEVICE:
130
131 ntStatus = HandleCancelStopDevice(DeviceObject, Irp);
132
133 break;
134
135 case IRP_MN_STOP_DEVICE:
136
137 ntStatus = HandleStopDevice(DeviceObject, Irp);
138
139 dprintf(("VBoxUSB_DispatchPnP::IRP_MN_STOP_DEVICE::"));
140 VBoxUSB_IoDecrement(deviceExtension);
141
142 return ntStatus;
143
144 case IRP_MN_QUERY_REMOVE_DEVICE:
145
146 //
147 // if we cannot remove the device, we fail the query remove irp
148 //
149 ntStatus = HandleQueryRemoveDevice(DeviceObject, Irp);
150
151 return ntStatus;
152
153 case IRP_MN_CANCEL_REMOVE_DEVICE:
154
155 ntStatus = HandleCancelRemoveDevice(DeviceObject, Irp);
156
157 break;
158
159 case IRP_MN_SURPRISE_REMOVAL:
160
161 ntStatus = HandleSurpriseRemoval(DeviceObject, Irp);
162
163 dprintf(("VBoxUSB_DispatchPnP::IRP_MN_SURPRISE_REMOVAL::"));
164 VBoxUSB_IoDecrement(deviceExtension);
165
166 return ntStatus;
167
168 case IRP_MN_REMOVE_DEVICE:
169
170 ntStatus = HandleRemoveDevice(DeviceObject, Irp);
171
172 return ntStatus;
173
174 case IRP_MN_QUERY_CAPABILITIES:
175
176 ntStatus = HandleQueryCapabilities(DeviceObject, Irp);
177
178 break;
179
180 default:
181
182 IoSkipCurrentIrpStackLocation(Irp);
183
184 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
185
186 dprintf(("VBoxUSB_DispatchPnP::default::"));
187 VBoxUSB_IoDecrement(deviceExtension);
188
189 return ntStatus;
190
191 } // switch
192
193//
194// complete request
195//
196
197 Irp->IoStatus.Status = ntStatus;
198 Irp->IoStatus.Information = 0;
199
200 IoCompleteRequest(Irp, IO_NO_INCREMENT);
201
202//
203// decrement count
204//
205 dprintf(("VBoxUSB_DispatchPnP::"));
206 VBoxUSB_IoDecrement(deviceExtension);
207
208 return ntStatus;
209}
210
211NTSTATUS
212HandleStartDevice(
213 IN PDEVICE_OBJECT DeviceObject,
214 IN PIRP Irp
215 )
216/*++
217
218Routine Description:
219
220 This is the dispatch routine for IRP_MN_START_DEVICE
221
222Arguments:
223
224 DeviceObject - pointer to a device object.
225
226 Irp - I/O request packet
227
228Return Value:
229
230 NT status value
231
232--*/
233{
234 KIRQL oldIrql;
235 KEVENT startDeviceEvent;
236 NTSTATUS ntStatus;
237 PDEVICE_EXTENSION deviceExtension;
238 LARGE_INTEGER dueTime;
239
240 dprintf(("HandleStartDevice - begins\n"));
241
242 //
243 // initialize variables
244 //
245 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
246 deviceExtension->UsbConfigurationDescriptor = NULL;
247 deviceExtension->UsbInterface = NULL;
248 deviceExtension->PipeContext = NULL;
249
250 //
251 // We cannot touch the device (send it any non pnp irps) until a
252 // start device has been passed down to the lower drivers.
253 // first pass the Irp down
254 //
255
256 KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
257
258 IoCopyCurrentIrpStackLocationToNext(Irp);
259
260 IoSetCompletionRoutine(Irp,
261 (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
262 (PVOID)&startDeviceEvent,
263 TRUE,
264 TRUE,
265 TRUE);
266
267 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
268
269 if(ntStatus == STATUS_PENDING) {
270
271 KeWaitForSingleObject(&startDeviceEvent,
272 Executive,
273 KernelMode,
274 FALSE,
275 NULL);
276
277 ntStatus = Irp->IoStatus.Status;
278 }
279
280 if(!NT_SUCCESS(ntStatus)) {
281
282 dprintf(("Lower drivers failed this Irp\n"));
283 return ntStatus;
284 }
285
286#if 0
287 //
288 // Read the device descriptor, configuration descriptor
289 // and select the interface descriptors
290 //
291
292 ntStatus = ReadandSelectDescriptors(DeviceObject);
293
294 if(!NT_SUCCESS(ntStatus)) {
295
296 dprintf(("ReadandSelectDescriptors failed\n"));
297 return ntStatus;
298 }
299#endif
300
301 //
302 // enable the symbolic links for system components to open
303 // handles to the device
304 //
305
306 ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
307 TRUE);
308
309 if(!NT_SUCCESS(ntStatus)) {
310
311 dprintf(("IoSetDeviceInterfaceState:enable:failed\n"));
312 return ntStatus;
313 }
314
315 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
316
317 SET_NEW_PNP_STATE(deviceExtension, Working);
318 deviceExtension->QueueState = AllowRequests;
319
320 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
321
322 //
323 // initialize wait wake outstanding flag to false.
324 // and issue a wait wake.
325
326 deviceExtension->FlagWWOutstanding = 0;
327 deviceExtension->FlagWWCancel = 0;
328 deviceExtension->WaitWakeIrp = NULL;
329
330 if(deviceExtension->WaitWakeEnable) {
331
332 IssueWaitWake(deviceExtension);
333 }
334
335 ProcessQueuedRequests(deviceExtension);
336
337
338 if(WinXpOrBetter == deviceExtension->WdmVersion) {
339
340
341 deviceExtension->SSEnable = deviceExtension->SSRegistryEnable;
342
343 //
344 // set timer.for selective suspend requests
345 //
346
347 if(deviceExtension->SSEnable) {
348
349 dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
350
351 KeSetTimerEx(&deviceExtension->Timer,
352 dueTime,
353 IDLE_INTERVAL, // 5000 ms
354 &deviceExtension->DeferredProcCall);
355
356 deviceExtension->FreeIdleIrpCount = 0;
357 }
358 }
359
360 dprintf(("HandleStartDevice - ends\n"));
361
362 return ntStatus;
363}
364
365
366NTSTATUS
367ReadandSelectDescriptors(
368 IN PDEVICE_OBJECT DeviceObject
369 )
370/*++
371
372Routine Description:
373
374 This routine configures the USB device.
375 In this routines we get the device descriptor,
376 the configuration descriptor and select the
377 configuration descriptor.
378
379Arguments:
380
381 DeviceObject - pointer to a device object
382
383Return Value:
384
385 NTSTATUS - NT status value.
386
387--*/
388{
389 PURB urb;
390 ULONG siz;
391 NTSTATUS ntStatus;
392 PUSB_DEVICE_DESCRIPTOR deviceDescriptor;
393
394 //
395 // initialize variables
396 //
397
398 urb = NULL;
399 deviceDescriptor = NULL;
400
401 //
402 // 1. Read the device descriptor
403 //
404
405 urb = (PURB)ExAllocatePool(NonPagedPool,
406 sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
407
408 if(urb) {
409
410 memset(urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
411
412 siz = sizeof(USB_DEVICE_DESCRIPTOR);
413 deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)ExAllocatePool(NonPagedPool, siz);
414
415 if(deviceDescriptor) {
416
417 UsbBuildGetDescriptorRequest(
418 urb,
419 (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
420 USB_DEVICE_DESCRIPTOR_TYPE,
421 0,
422 0,
423 deviceDescriptor,
424 NULL,
425 siz,
426 NULL);
427
428 ntStatus = CallUSBD(DeviceObject, urb);
429
430 if(NT_SUCCESS(ntStatus)) {
431
432 ASSERT(deviceDescriptor->bNumConfigurations);
433 ntStatus = ConfigureDevice(DeviceObject);
434 }
435
436 ExFreePool(urb);
437 ExFreePool(deviceDescriptor);
438 }
439 else {
440
441 dprintf(("Failed to allocate memory for deviceDescriptor\n"));
442
443 ExFreePool(urb);
444 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
445 }
446 }
447 else {
448
449 dprintf(("Failed to allocate memory for urb\n"));
450
451 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
452 }
453
454 return ntStatus;
455}
456
457NTSTATUS
458ConfigureDevice(
459 IN PDEVICE_OBJECT DeviceObject
460 )
461/*++
462
463Routine Description:
464
465 This helper routine reads the configuration descriptor
466 for the device in couple of steps.
467
468Arguments:
469
470 DeviceObject - pointer to a device object
471
472Return Value:
473
474 NTSTATUS - NT status value
475
476--*/
477{
478 PURB urb;
479 ULONG siz;
480 NTSTATUS ntStatus;
481 PDEVICE_EXTENSION deviceExtension;
482 PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
483
484 //
485 // initialize the variables
486 //
487
488 urb = NULL;
489 configurationDescriptor = NULL;
490 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
491
492 //
493 // Read the first configuration descriptor
494 // This requires two steps:
495 // 1. Read the fixed sized configuration descriptor (CD)
496 // 2. Read the CD with all embedded interface and endpoint descriptors
497 //
498
499 urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
500 if(urb) {
501
502 memset(urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
503 siz = sizeof(USB_CONFIGURATION_DESCRIPTOR);
504 configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)ExAllocatePool(NonPagedPool, siz);
505
506 if(configurationDescriptor) {
507
508 UsbBuildGetDescriptorRequest(
509 urb,
510 (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
511 USB_CONFIGURATION_DESCRIPTOR_TYPE,
512 0,
513 0,
514 configurationDescriptor,
515 NULL,
516 sizeof(USB_CONFIGURATION_DESCRIPTOR),
517 NULL);
518
519 ntStatus = CallUSBD(DeviceObject, urb);
520
521 if(!NT_SUCCESS(ntStatus)) {
522
523 dprintf(("UsbBuildGetDescriptorRequest failed\n"));
524 goto ConfigureDevice_Exit;
525 }
526 }
527 else {
528
529 dprintf(("Failed to allocate mem for config Descriptor\n"));
530
531 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
532 goto ConfigureDevice_Exit;
533 }
534
535 siz = configurationDescriptor->wTotalLength;
536
537 ExFreePool(configurationDescriptor);
538
539 configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)ExAllocatePool(NonPagedPool, siz);
540
541 if(configurationDescriptor) {
542 memset(configurationDescriptor, 0, siz);
543
544 UsbBuildGetDescriptorRequest(
545 urb,
546 (USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
547 USB_CONFIGURATION_DESCRIPTOR_TYPE,
548 0,
549 0,
550 configurationDescriptor,
551 NULL,
552 siz,
553 NULL);
554
555 ntStatus = CallUSBD(DeviceObject, urb);
556
557 if(!NT_SUCCESS(ntStatus)) {
558
559 dprintf(("Failed to read configuration descriptor\n"));
560 goto ConfigureDevice_Exit;
561 }
562 }
563 else {
564
565 dprintf(("Failed to alloc mem for config Descriptor\n"));
566 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
567 goto ConfigureDevice_Exit;
568 }
569 }
570 else {
571
572 dprintf(("Failed to allocate memory for urb\n"));
573 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
574 goto ConfigureDevice_Exit;
575 }
576
577 if(configurationDescriptor) {
578
579 //
580 // save a copy of configurationDescriptor in deviceExtension
581 // remember to free it later.
582 //
583 deviceExtension->UsbConfigurationDescriptor = configurationDescriptor;
584
585 if(configurationDescriptor->bmAttributes & REMOTE_WAKEUP_MASK)
586 {
587 //
588 // this configuration supports remote wakeup
589 //
590 deviceExtension->WaitWakeEnable = 1;
591 }
592 else
593 {
594 deviceExtension->WaitWakeEnable = 0;
595 }
596
597 ntStatus = SelectInterfaces(DeviceObject, configurationDescriptor);
598 }
599 else {
600
601 deviceExtension->UsbConfigurationDescriptor = NULL;
602 }
603
604ConfigureDevice_Exit:
605
606 if(urb) {
607
608 ExFreePool(urb);
609 }
610
611 return ntStatus;
612}
613
614NTSTATUS
615SelectInterfaces(
616 IN PDEVICE_OBJECT DeviceObject,
617 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
618 )
619/*++
620
621Routine Description:
622
623 This helper routine selects the configuration
624
625Arguments:
626
627 DeviceObject - pointer to device object
628 ConfigurationDescriptor - pointer to the configuration
629 descriptor for the device
630
631Return Value:
632
633 NT status value
634
635--*/
636{
637 LONG numberOfInterfaces,
638 interfaceNumber,
639 interfaceindex;
640 ULONG i;
641 PURB urb;
642 NTSTATUS ntStatus;
643 PDEVICE_EXTENSION deviceExtension;
644 PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
645 PUSBD_INTERFACE_LIST_ENTRY interfaceList,
646 tmp;
647 PUSBD_INTERFACE_INFORMATION Interface;
648
649 //
650 // initialize the variables
651 //
652
653 urb = NULL;
654 Interface = NULL;
655 interfaceDescriptor = NULL;
656 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
657 numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
658 interfaceindex = interfaceNumber = 0;
659
660 //
661 // Parse the configuration descriptor for the interface;
662 //
663
664 tmp = interfaceList = (PUSBD_INTERFACE_LIST_ENTRY)
665 ExAllocatePool(
666 NonPagedPool,
667 sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1));
668
669 if(!tmp) {
670
671 dprintf(("Failed to allocate mem for interfaceList\n"));
672 return STATUS_INSUFFICIENT_RESOURCES;
673 }
674
675
676 while(interfaceNumber < numberOfInterfaces) {
677
678 interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
679 ConfigurationDescriptor,
680 ConfigurationDescriptor,
681 interfaceindex,
682 0, -1, -1, -1);
683
684 if(interfaceDescriptor) {
685
686 interfaceList->InterfaceDescriptor = interfaceDescriptor;
687 interfaceList->Interface = NULL;
688 interfaceList++;
689 interfaceNumber++;
690 }
691
692 interfaceindex++;
693 }
694
695 interfaceList->InterfaceDescriptor = NULL;
696 interfaceList->Interface = NULL;
697 urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp);
698
699 if(urb) {
700
701 Interface = &urb->UrbSelectConfiguration.Interface;
702
703 for(i=0; i<Interface->NumberOfPipes; i++) {
704
705 //
706 // perform pipe initialization here
707 // set the transfer size and any pipe flags we use
708 // USBD sets the rest of the Interface struct members
709 //
710
711 Interface->Pipes[i].MaximumTransferSize =
712 USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
713 }
714
715 ntStatus = CallUSBD(DeviceObject, urb);
716
717 if(NT_SUCCESS(ntStatus)) {
718
719 //
720 // save a copy of interface information in the device extension.
721 //
722 deviceExtension->UsbInterface = (PUSBD_INTERFACE_INFORMATION)ExAllocatePool(NonPagedPool, Interface->Length);
723
724 if(deviceExtension->UsbInterface) {
725
726 RtlCopyMemory(deviceExtension->UsbInterface,
727 Interface,
728 Interface->Length);
729 }
730 else {
731
732 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
733 dprintf(("memory alloc for UsbInterface failed\n"));
734 }
735
736 //
737 // Dump the interface to the debugger
738 //
739
740 Interface = &urb->UrbSelectConfiguration.Interface;
741
742 dprintf(("---------\n"));
743 dprintf(("NumberOfPipes 0x%x\n",
744 Interface->NumberOfPipes));
745 dprintf(("Length 0x%x\n",
746 Interface->Length));
747 dprintf(("Alt Setting 0x%x\n",
748 Interface->AlternateSetting));
749 dprintf(("Interface Number 0x%x\n",
750 Interface->InterfaceNumber));
751 dprintf(("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
752 Interface->Class,
753 Interface->SubClass,
754 Interface->Protocol));
755 //
756 // Initialize the PipeContext
757 // Dump the pipe info
758 //
759
760 if(Interface->NumberOfPipes) {
761 deviceExtension->PipeContext = (PVBOXUSB_PIPE_CONTEXT)
762 ExAllocatePool(NonPagedPool,
763 Interface->NumberOfPipes *
764 sizeof(VBOXUSB_PIPE_CONTEXT));
765
766 if(deviceExtension->PipeContext) {
767
768 for(i=0; i<Interface->NumberOfPipes; i++) {
769
770 deviceExtension->PipeContext[i].PipeOpen = FALSE;
771 }
772 }
773 else {
774
775 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
776 dprintf(("memory alloc for UsbInterface failed\n"));
777 }
778 }
779
780 for(i=0; i<Interface->NumberOfPipes; i++) {
781
782 dprintf(("---------\n"));
783 dprintf(("PipeType 0x%x\n",
784 Interface->Pipes[i].PipeType));
785 dprintf(("EndpointAddress 0x%x\n",
786 Interface->Pipes[i].EndpointAddress));
787 dprintf(("MaxPacketSize 0x%x\n",
788 Interface->Pipes[i].MaximumPacketSize));
789 dprintf(("Interval 0x%x\n",
790 Interface->Pipes[i].Interval));
791 dprintf(("Handle 0x%x\n",
792 Interface->Pipes[i].PipeHandle));
793 dprintf(("MaximumTransferSize 0x%x\n",
794 Interface->Pipes[i].MaximumTransferSize));
795 }
796
797 dprintf(("---------\n"));
798 }
799 else {
800
801 dprintf(("Failed to select an interface\n"));
802 }
803 }
804 else {
805
806 dprintf(("USBD_CreateConfigurationRequestEx failed\n"));
807 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
808 }
809
810 if(tmp) {
811
812 ExFreePool(tmp);
813 }
814
815 if(urb) {
816
817 ExFreePool(urb);
818 }
819
820 return ntStatus;
821}
822
823
824NTSTATUS
825DeconfigureDevice(
826 IN PDEVICE_OBJECT DeviceObject
827 )
828/*++
829
830Routine Description:
831
832 This routine is invoked when the device is removed or stopped.
833 This routine de-configures the usb device.
834
835Arguments:
836
837 DeviceObject - pointer to device object
838
839Return Value:
840
841 NT status value
842
843--*/
844{
845 PURB urb;
846 ULONG siz;
847 NTSTATUS ntStatus;
848
849 //
850 // initialize variables
851 //
852
853 siz = sizeof(struct _URB_SELECT_CONFIGURATION);
854 urb = (PURB)ExAllocatePool(NonPagedPool, siz);
855 if(urb) {
856
857 UsbBuildSelectConfigurationRequest(urb, (USHORT)siz, NULL);
858
859 ntStatus = CallUSBD(DeviceObject, urb);
860
861 if(!NT_SUCCESS(ntStatus)) {
862
863 dprintf(("Failed to deconfigure device\n"));
864 }
865
866 ExFreePool(urb);
867 }
868 else {
869
870 dprintf(("Failed to allocate urb\n"));
871 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
872 }
873
874 return ntStatus;
875}
876
877NTSTATUS
878CallUSBD(
879 IN PDEVICE_OBJECT DeviceObject,
880 IN PURB Urb
881 )
882/*++
883
884Routine Description:
885
886 This routine synchronously submits an urb down the stack.
887
888Arguments:
889
890 DeviceObject - pointer to device object
891 Urb - USB request block
892
893Return Value:
894
895--*/
896{
897 PIRP irp;
898 KEVENT event;
899 NTSTATUS ntStatus;
900 IO_STATUS_BLOCK ioStatus;
901 PIO_STACK_LOCATION nextStack;
902 PDEVICE_EXTENSION deviceExtension;
903
904 //
905 // initialize the variables
906 //
907
908 irp = NULL;
909 deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
910
911 KeInitializeEvent(&event, NotificationEvent, FALSE);
912
913 irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
914 deviceExtension->TopOfStackDeviceObject,
915 NULL,
916 0,
917 NULL,
918 0,
919 TRUE,
920 &event,
921 &ioStatus);
922
923 if(!irp) {
924
925 dprintf(("IoBuildDeviceIoControlRequest failed\n"));
926 return STATUS_INSUFFICIENT_RESOURCES;
927 }
928
929 nextStack = IoGetNextIrpStackLocation(irp);
930 ASSERT(nextStack != NULL);
931 nextStack->Parameters.Others.Argument1 = Urb;
932
933 dprintf(("CallUSBD::"));
934 VBoxUSB_IoIncrement(deviceExtension);
935
936 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
937
938 if(ntStatus == STATUS_PENDING) {
939
940 KeWaitForSingleObject(&event,
941 Executive,
942 KernelMode,
943 FALSE,
944 NULL);
945
946 ntStatus = ioStatus.Status;
947 }
948
949 dprintf(("CallUSBD::"));
950 VBoxUSB_IoDecrement(deviceExtension);
951 return ntStatus;
952}
953
954NTSTATUS
955HandleQueryStopDevice(
956 IN PDEVICE_OBJECT DeviceObject,
957 IN PIRP Irp
958 )
959/*++
960
961Routine Description:
962
963 This routine services the Irps of minor type IRP_MN_QUERY_STOP_DEVICE
964
965Arguments:
966
967 DeviceObject - pointer to device object
968 Irp - I/O request packet sent by the pnp manager.
969
970Return Value:
971
972 NT status value
973
974--*/
975{
976 KIRQL oldIrql;
977 NTSTATUS ntStatus;
978 PDEVICE_EXTENSION deviceExtension;
979
980 dprintf(("HandleQueryStopDevice - begins\n"));
981
982 //
983 // initialize variables
984 //
985
986 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
987
988 //
989 // If we can stop the device, we need to set the QueueState to
990 // HoldRequests so further requests will be queued.
991 //
992
993 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
994
995 SET_NEW_PNP_STATE(deviceExtension, PendingStop);
996 deviceExtension->QueueState = HoldRequests;
997
998 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
999
1000 //
1001 // wait for the existing ones to be finished.
1002 // first, decrement this operation
1003 //
1004
1005 dprintf(("HandleQueryStopDevice::"));
1006 VBoxUSB_IoDecrement(deviceExtension);
1007
1008 KeWaitForSingleObject(&deviceExtension->StopEvent,
1009 Executive,
1010 KernelMode,
1011 FALSE,
1012 NULL);
1013
1014 Irp->IoStatus.Status = STATUS_SUCCESS;
1015 Irp->IoStatus.Information = 0;
1016
1017 IoSkipCurrentIrpStackLocation(Irp);
1018
1019 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1020
1021 dprintf(("HandleQueryStopDevice - ends\n"));
1022
1023 return ntStatus;
1024}
1025
1026NTSTATUS
1027HandleCancelStopDevice(
1028 IN PDEVICE_OBJECT DeviceObject,
1029 IN PIRP Irp
1030 )
1031/*++
1032
1033Routine Description:
1034
1035 This routine services Irp of minor type IRP_MN_CANCEL_STOP_DEVICE
1036
1037Arguments:
1038
1039 DeviceObject - pointer to device object
1040 Irp - I/O request packet sent by the pnp manager.
1041
1042Return Value:
1043
1044 NT value
1045
1046--*/
1047{
1048 KIRQL oldIrql;
1049 KEVENT event;
1050 NTSTATUS ntStatus;
1051 PDEVICE_EXTENSION deviceExtension;
1052
1053 dprintf(("HandleCancelStopDevice - begins\n"));
1054
1055 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1056
1057 //
1058 // Send this IRP down and wait for it to come back.
1059 // Set the QueueState flag to AllowRequests,
1060 // and process all the previously queued up IRPs.
1061 //
1062 // First check to see whether you have received cancel-stop
1063 // without first receiving a query-stop. This could happen if someone
1064 // above us fails a query-stop and passes down the subsequent
1065 // cancel-stop.
1066 //
1067
1068 if(PendingStop == deviceExtension->DeviceState) {
1069
1070 KeInitializeEvent(&event, NotificationEvent, FALSE);
1071
1072 IoCopyCurrentIrpStackLocationToNext(Irp);
1073 IoSetCompletionRoutine(Irp,
1074 (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
1075 (PVOID)&event,
1076 TRUE,
1077 TRUE,
1078 TRUE);
1079
1080 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1081
1082 if(ntStatus == STATUS_PENDING) {
1083
1084 KeWaitForSingleObject(&event,
1085 Executive,
1086 KernelMode,
1087 FALSE,
1088 NULL);
1089 ntStatus = Irp->IoStatus.Status;
1090 }
1091
1092 if(NT_SUCCESS(ntStatus)) {
1093
1094 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1095
1096 RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
1097 deviceExtension->QueueState = AllowRequests;
1098 ASSERT(deviceExtension->DeviceState == Working);
1099
1100 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1101
1102 ProcessQueuedRequests(deviceExtension);
1103 }
1104
1105 }
1106 else {
1107
1108 // spurious Irp
1109 ntStatus = STATUS_SUCCESS;
1110 }
1111
1112 dprintf(("HandleCancelStopDevice - ends\n"));
1113
1114 return ntStatus;
1115}
1116
1117NTSTATUS
1118HandleStopDevice(
1119 IN PDEVICE_OBJECT DeviceObject,
1120 IN PIRP Irp
1121 )
1122/*++
1123
1124Routine Description:
1125
1126 This routine services Irp of minor type IRP_MN_STOP_DEVICE
1127
1128Arguments:
1129
1130 DeviceObject - pointer to device object
1131 Irp - I/O request packet sent by the pnp manager.
1132
1133Return Value:
1134
1135 NT status value
1136
1137--*/
1138{
1139 KIRQL oldIrql;
1140 NTSTATUS ntStatus;
1141 PDEVICE_EXTENSION deviceExtension;
1142
1143 dprintf(("HandleStopDevice - begins\n"));
1144
1145 //
1146 // initialize variables
1147 //
1148
1149 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1150
1151
1152 if(WinXpOrBetter == deviceExtension->WdmVersion) {
1153
1154 if(deviceExtension->SSEnable) {
1155
1156 //
1157 // Cancel the timer so that the DPCs are no longer fired.
1158 // Thus, we are making judicious usage of our resources.
1159 // we do not need DPCs because the device is stopping.
1160 // The timers are re-initialized while handling the start
1161 // device irp.
1162 //
1163
1164 KeCancelTimer(&deviceExtension->Timer);
1165
1166 //
1167 // after the device is stopped, it can be surprise removed.
1168 // we set this to 0, so that we do not attempt to cancel
1169 // the timer while handling surprise remove or remove irps.
1170 // when we get the start device request, this flag will be
1171 // reinitialized.
1172 //
1173 deviceExtension->SSEnable = 0;
1174
1175 //
1176 // make sure that if a DPC was fired before we called cancel timer,
1177 // then the DPC and work-time have run to their completion
1178 //
1179 KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
1180 Executive,
1181 KernelMode,
1182 FALSE,
1183 NULL);
1184
1185 //
1186 // make sure that the selective suspend request has been completed.
1187 //
1188 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
1189 Executive,
1190 KernelMode,
1191 FALSE,
1192 NULL);
1193 }
1194 }
1195
1196 //
1197 // after the stop Irp is sent to the lower driver object,
1198 // the driver must not send any more Irps down that touch
1199 // the device until another Start has occurred.
1200 //
1201
1202 if(deviceExtension->WaitWakeEnable) {
1203
1204 CancelWaitWake(deviceExtension);
1205 }
1206
1207 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1208
1209 SET_NEW_PNP_STATE(deviceExtension, Stopped);
1210
1211 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1212
1213 //
1214 // This is the right place to actually give up all the resources used
1215 // This might include calls to IoDisconnectInterrupt, MmUnmapIoSpace,
1216 // etc.
1217 //
1218
1219 ReleaseMemory(DeviceObject);
1220
1221 ntStatus = DeconfigureDevice(DeviceObject);
1222
1223 Irp->IoStatus.Status = ntStatus;
1224 Irp->IoStatus.Information = 0;
1225
1226 IoSkipCurrentIrpStackLocation(Irp);
1227 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1228
1229 dprintf(("HandleStopDevice - ends\n"));
1230
1231 return ntStatus;
1232}
1233
1234NTSTATUS
1235HandleQueryRemoveDevice(
1236 IN PDEVICE_OBJECT DeviceObject,
1237 IN PIRP Irp
1238 )
1239/*++
1240
1241Routine Description:
1242
1243 This routine services Irp of minor type IRP_MN_QUERY_REMOVE_DEVICE
1244
1245Arguments:
1246
1247 DeviceObject - pointer to device object
1248 Irp - I/O request packet sent by the pnp manager.
1249
1250Return Value:
1251
1252 NT status value
1253
1254--*/
1255{
1256 KIRQL oldIrql;
1257 NTSTATUS ntStatus;
1258 PDEVICE_EXTENSION deviceExtension;
1259
1260 dprintf(("HandleQueryRemoveDevice - begins\n"));
1261
1262 //
1263 // initialize variables
1264 //
1265
1266 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1267
1268 //
1269 // If we can allow removal of the device, we should set the QueueState
1270 // to HoldRequests so further requests will be queued. This is required
1271 // so that we can process queued up requests in cancel-remove just in
1272 // case somebody else in the stack fails the query-remove.
1273 //
1274
1275 ntStatus = CanRemoveDevice(DeviceObject, Irp);
1276
1277 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1278
1279 deviceExtension->QueueState = HoldRequests;
1280 SET_NEW_PNP_STATE(deviceExtension, PendingRemove);
1281
1282 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1283
1284 dprintf(("HandleQueryRemoveDevice::"));
1285 VBoxUSB_IoDecrement(deviceExtension);
1286
1287 //
1288 // wait for all the requests to be completed
1289 //
1290
1291 KeWaitForSingleObject(&deviceExtension->StopEvent,
1292 Executive,
1293 KernelMode,
1294 FALSE,
1295 NULL);
1296
1297 Irp->IoStatus.Status = STATUS_SUCCESS;
1298 Irp->IoStatus.Information = 0;
1299
1300 IoSkipCurrentIrpStackLocation(Irp);
1301 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1302
1303 dprintf(("HandleQueryRemoveDevice - ends\n"));
1304
1305 return ntStatus;
1306}
1307
1308NTSTATUS
1309HandleCancelRemoveDevice(
1310 IN PDEVICE_OBJECT DeviceObject,
1311 IN PIRP Irp
1312 )
1313/*++
1314
1315Routine Description:
1316
1317 This routine services Irp of minor type IRP_MN_CANCEL_REMOVE_DEVICE
1318
1319Arguments:
1320
1321 DeviceObject - pointer to device object
1322 Irp - I/O request packet sent by the pnp manager.
1323
1324Return Value:
1325
1326 NT status value
1327
1328--*/
1329{
1330 KIRQL oldIrql;
1331 KEVENT event;
1332 NTSTATUS ntStatus;
1333 PDEVICE_EXTENSION deviceExtension;
1334
1335 dprintf(("HandleCancelRemoveDevice - begins\n"));
1336
1337 //
1338 // initialize variables
1339 //
1340
1341 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1342
1343 //
1344 // We need to reset the QueueState flag to ProcessRequest,
1345 // since the device resume its normal activities.
1346 //
1347
1348 //
1349 // First check to see whether you have received cancel-remove
1350 // without first receiving a query-remove. This could happen if
1351 // someone above us fails a query-remove and passes down the
1352 // subsequent cancel-remove.
1353 //
1354
1355 if(PendingRemove == deviceExtension->DeviceState) {
1356
1357 KeInitializeEvent(&event, NotificationEvent, FALSE);
1358
1359 IoCopyCurrentIrpStackLocationToNext(Irp);
1360 IoSetCompletionRoutine(Irp,
1361 (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
1362 (PVOID)&event,
1363 TRUE,
1364 TRUE,
1365 TRUE);
1366 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1367
1368 if(ntStatus == STATUS_PENDING) {
1369
1370 KeWaitForSingleObject(&event,
1371 Executive,
1372 KernelMode,
1373 FALSE,
1374 NULL);
1375
1376 ntStatus = Irp->IoStatus.Status;
1377 }
1378
1379 if(NT_SUCCESS(ntStatus)) {
1380
1381 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1382
1383 deviceExtension->QueueState = AllowRequests;
1384 RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
1385
1386 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1387 //
1388 // process the queued requests that arrive between
1389 // QUERY_REMOVE and CANCEL_REMOVE
1390 //
1391
1392 ProcessQueuedRequests(deviceExtension);
1393
1394 }
1395 }
1396 else {
1397
1398 //
1399 // spurious cancel-remove
1400 //
1401 ntStatus = STATUS_SUCCESS;
1402 }
1403
1404 dprintf(("HandleCancelRemoveDevice - ends\n"));
1405
1406 return ntStatus;
1407}
1408
1409NTSTATUS
1410HandleSurpriseRemoval(
1411 IN PDEVICE_OBJECT DeviceObject,
1412 IN PIRP Irp
1413 )
1414/*++
1415
1416Routine Description:
1417
1418 This routine services Irp of minor type IRP_MN_SURPRISE_REMOVAL
1419
1420Arguments:
1421
1422 DeviceObject - pointer to device object
1423 Irp - I/O request packet sent by the pnp manager.
1424
1425Return Value:
1426
1427 NT status value
1428
1429--*/
1430{
1431 KIRQL oldIrql;
1432 NTSTATUS ntStatus;
1433 PDEVICE_EXTENSION deviceExtension;
1434
1435 dprintf(("HandleSurpriseRemoval - begins\n"));
1436
1437 //
1438 // initialize variables
1439 //
1440
1441 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1442
1443 //
1444 // 1. fail pending requests
1445 // 2. return device and memory resources
1446 // 3. disable interfaces
1447 //
1448
1449 if(deviceExtension->WaitWakeEnable) {
1450
1451 CancelWaitWake(deviceExtension);
1452 }
1453
1454
1455 if(WinXpOrBetter == deviceExtension->WdmVersion) {
1456
1457 if(deviceExtension->SSEnable) {
1458
1459 //
1460 // Cancel the timer so that the DPCs are no longer fired.
1461 // we do not need DPCs because the device has been surprise
1462 // removed
1463 //
1464
1465 KeCancelTimer(&deviceExtension->Timer);
1466
1467 deviceExtension->SSEnable = 0;
1468
1469 //
1470 // make sure that if a DPC was fired before we called cancel timer,
1471 // then the DPC and work-time have run to their completion
1472 //
1473 KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
1474 Executive,
1475 KernelMode,
1476 FALSE,
1477 NULL);
1478
1479 //
1480 // make sure that the selective suspend request has been completed.
1481 //
1482 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
1483 Executive,
1484 KernelMode,
1485 FALSE,
1486 NULL);
1487 }
1488 }
1489
1490 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1491
1492 deviceExtension->QueueState = FailRequests;
1493 SET_NEW_PNP_STATE(deviceExtension, SurpriseRemoved);
1494
1495 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1496
1497 ProcessQueuedRequests(deviceExtension);
1498
1499 ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
1500 FALSE);
1501
1502 if(!NT_SUCCESS(ntStatus)) {
1503
1504 dprintf(("IoSetDeviceInterfaceState::disable:failed\n"));
1505 }
1506
1507 RtlFreeUnicodeString(&deviceExtension->InterfaceName);
1508
1509 VBoxUSB_AbortPipes(DeviceObject);
1510
1511 Irp->IoStatus.Status = STATUS_SUCCESS;
1512 Irp->IoStatus.Information = 0;
1513
1514 IoSkipCurrentIrpStackLocation(Irp);
1515 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1516
1517 dprintf(("HandleSurpriseRemoval - ends\n"));
1518
1519 return ntStatus;
1520}
1521
1522NTSTATUS
1523HandleRemoveDevice(
1524 IN PDEVICE_OBJECT DeviceObject,
1525 IN PIRP Irp
1526 )
1527/*++
1528
1529Routine Description:
1530
1531 This routine services Irp of minor type IRP_MN_REMOVE_DEVICE
1532
1533Arguments:
1534
1535 DeviceObject - pointer to device object
1536 Irp - I/O request packet sent by the pnp manager.
1537
1538Return Value:
1539
1540 NT status value
1541
1542--*/
1543{
1544 KIRQL oldIrql;
1545 ULONG requestCount;
1546 NTSTATUS ntStatus;
1547 PDEVICE_EXTENSION deviceExtension;
1548
1549 dprintf(("HandleRemoveDevice - begins\n"));
1550
1551 //
1552 // initialize variables
1553 //
1554
1555 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1556
1557 //
1558 // The Plug & Play system has dictated the removal of this device. We
1559 // have no choice but to detach and delete the device object.
1560 // (If we wanted to express an interest in preventing this removal,
1561 // we should have failed the query remove IRP).
1562 //
1563
1564 if(SurpriseRemoved != deviceExtension->DeviceState) {
1565
1566 //
1567 // we are here after QUERY_REMOVE
1568 //
1569
1570 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1571
1572 deviceExtension->QueueState = FailRequests;
1573
1574 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1575
1576 if(deviceExtension->WaitWakeEnable) {
1577
1578 CancelWaitWake(deviceExtension);
1579 }
1580
1581 if(WinXpOrBetter == deviceExtension->WdmVersion) {
1582
1583 if(deviceExtension->SSEnable) {
1584
1585 //
1586 // Cancel the timer so that the DPCs are no longer fired.
1587 // we do not need DPCs because the device has been removed
1588 //
1589 KeCancelTimer(&deviceExtension->Timer);
1590
1591 deviceExtension->SSEnable = 0;
1592
1593 //
1594 // make sure that if a DPC was fired before we called cancel timer,
1595 // then the DPC and work-time have run to their completion
1596 //
1597 KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,
1598 Executive,
1599 KernelMode,
1600 FALSE,
1601 NULL);
1602
1603 //
1604 // make sure that the selective suspend request has been completed.
1605 //
1606 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
1607 Executive,
1608 KernelMode,
1609 FALSE,
1610 NULL);
1611 }
1612 }
1613
1614 ProcessQueuedRequests(deviceExtension);
1615
1616 ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,
1617 FALSE);
1618
1619 if(!NT_SUCCESS(ntStatus)) {
1620
1621 dprintf(("IoSetDeviceInterfaceState::disable:failed\n"));
1622 }
1623
1624 RtlFreeUnicodeString(&deviceExtension->InterfaceName);
1625
1626 VBoxUSB_AbortPipes(DeviceObject);
1627 }
1628
1629 KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
1630
1631 SET_NEW_PNP_STATE(deviceExtension, Removed);
1632
1633 KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
1634
1635#ifdef SUPPORT_WMI
1636 VBoxUSB_WmiDeRegistration(deviceExtension);
1637#endif
1638 //
1639 // need 2 decrements
1640 //
1641
1642 dprintf(("HandleRemoveDevice::"));
1643 requestCount = VBoxUSB_IoDecrement(deviceExtension);
1644
1645 ASSERT(requestCount > 0);
1646
1647 dprintf(("HandleRemoveDevice::"));
1648 requestCount = VBoxUSB_IoDecrement(deviceExtension);
1649
1650 KeWaitForSingleObject(&deviceExtension->RemoveEvent,
1651 Executive,
1652 KernelMode,
1653 FALSE,
1654 NULL);
1655
1656 ReleaseMemory(DeviceObject);
1657 //
1658 // We need to send the remove down the stack before we detach,
1659 // but we don't need to wait for the completion of this operation
1660 // (and to register a completion routine).
1661 //
1662
1663 Irp->IoStatus.Status = STATUS_SUCCESS;
1664 Irp->IoStatus.Information = 0;
1665
1666 IoSkipCurrentIrpStackLocation(Irp);
1667 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1668
1669 //
1670 // Detach the FDO from the device stack
1671 //
1672 IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
1673 IoDeleteDevice(DeviceObject);
1674
1675 dprintf(("HandleRemoveDevice - ends\n"));
1676
1677 return ntStatus;
1678}
1679
1680NTSTATUS
1681HandleQueryCapabilities(
1682 IN PDEVICE_OBJECT DeviceObject,
1683 IN PIRP Irp
1684 )
1685/*++
1686
1687Routine Description:
1688
1689 This routine services Irp of minor type IRP_MN_QUERY_CAPABILITIES
1690
1691Arguments:
1692
1693 DeviceObject - pointer to device object
1694 Irp - I/O request packet sent by the pnp manager.
1695
1696Return Value:
1697
1698 NT status value
1699
1700--*/
1701{
1702 ULONG i;
1703 KEVENT event;
1704 NTSTATUS ntStatus;
1705 PDEVICE_EXTENSION deviceExtension;
1706 PDEVICE_CAPABILITIES pdc;
1707 PIO_STACK_LOCATION irpStack;
1708
1709 dprintf(("HandleQueryCapabilities - begins\n"));
1710
1711 //
1712 // initialize variables
1713 //
1714
1715 irpStack = IoGetCurrentIrpStackLocation(Irp);
1716 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1717 pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
1718
1719 //
1720 // We will provide here an example of an IRP that is processed
1721 // both on its way down and on its way up: there might be no need for
1722 // a function driver process this Irp (the bus driver will do that).
1723 // The driver will wait for the lower drivers (the bus driver among
1724 // them) to process this IRP, then it processes it again.
1725 //
1726
1727 if(pdc->Version < 1 || pdc->Size < sizeof(DEVICE_CAPABILITIES)) {
1728
1729 dprintf(("HandleQueryCapabilities::request failed\n"));
1730 ntStatus = STATUS_UNSUCCESSFUL;
1731 return ntStatus;
1732 }
1733
1734 //
1735 // Add in the SurpriseRemovalOK bit before passing it down.
1736 //
1737 pdc->SurpriseRemovalOK = TRUE;
1738 Irp->IoStatus.Status = STATUS_SUCCESS;
1739
1740 KeInitializeEvent(&event, NotificationEvent, FALSE);
1741
1742 IoCopyCurrentIrpStackLocationToNext(Irp);
1743 IoSetCompletionRoutine(Irp,
1744 (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
1745 (PVOID)&event,
1746 TRUE,
1747 TRUE,
1748 TRUE);
1749 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
1750
1751 if(ntStatus == STATUS_PENDING) {
1752
1753 KeWaitForSingleObject(&event,
1754 Executive,
1755 KernelMode,
1756 FALSE,
1757 NULL);
1758 ntStatus = Irp->IoStatus.Status;
1759 }
1760
1761 //
1762 // initialize PowerDownLevel to disabled
1763 //
1764
1765 deviceExtension->PowerDownLevel = PowerDeviceUnspecified;
1766
1767 if(NT_SUCCESS(ntStatus)) {
1768
1769 deviceExtension->DeviceCapabilities = *pdc;
1770
1771 for(i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++) {
1772
1773 if(deviceExtension->DeviceCapabilities.DeviceState[i] <
1774 PowerDeviceD3) {
1775
1776 deviceExtension->PowerDownLevel =
1777 deviceExtension->DeviceCapabilities.DeviceState[i];
1778 }
1779 }
1780
1781 //
1782 // since its safe to surprise-remove this device, we shall
1783 // set the SurpriseRemoveOK flag to suppress any dialog to
1784 // user.
1785 //
1786
1787 pdc->SurpriseRemovalOK = 1;
1788 }
1789
1790 if(deviceExtension->PowerDownLevel == PowerDeviceUnspecified ||
1791 deviceExtension->PowerDownLevel <= PowerDeviceD0) {
1792
1793 deviceExtension->PowerDownLevel = PowerDeviceD2;
1794 }
1795
1796 dprintf(("HandleQueryCapabilities - ends\n"));
1797
1798 return ntStatus;
1799}
1800
1801
1802VOID
1803DpcRoutine(
1804 IN PKDPC Dpc,
1805 IN PVOID DeferredContext,
1806 IN PVOID SystemArgument1,
1807 IN PVOID SystemArgument2
1808 )
1809/*++
1810
1811Routine Description:
1812
1813 DPC routine triggered by the timer to check the idle state
1814 of the device and submit an idle request for the device.
1815
1816Arguments:
1817
1818 DeferredContext - context for the dpc routine.
1819 DeviceObject in our case.
1820
1821Return Value:
1822
1823 None
1824
1825--*/
1826{
1827 NTSTATUS ntStatus;
1828 PDEVICE_OBJECT deviceObject;
1829 PDEVICE_EXTENSION deviceExtension;
1830 PIO_WORKITEM item;
1831
1832 dprintf(("DpcRoutine - begins\n"));
1833
1834 deviceObject = (PDEVICE_OBJECT)DeferredContext;
1835 deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
1836
1837 //
1838 // Clear this event since a DPC has been fired!
1839 //
1840 KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);
1841
1842 if(CanDeviceSuspend(deviceExtension)) {
1843
1844 dprintf(("Device is Idle\n"));
1845
1846 item = IoAllocateWorkItem(deviceObject);
1847
1848 if(item) {
1849
1850 IoQueueWorkItem(item,
1851 IdleRequestWorkerRoutine,
1852 DelayedWorkQueue,
1853 item);
1854
1855 ntStatus = STATUS_PENDING;
1856
1857 }
1858 else {
1859
1860 dprintf(("Cannot alloc memory for work item\n"));
1861
1862 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1863
1864 //
1865 // signal the NoDpcWorkItemPendingEvent.
1866 //
1867 KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
1868 IO_NO_INCREMENT,
1869 FALSE);
1870 }
1871 }
1872 else {
1873
1874 dprintf(("Idle event not signaled\n"));
1875
1876 //
1877 // signal the NoDpcWorkItemPendingEvent.
1878 //
1879 KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
1880 IO_NO_INCREMENT,
1881 FALSE);
1882 }
1883
1884 dprintf(("DpcRoutine - ends\n"));
1885}
1886
1887
1888VOID
1889IdleRequestWorkerRoutine(
1890 IN PDEVICE_OBJECT DeviceObject,
1891 IN PVOID Context
1892 )
1893/*++
1894
1895Routine Description:
1896
1897 This is the work item fired from the DPC.
1898 This workitem checks the idle state of the device
1899 and submits an idle request.
1900
1901Arguments:
1902
1903 DeviceObject - pointer to device object
1904 Context - context for the work item.
1905
1906Return Value:
1907
1908 None
1909
1910--*/
1911{
1912 NTSTATUS ntStatus;
1913 PDEVICE_EXTENSION deviceExtension;
1914 PIO_WORKITEM workItem;
1915
1916 dprintf(("IdleRequestWorkerRoutine - begins\n"));
1917
1918 //
1919 // initialize variables
1920 //
1921 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1922 workItem = (PIO_WORKITEM) Context;
1923
1924 if(CanDeviceSuspend(deviceExtension)) {
1925
1926 dprintf(("Device is idle\n"));
1927
1928 ntStatus = SubmitIdleRequestIrp(deviceExtension);
1929
1930 if(!NT_SUCCESS(ntStatus)) {
1931
1932 dprintf(("SubmitIdleRequestIrp failed\n"));
1933 }
1934 }
1935 else {
1936
1937 dprintf(("Device is not idle\n"));
1938 }
1939
1940 IoFreeWorkItem(workItem);
1941
1942 //
1943 // signal the NoDpcWorkItemPendingEvent.
1944 //
1945 KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
1946 IO_NO_INCREMENT,
1947 FALSE);
1948
1949 dprintf(("IdleRequestsWorkerRoutine - ends\n"));
1950}
1951
1952
1953VOID
1954ProcessQueuedRequests(
1955 IN OUT PDEVICE_EXTENSION DeviceExtension
1956 )
1957/*++
1958
1959Routine Description:
1960
1961 Remove and process the entries in the queue. If this routine is called
1962 when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
1963 or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
1964 If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
1965 are complete with STATUS_DELETE_PENDING
1966
1967Arguments:
1968
1969 DeviceExtension - pointer to device extension
1970
1971Return Value:
1972
1973 None
1974
1975--*/
1976{
1977 KIRQL oldIrql;
1978 PIRP nextIrp,
1979 cancelledIrp;
1980 PVOID cancelRoutine;
1981 LIST_ENTRY cancelledIrpList;
1982 PLIST_ENTRY listEntry;
1983
1984 dprintf(("ProcessQueuedRequests - begins\n"));
1985
1986 //
1987 // initialize variables
1988 //
1989
1990 cancelRoutine = NULL;
1991 InitializeListHead(&cancelledIrpList);
1992
1993 //
1994 // 1. dequeue the entries in the queue
1995 // 2. reset the cancel routine
1996 // 3. process them
1997 // 3a. if the device is active, send them down
1998 // 3b. else complete with STATUS_DELETE_PENDING
1999 //
2000
2001 while(1) {
2002
2003 KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
2004
2005 if(IsListEmpty(&DeviceExtension->NewRequestsQueue)) {
2006
2007 KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
2008 break;
2009 }
2010
2011 //
2012 // Remove a request from the queue
2013 //
2014
2015 listEntry = RemoveHeadList(&DeviceExtension->NewRequestsQueue);
2016 nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
2017
2018 //
2019 // set the cancel routine to NULL
2020 //
2021
2022 cancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
2023
2024 //
2025 // check if its already cancelled
2026 //
2027
2028 if(nextIrp->Cancel) {
2029 if(cancelRoutine) {
2030
2031 //
2032 // the cancel routine for this IRP hasn't been called yet
2033 // so queue the IRP in the cancelledIrp list and complete
2034 // after releasing the lock
2035 //
2036
2037 InsertTailList(&cancelledIrpList, listEntry);
2038 }
2039 else {
2040
2041 //
2042 // the cancel routine has run
2043 // it must be waiting to hold the queue lock
2044 // so initialize the IRPs listEntry
2045 //
2046
2047 InitializeListHead(listEntry);
2048 }
2049
2050 KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
2051 }
2052 else {
2053
2054 KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
2055
2056 if(FailRequests == DeviceExtension->QueueState) {
2057
2058 nextIrp->IoStatus.Information = 0;
2059 nextIrp->IoStatus.Status = STATUS_DELETE_PENDING;
2060 IoCompleteRequest(nextIrp, IO_NO_INCREMENT);
2061 }
2062 else {
2063
2064 dprintf(("ProcessQueuedRequests::"));
2065 VBoxUSB_IoIncrement(DeviceExtension);
2066
2067 IoSkipCurrentIrpStackLocation(nextIrp);
2068 IoCallDriver(DeviceExtension->TopOfStackDeviceObject, nextIrp);
2069
2070 dprintf(("ProcessQueuedRequests::"));
2071 VBoxUSB_IoDecrement(DeviceExtension);
2072 }
2073 }
2074 } // while loop
2075
2076 //
2077 // walk through the cancelledIrp list and cancel them
2078 //
2079
2080 while(!IsListEmpty(&cancelledIrpList)) {
2081
2082 PLIST_ENTRY cancelEntry = RemoveHeadList(&cancelledIrpList);
2083
2084 cancelledIrp = CONTAINING_RECORD(cancelEntry, IRP, Tail.Overlay.ListEntry);
2085
2086 cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
2087 cancelledIrp->IoStatus.Information = 0;
2088
2089 IoCompleteRequest(cancelledIrp, IO_NO_INCREMENT);
2090 }
2091
2092 dprintf(("ProcessQueuedRequests - ends\n"));
2093
2094 return;
2095}
2096
2097NTSTATUS
2098VBoxUSB_GetRegistryDword(
2099 IN PWCHAR RegPath,
2100 IN PWCHAR ValueName,
2101 IN OUT PULONG Value
2102 )
2103/*++
2104
2105Routine Description:
2106
2107 This routine reads the specified registry value.
2108
2109Arguments:
2110
2111 RegPath - registry path
2112 ValueName - property to be fetched from the registry
2113 Value - corresponding value read from the registry.
2114
2115Return Value:
2116
2117 NT status value
2118
2119--*/
2120{
2121 ULONG defaultData;
2122 WCHAR buffer[MAXIMUM_FILENAME_LENGTH];
2123 NTSTATUS ntStatus;
2124 UNICODE_STRING regPath;
2125 RTL_QUERY_REGISTRY_TABLE paramTable[2];
2126
2127 dprintf(("VBoxUSB_GetRegistryDword - begins\n"));
2128
2129 regPath.Length = 0;
2130 regPath.MaximumLength = MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR);
2131 regPath.Buffer = buffer;
2132
2133 RtlZeroMemory(regPath.Buffer, regPath.MaximumLength);
2134 RtlMoveMemory(regPath.Buffer,
2135 RegPath,
2136 wcslen(RegPath) * sizeof(WCHAR));
2137
2138 RtlZeroMemory(paramTable, sizeof(paramTable));
2139
2140 paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2141 paramTable[0].Name = ValueName;
2142 paramTable[0].EntryContext = Value;
2143 paramTable[0].DefaultType = REG_DWORD;
2144 paramTable[0].DefaultData = &defaultData;
2145 paramTable[0].DefaultLength = sizeof(ULONG);
2146
2147 ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE |
2148 RTL_REGISTRY_OPTIONAL,
2149 regPath.Buffer,
2150 paramTable,
2151 NULL,
2152 NULL);
2153
2154 if(NT_SUCCESS(ntStatus)) {
2155
2156 dprintf(("success Value = %X\n", *Value));
2157 return STATUS_SUCCESS;
2158 }
2159 else {
2160
2161 *Value = 0;
2162 return STATUS_UNSUCCESSFUL;
2163 }
2164}
2165
2166
2167NTSTATUS
2168VBoxUSB_DispatchClean(
2169 IN PDEVICE_OBJECT DeviceObject,
2170 IN PIRP Irp
2171 )
2172/*++
2173
2174Routine Description:
2175
2176 Dispatch routine for IRP_MJ_CLEANUP
2177
2178Arguments:
2179
2180 DeviceObject - pointer to device object
2181 Irp - I/O request packet sent by the pnp manager
2182
2183Return Value:
2184
2185 NT status value
2186
2187--*/
2188{
2189 PDEVICE_EXTENSION deviceExtension;
2190 KIRQL oldIrql;
2191 LIST_ENTRY cleanupList;
2192 PLIST_ENTRY thisEntry,
2193 nextEntry,
2194 listHead;
2195 PIRP pendingIrp;
2196 PIO_STACK_LOCATION pendingIrpStack,
2197 irpStack;
2198
2199 //
2200 // initialize variables
2201 //
2202
2203 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
2204 irpStack = IoGetCurrentIrpStackLocation(Irp);
2205 InitializeListHead(&cleanupList);
2206
2207 dprintf(("VBoxUSB_DispatchClean::"));
2208 VBoxUSB_IoIncrement(deviceExtension);
2209
2210 //
2211 // acquire queue lock
2212 //
2213 KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql);
2214
2215 //
2216 // remove all Irp's that belong to input Irp's fileobject
2217 //
2218
2219 listHead = &deviceExtension->NewRequestsQueue;
2220
2221 for(thisEntry = listHead->Flink, nextEntry = thisEntry->Flink;
2222 thisEntry != listHead;
2223 thisEntry = nextEntry, nextEntry = thisEntry->Flink) {
2224
2225 pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
2226
2227 pendingIrpStack = IoGetCurrentIrpStackLocation(pendingIrp);
2228
2229 if(irpStack->FileObject == pendingIrpStack->FileObject) {
2230
2231 RemoveEntryList(thisEntry);
2232
2233 //
2234 // set the cancel routine to NULL
2235 //
2236 if(NULL == IoSetCancelRoutine(pendingIrp, NULL)) {
2237
2238 InitializeListHead(thisEntry);
2239 }
2240 else {
2241
2242 InsertTailList(&cleanupList, thisEntry);
2243 }
2244 }
2245 }
2246
2247 //
2248 // Release the spin lock
2249 //
2250
2251 KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
2252
2253 //
2254 // walk thru the cleanup list and cancel all the Irps
2255 //
2256
2257 while(!IsListEmpty(&cleanupList)) {
2258
2259 //
2260 // complete the Irp
2261 //
2262 thisEntry = RemoveHeadList(&cleanupList);
2263
2264 pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
2265
2266 pendingIrp->IoStatus.Information = 0;
2267 pendingIrp->IoStatus.Status = STATUS_CANCELLED;
2268
2269 IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
2270 }
2271
2272 Irp->IoStatus.Information = 0;
2273 Irp->IoStatus.Status = STATUS_SUCCESS;
2274
2275 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2276
2277 dprintf(("VBoxUSB_DispatchClean::"));
2278 VBoxUSB_IoDecrement(deviceExtension);
2279
2280 return STATUS_SUCCESS;
2281}
2282
2283
2284BOOLEAN
2285CanDeviceSuspend(
2286 IN PDEVICE_EXTENSION DeviceExtension
2287 )
2288/*++
2289
2290Routine Description:
2291
2292 This is the routine where we check if the device
2293 can selectively suspend.
2294
2295Arguments:
2296
2297 DeviceExtension - pointer to device extension
2298
2299Return Value:
2300
2301 TRUE - if the device can suspend
2302 FALSE - otherwise.
2303
2304--*/
2305{
2306 dprintf(("CanDeviceSuspend\n"));
2307
2308 if((DeviceExtension->OpenHandleCount == 0) &&
2309 (DeviceExtension->OutStandingIO == 1)) {
2310
2311 return TRUE;
2312 }
2313 else {
2314
2315 return FALSE;
2316 }
2317}
2318
2319NTSTATUS
2320VBoxUSB_AbortPipes(
2321 IN PDEVICE_OBJECT DeviceObject
2322 )
2323/*++
2324
2325Routine Description
2326
2327 sends an abort pipe request for open pipes.
2328
2329Arguments:
2330
2331 DeviceObject - pointer to device object
2332
2333Return Value:
2334
2335 NT status value
2336
2337--*/
2338{
2339 PURB urb;
2340 ULONG i;
2341 NTSTATUS ntStatus;
2342 PDEVICE_EXTENSION deviceExtension;
2343 PVBOXUSB_PIPE_CONTEXT pipeContext;
2344 PUSBD_INTERFACE_INFORMATION interfaceInfo;
2345
2346 //
2347 // initialize variables
2348 //
2349 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
2350 pipeContext = deviceExtension->PipeContext;
2351 interfaceInfo = deviceExtension->UsbInterface;
2352
2353 dprintf(("VBoxUSB_AbortPipes - begins\n"));
2354
2355 if(interfaceInfo == NULL || pipeContext == NULL) {
2356
2357 return STATUS_SUCCESS;
2358 }
2359
2360 for(i=0; i<interfaceInfo->NumberOfPipes; i++) {
2361
2362 if(pipeContext[i].PipeOpen) {
2363
2364 dprintf(("Aborting open pipe %d\n", i));
2365
2366 urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
2367
2368 if(urb) {
2369
2370 urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
2371 urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
2372 urb->UrbPipeRequest.PipeHandle =
2373 interfaceInfo->Pipes[i].PipeHandle;
2374
2375 ntStatus = CallUSBD(DeviceObject, urb);
2376
2377 ExFreePool(urb);
2378 }
2379 else {
2380
2381 dprintf(("Failed to alloc memory for urb\n"));
2382
2383 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
2384 return ntStatus;
2385 }
2386
2387 if(NT_SUCCESS(ntStatus)) {
2388
2389 pipeContext[i].PipeOpen = FALSE;
2390 }
2391 }
2392 }
2393
2394 dprintf(("VBoxUSB_AbortPipes - ends\n"));
2395
2396 return STATUS_SUCCESS;
2397}
2398
2399NTSTATUS
2400IrpCompletionRoutine(
2401 IN PDEVICE_OBJECT DeviceObject,
2402 IN PIRP Irp,
2403 IN PVOID Context
2404 )
2405/*++
2406
2407Routine Description:
2408
2409 This routine is a completion routine.
2410 In this routine we set an event.
2411
2412 Since the completion routine returns
2413 STATUS_MORE_PROCESSING_REQUIRED, the Irps,
2414 which set this routine as the completion routine,
2415 should be marked pending.
2416
2417Arguments:
2418
2419 DeviceObject - pointer to device object
2420 Irp - I/O request packet
2421 Context -
2422
2423Return Value:
2424
2425 NT status value
2426
2427--*/
2428{
2429 PKEVENT event = (PKEVENT)Context;
2430
2431 KeSetEvent(event, 0, FALSE);
2432
2433 return STATUS_MORE_PROCESSING_REQUIRED;
2434}
2435
2436
2437LONG
2438VBoxUSB_IoIncrement(
2439 IN OUT PDEVICE_EXTENSION DeviceExtension
2440 )
2441/*++
2442
2443Routine Description:
2444
2445 This routine bumps up the I/O count.
2446 This routine is typically invoked when any of the
2447 dispatch routines handle new irps for the driver.
2448
2449Arguments:
2450
2451 DeviceExtension - pointer to device extension
2452
2453Return Value:
2454
2455 new value
2456
2457--*/
2458{
2459 LONG result = 0;
2460 KIRQL oldIrql;
2461
2462 KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
2463
2464 result = InterlockedIncrement((volatile LONG *)&DeviceExtension->OutStandingIO);
2465
2466 //
2467 // when OutStandingIO bumps from 1 to 2, clear the StopEvent
2468 //
2469
2470 if(result == 2) {
2471
2472 KeClearEvent(&DeviceExtension->StopEvent);
2473 }
2474
2475 KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
2476
2477 dprintf(("VBoxUSB_IoIncrement::%d\n", result));
2478
2479 return result;
2480}
2481
2482LONG
2483VBoxUSB_IoDecrement(
2484 IN OUT PDEVICE_EXTENSION DeviceExtension
2485 )
2486/*++
2487
2488Routine Description:
2489
2490 This routine decrements the outstanding I/O count
2491 This is typically invoked after the dispatch routine
2492 has finished processing the irp.
2493
2494Arguments:
2495
2496 DeviceExtension - pointer to device extension
2497
2498Return Value:
2499
2500 new value
2501
2502--*/
2503{
2504 LONG result = 0;
2505 KIRQL oldIrql;
2506
2507 KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
2508
2509 result = InterlockedDecrement((volatile LONG *)&DeviceExtension->OutStandingIO);
2510
2511 if(result == 1) {
2512
2513 KeSetEvent(&DeviceExtension->StopEvent, IO_NO_INCREMENT, FALSE);
2514 }
2515
2516 if(result == 0) {
2517
2518 ASSERT(Removed == DeviceExtension->DeviceState);
2519
2520 KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
2521 }
2522
2523 KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
2524
2525 dprintf(("VBoxUSB_IoDecrement::%d\n", result));
2526
2527 return result;
2528}
2529
2530NTSTATUS
2531CanStopDevice(
2532 IN PDEVICE_OBJECT DeviceObject,
2533 IN PIRP Irp
2534 )
2535/*++
2536
2537Routine Description:
2538
2539 This routine determines whether the device can be safely stopped. In our
2540 particular case, we'll assume we can always stop the device.
2541 A device might fail the request if it doesn't have a queue for the
2542 requests it might come or if it was notified that it is in the paging
2543 path.
2544
2545Arguments:
2546
2547 DeviceObject - pointer to the device object.
2548
2549 Irp - pointer to the current IRP.
2550
2551Return Value:
2552
2553 STATUS_SUCCESS if the device can be safely stopped, an appropriate
2554 NT Status if not.
2555
2556--*/
2557{
2558 //
2559 // We assume we can stop the device
2560 //
2561
2562 UNREFERENCED_PARAMETER(DeviceObject);
2563 UNREFERENCED_PARAMETER(Irp);
2564
2565 return STATUS_SUCCESS;
2566}
2567
2568NTSTATUS
2569CanRemoveDevice(
2570 IN PDEVICE_OBJECT DeviceObject,
2571 IN PIRP Irp
2572 )
2573/*++
2574
2575Routine Description:
2576
2577 This routine determines whether the device can be safely removed. In our
2578 particular case, we'll assume we can always remove the device.
2579 A device shouldn't be removed if, for example, it has open handles or
2580 removing the device could result in losing data (plus the reasons
2581 mentioned at CanStopDevice). The PnP manager on Windows 2000 fails
2582 on its own any attempt to remove, if there any open handles to the device.
2583 However on Win9x, the driver must keep count of open handles and fail
2584 query_remove if there are any open handles.
2585
2586Arguments:
2587
2588 DeviceObject - pointer to the device object.
2589
2590 Irp - pointer to the current IRP.
2591
2592Return Value:
2593
2594 STATUS_SUCCESS if the device can be safely removed, an appropriate
2595 NT Status if not.
2596
2597--*/
2598{
2599 //
2600 // We assume we can remove the device
2601 //
2602
2603 UNREFERENCED_PARAMETER(DeviceObject);
2604 UNREFERENCED_PARAMETER(Irp);
2605
2606 return STATUS_SUCCESS;
2607}
2608
2609NTSTATUS
2610ReleaseMemory(
2611 IN PDEVICE_OBJECT DeviceObject
2612 )
2613/*++
2614
2615Routine Description:
2616
2617 This routine returns all the memory allocations acquired during
2618 device startup.
2619
2620Arguments:
2621
2622 DeviceObject - pointer to the device object.
2623
2624
2625Return Value:
2626
2627 STATUS_SUCCESS if the device can be safely removed, an appropriate
2628 NT Status if not.
2629
2630--*/
2631{
2632 //
2633 // Disconnect from the interrupt and unmap any I/O ports
2634 //
2635
2636 PDEVICE_EXTENSION deviceExtension;
2637
2638 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
2639
2640 if(deviceExtension->UsbConfigurationDescriptor) {
2641
2642 ExFreePool(deviceExtension->UsbConfigurationDescriptor);
2643 deviceExtension->UsbConfigurationDescriptor = NULL;
2644 }
2645
2646 if(deviceExtension->UsbInterface) {
2647
2648 ExFreePool(deviceExtension->UsbInterface);
2649 deviceExtension->UsbInterface = NULL;
2650 }
2651
2652 if(deviceExtension->PipeContext) {
2653
2654 ExFreePool(deviceExtension->PipeContext);
2655 deviceExtension->PipeContext = NULL;
2656 }
2657
2658 VBoxUSB_FreeMemory(deviceExtension);
2659
2660 return STATUS_SUCCESS;
2661}
2662
2663PCHAR
2664PnPMinorFunctionString (
2665 UCHAR MinorFunction
2666 )
2667/*++
2668
2669Routine Description:
2670
2671Arguments:
2672
2673Return Value:
2674
2675--*/
2676{
2677 switch (MinorFunction) {
2678
2679 case IRP_MN_START_DEVICE:
2680 return "IRP_MN_START_DEVICE\n";
2681
2682 case IRP_MN_QUERY_REMOVE_DEVICE:
2683 return "IRP_MN_QUERY_REMOVE_DEVICE\n";
2684
2685 case IRP_MN_REMOVE_DEVICE:
2686 return "IRP_MN_REMOVE_DEVICE\n";
2687
2688 case IRP_MN_CANCEL_REMOVE_DEVICE:
2689 return "IRP_MN_CANCEL_REMOVE_DEVICE\n";
2690
2691 case IRP_MN_STOP_DEVICE:
2692 return "IRP_MN_STOP_DEVICE\n";
2693
2694 case IRP_MN_QUERY_STOP_DEVICE:
2695 return "IRP_MN_QUERY_STOP_DEVICE\n";
2696
2697 case IRP_MN_CANCEL_STOP_DEVICE:
2698 return "IRP_MN_CANCEL_STOP_DEVICE\n";
2699
2700 case IRP_MN_QUERY_DEVICE_RELATIONS:
2701 return "IRP_MN_QUERY_DEVICE_RELATIONS\n";
2702
2703 case IRP_MN_QUERY_INTERFACE:
2704 return "IRP_MN_QUERY_INTERFACE\n";
2705
2706 case IRP_MN_QUERY_CAPABILITIES:
2707 return "IRP_MN_QUERY_CAPABILITIES\n";
2708
2709 case IRP_MN_QUERY_RESOURCES:
2710 return "IRP_MN_QUERY_RESOURCES\n";
2711
2712 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
2713 return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n";
2714
2715 case IRP_MN_QUERY_DEVICE_TEXT:
2716 return "IRP_MN_QUERY_DEVICE_TEXT\n";
2717
2718 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
2719 return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n";
2720
2721 case IRP_MN_READ_CONFIG:
2722 return "IRP_MN_READ_CONFIG\n";
2723
2724 case IRP_MN_WRITE_CONFIG:
2725 return "IRP_MN_WRITE_CONFIG\n";
2726
2727 case IRP_MN_EJECT:
2728 return "IRP_MN_EJECT\n";
2729
2730 case IRP_MN_SET_LOCK:
2731 return "IRP_MN_SET_LOCK\n";
2732
2733 case IRP_MN_QUERY_ID:
2734 return "IRP_MN_QUERY_ID\n";
2735
2736 case IRP_MN_QUERY_PNP_DEVICE_STATE:
2737 return "IRP_MN_QUERY_PNP_DEVICE_STATE\n";
2738
2739 case IRP_MN_QUERY_BUS_INFORMATION:
2740 return "IRP_MN_QUERY_BUS_INFORMATION\n";
2741
2742 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
2743 return "IRP_MN_DEVICE_USAGE_NOTIFICATION\n";
2744
2745 case IRP_MN_SURPRISE_REMOVAL:
2746 return "IRP_MN_SURPRISE_REMOVAL\n";
2747
2748 default:
2749 return "IRP_MN_?????\n";
2750 }
2751}
2752
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