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.

641 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: pnppdo.c
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // This file contains functions associated with handling IRPs sent to a PDO
  12. //
  13. #include "pch.h"
  14. NTSTATUS
  15. ParPdoParallelPnp (
  16. IN PDEVICE_OBJECT pDeviceObject,
  17. IN PIRP pIrp
  18. )
  19. /*++
  20. Routine Description:
  21. This routine handles all PNP IRPs for the PDOs.
  22. Arguments:
  23. pDeviceObject - represents a parallel device
  24. pIrp - PNP Irp
  25. Return Value:
  26. STATUS_SUCCESS - if successful.
  27. STATUS_UNSUCCESSFUL - otherwise.
  28. --*/
  29. {
  30. NTSTATUS Status = STATUS_SUCCESS;
  31. PDEVICE_EXTENSION Extension;
  32. // PVOID pDriverObject;
  33. PIO_STACK_LOCATION pIrpStack;
  34. // PIO_STACK_LOCATION pNextIrpStack;
  35. // KEVENT Event;
  36. // ULONG cRequired;
  37. // GUID Guid;
  38. // WCHAR wszGuid[64];
  39. // UNICODE_STRING uniGuid;
  40. // WCHAR wszDeviceDesc[64];
  41. // UNICODE_STRING uniDevice;
  42. // ParDump(PARDUMP_VERBOSE_MAX,
  43. // ("PARALLEL: "
  44. // "Enter ParPdoParallelPnp(...): IRP_MJ_PNP\n") );
  45. pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
  46. Extension = pDeviceObject->DeviceExtension;
  47. //
  48. // dvdf RMT - don't blindly set information to 0
  49. // - kills info passed down by disk.sys and prevents ZipPlus
  50. // from getting assigned a drive letter.
  51. //
  52. // pIrp->IoStatus.Information = 0; // dvdr
  53. //
  54. // bail out if a delete is pending for this device object
  55. //
  56. if(Extension->DeviceStateFlags & PAR_DEVICE_DELETE_PENDING) {
  57. pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  58. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  59. return STATUS_DELETE_PENDING;
  60. }
  61. if(Extension->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
  62. ParDumpP( ("PDO PnP Dispatch - PAR_DEVICE_PORT_REMOVE_PENDING - IRP MN == %x\n", pIrpStack->MinorFunction) );
  63. }
  64. //
  65. // The only PnP IRP that a PODO should receive is QDR/TargetDeviceRelation.
  66. // Any other PnP IRP is an error.
  67. //
  68. if( ( Extension->DeviceType == PAR_DEVTYPE_PODO ) &&
  69. ! ( ( pIrpStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS ) &&
  70. ( pIrpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) ) ) {
  71. ASSERTMSG( "PnP IRP sent to legacy device object ", FALSE);
  72. pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  73. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  74. return STATUS_NOT_SUPPORTED;
  75. }
  76. switch (pIrpStack->MinorFunction) {
  77. case IRP_MN_START_DEVICE:
  78. ParDumpP( ("START_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
  79. Extension->DeviceStateFlags = PAR_DEVICE_STARTED;
  80. // tell parport device to list us in its PnP QDR/RemovalRelations response
  81. // yes, we ignore the return value
  82. Status = ParRegisterForParportRemovalRelations( Extension );
  83. // initialize WMI context structure and register for WMI
  84. // yes, we ignore the return value
  85. Status = ParWmiPdoInitWmi(pDeviceObject);
  86. pIrp->IoStatus.Status = STATUS_SUCCESS;
  87. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  88. KeSetEvent(&Extension->PauseEvent, 0, FALSE);
  89. return STATUS_SUCCESS;
  90. case IRP_MN_QUERY_CAPABILITIES:
  91. ParDumpP( ("QUERY_CAPABILITIES - %wZ\n", &Extension->SymbolicLinkName) );
  92. pIrpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
  93. Status = STATUS_SUCCESS;
  94. break;
  95. case IRP_MN_QUERY_DEVICE_RELATIONS:
  96. ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - Type=%d\n",
  97. &Extension->SymbolicLinkName, pIrpStack->Parameters.QueryDeviceRelations.Type) );
  98. if ( pIrpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) {
  99. #if 0
  100. //
  101. // Return a reference to this PDO (self)
  102. //
  103. PDEVICE_RELATIONS devRel;
  104. ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - TargetRelation\n", &Extension->SymbolicLinkName) );
  105. devRel = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
  106. if (devRel){
  107. //
  108. // Add a reference to the PDO, since CONFIGMG will free it.
  109. //
  110. ObReferenceObject(Extension->DeviceObject);
  111. devRel->Objects[0] = Extension->DeviceObject;
  112. devRel->Count = 1;
  113. pIrp->IoStatus.Information = (ULONG_PTR)devRel;
  114. Status = STATUS_SUCCESS;
  115. } else {
  116. Status = STATUS_INSUFFICIENT_RESOURCES;
  117. }
  118. #else
  119. //
  120. // Forward PnP QueryTargetRelation IRP to ParPort device
  121. //
  122. ParDumpP(("Preparing to forward QDR/TargetDevRel to ParPort\n"));
  123. IoSkipCurrentIrpStackLocation(pIrp);
  124. return ParCallDriver(Extension->PortDeviceObject, pIrp);
  125. #endif // 0
  126. } else {
  127. //
  128. // We don't handle this type of DeviceRelations query, so...
  129. //
  130. // Fail this Irp by returning the default status (typically STATUS_NOT_SUPPORTED).
  131. //
  132. // ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - unhandled relation (!TargetRelation)\n",
  133. // &Extension->SymbolicLinkName) );
  134. Status = pIrp->IoStatus.Status;
  135. }
  136. //
  137. // Complete the IRP...
  138. //
  139. pIrp->IoStatus.Status = Status;
  140. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  141. return Status;
  142. case IRP_MN_QUERY_DEVICE_TEXT:
  143. switch(pIrpStack->Parameters.QueryDeviceText.DeviceTextType) {
  144. case DeviceTextDescription:
  145. {
  146. UCHAR RawString[MAX_ID_SIZE];
  147. ANSI_STRING AnsiTextString;
  148. UNICODE_STRING UnicodeDeviceText;
  149. RtlInitAnsiString(&AnsiTextString,Extension->DeviceDescription);
  150. Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceText,&AnsiTextString,TRUE);
  151. if( NT_SUCCESS( Status ) ) {
  152. ParDumpP( ("QUERY_DEVICE_TEXT - DeviceTextDescription - %wZ\n", &UnicodeDeviceText) );
  153. pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceText.Buffer;
  154. }
  155. }
  156. break;
  157. case DeviceTextLocationInformation:
  158. {
  159. //
  160. // Report SymbolicLinkName without the L"\\DosDevices\\" prefix
  161. // as the location
  162. //
  163. ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
  164. ULONG bufferLength = Extension->SymbolicLinkName.Length - prefixLength + sizeof(UNICODE_NULL);
  165. PWSTR buffer;
  166. ParDumpP( ("QUERY_DEVICE_TEXT - DeviceTextLocationInformation\n") );
  167. ParDumpP( (" - SymbolicLinkName = %wZ , bufferLength = %d\n",
  168. &Extension->SymbolicLinkName, bufferLength) );
  169. if(bufferLength <= MAX_ID_SIZE) {
  170. buffer = ExAllocatePool(PagedPool, bufferLength);
  171. } else {
  172. // assume that something went very wrong
  173. buffer = NULL;
  174. }
  175. if(!buffer) {
  176. // unable to allocate a buffer to hold location information
  177. pIrp->IoStatus.Information = 0;
  178. Status = STATUS_INSUFFICIENT_RESOURCES;
  179. } else {
  180. // copy location information to buffer and null terminate it
  181. PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
  182. RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
  183. buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
  184. pIrp->IoStatus.Information = (ULONG_PTR)buffer;
  185. Status = STATUS_SUCCESS;
  186. ParDumpP( ("QUERY_DEVICE_TEXT - Device Location - %S\n", buffer) );
  187. }
  188. }
  189. break; // from case DeviceTextLocationInformation:
  190. default:
  191. // unknown request type
  192. // pIrp->IoStatus.Information = 0;
  193. Status = pIrp->IoStatus.Status;
  194. }
  195. break; // from case IRP_MN_QUERY_DEVICE_TEXT:
  196. case IRP_MN_QUERY_ID:
  197. {
  198. //
  199. // report the id depending on what the device attached to the port returned us
  200. //
  201. UCHAR DeviceIdString[MAX_ID_SIZE] = "LPTENUM\\NoPrinterOrNonPnpModel";
  202. UCHAR RawString[MAX_ID_SIZE];
  203. ANSI_STRING AnsiIdString;
  204. UNICODE_STRING UnicodeDeviceId;
  205. UNICODE_STRING UnicodeTemp;
  206. ULONG DeviceIdLength;
  207. HANDLE KeyHandle;
  208. if (Extension->DeviceIdString[0] == 0) {
  209. Status = STATUS_INVALID_DEVICE_REQUEST;
  210. break;
  211. }
  212. RtlZeroMemory(RawString, sizeof(RawString));
  213. Status = STATUS_SUCCESS;
  214. switch(pIrpStack->Parameters.QueryId.IdType) {
  215. case BusQueryDeviceID:
  216. if (Extension->DeviceIdString[0] == 0) {
  217. Status = STATUS_NOT_FOUND;
  218. break;
  219. } else {
  220. sprintf((PCHAR)RawString,"LPTENUM\\%s",Extension->DeviceIdString );
  221. ParFixupDeviceId( (PUCHAR)RawString );
  222. RtlInitAnsiString(&AnsiIdString, (PCHAR)RawString);
  223. Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceId, &AnsiIdString, TRUE);
  224. }
  225. if( NT_SUCCESS( Status ) ) {
  226. ParDumpP( ("QUERY_ID - BusQueryDeviceID - %wZ\n", &UnicodeDeviceId) );
  227. pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceId.Buffer;
  228. }
  229. break;
  230. case BusQueryInstanceID:
  231. if (Extension->DeviceIdString[0] == 0) {
  232. Status = STATUS_NOT_FOUND;
  233. break;
  234. }
  235. //
  236. // Report SymbolicLinkName without the L"\\DosDevices\\" prefix
  237. // as the instance ID
  238. //
  239. {
  240. ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
  241. ULONG bufferLength = Extension->SymbolicLinkName.Length - prefixLength + sizeof(UNICODE_NULL);
  242. PWSTR buffer;
  243. ParDumpP( ("QUERY_ID - BusQueryInstanceID - "
  244. "SymbolicLinkName = %wZ , bufferLength = %d\n",
  245. &Extension->SymbolicLinkName, bufferLength) );
  246. if(bufferLength <= MAX_ID_SIZE) {
  247. buffer = ExAllocatePool(PagedPool, bufferLength);
  248. } else {
  249. // assume that something went very wrong
  250. buffer = NULL;
  251. }
  252. if(!buffer) {
  253. // unable to allocate a buffer to hold location information
  254. pIrp->IoStatus.Information = 0;
  255. Status = STATUS_INSUFFICIENT_RESOURCES;
  256. } else {
  257. // copy location information to buffer and null terminate it
  258. PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
  259. RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
  260. buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
  261. pIrp->IoStatus.Information = (ULONG_PTR)buffer;
  262. Status = STATUS_SUCCESS;
  263. ParDumpP( ("QUERY_ID - BusQueryInstanceID - %S\n", buffer) );
  264. }
  265. }
  266. break;
  267. case BusQueryHardwareIDs:
  268. if (Extension->DeviceIdString[0] == 0) {
  269. // bail out if we don't have a device id
  270. Status = STATUS_NOT_FOUND;
  271. break;
  272. }
  273. //
  274. // Store the port we are attached in the registry under our device instance
  275. //
  276. Status = IoOpenDeviceRegistryKey( pDeviceObject, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &KeyHandle );
  277. if ( NT_SUCCESS(Status) ) {
  278. //
  279. // Create a new value under our instance, for the port number
  280. //
  281. sprintf((PCHAR)RawString,"PortName");
  282. RtlInitAnsiString(&AnsiIdString,(PCHAR)RawString);
  283. //
  284. // Now we have to build the actual value contents
  285. //
  286. {
  287. //
  288. // - Start with the SymbolicLinkName
  289. // - Discard the L"\\DosDevices\\" prefix
  290. // WORKWORK/RMT TODO: - Discard the L".N" suffix if this is an End-Of-Chain device
  291. // - Append L':'
  292. //
  293. ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
  294. ULONG bufferLength = Extension->SymbolicLinkName.Length
  295. - prefixLength + sizeof(PAR_UNICODE_COLON) + sizeof(UNICODE_NULL);
  296. PWSTR buffer;
  297. ParDumpV( ( "QUERY_ID - BusQueryHardwareIDs - SymbolicLinkName = %wZ , bufferLength = %d\n",
  298. &Extension->SymbolicLinkName, bufferLength) );
  299. if(bufferLength > MAX_ID_SIZE) {
  300. // we had a rollover and our bufferLength is not valid
  301. buffer = NULL;
  302. } else {
  303. buffer = ExAllocatePool(PagedPool, bufferLength);
  304. }
  305. if(!buffer) {
  306. // unable to allocate a buffer to hold location information
  307. pIrp->IoStatus.Information = 0;
  308. pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  309. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  310. return STATUS_INSUFFICIENT_RESOURCES;
  311. } else {
  312. // copy location information to buffer and null terminate it
  313. PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
  314. RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
  315. buffer[ bufferLength/2 - 2 ] = PAR_UNICODE_COLON;
  316. buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
  317. {
  318. // if this is an End-Of-Chain device, discard the L".N" suffix
  319. // WARNING - HACKHACK until spooler is fully PnP
  320. if( ( (Extension->Ieee1284_3DeviceId == DOT3_END_OF_CHAIN_ID) || Extension->EndOfChain ) &&
  321. (buffer[bufferLength/2 - 3] <= L'9') &&
  322. (buffer[bufferLength/2 - 3] >= L'0') &&
  323. (buffer[bufferLength/2 - 4] == L'.') ) {
  324. buffer[bufferLength/2 - 4] = PAR_UNICODE_COLON;
  325. buffer[bufferLength/2 - 3] = UNICODE_NULL;
  326. }
  327. }
  328. RtlInitUnicodeString(&UnicodeTemp, buffer);
  329. }
  330. }
  331. {
  332. UNICODE_STRING UnicodeRegValueName;
  333. NTSTATUS status;
  334. status = RtlAnsiStringToUnicodeString(&UnicodeRegValueName,&AnsiIdString,TRUE);
  335. if( NT_SUCCESS ( status ) ) {
  336. ZwSetValueKey( KeyHandle, &UnicodeRegValueName, 0, REG_SZ, UnicodeTemp.Buffer, UnicodeTemp.Length*sizeof(UCHAR) );
  337. RtlFreeUnicodeString(&UnicodeRegValueName);
  338. }
  339. }
  340. ZwClose(KeyHandle);
  341. }
  342. ParDumpP( ("QUERY_ID - BusQueryHardwareIDs\n") );
  343. //
  344. // continue on, to return the actual HardwareID string
  345. //
  346. case BusQueryCompatibleIDs:
  347. if (Extension->DeviceIdString[0] == 0) {
  348. Status = STATUS_NOT_FOUND;
  349. break;
  350. }
  351. Status = ParPnpGetId(Extension->DeviceIdString,pIrpStack->Parameters.QueryId.IdType,RawString, NULL);
  352. if( NT_SUCCESS( Status ) ) {
  353. RawString[strlen((PCHAR)RawString)+1]=0;
  354. RawString[strlen((PCHAR)RawString)]=32;
  355. ParFixupDeviceId( (PUCHAR)RawString );
  356. RtlInitAnsiString(&AnsiIdString,(PCHAR)RawString);
  357. Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceId,&AnsiIdString,TRUE);
  358. if( NT_SUCCESS( Status ) ) {
  359. ParDumpP( ("QUERY_ID - BusQueryHardwareIDs/BusQueryCompatibleIDs - %wZ\n", &UnicodeDeviceId) );
  360. // Now append another NULL, to terminate the multi_sz
  361. UnicodeTemp.Buffer = UnicodeDeviceId.Buffer;
  362. ((PSTR)UnicodeTemp.Buffer) += (UnicodeDeviceId.Length-2);
  363. RtlZeroMemory(UnicodeTemp.Buffer,sizeof(WCHAR));
  364. pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceId.Buffer;
  365. }
  366. }
  367. break;
  368. default:
  369. //
  370. // unrecognized IdType
  371. //
  372. Status = pIrp->IoStatus.Status;
  373. } // end switch(pIrpStack->Parameters.QueryId.IdType)
  374. break;
  375. }
  376. case IRP_MN_QUERY_STOP_DEVICE:
  377. ParDumpP( ("QUERY_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
  378. Extension->DeviceStateFlags |= (PAR_DEVICE_STOP_PENDING | PAR_DEVICE_PAUSED);
  379. KeClearEvent(&Extension->PauseEvent);
  380. Status = STATUS_SUCCESS;
  381. break;
  382. case IRP_MN_CANCEL_STOP_DEVICE:
  383. ParDumpP( ("IRP_MN_CANCEL_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
  384. Extension->DeviceStateFlags &= ~PAR_DEVICE_STOP_PENDING;
  385. KeSetEvent(&Extension->PauseEvent, 0, FALSE);
  386. Status = STATUS_SUCCESS;
  387. break;
  388. case IRP_MN_STOP_DEVICE:
  389. ParDumpP( ("IRP_MN_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
  390. Extension->DeviceStateFlags |= PAR_DEVICE_PAUSED;
  391. Extension->DeviceStateFlags &= ~PAR_DEVICE_STARTED;
  392. KeClearEvent(&Extension->PauseEvent);
  393. Status = STATUS_SUCCESS;
  394. break;
  395. case IRP_MN_QUERY_REMOVE_DEVICE:
  396. // Succeed if no one has an open handle to us, fail otherwise
  397. ExAcquireFastMutex(&Extension->OpenCloseMutex);
  398. if(Extension->OpenCloseRefCount > 0) {
  399. DDPnP1(("## Fail QueryRemove - %wZ\n",&Extension->SymbolicLinkName));
  400. ParDump2(PARPNP1, ("QUERY_REMOVE_DEVICE - %wZ - FAIL - open handles to us\n", &Extension->SymbolicLinkName) );
  401. Status = STATUS_DEVICE_BUSY;
  402. } else {
  403. DDPnP1(("## Succeed QueryRemove - %wZ\n",&Extension->SymbolicLinkName));
  404. ParDump2(PARPNP1, ("IRP_MN_QUERY_REMOVE_DEVICE - %wZ - SUCCEED\n", &Extension->SymbolicLinkName) );
  405. Extension->DeviceStateFlags |= (PAR_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
  406. KeClearEvent(&Extension->PauseEvent);
  407. if( Extension->PortDeviceFileObject ) {
  408. //
  409. // close our handle to parport so we don't block a parport removal
  410. //
  411. ParDump2(PARPNP1, ("CLOSE our handle to ParPort\n") );
  412. ObDereferenceObject( Extension->PortDeviceFileObject );
  413. Extension->PortDeviceFileObject = NULL;
  414. }
  415. Status = STATUS_SUCCESS;
  416. }
  417. ExReleaseFastMutex(&Extension->OpenCloseMutex);
  418. break;
  419. case IRP_MN_CANCEL_REMOVE_DEVICE:
  420. DDPnP1(("## CancelRemove - %wZ\n",&Extension->SymbolicLinkName));
  421. ParDumpP( ("CANCEL_REMOVE_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
  422. Extension->DeviceStateFlags &= ~(PAR_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
  423. if( !Extension->PortDeviceFileObject ) {
  424. //
  425. // we dropped our connection to our ParPort prior to
  426. // our ParPort receiving QUERY_REMOVE, reestablish
  427. // a FILE connection and resume operation
  428. //
  429. NTSTATUS status;
  430. PFILE_OBJECT portDeviceFileObject;
  431. PDEVICE_OBJECT portDeviceObject;
  432. ParDump2(PARPNP1, ("reopening file against our ParPort\n") );
  433. status = IoGetDeviceObjectPointer(&Extension->PortSymbolicLinkName,
  434. STANDARD_RIGHTS_ALL,
  435. &portDeviceFileObject,
  436. &portDeviceObject);
  437. if(NT_SUCCESS(status) && portDeviceFileObject && portDeviceObject) {
  438. // save REFERENCED PFILE_OBJECT in our device extension
  439. Extension->PortDeviceFileObject = portDeviceFileObject;
  440. // our ParPort device object should not have changed
  441. ASSERT(Extension->PortDeviceObject == portDeviceObject);
  442. } else {
  443. ParDump2(PARPNP1, ("Unable to reopen FILE against our ParPort\n") );
  444. //
  445. // Unable to reestablish connection? Inconceivable!
  446. //
  447. ASSERT(FALSE);
  448. }
  449. }
  450. KeSetEvent(&Extension->PauseEvent, 0, FALSE);
  451. Status = STATUS_SUCCESS;
  452. break;
  453. case IRP_MN_REMOVE_DEVICE:
  454. DDPnP1(("## RemoveDevice - %wZ\n",&Extension->SymbolicLinkName));
  455. ParDumpP( ("REMOVE_DEVICE - %x <%wZ>\n", Extension->DeviceObject, &Extension->SymbolicLinkName) );
  456. Status = ParUnregisterForParportRemovalRelations( Extension );
  457. //
  458. // Unregister with WMI
  459. //
  460. ParWMIRegistrationControl(pDeviceObject, WMIREG_ACTION_DEREGISTER);
  461. ParDumpP( ("REMOVE_DEVICE - %wZ - Checking if device still there...\n",
  462. &Extension->SymbolicLinkName) );
  463. if( !(Extension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE) && ParDeviceExists(Extension,FALSE) ) {
  464. ParDumpP( ("REMOVE_DEVICE - %wZ - Device still there - Keep DO\n",
  465. &Extension->SymbolicLinkName) );
  466. Extension->DeviceStateFlags = PAR_DEVICE_PAUSED;
  467. } else {
  468. ParDumpP( ("REMOVE_DEVICE - %wZ - Device no longer present - Kill DO\n",
  469. &Extension->SymbolicLinkName) );
  470. {
  471. //
  472. // Clean up the device object
  473. //
  474. PDEVICE_EXTENSION FdoExtension = Extension->ParClassFdo->DeviceExtension;
  475. ExAcquireFastMutex(&FdoExtension->DevObjListMutex);
  476. ParKillDeviceObject(pDeviceObject);
  477. ExReleaseFastMutex(&FdoExtension->DevObjListMutex);
  478. }
  479. }
  480. Status = STATUS_SUCCESS;
  481. break;
  482. case IRP_MN_SURPRISE_REMOVAL:
  483. #define PAR_HANDLE_SURPRISE_REMOVAL 1
  484. #if PAR_HANDLE_SURPRISE_REMOVAL
  485. ParDumpP( ("SURPRISE_REMOVAL - %wZ - handled\n", &Extension->SymbolicLinkName) );
  486. // note in our extension that we received SURPRISE_REMOVAL
  487. Extension->DeviceStateFlags |= PAR_DEVICE_SURPRISE_REMOVAL;
  488. // stop the worker thread
  489. KeClearEvent(&Extension->PauseEvent);
  490. Status = STATUS_SUCCESS;
  491. break;
  492. #else
  493. ParDumpP( ("SURPRISE_REMOVAL - %wZ - NOT handled\n", &Extension->SymbolicLinkName) );
  494. // we don't handle yet - fall through to default
  495. #endif
  496. default:
  497. ParDumpP(("ParPdoParallelPnp - %wZ - Unhandled IRP %x\n",
  498. &Extension->SymbolicLinkName, pIrpStack->MinorFunction) );
  499. Status = pIrp->IoStatus.Status; // Don't modify status
  500. break;
  501. }
  502. //
  503. // Complete the IRP...
  504. //
  505. pIrp->IoStatus.Status = Status;
  506. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  507. return Status;
  508. }