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.

708 lines
25 KiB

  1. #include "pch.h"
  2. NTSTATUS PptPdoStartDevice( PDEVICE_OBJECT DevObj, PIRP Irp );
  3. NTSTATUS PptPdoQueryRemove( PDEVICE_OBJECT DevObj, PIRP Irp );
  4. NTSTATUS PptPdoRemoveDevice( PDEVICE_OBJECT DevObj, PIRP Irp );
  5. NTSTATUS PptPdoCancelRemove( PDEVICE_OBJECT DevObj, PIRP Irp );
  6. NTSTATUS PptPdoStopDevice( PDEVICE_OBJECT DevObj, PIRP Irp );
  7. NTSTATUS PptPdoQueryStop( PDEVICE_OBJECT DevObj, PIRP Irp );
  8. NTSTATUS PptPdoCancelStop( PDEVICE_OBJECT DevObj, PIRP Irp );
  9. NTSTATUS PptPdoQueryDeviceRelations( PDEVICE_OBJECT DevObj, PIRP Irp );
  10. NTSTATUS PptPdoQueryCapabilities( PDEVICE_OBJECT DevObj, PIRP Irp );
  11. NTSTATUS PptPdoQueryDeviceText( PDEVICE_OBJECT DevObj, PIRP Irp );
  12. NTSTATUS PptPdoQueryId( PDEVICE_OBJECT DevObj, PIRP Irp );
  13. NTSTATUS PptPdoQueryPnpDeviceState( PDEVICE_OBJECT DevObj, PIRP Irp );
  14. NTSTATUS PptPdoQueryBusInformation( PDEVICE_OBJECT DevObj, PIRP Irp );
  15. NTSTATUS PptPdoSurpriseRemoval( PDEVICE_OBJECT DevObj, PIRP Irp );
  16. NTSTATUS PptPdoDefaultPnpHandler( PDEVICE_OBJECT DevObj, PIRP Irp );
  17. PDRIVER_DISPATCH
  18. PptPdoPnpDispatchTable[] =
  19. {
  20. PptPdoStartDevice, // IRP_MN_START_DEVICE 0x00
  21. PptPdoQueryRemove, // IRP_MN_QUERY_REMOVE_DEVICE 0x01
  22. PptPdoRemoveDevice, // IRP_MN_REMOVE_DEVICE 0x02
  23. PptPdoCancelRemove, // IRP_MN_CANCEL_REMOVE_DEVICE 0x03
  24. PptPdoStopDevice, // IRP_MN_STOP_DEVICE 0x04
  25. PptPdoQueryStop, // IRP_MN_QUERY_STOP_DEVICE 0x05
  26. PptPdoCancelStop, // IRP_MN_CANCEL_STOP_DEVICE 0x06
  27. PptPdoQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS 0x07
  28. PptPdoDefaultPnpHandler, // IRP_MN_QUERY_INTERFACE 0x08
  29. PptPdoQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES 0x09
  30. PptPdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCES 0x0A
  31. PptPdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B
  32. PptPdoQueryDeviceText, // IRP_MN_QUERY_DEVICE_TEXT 0x0C
  33. PptPdoDefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D
  34. PptPdoDefaultPnpHandler, // no such PnP request 0x0E
  35. PptPdoDefaultPnpHandler, // IRP_MN_READ_CONFIG 0x0F
  36. PptPdoDefaultPnpHandler, // IRP_MN_WRITE_CONFIG 0x10
  37. PptPdoDefaultPnpHandler, // IRP_MN_EJECT 0x11
  38. PptPdoDefaultPnpHandler, // IRP_MN_SET_LOCK 0x12
  39. PptPdoQueryId, // IRP_MN_QUERY_ID 0x13
  40. PptPdoQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE 0x14
  41. PptPdoQueryBusInformation, // IRP_MN_QUERY_BUS_INFORMATION 0x15
  42. PptPdoDefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16
  43. PptPdoSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 0x17
  44. PptPdoDefaultPnpHandler // IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18
  45. };
  46. NTSTATUS
  47. PptPdoStartDevice(
  48. IN PDEVICE_OBJECT Pdo,
  49. IN PIRP Irp
  50. )
  51. {
  52. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  53. pdx->DeviceStateFlags = PPT_DEVICE_STARTED;
  54. KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread
  55. PptRegGetDeviceParameterDword( Pdo, L"Event22Delay", &pdx->Event22Delay );
  56. //
  57. // Register device interface for Legacy LPTx interface PDOs and set the interface active
  58. // - succeed start even if the device interface code fails
  59. //
  60. if( PdoTypeRawPort == pdx->PdoType ) {
  61. // This is a legacy interface "raw port" PDO, don't set interface for other types of PDOs
  62. NTSTATUS status;
  63. BOOLEAN setActive = FALSE;
  64. if( NULL == pdx->DeviceInterface.Buffer ) {
  65. // Register device interface
  66. status = IoRegisterDeviceInterface( Pdo, &GUID_PARCLASS_DEVICE, NULL, &pdx->DeviceInterface );
  67. if( STATUS_SUCCESS == status ) {
  68. setActive = TRUE;
  69. }
  70. }
  71. if( (TRUE == setActive) && (FALSE == pdx->DeviceInterfaceState) ) {
  72. // set interface active
  73. status = IoSetDeviceInterfaceState( &pdx->DeviceInterface, TRUE );
  74. if( STATUS_SUCCESS == status ) {
  75. pdx->DeviceInterfaceState = TRUE;
  76. }
  77. }
  78. }
  79. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  80. }
  81. NTSTATUS
  82. PptPdoQueryRemove(
  83. IN PDEVICE_OBJECT Pdo,
  84. IN PIRP Irp
  85. )
  86. {
  87. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  88. // DDpnp2( ("PptPdoQueryRemove\n") );
  89. // PnP won't remove us if there are open handles to us - so WE don't need to check for open handles
  90. pdx->DeviceStateFlags |= (PPT_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
  91. KeClearEvent(&pdx->PauseEvent); // pause any worker thread
  92. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  93. }
  94. NTSTATUS
  95. PptPdoRemoveDevice(
  96. IN PDEVICE_OBJECT Pdo,
  97. IN PIRP Irp
  98. )
  99. {
  100. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  101. NTSTATUS status;
  102. pdx->DeviceStateFlags = PAR_DEVICE_PAUSED;
  103. KeClearEvent(&pdx->PauseEvent); // pause any worker thread
  104. // Set Device Interface inactive for PdoTypeRawPort - other PDO types don't have device interfaces
  105. if( PdoTypeRawPort == pdx->PdoType ) {
  106. if( (pdx->DeviceInterface.Buffer != NULL) && (TRUE == pdx->DeviceInterfaceState) ) {
  107. IoSetDeviceInterfaceState( &pdx->DeviceInterface, FALSE );
  108. pdx->DeviceInterfaceState = FALSE;
  109. }
  110. }
  111. // If we were not reported in the last FDO BusRelations enumeration then it is safe to delete self
  112. if( pdx->DeleteOnRemoveOk ) {
  113. DD((PCE)pdx,DDT,"PptPdoRemoveDevice - DeleteOnRemoveOk == TRUE - cleaning up self\n");
  114. P4DestroyPdo( Pdo );
  115. status = P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  116. return status;
  117. } else {
  118. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  119. }
  120. }
  121. NTSTATUS
  122. PptPdoCancelRemove(
  123. IN PDEVICE_OBJECT Pdo,
  124. IN PIRP Irp
  125. )
  126. {
  127. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  128. pdx->DeviceStateFlags &= ~(PPT_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
  129. KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread
  130. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  131. }
  132. NTSTATUS
  133. PptPdoStopDevice(
  134. IN PDEVICE_OBJECT Pdo,
  135. IN PIRP Irp
  136. )
  137. {
  138. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  139. // DDpnp2( ("PptPdoStopDevice\n") );
  140. pdx->DeviceStateFlags |= PAR_DEVICE_PAUSED;
  141. pdx->DeviceStateFlags &= ~PPT_DEVICE_STARTED;
  142. KeClearEvent(&pdx->PauseEvent); // pause any worker thread
  143. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  144. }
  145. NTSTATUS
  146. PptPdoQueryStop(
  147. IN PDEVICE_OBJECT Pdo,
  148. IN PIRP Irp
  149. )
  150. {
  151. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  152. // DDpnp2( ("PptPdoQueryStop\n") );
  153. pdx->DeviceStateFlags |= (PPT_DEVICE_STOP_PENDING | PAR_DEVICE_PAUSED);
  154. KeClearEvent(&pdx->PauseEvent); // pause any worker thread
  155. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  156. }
  157. NTSTATUS
  158. PptPdoCancelStop(
  159. IN PDEVICE_OBJECT Pdo,
  160. IN PIRP Irp
  161. )
  162. {
  163. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  164. pdx->DeviceStateFlags &= ~PPT_DEVICE_STOP_PENDING;
  165. KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread
  166. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  167. }
  168. NTSTATUS
  169. PptPdoQueryDeviceRelations(
  170. IN PDEVICE_OBJECT Pdo,
  171. IN PIRP Irp
  172. )
  173. {
  174. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  175. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  176. DEVICE_RELATION_TYPE requestType = irpSp->Parameters.QueryDeviceRelations.Type;
  177. NTSTATUS status = Irp->IoStatus.Status;
  178. ULONG_PTR info = Irp->IoStatus.Information;
  179. if( TargetDeviceRelation == requestType ) {
  180. PDEVICE_RELATIONS devRel = ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) );
  181. if( devRel ) {
  182. devRel->Count = 1;
  183. ObReferenceObject( Pdo );
  184. devRel->Objects[0] = Pdo;
  185. status = STATUS_SUCCESS;
  186. info = (ULONG_PTR)devRel;
  187. } else {
  188. status = STATUS_NO_MEMORY;
  189. }
  190. } else {
  191. DD((PCE)pdx,DDT,"PptPdoQueryDeviceRelations - unhandled request Type = %d\n",requestType);
  192. }
  193. return P4CompleteRequest( Irp, status, info );
  194. }
  195. NTSTATUS
  196. PptPdoQueryCapabilities(
  197. IN PDEVICE_OBJECT Pdo,
  198. IN PIRP Irp
  199. )
  200. {
  201. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  202. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  203. irpSp->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
  204. if( PdoTypeRawPort == pdx->PdoType ) {
  205. // This is the legacy LPTx interface device - no driver should
  206. // ever be installed for this so don't bother the user with a popup.
  207. irpSp->Parameters.DeviceCapabilities.Capabilities->SilentInstall = TRUE;
  208. }
  209. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  210. }
  211. NTSTATUS
  212. PptPdoQueryDeviceText(
  213. IN PDEVICE_OBJECT Pdo,
  214. IN PIRP Irp
  215. )
  216. {
  217. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  218. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  219. PWSTR buffer = NULL;
  220. ULONG bufLen;
  221. ULONG_PTR info;
  222. NTSTATUS status;
  223. if( DeviceTextDescription == irpSp->Parameters.QueryDeviceText.DeviceTextType ) {
  224. //
  225. // DeviceTextDescription is: catenation of MFG+<SPACE>+MDL
  226. //
  227. if( pdx->Mfg && pdx->Mdl ) {
  228. //
  229. // Construct UNICODE string to return from the ANSI strings
  230. // that we have in our extension
  231. //
  232. // need space for <SPACE> and terminating NULL
  233. //
  234. bufLen = strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl ) + 2 * sizeof(CHAR);
  235. bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) );
  236. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  237. if( buffer ) {
  238. RtlZeroMemory( buffer, bufLen );
  239. _snwprintf( buffer, bufLen/2, L"%S %S", pdx->Mfg, pdx->Mdl );
  240. DD((PCE)pdx,DDT,"PptPdoQueryDeviceText - DeviceTextDescription - <%S>\n",buffer);
  241. status = STATUS_SUCCESS;
  242. } else {
  243. status = STATUS_NO_MEMORY;
  244. }
  245. } else {
  246. DD((PCE)pdx,DDE,"PptPdoQueryDeviceText - MFG and/or MDL NULL - FAIL DeviceTextDescription\n");
  247. status = STATUS_UNSUCCESSFUL;
  248. }
  249. } else if( DeviceTextLocationInformation == irpSp->Parameters.QueryDeviceText.DeviceTextType ) {
  250. //
  251. // DeviceTextLocationInformation is LPTx or LPTx.y (note that
  252. // this is also the symlink name minus the L"\\DosDevices\\"
  253. // prefix)
  254. //
  255. if( pdx->Location ) {
  256. bufLen = strlen( (const PCHAR)pdx->Location ) + sizeof(CHAR);
  257. bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) );
  258. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  259. if( buffer ) {
  260. RtlZeroMemory( buffer, bufLen );
  261. _snwprintf( buffer, bufLen/2, L"%S", pdx->Location );
  262. DD((PCE)pdx,DDT,"PptPdoQueryDeviceText - DeviceTextLocationInformation - <%S>\n",buffer);
  263. status = STATUS_SUCCESS;
  264. } else {
  265. status = STATUS_NO_MEMORY;
  266. }
  267. } else {
  268. DD((PCE)pdx,DDE,"PptPdoQueryDeviceText - Location NULL - FAIL DeviceTextLocationInformation\n");
  269. status = STATUS_UNSUCCESSFUL;
  270. }
  271. } else {
  272. // Unknown DeviceTextType - don't change anything in IRP
  273. buffer = NULL;
  274. status = Irp->IoStatus.Status;
  275. }
  276. if( (STATUS_SUCCESS == status) && buffer ) {
  277. info = (ULONG_PTR)buffer;
  278. } else {
  279. if( buffer ) {
  280. ExFreePool( buffer );
  281. }
  282. info = Irp->IoStatus.Information;
  283. }
  284. return P4CompleteRequest( Irp, status, info );
  285. }
  286. NTSTATUS
  287. PptPdoQueryId( PDEVICE_OBJECT Pdo, PIRP Irp )
  288. {
  289. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  290. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  291. PWSTR buffer = NULL;
  292. ULONG bufLen;
  293. NTSTATUS status;
  294. ULONG_PTR info;
  295. switch( irpSp->Parameters.QueryId.IdType ) {
  296. case BusQueryDeviceID :
  297. //
  298. // DeviceID generation: catenate MFG and MDL fields from the
  299. // IEEE 1284 device ID string (no space between fields), append
  300. // MFG+MDL catenation to LPTENUM\ prefix
  301. //
  302. if( pdx->Mfg && pdx->Mdl ) {
  303. //
  304. // Construct UNICODE string to return from the ANSI strings
  305. // that we have in our extension
  306. //
  307. CHAR prefix[] = "LPTENUM\\";
  308. // sizeof(prefix) provides space for NULL terminator
  309. bufLen = sizeof(prefix) + strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl );
  310. bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) );
  311. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  312. if( buffer ) {
  313. RtlZeroMemory( buffer, bufLen );
  314. _snwprintf( buffer, bufLen/2, L"%S%S%S", prefix, pdx->Mfg, pdx->Mdl );
  315. P4SanitizeId( buffer ); // replace any illegal characters with underscore
  316. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryDeviceID - <%S>\n",buffer);
  317. status = STATUS_SUCCESS;
  318. } else {
  319. status = STATUS_NO_MEMORY;
  320. }
  321. } else {
  322. DD((PCE)pdx,DDE,"PptPdoQueryId - MFG and/or MDL NULL - FAIL BusQueryDeviceID\n");
  323. status = STATUS_UNSUCCESSFUL;
  324. }
  325. break;
  326. case BusQueryInstanceID :
  327. //
  328. // InstanceID is LPTx or LPTx.y Location of the device (note
  329. // that this is also the symlink name minus the
  330. // \DosDevices\ prefix)
  331. //
  332. if( pdx->Location ) {
  333. //
  334. // Construct UNICODE string to return from the ANSI string
  335. // that we have in our extension
  336. //
  337. bufLen = strlen( (const PCHAR)pdx->Location ) + sizeof(CHAR);
  338. bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) );
  339. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  340. if( buffer ) {
  341. RtlZeroMemory( buffer, bufLen );
  342. _snwprintf( buffer, bufLen/2, L"%S", pdx->Location );
  343. P4SanitizeId( buffer ); // replace any illegal characters with underscore
  344. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryInstanceID - <%S>\n",buffer);
  345. status = STATUS_SUCCESS;
  346. } else {
  347. status = STATUS_NO_MEMORY;
  348. }
  349. } else {
  350. DD((PCE)pdx,DDE,"PptPdoQueryId - Location NULL - FAIL BusQueryInstanceID\n");
  351. status = STATUS_UNSUCCESSFUL;
  352. }
  353. break;
  354. case BusQueryHardwareIDs :
  355. //
  356. // HardwareID generation:
  357. //
  358. // Generate MfgMdlCrc string as follows:
  359. // 1) catenate MFG and MDL fields
  360. // 2) generate checksum on MFG+MDL catenation
  361. // 3) truncate MFG+MDL catenation
  362. // 4) append checksum
  363. //
  364. // Return as HardwareID MULTI_SZ: LPTENUM\%MfgMdlCrc% followed by bare %MfgMdlCrc%
  365. //
  366. // example: LPTENUM\Acme_CorpFooBarPrint3FA5\0Acme_CorpFooBarPrint3FA5\0\0
  367. //
  368. if( pdx->Mfg && pdx->Mdl ) {
  369. ULONG lengthOfMfgMdlBuffer = strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl ) + sizeof(CHAR);
  370. PCHAR mfgMdlBuffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, lengthOfMfgMdlBuffer );
  371. if( mfgMdlBuffer ) {
  372. const CHAR prefix[] = "LPTENUM\\";
  373. const ULONG mfgMdlTruncationLimit = 20;
  374. const ULONG checksumLength = 4;
  375. USHORT checksum;
  376. // 1) catenate MFG and MDL fields and 2) generate checksum on catenation
  377. RtlZeroMemory( mfgMdlBuffer, lengthOfMfgMdlBuffer );
  378. _snprintf( mfgMdlBuffer, lengthOfMfgMdlBuffer, "%s%s", pdx->Mfg, pdx->Mdl );
  379. GetCheckSum( mfgMdlBuffer, (USHORT)strlen(mfgMdlBuffer), &checksum );
  380. //
  381. // alloc buffer large enough for result returned to PnP,
  382. // include space for 4 checksum chars (twice) + 1 NULL between strings + 2 termination chars (MULTI_SZ)
  383. //
  384. bufLen = strlen( prefix ) + 2 * mfgMdlTruncationLimit + 2 * checksumLength + 3 * sizeof(CHAR);
  385. bufLen *= (sizeof(WCHAR)/sizeof(CHAR)); // convert to size needed for WCHARs
  386. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  387. if( buffer ) {
  388. ULONG wcharsWritten;
  389. RtlZeroMemory( buffer, bufLen );
  390. // Construct the HardwareID MULTI_SZ:
  391. //
  392. // Write the first Hardware ID: LPTENUM\xxx
  393. wcharsWritten = _snwprintf( buffer, bufLen/2, L"%S%.20S%04X", prefix, mfgMdlBuffer, checksum );
  394. // Skip forward a UNICODE_NULL past the end of the first Hardware ID and write the second
  395. // Hardware ID: bare xxx
  396. _snwprintf( buffer+wcharsWritten+1, bufLen/2-wcharsWritten-1, L"%.20S%04X", mfgMdlBuffer, checksum );
  397. ExFreePool( mfgMdlBuffer );
  398. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryHardwareIDs 1st ID - <%S>\n",buffer);
  399. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryHardwareIDs 2nd ID - <%S>\n",buffer+wcslen(buffer)+1);
  400. // replace any illegal characters with underscore, preserve UNICODE_NULLs
  401. P4SanitizeMultiSzId( buffer, bufLen/2 );
  402. status = STATUS_SUCCESS;
  403. // printing looks for PortName in the devnode - Pdo's Location is the PortName
  404. P4WritePortNameToDevNode( Pdo, pdx->Location );
  405. } else {
  406. ExFreePool( mfgMdlBuffer );
  407. DD((PCE)pdx,DDT,"PptPdoQueryId - no pool for buffer - FAIL BusQueryHardwareIDs\n");
  408. status = STATUS_INSUFFICIENT_RESOURCES;
  409. }
  410. } else {
  411. DD((PCE)pdx,DDT,"PptPdoQueryId - no pool for mfgMdlBuffer - FAIL BusQueryHardwareIDs\n");
  412. status = STATUS_INSUFFICIENT_RESOURCES;
  413. }
  414. } else {
  415. DD((PCE)pdx,DDT,"PptPdoQueryId - MFG and/or MDL NULL - FAIL BusQueryHardwareIDs\n");
  416. status = STATUS_UNSUCCESSFUL;
  417. }
  418. //
  419. // Save the MFG and MDL fields from the IEEE 1284 Device ID string under the
  420. // "<DevNode>\Device Parameters" key so that user mode code (e.g., printing)
  421. // can retrieve the fields.
  422. //
  423. PptWriteMfgMdlToDevNode( Pdo, pdx->Mfg, pdx->Mdl );
  424. break;
  425. case BusQueryCompatibleIDs :
  426. //
  427. // Printing group specified that we not report compatible IDs - 2000-04-24
  428. //
  429. #define PPT_REPORT_COMPATIBLE_IDS 0
  430. #if (0 == PPT_REPORT_COMPATIBLE_IDS)
  431. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryCompatibleIDs - query not supported\n");
  432. status = Irp->IoStatus.Status;
  433. #else
  434. //
  435. // Return the compatible ID string reported by device, if any
  436. //
  437. if( pdx->Cid ) {
  438. //
  439. // Construct UNICODE string to return from the ANSI string
  440. // that we have in our extension
  441. //
  442. bufLen = strlen( pdx->Cid ) + 2 * sizeof(CHAR);
  443. bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) );
  444. buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen );
  445. if( buffer ) {
  446. RtlZeroMemory( buffer, bufLen );
  447. _snwprintf( buffer, bufLen/2, L"%S", pdx->Cid );
  448. DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryCompatibleIDs - <%S>\n",buffer);
  449. //
  450. // convert the 1284 ID representation of a Compatible ID seperator (',') into
  451. // a MULTI_SZ - (i.e., scan the WSTR and replace any L',' with L'\0')
  452. //
  453. {
  454. PWCHAR p = buffer;
  455. while( *p ) {
  456. if( L',' == *p ) {
  457. *p = L'\0';
  458. }
  459. ++p;
  460. }
  461. }
  462. // replace any illegal characters with underscore, preserve UNICODE_NULLs
  463. P4SanitizeMultiSzId( buffer, bufLen/2 );
  464. status = STATUS_SUCCESS;
  465. } else {
  466. DD((PCE)pdx,DDT,"PptPdoQueryId - no pool - FAIL BusQueryCompatibleIDs\n");
  467. status = STATUS_INSUFFICIENT_RESOURCES;
  468. }
  469. } else {
  470. DD((PCE)pdx,DDT,"PptPdoQueryId - CID NULL - BusQueryCompatibleIDs\n");
  471. status = Irp->IoStatus.Status;
  472. }
  473. #endif // #if (0 == PPT_REPORT_COMPATIBLE_IDS)
  474. break;
  475. default :
  476. //
  477. // Invalid irpSp->Parameters.QueryId.IdType
  478. //
  479. DD((PCE)pdx,DDT,"PptPdoQueryId - unrecognized irpSp->Parameters.QueryId.IdType\n");
  480. status = Irp->IoStatus.Status;
  481. }
  482. if( (STATUS_SUCCESS == status) && buffer ) {
  483. info = (ULONG_PTR)buffer;
  484. } else {
  485. if( buffer ) {
  486. ExFreePool( buffer );
  487. }
  488. info = Irp->IoStatus.Information;
  489. }
  490. return P4CompleteRequest( Irp, status, info );
  491. }
  492. NTSTATUS
  493. PptPdoQueryPnpDeviceState( PDEVICE_OBJECT Pdo, PIRP Irp )
  494. {
  495. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  496. NTSTATUS status = Irp->IoStatus.Status;
  497. ULONG_PTR info = Irp->IoStatus.Information;
  498. if( PdoTypeRawPort == pdx->PdoType ) {
  499. info |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
  500. status = STATUS_SUCCESS;
  501. }
  502. return P4CompleteRequest( Irp, status, info );
  503. }
  504. NTSTATUS
  505. PptPdoQueryBusInformation( PDEVICE_OBJECT Pdo, PIRP Irp )
  506. {
  507. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  508. NTSTATUS status;
  509. ULONG_PTR info;
  510. if( pdx->PdoType != PdoTypeRawPort ) {
  511. //
  512. // we are a "real" device enumerated by parport - report BusInformation
  513. //
  514. PPNP_BUS_INFORMATION pBusInfo = ExAllocatePool( PagedPool, sizeof(PNP_BUS_INFORMATION) );
  515. if( pBusInfo ) {
  516. pBusInfo->BusTypeGuid = GUID_BUS_TYPE_LPTENUM;
  517. pBusInfo->LegacyBusType = PNPBus;
  518. pBusInfo->BusNumber = 0;
  519. status = STATUS_SUCCESS;
  520. info = (ULONG_PTR)pBusInfo;
  521. } else {
  522. // no pool
  523. status = STATUS_NO_MEMORY;
  524. info = Irp->IoStatus.Information;
  525. }
  526. } else {
  527. //
  528. // we are a pseudo device (Legacy Interface Raw Port PDO LPTx) - don't report BusInformation
  529. //
  530. status = Irp->IoStatus.Status;
  531. info = Irp->IoStatus.Information;
  532. }
  533. return P4CompleteRequest( Irp, status, info );
  534. }
  535. NTSTATUS
  536. PptPdoSurpriseRemoval(
  537. IN PDEVICE_OBJECT Pdo,
  538. IN PIRP Irp
  539. )
  540. {
  541. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  542. // Set Device Interface inactive for PdoTypeRawPort - other PDO types don't have device interfaces
  543. if( PdoTypeRawPort == pdx->PdoType ) {
  544. if( (pdx->DeviceInterface.Buffer != NULL) && (TRUE == pdx->DeviceInterfaceState) ) {
  545. IoSetDeviceInterfaceState( &pdx->DeviceInterface, FALSE );
  546. pdx->DeviceInterfaceState = FALSE;
  547. }
  548. }
  549. pdx->DeviceStateFlags |= PPT_DEVICE_SURPRISE_REMOVED;
  550. KeClearEvent(&pdx->PauseEvent); // pause any worker thread
  551. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  552. }
  553. NTSTATUS
  554. PptPdoDefaultPnpHandler(
  555. IN PDEVICE_OBJECT Pdo,
  556. IN PIRP Irp
  557. )
  558. {
  559. UNREFERENCED_PARAMETER( Pdo );
  560. return P4CompleteRequest( Irp, Irp->IoStatus.Status, Irp->IoStatus.Information );
  561. }
  562. NTSTATUS
  563. PptPdoPnp(
  564. IN PDEVICE_OBJECT Pdo,
  565. IN PIRP Irp
  566. )
  567. {
  568. PPDO_EXTENSION pdx = Pdo->DeviceExtension;
  569. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  570. // diagnostic
  571. PptPdoDumpPnpIrpInfo( Pdo, Irp);
  572. if( pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING ) {
  573. DD((PCE)pdx,DDT,"PptPdoPnp - PPT_DEVICE_DELETE_PENDING - bailing out\n");
  574. return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  575. }
  576. if( irpSp->MinorFunction < arraysize(PptPdoPnpDispatchTable) ) {
  577. return PptPdoPnpDispatchTable[ irpSp->MinorFunction ]( Pdo, Irp );
  578. } else {
  579. DD((PCE)pdx,DDT,"PptPdoPnp - Default Handler - IRP_MN = %x\n",irpSp->MinorFunction);
  580. return PptPdoDefaultPnpHandler( Pdo, Irp );
  581. }
  582. }