main.c
上传用户:zanmei2
上传日期:2010-03-06
资源大小:775k
文件大小:19k
源码类别:

通讯编程文档

开发平台:

C/C++

  1. /*++
  2. Copyright (c) 2005  Changzhi Zhou All Rights Reserved
  3. Module Name:
  4.     main.c
  5. Abstract:
  6.     This module is main module that deals with
  7. DriverEntry, AddDevice, Unload, handles to device name.
  8. SampleIoCrement and SampleIoDecrement.
  9. Environment:
  10.     Kernel mode
  11. Revision History:
  12. Changzhi Zhou Dec 20  2004
  13. --*/
  14. #include <wdm.h>
  15. #include <ntddk.h>
  16. #include <initguid.h>
  17. #include "main.h"
  18. #include "..incwdmioctl.h"
  19. #include <wmistr.h>
  20. #include <wmilib.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text (INIT, DriverEntry)
  23. #pragma alloc_text (PAGE, AddDevice)
  24. #pragma alloc_text (PAGE, SamplePnpDispatch)
  25. #pragma alloc_text (PAGE, Unload)
  26. #endif
  27. NTSTATUS
  28. DriverEntry(
  29.     IN PDRIVER_OBJECT  DriverObject,
  30.     IN PUNICODE_STRING RegistryPath
  31.     )
  32. /*++
  33. Routine Description:
  34.     Installable driver initialization entry point.
  35.     This entry point is called directly by the I/O system.
  36. Arguments:
  37.     DriverObject - pointer to the driver object
  38.     RegistryPath - pointer to a unicode string representing the path,
  39.                    to driver-specific key in the registry.
  40. Return Value:
  41.     STATUS_SUCCESS if successful,
  42.     STATUS_UNSUCCESSFUL otherwise.
  43. --*/
  44. {
  45. NTSTATUS            status;
  46.     UNREFERENCED_PARAMETER (RegistryPath);
  47.     DbgPrint("------  VirtualSerial Build on %s %s -------n", __DATE__, __TIME__ );
  48. status = STATUS_SUCCESS;
  49.     DriverObject->MajorFunction[IRP_MJ_PNP] = SamplePnpDispatch;
  50.     DriverObject->MajorFunction[IRP_MJ_POWER] = SamplePowerDispatch;
  51.     DriverObject->MajorFunction[IRP_MJ_CREATE] = SampleCreate;
  52.     DriverObject->MajorFunction[IRP_MJ_CLOSE] = SampleClose;
  53. DriverObject->MajorFunction[IRP_MJ_CLEANUP ] = SampleCleanup;
  54.     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SampleIoControl;
  55. DriverObject->MajorFunction[IRP_MJ_WRITE]           = SampleWrite;
  56. DriverObject->MajorFunction[IRP_MJ_READ]            = SampleRead;
  57.     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ToasterSystemControl;
  58.     DriverObject->DriverExtension->AddDevice = AddDevice;
  59.     DriverObject->DriverUnload = Unload;
  60.     return status;
  61. }
  62. NTSTATUS
  63. AddDevice(
  64.     IN PDRIVER_OBJECT DriverObject,
  65.     IN PDEVICE_OBJECT PhysicalDeviceObject
  66.     )
  67. /*++
  68. Routine Description:
  69.     The Plug & Play subsystem is handing us a brand new PDO, for which we
  70.     (by means of INF registration) have been asked to provide a driver.
  71.     We need to determine if we need to be in the driver stack for the device.
  72.     Create a function device object to attach to the stack
  73.     Initialize that device object
  74.     Return status success.
  75.     Remember: We can NOT actually send ANY non pnp IRPS to the given driver
  76.     stack, UNTIL we have received an IRP_MN_START_DEVICE.
  77. Arguments:
  78.     DeviceObject - pointer to a device object.
  79.     PhysicalDeviceObject -  pointer to a device object created by the
  80.                             underlying bus driver.
  81. Return Value:
  82.     NT status code.
  83. --*/
  84. {
  85.     NTSTATUS                status = STATUS_SUCCESS;
  86.     PDEVICE_OBJECT          deviceObject = NULL;
  87.     PDEVICE_EXTENSION       deviceExtension;
  88. UNICODE_STRING deviceObjName;
  89.     PAGED_CODE ();
  90. DbgPrint("------- AddDevice  build on %s %s ---------n", __DATE__, __TIME__);
  91. if( FALSE == InitializeSerialDevName( &deviceObjName ) )
  92. return STATUS_INSUFFICIENT_RESOURCES;
  93.     status = IoCreateDevice (DriverObject,
  94.                              sizeof (DEVICE_EXTENSION),
  95.                              &deviceObjName,
  96.                              FILE_DEVICE_SERIAL_PORT,
  97.                              FILE_DEVICE_SECURE_OPEN,
  98.                              FALSE,
  99.                              &deviceObject);
  100.     if (!NT_SUCCESS (status)) {
  101. DebugPrint(("IoCreateDevice failedn"));
  102. if ( deviceObjName.Buffer != NULL )
  103. ExFreePool ( deviceObjName.Buffer );
  104.         return status;
  105.     }
  106.     DebugPrint (("AddDevice PDO (0x%x) FDO (0x%x)n", PhysicalDeviceObject, deviceObject));
  107.     deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  108. deviceExtension->DeviceName.MaximumLength = deviceObjName.MaximumLength;
  109. deviceExtension->DeviceName.Length = deviceObjName.Length;
  110. deviceExtension->DeviceName.Buffer = deviceObjName.Buffer;
  111. deviceExtension->CreatedSerialCommEntry = FALSE;
  112. deviceExtension->CreatedSymbolicLink = FALSE;
  113. // for working thread
  114. KeInitializeSpinLock( &deviceExtension->ThreadSpinLock );
  115.     deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack (
  116.                                        deviceObject,
  117.                                        PhysicalDeviceObject);
  118.     if(NULL == deviceExtension->NextLowerDriver) {
  119.         IoDeleteDevice(deviceObject);
  120.         return STATUS_UNSUCCESSFUL;
  121.     }
  122.     DebugPrint(("AddDevice: %x to %x->%x n", deviceObject, 
  123.                        deviceExtension->NextLowerDriver,
  124.                        PhysicalDeviceObject));
  125.     // Initialize the remove event to not-signaled.
  126.     //
  127.     KeInitializeEvent(&deviceExtension->RemoveEvent, 
  128.                       SynchronizationEvent, 
  129.                       FALSE);
  130.     //
  131.     // Initialize the stop event to signaled.
  132.     // This event is signaled when the OutstandingIO becomes 1
  133.     //
  134.     KeInitializeEvent(&deviceExtension->StopEvent, 
  135.                       SynchronizationEvent, 
  136.                       TRUE);
  137.     deviceExtension->OutStandingIO = 1;
  138. deviceExtension->bIsOpen = FALSE;
  139.     
  140. KeInitializeSpinLock( &deviceExtension->IOCountLock );
  141. if ( PhysicalDeviceObject->Flags & DO_POWER_PAGABLE) {
  142.         deviceObject->Flags |= DO_POWER_PAGABLE;
  143.     }
  144.     deviceObject->Flags |= DO_DIRECT_IO;
  145.     deviceExtension->Self = deviceObject;
  146. // Initialize serial-related parameters
  147. deviceExtension->WaitOnMaskIrp = NULL;
  148. deviceExtension->CurrentBaud = 0;
  149. deviceExtension->PendingReadIrp = NULL;
  150. KeInitializeTimer ( &deviceExtension->ReadTimer );
  151. KeInitializeDpc ( &deviceExtension->ReadDpc, ReadDpcRoutine, (PVOID)deviceExtension );
  152. RtlZeroMemory( &deviceExtension->SerialStatus, sizeof( SERIAL_STATUS ) );
  153. // initialize  members relevant to TDI.
  154. deviceExtension->RxBuffer = ExAllocatePoolWithTag( NonPagedPool, RINGBUFFER_SIZE, 'RBuf' );
  155. if ( deviceExtension->RxBuffer == NULL )
  156. goto Error_Exit;
  157. deviceExtension->lpRead = deviceExtension->RxBuffer;
  158. deviceExtension->lpRx = deviceExtension->RxBuffer;
  159. deviceExtension->hTransAddr = NULL;
  160. deviceExtension->lpTransAddrFileObject = NULL;
  161. deviceExtension->TDILowerDeviceObject = NULL;
  162. deviceExtension->RemoteAddress = 0x601a8c0; // 192.168.1.6
  163. deviceExtension->RemotePort = 0x7217; // 6002
  164. RtlZeroMemory( (PVOID)&deviceExtension->recvContext, sizeof( RECV_CONTEXT ) );
  165. deviceExtension->recvContext.RemainderBuffer = ExAllocatePoolWithTag ( NonPagedPool, RECVREMAINDER_BUFFER_SIZE, 'Rrem' );
  166. if ( deviceExtension->recvContext.RemainderBuffer == NULL )
  167. goto Error_Exit;
  168.     KeInitializeEvent(&deviceExtension->recvContext.Event, 
  169.                       SynchronizationEvent,
  170.                       FALSE);
  171. RtlZeroMemory ( (PVOID)&deviceExtension->recvContext.ReceiveDatagramInfo, sizeof ( TDI_CONNECTION_INFORMATION ) );
  172. RtlZeroMemory ( (PVOID)&deviceExtension->recvContext.ReturnInfo, sizeof ( TDI_CONNECTION_INFORMATION ) );
  173.     INITIALIZE_PNP_STATE(deviceExtension);
  174.  
  175. //++ Register device interface for win32app
  176. status = IoRegisterDeviceInterface( PhysicalDeviceObject,
  177. (LPGUID)&GUID_CLASS_COMPORT,
  178. NULL,
  179. &deviceExtension->InterfaceName );
  180. DebugPrint(("InterfaceName:  %wsn", deviceExtension->InterfaceName.Buffer ));
  181. if( !NT_SUCCESS ( status ) ){
  182. DebugPrint(( "AddDevice:  IoRegisterDeviceInterface failed (%x) n", status ));
  183. goto Error_Exit;
  184. }
  185. //--
  186.     deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  187.     return STATUS_SUCCESS;
  188. Error_Exit:
  189. if( deviceExtension->RxBuffer  )
  190. {
  191. ExFreePool ( deviceExtension->RxBuffer );
  192. deviceExtension->RxBuffer = NULL;
  193. }
  194. if ( deviceExtension->recvContext.RemainderBuffer )
  195. {
  196. ExFreePool ( deviceExtension->recvContext.RemainderBuffer );
  197. deviceExtension->recvContext.RemainderBuffer = NULL;
  198. }
  199. IoDetachDevice( deviceExtension->NextLowerDriver );
  200. IoDeleteDevice( deviceObject );
  201. return status;
  202. }
  203. NTSTATUS
  204. SerialDoExternalNaming(
  205. IN PDEVICE_EXTENSION deviceExtension,
  206. IN LONG ComX
  207. )
  208. /*++
  209. Routine Description:
  210. Create external name, SymbolicLinkName and DOS name.
  211. Arguments:
  212.     deviceExtension - pointer to a device object extension.
  213.     ComX -  indicates the number of Serial Ports.
  214. Return Value:
  215.     NT status code.
  216. --*/
  217. {
  218. NTSTATUS status;
  219. ULONG bufLen;
  220. WCHAR ComXBuffer[ 4 ];
  221. UNICODE_STRING instanceStr;
  222. DebugPrint(("Enter SerialdoExternalNaming routine...n"));
  223. if( deviceExtension->CreatedSymbolicLink || deviceExtension->CreatedSerialCommEntry ){
  224. DebugPrint(("Already create symboliclink or serial commentryn"));
  225. return STATUS_UNSUCCESSFUL;
  226. }
  227. ASSERT( deviceExtension->SymbolicLinkName.Buffer == NULL );
  228. ASSERT( deviceExtension->DosName.Buffer == NULL );
  229. RtlInitUnicodeString(&instanceStr, NULL);
  230. instanceStr.MaximumLength = sizeof( ComXBuffer );
  231. instanceStr.Buffer = ComXBuffer; // 4 WCHAR
  232. RtlIntegerToUnicodeString( ComX, 10, &instanceStr );
  233. // 将SymbolicLinkName设置为 DosDevicesCOMn 的形式。其中n = ComX
  234. RtlZeroMemory( &deviceExtension->SymbolicLinkName, sizeof( UNICODE_STRING ) );
  235. deviceExtension->SymbolicLinkName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH + sizeof( WCHAR );
  236. deviceExtension->SymbolicLinkName.Buffer = ExAllocatePoolWithTag( PagedPool, deviceExtension->SymbolicLinkName.MaximumLength, 'SymL' );
  237. if( deviceExtension->SymbolicLinkName.Buffer == NULL ){
  238. DebugPrint(("SERIAL: Couldn't allocate memory for symbolic link namen"));
  239. status = STATUS_INSUFFICIENT_RESOURCES;
  240. goto SerialDoExternalNamingError;
  241. }
  242. RtlZeroMemory( deviceExtension->SymbolicLinkName.Buffer, deviceExtension->SymbolicLinkName.MaximumLength );
  243. RtlAppendUnicodeToString( &deviceExtension->SymbolicLinkName, DOS_DEVICE_NAME ); //L"\DosDevices\COM"
  244. RtlAppendUnicodeStringToString( &deviceExtension->SymbolicLinkName, &instanceStr);
  245. DebugPrint(("SymbolicLinkName:   %wZn",  deviceExtension->SymbolicLinkName ));
  246. // 将DosName初始化 COMn 的形式, 其中 n = ComX
  247. deviceExtension->DosName.MaximumLength = 64 + sizeof(WCHAR);
  248. deviceExtension->DosName.Buffer = ExAllocatePoolWithTag( PagedPool, 64 + sizeof( WCHAR ), 'Name' );
  249. if( deviceExtension->DosName.Buffer == NULL ){
  250. DebugPrint(("SERIAL: Couldn't allocate memory for Dos namen"));
  251. status =  STATUS_INSUFFICIENT_RESOURCES;
  252. goto SerialDoExternalNamingError;
  253. }
  254. deviceExtension->DosName.Length = 0;
  255. RtlZeroMemory( deviceExtension->DosName.Buffer, deviceExtension->DosName.MaximumLength );
  256. RtlAppendUnicodeToString( &deviceExtension->DosName, L"COM" );
  257. RtlAppendUnicodeStringToString( &deviceExtension->DosName, &instanceStr);
  258. DebugPrint(("DosName:   %wZn", &deviceExtension->DosName ));
  259. DebugPrint(("DeviceName:    %wZn", &deviceExtension->DeviceName ));
  260. // 生成符号连接,至此本设备对win32应用表现的Dos设备名为 DosDevicesCOMn
  261. status = IoCreateSymbolicLink( &deviceExtension->SymbolicLinkName, &deviceExtension->DeviceName );
  262. if( !NT_SUCCESS( status )){
  263. DebugPrint(("SERIAL:  Couldn't create the symbolic link with error %dn", status));
  264. goto SerialDoExternalNamingError;
  265. }else{
  266. DebugPrint(("Create the symbolic link OKn"));
  267. deviceExtension->CreatedSymbolicLink = TRUE;
  268. }
  269. // 在注册表的 HKEY_LOCAL_MACHINEHARDWAREDEVICEMAPSERIALCOMM 中,添加ComX的键值
  270. // 若不进行这一步,则超级终端程序无法检测到本虚拟串口设备
  271. status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP,
  272. deviceExtension->DeviceName.Buffer, REG_SZ,
  273. deviceExtension->DosName.Buffer,
  274. deviceExtension->DosName.Length + sizeof(WCHAR));
  275. if( !NT_SUCCESS( status )){
  276. DebugPrint(("SERIAL: Couldn't create the device map entryn------- for port %wZn", deviceExtension->DeviceName ));
  277. goto SerialDoExternalNamingError;
  278. }
  279. deviceExtension->ComX = ComX;
  280. deviceExtension->CreatedSerialCommEntry = TRUE;
  281. SerialDoExternalNamingError:
  282. if( !NT_SUCCESS( status )){
  283. if( deviceExtension->DosName.Buffer != NULL ){
  284. ExFreePool( deviceExtension->DosName.Buffer );
  285. deviceExtension->DosName.Buffer = NULL;
  286. deviceExtension->CreatedSerialCommEntry = FALSE;
  287. }
  288. if( deviceExtension->CreatedSymbolicLink ){
  289. IoDeleteSymbolicLink( &deviceExtension->SymbolicLinkName );
  290. deviceExtension->CreatedSymbolicLink = FALSE;
  291. }
  292. if( deviceExtension->SymbolicLinkName.Buffer != NULL ){
  293. ExFreePool( deviceExtension->SymbolicLinkName.Buffer );
  294. deviceExtension->SymbolicLinkName.Buffer = NULL;
  295. }
  296. }
  297. return status;
  298. }
  299. BOOLEAN InitializeSerialDevName( PUNICODE_STRING lpDeviceName )
  300. /*++
  301. Routine Description:
  302. Initialize serial device name. This name is available in Kernel Mode.
  303. Arguments:
  304.     PUNICODE_STRING lpDeviceName - the pointer to device name string.
  305. Return Value:
  306.     return TRUE if it is successful, otherwise return FALSE.
  307. --*/
  308. {
  309. WCHAR instanceNumberBuffer[ 4 ];
  310. UNICODE_STRING instanceStr;
  311. static ULONG currentInstance = 10;
  312. // 首先处理deviceObjName,这是一个核心态使用的设备名,形如"\Device\SiSerial0"
  313. // Zero out allocated memory pointers so we know if they must be freed
  314. RtlZeroMemory( lpDeviceName, sizeof(UNICODE_STRING) );
  315. lpDeviceName->MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
  316. lpDeviceName->Buffer = ExAllocatePool(PagedPool, lpDeviceName->MaximumLength + sizeof(WCHAR));
  317. if ( lpDeviceName->Buffer == NULL) {
  318. DebugPrint(("Couldn't allocate memory for device namen"));
  319. return FALSE;
  320. }
  321. RtlZeroMemory( lpDeviceName->Buffer, lpDeviceName->MaximumLength + sizeof(WCHAR));
  322. // now, the size of deviceObjName.Buffer is (128 + 1)(WCHAR)
  323. RtlAppendUnicodeToString( lpDeviceName, DEVICE_NAME); // L"\Device\VSer"
  324. // 处理 lpDeviceName 的后缀序号
  325. RtlInitUnicodeString(&instanceStr, NULL);
  326. instanceStr.MaximumLength = sizeof(instanceNumberBuffer);
  327. instanceStr.Buffer = instanceNumberBuffer; // 20 WCHAR
  328. currentInstance++;
  329. RtlIntegerToUnicodeString( currentInstance, 10, &instanceStr);
  330. RtlAppendUnicodeStringToString( lpDeviceName, &instanceStr);
  331. DebugPrint(("DeviceName:n"));
  332. DebugPrint(("----------- %wsn", lpDeviceName->Buffer ));
  333. return TRUE;
  334. }
  335. NTSTATUS
  336. SerialUndoExternalNaming(
  337. IN PDEVICE_EXTENSION deviceExtension
  338. )
  339. /*++
  340. Routine Description:
  341. Delete or unregister external name, SymbolicLinkName and DOS name.
  342. Arguments:
  343.     deviceExtension - pointer to a device object extension.
  344. Return Value:
  345.     NT status code.
  346. --*/
  347. {
  348. NTSTATUS status = STATUS_SUCCESS;
  349. if( deviceExtension->CreatedSymbolicLink ){
  350. IoDeleteSymbolicLink( &deviceExtension->SymbolicLinkName );
  351. ExFreePool( deviceExtension->SymbolicLinkName.Buffer );
  352. deviceExtension->SymbolicLinkName.Buffer = NULL;
  353. deviceExtension->CreatedSymbolicLink = FALSE;
  354. }else{
  355. ASSERT( deviceExtension->SymbolicLinkName.Buffer == NULL );
  356. }
  357. ASSERT( deviceExtension->DeviceName.Buffer != NULL );
  358. if( deviceExtension->CreatedSerialCommEntry ){
  359. status = RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, SERIAL_DEVICE_MAP, deviceExtension->DeviceName.Buffer );
  360. if( !NT_SUCCESS( status ) ){
  361. DebugPrint(("RtlDeleteRegistryValue device map failedn"));
  362. }
  363. ExFreePool( deviceExtension->DosName.Buffer );
  364. deviceExtension->DosName.Buffer = NULL;
  365. deviceExtension->CreatedSerialCommEntry = FALSE;
  366. }else{
  367. ASSERT( deviceExtension->DosName.Buffer == NULL );
  368. }
  369. return status;
  370. }
  371. NTSTATUS
  372. SerialRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
  373. /*++
  374. Routine Description:
  375.     Removes a serial device object from the system.
  376. Arguments:
  377.     PDevObj - A pointer to the Device Object we want removed.
  378. Return Value:
  379.     Always TRUE
  380. --*/
  381. {
  382. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  383. PAGED_CODE();
  384. DebugPrint(("SERIAL: Enter SerialRemoveDevObjn"));
  385. //
  386. // Free memory allocated in the extension
  387. //
  388. if (pDevExt->DeviceName.Buffer != NULL) {
  389. ExFreePool(pDevExt->DeviceName.Buffer);
  390. }
  391. if (pDevExt->SymbolicLinkName.Buffer != NULL) {
  392. ExFreePool(pDevExt->SymbolicLinkName.Buffer);
  393. }
  394. if (pDevExt->DosName.Buffer != NULL) {
  395. ExFreePool(pDevExt->DosName.Buffer);
  396. }
  397. DebugPrint(("SERIAL: Leave SerialRemoveDevObjn"));
  398. return STATUS_SUCCESS;
  399. }
  400. NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG info)
  401. {
  402.     Irp->IoStatus.Status = status;
  403.     Irp->IoStatus.Information = info;
  404.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
  405.     return status;
  406. }
  407.     
  408. VOID
  409. Unload(
  410.     IN PDRIVER_OBJECT DriverObject
  411.     )
  412. /*++
  413. Routine Description:
  414.     Free all the allocated resources in DriverEntry, etc.
  415. Arguments:
  416.     DriverObject - pointer to a driver object.
  417. Return Value:
  418.     VOID.
  419. --*/
  420. {
  421.     PAGED_CODE ();
  422.     //
  423.     // The device object(s) should be NULL now
  424.     // (since we unload, all the devices objects associated with this
  425.     // driver must be deleted.
  426.     //
  427. DebugPrint( ("Is unloading......n") );
  428.     ASSERT(DriverObject->DeviceObject == NULL);
  429.     
  430.     //
  431.     // We should not be unloaded until all the devices we control 
  432.     // have been removed from our queue.  
  433.     //
  434.     DebugPrint (("Unload:  unloadn"));
  435.     return;
  436. }
  437. LONG
  438. SampleIoIncrement(
  439.     IN OUT PDEVICE_EXTENSION DeviceExtension
  440.     )
  441. /* ++
  442.  
  443. Routine Description:
  444. Increment deviceExtension->OutStandingIO within the scope of IOCountLock.
  445. Arguments:
  446. deviceExtension - pointer to a device object extension.
  447. Return Value:
  448. deviceExtension->OutStandingIO
  449. --*/
  450. {
  451.     LONG  result = 0;
  452.     KIRQL oldIrql;
  453.     KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
  454.     result = InterlockedIncrement(&DeviceExtension->OutStandingIO);
  455.     //
  456.     // when OutStandingIO bumps from 1 to 2, clear the StopEvent
  457.     //
  458.     if(result == 2) {
  459.         KeClearEvent(&DeviceExtension->StopEvent);
  460.     }
  461.     KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
  462. DebugPrint(("SampleIncrement: %dn", result));
  463.     return result;
  464. }
  465. LONG
  466. SampleIoDecrement(
  467.     IN OUT PDEVICE_EXTENSION DeviceExtension
  468.     )
  469. /*++
  470.  
  471. Routine Description:
  472.   Decrement deviceExtension->OutStandingIO within the scope of IOCountLock.
  473. Arguments:
  474. deviceExtension - pointer to a device object extension.
  475. Return Value:
  476. deviceExtension->OutStandingIO
  477. --*/
  478. {
  479.     LONG  result = 0;
  480.     KIRQL oldIrql;
  481.     KeAcquireSpinLock(&DeviceExtension->IOCountLock, &oldIrql);
  482.     result = InterlockedDecrement(&DeviceExtension->OutStandingIO);
  483.     if(result == 1) {
  484.         KeSetEvent(&DeviceExtension->StopEvent, IO_NO_INCREMENT, FALSE);
  485.     }
  486.     if(result == 0) {
  487.         ASSERT(Removed == DeviceExtension->DevicePnPState);
  488.         KeSetEvent(&DeviceExtension->RemoveEvent, IO_NO_INCREMENT, FALSE);
  489.     }
  490.     KeReleaseSpinLock(&DeviceExtension->IOCountLock, oldIrql);
  491. DebugPrint(("SampleIoDecrement: %dn", result));
  492.     return result;
  493. }