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.

574 lines
19 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: pnpfdo.c
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // This file contains functions for handing AddDevice and PnP IRPs sent to the FDO
  12. //
  13. #include "pch.h"
  14. NTSTATUS
  15. ParPnpNotifyHwProfileChange(
  16. IN PHWPROFILE_CHANGE_NOTIFICATION NotificationStructure,
  17. IN PDEVICE_OBJECT Fdo
  18. )
  19. //
  20. // We just completed either a dock or an undock - trigger bus rescan to check for new devices
  21. //
  22. {
  23. PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  24. PAGED_CODE();
  25. if( IsEqualGUID( (LPGUID)&(NotificationStructure->Event), (LPGUID)&GUID_HWPROFILE_CHANGE_COMPLETE) ) {
  26. IoInvalidateDeviceRelations( fdoExt->PhysicalDeviceObject, BusRelations );
  27. }
  28. return STATUS_SUCCESS;
  29. }
  30. NTSTATUS
  31. ParPnpFdoStartDevice(
  32. IN PDEVICE_OBJECT Fdo,
  33. IN PIRP Irp
  34. )
  35. {
  36. NTSTATUS status = STATUS_NOT_SUPPORTED;
  37. PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  38. KEVENT event;
  39. ParDumpP( ("IRP_MN_START_DEVICE - FDO\n") );
  40. //
  41. // The stack below us must successfully START before we can START.
  42. //
  43. // Pass the IRP down the stack and catch it on the way back up in our
  44. // completion routine. Our completion routine simply sets "event"
  45. // to its signalled state and returns STATUS_MORE_PROCESSING_REQUIRED,
  46. // which allows us to regain control of the IRP in this routine after
  47. // the stack below us has finished processing the START.
  48. //
  49. KeInitializeEvent(&event, NotificationEvent, FALSE);
  50. IoCopyCurrentIrpStackLocationToNext(Irp);
  51. IoSetCompletionRoutine(Irp, ParSynchCompletionRoutine, &event, TRUE, TRUE, TRUE );
  52. status = ParCallDriver(fdoExt->ParentDeviceObject, Irp);
  53. // wait for our completion routine to signal that it has caught the IRP
  54. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  55. //
  56. // We have control of the IRP again and the stack below us has finished processing.
  57. //
  58. if( status == STATUS_PENDING ) {
  59. // IRP completed asynchronously below us - extract "real" status from the IRP
  60. status = Irp->IoStatus.Status;
  61. }
  62. //
  63. // did anyone below us FAIL the IRP?
  64. //
  65. if( !NT_SUCCESS(status) ) {
  66. // someone below us FAILed the IRP, bail out
  67. ParDump2(PARERRORS, ("START IRP FAILED below us in stack, status=%x\n", status) );
  68. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  69. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  70. return status;
  71. }
  72. //
  73. // The stack below us is STARTed.
  74. //
  75. //
  76. // Register for ParPort PnP Interface changes.
  77. //
  78. // We will get an ARRIVAL callback for every ParPort device that is STARTed and
  79. // a REMOVAL callback for every ParPort that is REMOVEd
  80. //
  81. #if 0 // disable parclass enumeration to work with new parport enumerator - DFritz - 2000-03-25
  82. status = IoRegisterPlugPlayNotification (EventCategoryDeviceInterfaceChange,
  83. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  84. (PVOID)&GUID_PARALLEL_DEVICE,
  85. Fdo->DriverObject,
  86. (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)ParPnpNotifyInterfaceChange,
  87. (PVOID)Fdo,
  88. &fdoExt->NotificationHandle);
  89. if (!NT_SUCCESS(status)) {
  90. // registration failed, we will never have any ParPort devices to talk to
  91. ParDumpP( ("IoRegisterPlugPlayNotification InterfaceChange FAILED, status= %x\n", status) );
  92. }
  93. status = IoRegisterPlugPlayNotification( EventCategoryHardwareProfileChange,
  94. 0,
  95. NULL,
  96. Fdo->DriverObject,
  97. (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)ParPnpNotifyHwProfileChange,
  98. (PVOID)Fdo,
  99. &fdoExt->HwProfileChangeNotificationHandle );
  100. if (!NT_SUCCESS(status)) {
  101. // registration failed, we will never have any ParPort devices to talk to
  102. ParDumpP( ("IoRegisterPlugPlayNotification HwProfileChange FAILED, status= %x\n", status) );
  103. }
  104. #endif // 0
  105. Irp->IoStatus.Status = status;
  106. Irp->IoStatus.Information = 0;
  107. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  108. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  109. return status;
  110. }
  111. NTSTATUS
  112. ParPnpFdoQueryCapabilities(
  113. IN PDEVICE_OBJECT Fdo,
  114. IN PIRP Irp
  115. )
  116. {
  117. NTSTATUS status;
  118. PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  119. // KEVENT event;
  120. PIO_STACK_LOCATION irpStack;
  121. ParDumpP( ("IRP_MN_QUERY_CAPABILITIES - FDO\n") );
  122. irpStack = IoGetCurrentIrpStackLocation( Irp );
  123. // - does RawDeviceOK = TRUE make sense for the FDO?
  124. //
  125. // Start us even if no function driver or filter driver is found.
  126. //
  127. irpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
  128. //
  129. // The instance ID's that we report are system wide unique.
  130. //
  131. // irpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = TRUE;
  132. // - change to FALSE because we reuse names for LPTx.y during rescan
  133. // when we detect that the daisy chain devices changed
  134. //
  135. irpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = FALSE;
  136. Irp->IoStatus.Status = STATUS_SUCCESS;
  137. Irp->IoStatus.Information = 0;
  138. IoSkipCurrentIrpStackLocation(Irp);
  139. status = ParCallDriver(fdoExt->ParentDeviceObject, Irp);
  140. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  141. return status;
  142. }
  143. NTSTATUS
  144. ParFdoParallelPnp (
  145. IN PDEVICE_OBJECT pDeviceObject,
  146. IN PIRP pIrp
  147. )
  148. /*++
  149. Routine Description:
  150. This routine handles all PNP IRPs sent to the ParClass FDO.
  151. We got here because !(Extension->IsPdo)
  152. Arguments:
  153. pDeviceObject - The ParClass FDO
  154. pIrp - PNP Irp
  155. Return Value:
  156. STATUS_SUCCESS - if successful.
  157. STATUS_UNSUCCESSFUL - otherwise.
  158. --*/
  159. {
  160. NTSTATUS Status = STATUS_NOT_SUPPORTED;
  161. PDEVICE_EXTENSION Extension;
  162. PVOID pDriverObject;
  163. PIO_STACK_LOCATION pIrpStack;
  164. PIO_STACK_LOCATION pNextIrpStack;
  165. KEVENT Event;
  166. ULONG cRequired;
  167. // GUID Guid;
  168. WCHAR wszGuid[64];
  169. UNICODE_STRING uniGuid;
  170. // WCHAR wszDeviceDesc[64];
  171. UNICODE_STRING uniDevice;
  172. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
  173. Extension = pDeviceObject->DeviceExtension; // FDO Extension
  174. {
  175. NTSTATUS status = ParAcquireRemoveLock(&Extension->RemoveLock, pIrp);
  176. if ( !NT_SUCCESS( status ) ) {
  177. //
  178. // Someone gave us a pnp irp after a remove. Unthinkable!
  179. //
  180. // ASSERT(FALSE);
  181. pIrp->IoStatus.Information = 0;
  182. pIrp->IoStatus.Status = status;
  183. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  184. return status;
  185. }
  186. }
  187. // dvdr
  188. // pIrp->IoStatus.Information = 0;
  189. switch (pIrpStack->MinorFunction) {
  190. case IRP_MN_START_DEVICE:
  191. return ParPnpFdoStartDevice(pDeviceObject, pIrp);
  192. case IRP_MN_QUERY_CAPABILITIES:
  193. ParDumpP( ("IRP_MN_QUERY_CAPABILITIES - FDO\n") );
  194. pIrpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE; // no Function Driver required
  195. pIrpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = TRUE; // ID's reported are system wide unique
  196. pIrp->IoStatus.Status = STATUS_SUCCESS;
  197. IoSkipCurrentIrpStackLocation(pIrp);
  198. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  199. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  200. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  201. ParDumpP( ("QUERY_DEVICE_RELATIONS - FDO\n") );
  202. if(pIrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) {
  203. break; // bail out if we don't handle this query type
  204. } else {
  205. return ParPnpFdoQueryDeviceRelationsBusRelations(pDeviceObject, pIrp);
  206. }
  207. }
  208. case IRP_MN_QUERY_STOP_DEVICE:
  209. // always SUCCEED
  210. ParDumpP( ( "QUERY_STOP_DEVICE - FDO\n") );
  211. pIrp->IoStatus.Status = STATUS_SUCCESS;
  212. IoSkipCurrentIrpStackLocation (pIrp);
  213. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  214. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  215. case IRP_MN_CANCEL_STOP_DEVICE:
  216. ParDumpP( ("CANCEL_STOP_DEVICE - FDO\n") );
  217. // handle IRP synchronously:
  218. // - set completion routine and event to wake on
  219. // - pass IRP down the stack
  220. // - our completion routine sets the event which wakes us
  221. // - we wake on the event and regain control of
  222. // the IRP on its way back up
  223. // setup
  224. IoCopyCurrentIrpStackLocationToNext(pIrp);
  225. IoSetCompletionRoutine(pIrp, ParSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
  226. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  227. // pass IRP down the stack
  228. Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
  229. // wait for our completion routine to wake us up
  230. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  231. // we have NOW regained control of the IRP on its way back up the stack
  232. // extract "real" status from IRP if IoCallDriver returned PENDING
  233. if (Status == STATUS_PENDING) {
  234. Status = pIrp->IoStatus.Status;
  235. }
  236. // check if anyone below us in the stack failed the IRP
  237. if ( !NT_SUCCESS(Status) && (Status != STATUS_NOT_SUPPORTED) ) {
  238. ParDumpP( ("CANCEL_STOP_DEVICE failed at parent, Status= %x\n", Status) );
  239. break;
  240. }
  241. // SUCCESS
  242. pIrp->IoStatus.Status = STATUS_SUCCESS;
  243. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  244. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  245. return STATUS_SUCCESS;
  246. case IRP_MN_STOP_DEVICE:
  247. // always SUCCEED
  248. ParDumpP( ("STOP_DEVICE - FDO\n") );
  249. pIrp->IoStatus.Status = STATUS_SUCCESS;
  250. IoSkipCurrentIrpStackLocation (pIrp);
  251. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  252. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  253. case IRP_MN_QUERY_REMOVE_DEVICE:
  254. // SUCCEED if no PODOs (i.e., no parallel ports), FAIL otherwise
  255. if( Extension->ParClassPdo ) {
  256. ParDumpP( ("QUERY_REMOVE_DEVICE - FDO - FAIL - Legacy PODOs may be using Ports\n") );
  257. pIrp->IoStatus.Status = STATUS_DEVICE_BUSY;
  258. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  259. ParCompleteRequest(pIrp, IO_NO_INCREMENT);
  260. return STATUS_DEVICE_BUSY;
  261. } else {
  262. ParDumpP( ("QUERY_REMOVE_DEVICE - FDO - SUCCESS - no ParPorts exist\n") );
  263. pIrp->IoStatus.Status = STATUS_SUCCESS;
  264. IoSkipCurrentIrpStackLocation (pIrp);
  265. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  266. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  267. }
  268. case IRP_MN_CANCEL_REMOVE_DEVICE:
  269. ParDumpP( ( "CANCEL_REMOVE_DEVICE - FDO\n") );
  270. // handle IRP synchronously:
  271. // - set completion routine and event to wake on
  272. // - pass IRP down the stack
  273. // - our completion routine sets the event which wakes us
  274. // - we wake on the event and regain control of
  275. // the IRP on its way back up
  276. // setup
  277. IoCopyCurrentIrpStackLocationToNext(pIrp);
  278. IoSetCompletionRoutine(pIrp, ParSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
  279. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  280. // pass IRP down the stack
  281. Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
  282. // wait for our completion routine to wake us up
  283. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  284. // we have NOW regained control of the IRP on its way back up the stack
  285. // extract "real" status from IRP if IoCallDriver returned PENDING
  286. if (Status == STATUS_PENDING) {
  287. Status = pIrp->IoStatus.Status;
  288. }
  289. // check if anyone below us in the stack failed the IRP
  290. if (!NT_SUCCESS(Status)) {
  291. ParDumpP( ("CANCEL_REMOVE_DEVICE FAILED, Status = %x\n", Status) );
  292. break;
  293. }
  294. // SUCCESS
  295. pIrp->IoStatus.Status = STATUS_SUCCESS;
  296. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  297. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  298. return STATUS_SUCCESS;
  299. case IRP_MN_REMOVE_DEVICE:
  300. ParDumpP( ("REMOVE_DEVICE - FDO\n") );
  301. Extension->DeviceStateFlags |= PAR_DEVICE_REMOVED;
  302. if(Extension->NotificationHandle) {
  303. IoUnregisterPlugPlayNotification (Extension->NotificationHandle);
  304. Extension->NotificationHandle = 0;
  305. }
  306. if( Extension->HwProfileChangeNotificationHandle ) {
  307. IoUnregisterPlugPlayNotification( Extension->HwProfileChangeNotificationHandle );
  308. Extension->HwProfileChangeNotificationHandle = 0;
  309. }
  310. IoSkipCurrentIrpStackLocation(pIrp);
  311. pIrp->IoStatus.Status = STATUS_SUCCESS;
  312. Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
  313. ParReleaseRemoveLockAndWait(&Extension->RemoveLock, pIrp);
  314. IoDetachDevice(Extension->ParentDeviceObject);
  315. if (Extension->ClassName.Buffer) {
  316. ExFreePool(Extension->ClassName.Buffer);
  317. }
  318. //
  319. // walk the list of remaining ParClass ejected device objects and kill them
  320. //
  321. {
  322. PDEVICE_OBJECT current;
  323. PDEVICE_EXTENSION FdoExtension = Extension; // fix alanmo discovered bug from machine where parport not started
  324. ExAcquireFastMutex(&FdoExtension->DevObjListMutex);
  325. current = Extension->ParClassPdo;
  326. while(current) {
  327. PDEVICE_OBJECT next = ( (PDEVICE_EXTENSION)(current->DeviceExtension) )->Next;
  328. ParKillDeviceObject(current);
  329. current = next;
  330. }
  331. ExReleaseFastMutex(&FdoExtension->DevObjListMutex);
  332. }
  333. Extension->DeviceStateFlags |= PAR_DEVICE_DELETED;
  334. IoDeleteDevice(pDeviceObject);
  335. return Status;
  336. case IRP_MN_SURPRISE_REMOVAL:
  337. // ParClass FDO is root enumerated - we should never get this IRP
  338. ParDumpP( ("IRP_MN_SURPRISE_REMOVAL - FDO - We are not supposed to get this IRP!!!\n") );
  339. // fall through into default case since we don't handle this
  340. default:
  341. // We don't handle this request, simply pass it down the stack
  342. ParDumpP( ("Unhandled PNP IRP: %x - FDO\n", pIrpStack->MinorFunction) );
  343. IoSkipCurrentIrpStackLocation(pIrp);
  344. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  345. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  346. }
  347. //
  348. // Set the return code only if we have something to add.
  349. //
  350. if( Status != STATUS_NOT_SUPPORTED ) {
  351. pIrp->IoStatus.Status = Status ;
  352. }
  353. //
  354. // Complete immediately if we have failed the Irp for any reason other
  355. // than STATUS_NOT_SUPPORTED. Otherwise, pass down.
  356. //
  357. if( NT_SUCCESS(Status) || (Status == STATUS_NOT_SUPPORTED) ) {
  358. IoSkipCurrentIrpStackLocation(pIrp);
  359. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  360. return ParCallDriver(Extension->ParentDeviceObject, pIrp);
  361. }
  362. //
  363. // Complete the IRP...
  364. //
  365. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  366. ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
  367. return Status;
  368. }
  369. NTSTATUS
  370. ParPnpAddDevice(
  371. IN PDRIVER_OBJECT pDriverObject,
  372. IN PDEVICE_OBJECT pPhysicalDeviceObject
  373. )
  374. /*++
  375. Routine Description:
  376. This routine is the ParClass AddDevice routine.
  377. This routine creates the ParClass FDO and attaches it to the device stack
  378. Arguments:
  379. pDriverObject - pointer to the driver object for this instance of parport.
  380. pPhysicalDeviceObject - pointer to the device object that represents the port.
  381. Return Value:
  382. STATUS_SUCCESS - if successful.
  383. !STATUS_SUCCESS - otherwise.
  384. --*/
  385. {
  386. PDEVICE_OBJECT pDeviceObject;
  387. PDEVICE_EXTENSION Extension;
  388. NTSTATUS Status;
  389. ParBreak(PAR_BREAK_ON_ADD_DEVICE, ("ParPnpAddDevice(PDRIVER_OBJECT, PDEVICE_OBJECT)\n") );
  390. //
  391. // Create the device object for this device.
  392. //
  393. Status = ParCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), NULL,
  394. FILE_DEVICE_PARALLEL_PORT, 0, TRUE, &pDeviceObject);
  395. if (!NT_SUCCESS(Status)) {
  396. ParLogError(pDriverObject, NULL, PhysicalZero, PhysicalZero, 0, 0, 0, 9, STATUS_SUCCESS, Status);
  397. ParDump(PARERRORS, ("PARALLEL: Could not create a Device Object for FDO\n") );
  398. return Status;
  399. }
  400. //
  401. // Setup buffered I/O
  402. //
  403. pDeviceObject->Flags |= DO_BUFFERED_IO;
  404. Extension = pDeviceObject->DeviceExtension;
  405. RtlZeroMemory(Extension, sizeof(DEVICE_EXTENSION));
  406. Extension->DeviceType = PAR_DEVTYPE_FDO;
  407. ExInitializeFastMutex(&Extension->OpenCloseMutex);
  408. ExInitializeFastMutex(&Extension->DevObjListMutex); // only FDO has this Mutex
  409. IoInitializeRemoveLock(&Extension->RemoveLock, PARCLASS_POOL_TAG, 1, 10);
  410. Extension->ExtensionSignature = PARCLASS_EXTENSION_SIGNATURE;
  411. Extension->ExtensionSignatureEnd = PARCLASS_EXTENSION_SIGNATURE;
  412. Extension->DeviceObject = pDeviceObject;
  413. //
  414. // Attach our new Device to our parent's stack.
  415. //
  416. Extension->ParentDeviceObject = IoAttachDeviceToDeviceStack( pDeviceObject, pPhysicalDeviceObject);
  417. ParDumpV( ("ParPnpAddDevice(...): "
  418. "pDeviceObject= %08x , Extension= %08x , ParentDeviceObject= %08x\n",
  419. pDeviceObject, Extension, Extension->ParentDeviceObject) );
  420. if (NULL == Extension->ParentDeviceObject) {
  421. ParDump2(PARERRORS, ("ParPnpAddDevice(...): IoAttachDeviceToDeviceStack FAILED\n") );
  422. IoDeleteDevice(pDeviceObject);
  423. return STATUS_UNSUCCESSFUL;
  424. }
  425. //
  426. // Done initializing
  427. //
  428. Extension->PhysicalDeviceObject = pPhysicalDeviceObject;
  429. pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  430. return STATUS_SUCCESS;
  431. }