Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

744 lines
25 KiB

  1. // @doc
  2. /**********************************************************************
  3. *
  4. * @module SWVBENUM.cpp |
  5. *
  6. * SideWinder Virtual Bus Enumerator
  7. *
  8. * History
  9. * ----------------------------------------------------------
  10. * Mitchell S. Dernis Original
  11. *
  12. * (c) 1986-1998 Microsoft Corporation. All right reserved.
  13. * @index SideWinder Virtual Bus | SWVBENUM
  14. *
  15. * @topic SWVBENUM |
  16. * This module implements the SideWinder Virtual Bus.
  17. * The bus is nothing more than attaching this code on top of
  18. * a FilterDO of a raw HID PDO, for the purpose of adding DevNodes
  19. * for a virtual keyboard, virtual mouse, and the future virtual
  20. * mixed devices. All of these devices are expected to be HID
  21. * devices.<nl>
  22. *
  23. * The function driver for these devices the SWVBHID.sys (SideWinder
  24. * Virtual Bus - HID). This driver is a HID mini-driver, however
  25. * all IRPs are simply passed down to their PDO's, i.e. this
  26. * code.<nl>
  27. *
  28. * The code in this module is independent of the functionality
  29. * of the virtual devices. Basically all Power and PnP IRPs
  30. * are handled here. All IRP_MJ_READ, IRP_MJ_WRITE,
  31. * IRP_MJ_INTERNAL_IOCTL, and IRP_MJ_IOCTL entries are delegated
  32. * via service table provided in the expose call to this module
  33. * and stored in the device extension to a code module
  34. * in this driver representing the device.<nl>
  35. *
  36. **********************************************************************/
  37. #define __DEBUG_MODULE_IN_USE__ GCK_SWVBENUM_C
  38. extern "C"
  39. {
  40. #include <WDM.H>
  41. #include "GckShell.h"
  42. #include "debug.h"
  43. #include <stdio.h>
  44. DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
  45. //DECLARE_MODULE_DEBUG_LEVEL((DBG_ALL));
  46. }
  47. #include "SWVBENUM.h"
  48. //
  49. // Mark the pageable routines as such
  50. //
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text (INIT, GCK_SWVB_DriverEntry)
  53. #endif
  54. // @globalv Globals for SWVB module
  55. SWVB_GLOBALS SwvbGlobals;
  56. /***********************************************************************************
  57. **
  58. ** NTSTATUS GCK_SWVB_DriverEntry
  59. **
  60. ** @func Initializes SWVB module. In particular the globals.
  61. **
  62. ** @rdesc Returns STATUS_SUCCESS always.
  63. **
  64. ** @comm Called by DriverEntry of main filter.
  65. **
  66. *************************************************************************************/
  67. NTSTATUS
  68. GCK_SWVB_DriverEntry
  69. (
  70. IN PDRIVER_OBJECT pDriverObject, // @parm DriverObject for module
  71. IN PUNICODE_STRING puniRegistryPath // @parm Registry Path
  72. )
  73. {
  74. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_DriverEntry\n"));
  75. UNREFERENCED_PARAMETER(pDriverObject);
  76. UNREFERENCED_PARAMETER(puniRegistryPath);
  77. SwvbGlobals.pBusFdo=NULL;
  78. SwvbGlobals.pBusPdo=NULL;
  79. SwvbGlobals.pDeviceRelations=NULL;
  80. SwvbGlobals.ulDeviceRelationsAllocCount=0;
  81. SwvbGlobals.ulDeviceNumber=0;
  82. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_DriverEntry\n"));
  83. return STATUS_SUCCESS;
  84. }
  85. VOID
  86. GCK_SWVB_UnLoad()
  87. {
  88. if(SwvbGlobals.pDeviceRelations)
  89. {
  90. ExFreePool(SwvbGlobals.pDeviceRelations);
  91. SwvbGlobals.pDeviceRelations = NULL;
  92. }
  93. }
  94. /***********************************************************************************
  95. **
  96. ** NTSTATUS GCK_SWVB_SetBusDOs
  97. **
  98. ** @func Sets the Device Object (PDO and FDO), to use as the base of the
  99. ** SideWinder Virtual Bus.
  100. **
  101. ** @rdesc S_OK on success
  102. **
  103. ** @comm A real device is needed on the system in order to
  104. ** support the virtual device. When the first such device is detected,
  105. ** this function is called to set the filter device object of that
  106. ** device to be the Fdo of the SWVB, and its Pdo to be the Pdo of the bus.
  107. ** If that device object is removed, this function can be called to move
  108. ** the SWVB unto another physical device, or it can be called with NULL
  109. ** for both arguments to remove the SWVB.
  110. **
  111. *************************************************************************************/
  112. NTSTATUS
  113. GCK_SWVB_SetBusDOs
  114. (
  115. IN PDEVICE_OBJECT pBusFdo, // @parm [in] Pointer to Fdo (Filter Device Object - actually)
  116. IN PDEVICE_OBJECT pBusPdo // @parm [in] Pointer to Pdo
  117. )
  118. {
  119. PDEVICE_OBJECT pOldBusFdo;
  120. PDEVICE_OBJECT pOldBusPdo;
  121. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_SetBusDOs\n"));
  122. // Save old Bus DO info
  123. pOldBusFdo = SwvbGlobals.pBusFdo;
  124. pOldBusPdo = SwvbGlobals.pBusPdo;
  125. // Update Bus DO info
  126. SwvbGlobals.pBusFdo = pBusFdo;
  127. SwvbGlobals.pBusPdo = pBusPdo;
  128. // Invalidate the old and the new pBusPdo's - iff
  129. // (they exist && there is at least one device on the bus)
  130. // This will fire up the PnP system and cause it to re-detect
  131. // everything.
  132. if(SwvbGlobals.pDeviceRelations && SwvbGlobals.pDeviceRelations->Count)
  133. {
  134. if(pOldBusPdo)
  135. {
  136. IoInvalidateDeviceRelations(pOldBusPdo, BusRelations);
  137. }
  138. if(SwvbGlobals.pBusPdo)
  139. {
  140. IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
  141. }
  142. }
  143. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_SetBusDOs\n"));
  144. return STATUS_SUCCESS;
  145. }
  146. /***********************************************************************************
  147. **
  148. ** NTSTATUS GCK_SWVB_HandleBusRelations
  149. **
  150. ** @func Handles queries for the BusRelations on behalf of the filter device object,
  151. ** which the SWVB is sitting on. Basically all we need do is copy over
  152. ** over our device relations, being cognizant that someone may layer on top
  153. ** of us and possibly has added stuff already.
  154. ** @rdesc Same as in the IoStatus and appropriate to return.
  155. **
  156. *************************************************************************************/
  157. NTSTATUS
  158. GCK_SWVB_HandleBusRelations
  159. (
  160. IN OUT PIO_STATUS_BLOCK pIoStatus // @parm [out] IoStatus block is filled out by this routine.
  161. )
  162. {
  163. ULONG ulTotalCount;
  164. PDEVICE_RELATIONS pExistingRelations;
  165. PDEVICE_RELATIONS pDeviceRelations;
  166. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_HandleBusRelations. pIoStatus = 0x%0.8x\n", pIoStatus));
  167. // Copy the count of what we know about
  168. ulTotalCount = SwvbGlobals.pDeviceRelations->Count;
  169. GCK_DBG_TRACE_PRINT(("We have %d PDOs\n", ulTotalCount));
  170. // Read existing relations
  171. pExistingRelations = (PDEVICE_RELATIONS)pIoStatus->Information;
  172. // Add the count that someone on top of us may have added.
  173. if( NULL != pExistingRelations)
  174. {
  175. GCK_DBG_TRACE_PRINT(("There were %d existing bus relations.\n", pExistingRelations->Count));
  176. ulTotalCount += pExistingRelations->Count;
  177. }
  178. // Allocate new relations structure
  179. pDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, (sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (ulTotalCount-1)) );
  180. // Abort if allocation failed
  181. if(!pDeviceRelations)
  182. {
  183. pIoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
  184. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_BusRelations(1): STATUS_INSUFFICIENT_RESOURCES\n"));
  185. return STATUS_INSUFFICIENT_RESOURCES;
  186. }
  187. pDeviceRelations->Count = 0;
  188. // Copy pExistingRelations (from above us perhaps) if there are any.
  189. if( pExistingRelations )
  190. {
  191. for( pDeviceRelations->Count = 0; pDeviceRelations->Count < pExistingRelations->Count; pDeviceRelations->Count++)
  192. {
  193. GCK_DBG_TRACE_PRINT(("Exiting relation (PDO = 0x%0.8x)\n", pExistingRelations->Objects[pDeviceRelations->Count]));
  194. pDeviceRelations->Objects[pDeviceRelations->Count] = pExistingRelations->Objects[pDeviceRelations->Count];
  195. }
  196. ExFreePool(pExistingRelations);
  197. }
  198. // Add the relations that we know about
  199. if(SwvbGlobals.pDeviceRelations)
  200. {
  201. ULONG ulIndex;
  202. for(ulIndex=0; ulIndex < SwvbGlobals.pDeviceRelations->Count; ulIndex++, pDeviceRelations->Count++)
  203. {
  204. GCK_DBG_TRACE_PRINT(("Our relation (PDO = 0x%0.8x)\n", SwvbGlobals.pDeviceRelations->Objects[ulIndex]));
  205. pDeviceRelations->Objects[pDeviceRelations->Count] = SwvbGlobals.pDeviceRelations->Objects[ulIndex];
  206. // Reference these guys as you add them
  207. ObReferenceObject(pDeviceRelations->Objects[pDeviceRelations->Count]);
  208. }
  209. //minor sanity check
  210. ASSERT(pDeviceRelations->Count == ulTotalCount);
  211. }
  212. // Fill out the IoStatus block
  213. pIoStatus->Information = (ULONG)pDeviceRelations;
  214. pIoStatus->Status = STATUS_SUCCESS;
  215. //Get outta here
  216. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_BusRelations(2): STATUS_SUCCESS\n"));
  217. return STATUS_SUCCESS;
  218. }
  219. /***********************************************************************************
  220. **
  221. ** NTSTATUS GCK_SWVB_Expose
  222. **
  223. ** @func Exposes a new virtual device
  224. **
  225. ** @rdesc STATUS_SUCCESS on success, various errors
  226. **
  227. ** @comm Expose is called to add a new virtual device to the system.<nl>
  228. ** The new device object is not returned, rather the InitDevice function
  229. ** passed in pSwvbExposeData is called when it is time to initialize the
  230. ** new device, the caller also must cache the device during that call
  231. ** so that it can remove it later.
  232. **
  233. ** @xref SWVB_EXPOSE_DATA
  234. *************************************************************************************/
  235. NTSTATUS
  236. GCK_SWVB_Expose
  237. (
  238. IN PSWVB_EXPOSE_DATA pSwvbExposeData // @parm all the data needed to expose a PDO
  239. )
  240. {
  241. NTSTATUS NtStatus;
  242. UNICODE_STRING uniPdoNameString;
  243. PWCHAR pcwPdoName;
  244. PDEVICE_OBJECT pVdPdo;
  245. PSWVB_PDO_EXT pSwvbPdoExt;
  246. ULONG ulTotalExtensionSize;
  247. ULONG ulHardwareIDLength;
  248. PAGED_CODE();
  249. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Expose. pSwvbExposeData = 0x%0.8x\n", pSwvbExposeData));
  250. //Calculate the needed extension size
  251. ulTotalExtensionSize = sizeof(SWVB_PDO_EXT) + pSwvbExposeData->ulDeviceExtensionSize;
  252. // Create a name for the Pdo
  253. pcwPdoName = (PWCHAR)EX_ALLOCATE_POOL(PagedPool, sizeof(SWVB_DEVICE_NAME_BASE));
  254. if( !pcwPdoName )
  255. {
  256. GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(1) ERROR:Failed to allocate PDO Name\n"));
  257. return STATUS_INSUFFICIENT_RESOURCES;
  258. }
  259. swprintf(pcwPdoName, SWVB_DEVICE_NAME_TMPLT, SwvbGlobals.ulDeviceNumber++);
  260. RtlInitUnicodeString(&uniPdoNameString, pcwPdoName);
  261. // Create the PDO
  262. NtStatus = IoCreateDevice(
  263. SwvbGlobals.pBusFdo->DriverObject,
  264. ulTotalExtensionSize,
  265. &uniPdoNameString,
  266. FILE_DEVICE_UNKNOWN,
  267. 0,
  268. FALSE,
  269. &pVdPdo
  270. );
  271. //Done with the name
  272. ExFreePool(pcwPdoName);
  273. if( !NT_SUCCESS(NtStatus) )
  274. {
  275. GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(2) ERROR:Failed to Create PDO, NtStatus = 0x%0.8x\n", NtStatus));
  276. return NtStatus;
  277. }
  278. // Ensure that we will be able to remember this new Pdo.
  279. if(!SwvbGlobals.pDeviceRelations)
  280. {
  281. //
  282. // Three PDO's is pretty cheap and will suffice most of the time, avoiding reallocation.
  283. // We hard code this here, as this is not really a parameter that you need to change.
  284. // If we run over 3 than it will reallocate as needed anyway. - The device relations
  285. // already as room for 1 device object so we just need to add the size of 2 pointers
  286. // to get to three.
  287. //
  288. ULONG ulSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*2;
  289. SwvbGlobals.pDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, ulSize);
  290. if(!SwvbGlobals.pDeviceRelations)
  291. {
  292. IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
  293. GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(3): Failed to allocate SwvbGlobals.pDeviceRelations\n"));
  294. return STATUS_INSUFFICIENT_RESOURCES;
  295. }
  296. SwvbGlobals.pDeviceRelations->Count = 0;
  297. SwvbGlobals.ulDeviceRelationsAllocCount = 3; //we made space for three
  298. }
  299. // If the DEVICE_RELATIONS structure is not large enough, grow it.
  300. if(SwvbGlobals.pDeviceRelations->Count == SwvbGlobals.ulDeviceRelationsAllocCount)
  301. {
  302. ULONG ulNewAllocCount;
  303. ULONG ulNewAllocSize;
  304. ULONG ulOldAllocSize;
  305. PDEVICE_RELATIONS pTempDeviceRelations;
  306. ulNewAllocCount = SwvbGlobals.ulDeviceRelationsAllocCount*2;
  307. ulNewAllocSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*(ulNewAllocCount-1);
  308. ulOldAllocSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*(SwvbGlobals.ulDeviceRelationsAllocCount-1);
  309. pTempDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, ulNewAllocSize);
  310. //Make sure that allocation worked
  311. if(!pTempDeviceRelations)
  312. {
  313. IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
  314. GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(4): Failed to grow SwvbGlobals.pDeviceRelations\n"));
  315. return STATUS_INSUFFICIENT_RESOURCES;
  316. }
  317. //Copy all data
  318. RtlCopyMemory(pTempDeviceRelations, SwvbGlobals.pDeviceRelations, ulOldAllocSize);
  319. //Update info
  320. SwvbGlobals.ulDeviceRelationsAllocCount = ulNewAllocCount;
  321. SwvbGlobals.pDeviceRelations = pTempDeviceRelations;
  322. /*
  323. * BUGBUG: Memory Leak. After RC replace above line with the following
  324. *
  325. * PDEVICE_RELATIONS pTemp2 = SwvbGlobals.pDeviceRelations;
  326. * SwvbGlobals.pDeviceRelations = pTempDeviceRelations;
  327. * ExFreePool(pTemp2);
  328. *
  329. */
  330. }
  331. // Reference the newly created pdo
  332. ObReferenceObject(pVdPdo);
  333. // Initialize the device extention
  334. pSwvbPdoExt = (PSWVB_PDO_EXT)pVdPdo->DeviceExtension;
  335. pSwvbPdoExt->ulGckDevObjType = GCK_DO_TYPE_SWVB;
  336. pSwvbPdoExt->fAttached=TRUE;
  337. pSwvbPdoExt->fStarted=FALSE;
  338. pSwvbPdoExt->fRemoved = FALSE;
  339. pSwvbPdoExt->pServiceTable = pSwvbExposeData->pServiceTable;
  340. pSwvbPdoExt->ulInstanceNumber = pSwvbExposeData->ulInstanceNumber;
  341. pSwvbPdoExt->ulOpenCount = 0;
  342. GCK_InitRemoveLock(&pSwvbPdoExt->RemoveLock, "Virtual Device");
  343. // Copy the HardwareID
  344. ulHardwareIDLength = MultiSzWByteLength(pSwvbExposeData->pmwszDeviceId);
  345. pSwvbPdoExt->pmwszHardwareID = (PWCHAR)EX_ALLOCATE_POOL( NonPagedPool, ulHardwareIDLength);
  346. if(!pSwvbPdoExt->pmwszHardwareID)
  347. {
  348. ObDereferenceObject(pVdPdo);
  349. IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
  350. GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(5): Failed to allocate space for HardwareId\n"));
  351. return STATUS_INSUFFICIENT_RESOURCES;
  352. }
  353. RtlCopyMemory( pSwvbPdoExt->pmwszHardwareID, pSwvbExposeData->pmwszDeviceId, ulHardwareIDLength);
  354. //** CAVEAT From here to end of function must succeed! We
  355. //** CAVEAT have no way of telling the virtual device
  356. //** CAVEAT that afterall, we decided not to expose that PDO it
  357. //** CAVEAT it has already initialized!
  358. // Allow virtual device code to init its part of the extension
  359. pSwvbExposeData->pfnInitDevice(pVdPdo, pSwvbExposeData->ulInitContext);
  360. //mark end of initialization in the device object
  361. pVdPdo->Flags |= (DO_DIRECT_IO | DO_POWER_PAGABLE);
  362. pVdPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  363. //Sanity check of code a few steps ago.
  364. ASSERT(SwvbGlobals.pDeviceRelations->Count < SwvbGlobals.ulDeviceRelationsAllocCount);
  365. //Add our Pdo to the list
  366. SwvbGlobals.pDeviceRelations->Objects[SwvbGlobals.pDeviceRelations->Count++] = pVdPdo;
  367. //
  368. // Invalidate Device Relations - will pique some interest in what we have done here
  369. // Verify that we have a bus if not we are OK, when the bus is set everything will work,
  370. // but we assert becuase we really want to force the client code to add the bus before the device.
  371. //
  372. ASSERT( SwvbGlobals.pBusFdo );
  373. ASSERT( SwvbGlobals.pBusPdo );
  374. if( SwvbGlobals.pBusFdo && SwvbGlobals.pBusPdo)
  375. {
  376. IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
  377. }
  378. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Expose(5): Success\n"));
  379. return STATUS_SUCCESS;
  380. }
  381. /***********************************************************************************
  382. **
  383. ** NTSTATUS GCK_SWVB_Remove
  384. **
  385. ** @func Removes a virtual device from the system. Actually we just mark it
  386. ** for removal and tell PnP to reenumerate.
  387. **
  388. ** @rdesc STATUS_SUCCESS on success, various errors
  389. **
  390. ** @comm The Pdo should be one that was sent to pfnInitDevice when <f GCK_SWVB_Expose>
  391. ** was called.<nl>
  392. **
  393. *************************************************************************************/
  394. NTSTATUS
  395. GCK_SWVB_Remove
  396. (
  397. IN PDEVICE_OBJECT pPdo // @parm Pdo to remove
  398. )
  399. {
  400. ULONG ulMatchIndex = 0xFFFFFFFF;
  401. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Remove: pPdo = 0x%0.8x\n", pPdo));
  402. // Find and Remove Pdo from SwvbGlobals.pDeviceRelations
  403. if(SwvbGlobals.pDeviceRelations)
  404. {
  405. ULONG ulIndex;
  406. for(ulIndex = 0; ulIndex < SwvbGlobals.pDeviceRelations->Count; ulIndex++)
  407. {
  408. if(SwvbGlobals.pDeviceRelations->Objects[ulIndex] == pPdo)
  409. {
  410. ulMatchIndex = ulIndex;
  411. break;
  412. }
  413. }
  414. }
  415. //if we found a match remove it from it
  416. if(0xFFFFFFFF == ulMatchIndex)
  417. {
  418. //No one should ever try to remove a device that is not in the list
  419. ASSERT(FALSE);
  420. GCK_DBG_EXIT_PRINT(("Error GCK_SWVB_Remove: Attempt to remove non-existant device!\n"));
  421. return STATUS_UNSUCCESSFUL;
  422. }
  423. //Copy last PDO over this one and dec count, works even if we are last
  424. SwvbGlobals.pDeviceRelations->Objects[ulMatchIndex]
  425. = SwvbGlobals.pDeviceRelations->Objects[--(SwvbGlobals.pDeviceRelations->Count)];
  426. //
  427. // Mark device as unattached so when PnP says to remove it, we
  428. // do remove it and clean up everything, rather than hanging on
  429. // to it and waiting for more querying IRPs
  430. ((PSWVB_PDO_EXT)pPdo->DeviceExtension)->fAttached =FALSE;
  431. //
  432. // If it has been removed already, we need to delete, because the PnP system already
  433. // doesn't know about, and we just detattached, so once we leave this routine, we don't
  434. // know about it. So Delete now, or it sticks to us. Then we go to remove ourselves
  435. // we will notice that we still have some Device Objects in our pockets(pDriverObject device object list),
  436. // and we will wonder where they came from, and what type they are? So delete them now!
  437. //
  438. if(TRUE == ((PSWVB_PDO_EXT)pPdo->DeviceExtension)->fRemoved)
  439. {
  440. PSWVB_PDO_EXT pPdoExt = (PSWVB_PDO_EXT)pPdo->DeviceExtension;
  441. NTSTATUS NtStatus;
  442. // Give virtual device a chance at the IRP
  443. if(pPdoExt->pServiceTable->pfnRemove)
  444. {
  445. NtStatus = pPdoExt->pServiceTable->pfnRemove(pPdo, NULL);
  446. }
  447. // failure to succeed is pretty darn serious
  448. if(!NT_SUCCESS(NtStatus))
  449. {
  450. ASSERT(FALSE);
  451. GCK_DBG_CRITICAL_PRINT(("Virtual Device had the gall to fail remove!\n"));
  452. }
  453. // free memory for storing the HardwareID
  454. ASSERT(pPdoExt->pmwszHardwareID);
  455. ExFreePool(pPdoExt->pmwszHardwareID);
  456. GCK_DBG_TRACE_PRINT(("Detattached device has already been removed by PnP, so clean it up.\n"));
  457. if( 0 == ((PSWVB_PDO_EXT)pPdo->DeviceExtension)->ulOpenCount )
  458. {
  459. ObDereferenceObject(pPdo);
  460. IoDeleteDevice(pPdo);
  461. }
  462. }
  463. // Invalidate the BUS relations so that PnP will renumerate the bus.
  464. // Of course since we rely on others, it is possible that we temporarily
  465. // don't have a Bus, in which case we skip this step.
  466. //
  467. // If we don't have DO for the Bus we shouldn't lose any sleep on two accounts:
  468. // 1. It is possible that all the real devices have been yanked from the system, in which case
  469. // PnP will start removing everyone below the node that was yanked, starting at the bottom.
  470. // That means virtual devices have been removed as far as PnP is concerned and our remove
  471. // routine for those devices has been called. However, until all the underlying real devices
  472. // get removed by PnP (which is later), they don't relealize it is time to tell us to get rid of the
  473. // virtual devices. No big woop. We will delete the devices when they tell us. If the virtual
  474. // device is shared among real devices (like a virtual keyboard), they will tell us when the last
  475. // one is removed. This scenario is infact the normal way things happen when the last device is pulled,
  476. // or when the system is powered down.
  477. // 2. It is possible that the filter drivers have temporarily decided to pull our bus. In this case,
  478. // everything will be fine and dandy when we get a new bus to sit on, as we will Invalidate Bus relations
  479. // at that time.
  480. if(SwvbGlobals.pBusPdo)
  481. {
  482. IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
  483. }
  484. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Remove: Success\n"));
  485. return STATUS_SUCCESS;
  486. }
  487. /***********************************************************************************
  488. **
  489. ** ULONG MultiSzWByteLength(PWCHAR pmwszBuffer);
  490. **
  491. ** @func Calculates the length in bytes of a Wide Multi String,
  492. ** including terminating characters. Multi-sz is terminated by two NULLs
  493. ** in a row.
  494. **
  495. ** @rdesc Size in characters, including terminating characters.
  496. **
  497. *************************************************************************************/
  498. ULONG
  499. MultiSzWByteLength
  500. (
  501. PWCHAR pmwszBuffer // @parm Pointer to UNICODE multi-string
  502. )
  503. {
  504. PWCHAR pmwszStart = pmwszBuffer;
  505. do
  506. {
  507. while(*pmwszBuffer++);
  508. }while(*pmwszBuffer++);
  509. return (ULONG)((PCHAR)pmwszBuffer -(PCHAR)pmwszStart);
  510. }
  511. /***********************************************************************************
  512. **
  513. ** NTSTATUS GCK_SWVB_Create
  514. **
  515. ** @func Handles IRP_MJ_CREATE for virtual devices.
  516. ** delegates using their service table.
  517. **
  518. ** @rdesc STATUS_SUCCESS on success, various errors
  519. **
  520. ** @todo Add basic checks to make sure device is valid before delegating
  521. **
  522. *************************************************************************************/
  523. NTSTATUS
  524. GCK_SWVB_Create
  525. (
  526. IN PDEVICE_OBJECT pDeviceObject,
  527. IN PIRP pIrp
  528. )
  529. {
  530. NTSTATUS NtStatus;
  531. PSWVB_PDO_EXT pPdoExt;
  532. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Create\n"));
  533. // Cast device extension
  534. pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
  535. // Just an extra sanity check
  536. ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
  537. //Delegate
  538. NtStatus = pPdoExt->pServiceTable->pfnCreate(pDeviceObject, pIrp);
  539. if( NT_SUCCESS(NtStatus) )
  540. {
  541. pPdoExt->ulOpenCount++;
  542. }
  543. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Create, Status = 0x%0.8x\n", NtStatus));
  544. return NtStatus;
  545. }
  546. /***********************************************************************************
  547. **
  548. ** NTSTATUS GCK_SWVB_Close
  549. **
  550. ** @func Handles IRP_MJ_CLOSE for virtual devices.
  551. ** delegates using their service table.
  552. **
  553. ** @rdesc STATUS_SUCCESS on success, various errors
  554. **
  555. ** @todo Add basic checks to make sure device is valid before delegating
  556. **
  557. *************************************************************************************/
  558. NTSTATUS
  559. GCK_SWVB_Close
  560. (
  561. IN PDEVICE_OBJECT pDeviceObject,
  562. IN PIRP pIrp
  563. )
  564. {
  565. NTSTATUS NtStatus;
  566. PSWVB_PDO_EXT pPdoExt;
  567. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Close\n"));
  568. // Cast device extension
  569. pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
  570. // Just an extra sanity check
  571. ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
  572. //Delegate
  573. NtStatus = pPdoExt->pServiceTable->pfnClose(pDeviceObject, pIrp);
  574. //if successfully closed, decrement count
  575. if( NT_SUCCESS(NtStatus) )
  576. {
  577. if(0==--pPdoExt->ulOpenCount)
  578. {
  579. //if the device is removed, we need to delete it.
  580. if(pPdoExt->fRemoved)
  581. {
  582. ObDereferenceObject(pDeviceObject);
  583. IoDeleteDevice(pDeviceObject);
  584. }
  585. }
  586. }
  587. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Close, Status = 0x%0.8x\n", NtStatus));
  588. return NtStatus;
  589. }
  590. /***********************************************************************************
  591. **
  592. ** NTSTATUS GCK_SWVB_Read
  593. **
  594. ** @func Handles IRP_MJ_READ for virtual devices.
  595. ** delegates using their service table.
  596. **
  597. ** @rdesc STATUS_SUCCESS on success, various errors
  598. **
  599. ** @todo Add basic checks to make sure device is valid before delegating
  600. **
  601. *************************************************************************************/
  602. NTSTATUS
  603. GCK_SWVB_Read
  604. (
  605. IN PDEVICE_OBJECT pDeviceObject,
  606. IN PIRP pIrp
  607. )
  608. {
  609. NTSTATUS NtStatus;
  610. PSWVB_PDO_EXT pPdoExt;
  611. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Reade\n"));
  612. // Cast device extension
  613. pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
  614. // Just an extra sanity check
  615. ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
  616. //Delegate
  617. NtStatus = pPdoExt->pServiceTable->pfnRead(pDeviceObject, pIrp);
  618. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Read, Status = 0x%0.8x\n", NtStatus));
  619. return NtStatus;
  620. }
  621. /***********************************************************************************
  622. **
  623. ** NTSTATUS GCK_SWVB_Ioctl
  624. **
  625. ** @func Handles IRP_MJ_IOCTL and IRP_MJ_INTERNAL_IOCTL for virtual devices.
  626. ** delegates using their service table.
  627. **
  628. ** @rdesc STATUS_SUCCESS on success, various errors
  629. **
  630. ** @todo Add basic checks to make sure device is valid before delegating
  631. **
  632. *************************************************************************************/
  633. NTSTATUS
  634. GCK_SWVB_Ioctl
  635. (
  636. IN PDEVICE_OBJECT pDeviceObject,
  637. IN PIRP pIrp
  638. )
  639. {
  640. NTSTATUS NtStatus;
  641. PSWVB_PDO_EXT pPdoExt;
  642. GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Ioctl\n"));
  643. // Cast device extension
  644. pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
  645. // Just an extra sanity check
  646. ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
  647. //if device is stopped, complete here, less work for virtual devices
  648. if(
  649. (pPdoExt->fRemoved) ||
  650. (!pPdoExt->fStarted)
  651. )
  652. {
  653. pIrp->IoStatus.Information = 0;
  654. pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  655. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  656. return STATUS_DELETE_PENDING;
  657. }
  658. //Delegate
  659. NtStatus = pPdoExt->pServiceTable->pfnIoctl(pDeviceObject, pIrp);
  660. GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Ioctl, Status = 0x%0.8x\n", NtStatus));
  661. return NtStatus;
  662. }