Source code of Windows XP (NT5)
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.

620 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module contains the code for a serial imaging devices driver
  7. supporting PnP functionality
  8. Author:
  9. Vlad Sadovsky vlads 10-April-1998
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. vlads 04/10/1998 Created first draft
  14. --*/
  15. #include "serscan.h"
  16. #include "serlog.h"
  17. //#include <ntpoapi.h>
  18. extern ULONG SerScanDebugLevel;
  19. extern const PHYSICAL_ADDRESS PhysicalZero ;
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, SerScanPnp)
  22. #pragma alloc_text(PAGE, SerScanPower)
  23. #endif
  24. NTSTATUS
  25. SerScanPnp (
  26. IN PDEVICE_OBJECT pDeviceObject,
  27. IN PIRP pIrp
  28. )
  29. /*++
  30. Routine Description:
  31. This routine handles all PNP IRPs, dispatching them as appropriate .
  32. Arguments:
  33. pDeviceObject - represents a device
  34. pIrp - PNP Irp
  35. Return Value:
  36. STATUS_SUCCESS - if successful.
  37. STATUS_UNSUCCESSFUL - otherwise.
  38. --*/
  39. {
  40. NTSTATUS Status ;
  41. PDEVICE_EXTENSION Extension;
  42. PIO_STACK_LOCATION pIrpStack;
  43. PVOID pObject;
  44. ULONG NewReferenceCount;
  45. NTSTATUS ReturnStatus;
  46. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
  47. Extension = pDeviceObject->DeviceExtension;
  48. Status = STATUS_SUCCESS;
  49. DebugDump(SERINITDEV,("Entering PnP Dispatcher\n"));
  50. switch (pIrpStack->MinorFunction) {
  51. case IRP_MN_START_DEVICE:
  52. //
  53. // Initialize PendingIoEvent. Set the number of pending i/o requests for this device to 1.
  54. // When this number falls to zero, it is okay to remove, or stop the device.
  55. //
  56. DebugDump(SERINITDEV,("Entering Start Device \n"));
  57. KeInitializeEvent(&Extension -> PdoStartEvent, SynchronizationEvent, FALSE);
  58. IoCopyCurrentIrpStackLocationToNext(pIrp);
  59. Status = WaitForLowerDriverToCompleteIrp(
  60. Extension->LowerDevice,
  61. pIrp,
  62. &Extension->PdoStartEvent);
  63. if (!NT_SUCCESS(Status)) {
  64. pIrp->IoStatus.Status = Status;
  65. pIrp->IoStatus.Information = 0;
  66. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  67. return (Status);
  68. }
  69. #ifdef CREATE_SYMBOLIC_NAME
  70. //
  71. // Now setup the symbolic link for windows.
  72. //
  73. Status = IoCreateUnprotectedSymbolicLink(&Extension->SymbolicLinkName, &Extension->ClassName);
  74. if (NT_SUCCESS(Status)) {
  75. // We were able to create the symbolic link, so record this
  76. // value in the extension for cleanup at unload time.
  77. Extension->CreatedSymbolicLink = TRUE;
  78. // Write out the result of the symbolic link to the registry.
  79. Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
  80. L"Serial Scanners",
  81. Extension->ClassName.Buffer,
  82. REG_SZ,
  83. Extension->SymbolicLinkName.Buffer,
  84. Extension->SymbolicLinkName.Length + sizeof(WCHAR));
  85. if (!NT_SUCCESS(Status)) {
  86. //
  87. // It didn't work. Just go to cleanup.
  88. //
  89. DebugDump(SERERRORS,
  90. ("SerScan: Couldn't create the device map entry\n"
  91. "-------- for port %wZ\n",
  92. &Extension->ClassName));
  93. SerScanLogError(pDeviceObject->DriverObject,
  94. pDeviceObject,
  95. PhysicalZero,
  96. PhysicalZero,
  97. 0,
  98. 0,
  99. 0,
  100. 6,
  101. Status,
  102. SER_NO_DEVICE_MAP_CREATED);
  103. }
  104. } else {
  105. //
  106. // Couldn't create the symbolic link.
  107. //
  108. Extension->CreatedSymbolicLink = FALSE;
  109. ExFreePool(Extension->SymbolicLinkName.Buffer);
  110. Extension->SymbolicLinkName.Buffer = NULL;
  111. DebugDump(SERERRORS,
  112. ("SerScan: Couldn't create the symbolic link\n"
  113. "-------- for port %wZ\n",
  114. &Extension->ClassName));
  115. SerScanLogError(pDeviceObject->DriverObject,
  116. pDeviceObject,
  117. PhysicalZero,
  118. PhysicalZero,
  119. 0,
  120. 0,
  121. 0,
  122. 5,
  123. Status,
  124. SER_NO_SYMLINK_CREATED);
  125. }
  126. #endif
  127. ExFreePool(Extension->ClassName.Buffer);
  128. Extension->ClassName.Buffer = NULL;
  129. //
  130. // Ignore status of link registry write - always succeed
  131. //
  132. //
  133. // Clear InInit flag to indicate device object can be used
  134. //
  135. pDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING);
  136. pIrp->IoStatus.Status = Status;
  137. pIrp->IoStatus.Information = 0;
  138. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  139. return (Status);
  140. break;
  141. case IRP_MN_QUERY_REMOVE_DEVICE:
  142. //
  143. // Always pass to lower device in stack after indicating that we don't object
  144. //
  145. DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE\n"));
  146. Extension->Removing = TRUE;
  147. IoCopyCurrentIrpStackLocationToNext( pIrp );
  148. return (IoCallDriver(Extension->LowerDevice, pIrp));
  149. break;
  150. case IRP_MN_CANCEL_REMOVE_DEVICE:
  151. //
  152. // Always pass to lower device in stack , reset indicator as somebody canceled
  153. //
  154. DebugDump(SERALWAYS,("IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  155. Extension->Removing = FALSE;
  156. //
  157. // Kill symbolic link
  158. //
  159. if (Extension->CreatedSymbolicLink) {
  160. IoDeleteSymbolicLink(&Extension->SymbolicLinkName);
  161. Extension->CreatedSymbolicLink = FALSE;
  162. }
  163. IoCopyCurrentIrpStackLocationToNext( pIrp );
  164. return (IoCallDriver(Extension->LowerDevice, pIrp));
  165. break;
  166. case IRP_MN_SURPRISE_REMOVAL:
  167. //
  168. // Should not ever happen with us, but still process
  169. //
  170. DebugDump(SERALWAYS,("IRP_MN_SURPRISE_REMOVAL\n"));
  171. Extension->Removing = TRUE;
  172. //
  173. // Get rid of the symbolic link
  174. //
  175. SerScanHandleSymbolicLink(
  176. Extension->Pdo,
  177. &Extension->InterfaceNameString,
  178. FALSE
  179. );
  180. #ifdef USE_EXECUTIVE_RESOURCE
  181. ExAcquireResourceExclusiveLite(
  182. &Extension->Resource,
  183. TRUE
  184. );
  185. #else
  186. ExAcquireFastMutex(&Extension->Mutex);
  187. #endif
  188. pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL);
  189. if (pObject) {
  190. ObDereferenceObject(pObject);
  191. }
  192. pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL);
  193. if (pObject) {
  194. ObDereferenceObject(pObject);
  195. }
  196. #ifdef USE_EXECUTIVE_RESOURCE
  197. ExReleaseResourceLite(&Extension->Resource);
  198. #else
  199. ExReleaseFastMutex(&Extension->Mutex);
  200. #endif
  201. IoCopyCurrentIrpStackLocationToNext( pIrp );
  202. return (IoCallDriver(Extension->LowerDevice, pIrp));
  203. break;
  204. case IRP_MN_REMOVE_DEVICE:
  205. DebugDump(SERALWAYS,("IRP_MN_REMOVE_DEVICE\n"));
  206. DebugDump(SERINITDEV,("Entering PnP Remove Device\n"));
  207. //
  208. // Stop new requests - device is being removed
  209. //
  210. Extension->Removing = TRUE;
  211. //
  212. // Get rid of the symbolic link
  213. //
  214. SerScanHandleSymbolicLink(
  215. Extension->Pdo,
  216. &Extension->InterfaceNameString,
  217. FALSE
  218. );
  219. #ifdef USE_EXECUTIVE_RESOURCE
  220. ExAcquireResourceExclusiveLite(
  221. &Extension->Resource,
  222. TRUE
  223. );
  224. #else
  225. ExAcquireFastMutex(&Extension->Mutex);
  226. #endif
  227. pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL);
  228. if (pObject) {
  229. ObDereferenceObject(pObject);
  230. }
  231. pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL);
  232. if (pObject) {
  233. ObDereferenceObject(pObject);
  234. }
  235. #ifdef USE_EXECUTIVE_RESOURCE
  236. ExReleaseResourceLite(&Extension->Resource);
  237. #else
  238. ExReleaseFastMutex(&Extension->Mutex);
  239. #endif
  240. //
  241. // Send IRP down to lower device
  242. //
  243. IoCopyCurrentIrpStackLocationToNext( pIrp );
  244. ReturnStatus = IoCallDriver(Extension->LowerDevice, pIrp);
  245. //
  246. // Decrement ref count
  247. //
  248. NewReferenceCount = InterlockedDecrement(&Extension->ReferenceCount);
  249. if (NewReferenceCount != 0) {
  250. //
  251. // Wait for any io requests pending in our driver to
  252. // complete before finishing the remove
  253. //
  254. KeWaitForSingleObject(&Extension -> RemoveEvent,
  255. Suspended,
  256. KernelMode,
  257. FALSE,
  258. NULL);
  259. }
  260. // ASSERT(&Extension->ReferenceCount == 0);
  261. #ifdef USE_EXECUTIVE_RESOURCE
  262. ExDeleteResourceLite(&Extension->Resource);
  263. #endif
  264. DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE - Calling IoDeleteDevice - gone\n"));
  265. IoDetachDevice(Extension->LowerDevice);
  266. //
  267. // Free allocated resource.
  268. //
  269. if(NULL != Extension->ClassName.Buffer){
  270. ExFreePool(Extension->ClassName.Buffer);
  271. } // if(NULL != Extension->ClassName.Buffer)
  272. if(NULL != Extension->SymbolicLinkName.Buffer){
  273. ExFreePool(Extension->SymbolicLinkName.Buffer);
  274. } // if(NULL != Extension->SymbolicLinkName.Buffer)
  275. IoDeleteDevice(pDeviceObject);
  276. return ReturnStatus;
  277. break;
  278. case IRP_MN_STOP_DEVICE:
  279. //
  280. // Pass down
  281. //
  282. DebugDump(SERALWAYS,("IRP_MN_STOP_DEVICE\n"));
  283. IoCopyCurrentIrpStackLocationToNext( pIrp );
  284. return (IoCallDriver(Extension->LowerDevice, pIrp));
  285. break;
  286. case IRP_MN_QUERY_STOP_DEVICE:
  287. //
  288. // Check open counts
  289. //
  290. DebugDump(SERALWAYS,("IRP_MN_QUERY_STOP_DEVICE\n"));
  291. if (Extension->OpenCount > 0 ) {
  292. DebugDump(SERALWAYS,("Rejecting QUERY_STOP_DEVICE\n"));
  293. pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  294. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  295. return STATUS_UNSUCCESSFUL;
  296. }
  297. IoCopyCurrentIrpStackLocationToNext( pIrp );
  298. return (IoCallDriver(Extension->LowerDevice, pIrp));
  299. break;
  300. case IRP_MN_CANCEL_STOP_DEVICE:
  301. //
  302. // Nothing to do here, but pass to lower
  303. //
  304. DebugDump(SERALWAYS,("IRP_MN_CANCEL_STOP_DEVICE\n"));
  305. IoCopyCurrentIrpStackLocationToNext( pIrp );
  306. return (IoCallDriver(Extension->LowerDevice, pIrp));
  307. break;
  308. case IRP_MN_QUERY_CAPABILITIES:
  309. {
  310. ULONG i;
  311. KEVENT WaitEvent;
  312. //
  313. // Send this down to the PDO first
  314. //
  315. KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE);
  316. IoCopyCurrentIrpStackLocationToNext(pIrp);
  317. Status=WaitForLowerDriverToCompleteIrp(
  318. Extension->LowerDevice,
  319. pIrp,
  320. &WaitEvent
  321. );
  322. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  323. for (i = PowerSystemUnspecified; i < PowerSystemMaximum; i++) {
  324. Extension->SystemPowerStateMap[i]=PowerDeviceD3;
  325. }
  326. for (i = PowerSystemUnspecified; i < PowerSystemHibernate; i++) {
  327. Extension->SystemPowerStateMap[i]=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
  328. }
  329. Extension->SystemPowerStateMap[PowerSystemWorking]=PowerDeviceD0;
  330. Extension->SystemWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake;
  331. Extension->DeviceWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
  332. IoCompleteRequest(
  333. pIrp,
  334. IO_NO_INCREMENT
  335. );
  336. return Status;
  337. }
  338. break;
  339. default:
  340. //
  341. // Unknown function - pass down
  342. //
  343. DebugDump(SERALWAYS,("Passing Pnp Irp down. MnFunc=%x , status = %x\n",pIrpStack->MinorFunction, Status));
  344. IoCopyCurrentIrpStackLocationToNext( pIrp );
  345. return (IoCallDriver(Extension->LowerDevice, pIrp));
  346. break;
  347. }
  348. //
  349. // Complete the IRP...
  350. //
  351. if (!NT_SUCCESS(Status)) {
  352. pIrp -> IoStatus.Status = Status;
  353. pIrp->IoStatus.Information = 0;
  354. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  355. }
  356. else {
  357. DebugDump(SERALWAYS,("Passing Pnp Irp down, status = %x\n", Status));
  358. IoCopyCurrentIrpStackLocationToNext(pIrp);
  359. Status = IoCallDriver(Extension->LowerDevice, pIrp);
  360. }
  361. return( Status );
  362. }
  363. VOID
  364. DevicePowerCompleteRoutine(
  365. PDEVICE_OBJECT DeviceObject,
  366. IN UCHAR MinorFunction,
  367. IN POWER_STATE PowerState,
  368. IN PVOID Context,
  369. IN PIO_STATUS_BLOCK IoStatus
  370. )
  371. {
  372. return;
  373. }
  374. NTSTATUS
  375. SerScanPower(
  376. IN PDEVICE_OBJECT pDeviceObject,
  377. IN PIRP pIrp
  378. )
  379. /*++
  380. Routine Description:
  381. Process the Power IRPs sent to the PDO for this device.
  382. Arguments:
  383. pDeviceObject - pointer to the functional device object (FDO) for this device.
  384. pIrp - pointer to an I/O Request Packet
  385. Return Value:
  386. NT status code
  387. --*/
  388. {
  389. NTSTATUS Status;
  390. PDEVICE_EXTENSION Extension = pDeviceObject->DeviceExtension;
  391. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  392. POWER_STATE PowerState;
  393. PAGED_CODE();
  394. Status = STATUS_SUCCESS;
  395. switch (pIrpStack->MinorFunction) {
  396. case IRP_MN_SET_POWER:
  397. if (pIrpStack->Parameters.Power.Type == SystemPowerState) {
  398. //
  399. // system power state change
  400. //
  401. //
  402. // request the change in device power state based on systemstate map
  403. //
  404. PowerState.DeviceState=Extension->SystemPowerStateMap[pIrpStack->Parameters.Power.State.SystemState];
  405. PoRequestPowerIrp(
  406. Extension->Pdo,
  407. IRP_MN_SET_POWER,
  408. PowerState,
  409. DevicePowerCompleteRoutine,
  410. pIrp,
  411. NULL
  412. );
  413. } else {
  414. //
  415. // changing device state
  416. //
  417. PoSetPowerState(
  418. Extension->Pdo,
  419. pIrpStack->Parameters.Power.Type,
  420. pIrpStack->Parameters.Power.State
  421. );
  422. }
  423. break;
  424. case IRP_MN_QUERY_POWER:
  425. pIrp->IoStatus.Status = STATUS_SUCCESS;
  426. break;
  427. default:
  428. break;
  429. }
  430. PoStartNextPowerIrp(pIrp);
  431. IoSkipCurrentIrpStackLocation(pIrp);
  432. Status=PoCallDriver(Extension->LowerDevice, pIrp);
  433. return Status;
  434. }