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.

1993 lines
51 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. pnp code for the pnp print class
  7. Author:
  8. George Chrysanthakopoulos May-1998
  9. Environment:
  10. Kernel mode
  11. Revision History :
  12. dankn, 22-Jul-99 : Added ability to block & resubmit failed writes for
  13. 1394 printers to behave more like other print stacks
  14. (i.e. USB) and therefore keep USBMON.DLL (the Win2k
  15. port monitor) happy. USBMON does not deal well
  16. with failed writes.
  17. --*/
  18. #include "printpnp.h"
  19. #include "1394.h"
  20. #include "ntddsbp2.h"
  21. #include "stdarg.h"
  22. #include "stdio.h"
  23. #include "string.h"
  24. VOID
  25. PrinterUnload(
  26. IN PDRIVER_OBJECT DriverObject
  27. );
  28. NTSTATUS
  29. GetPortNumber(
  30. HANDLE hFdoKey,
  31. PUNICODE_STRING uni,
  32. PULONG ulReturnNumber
  33. );
  34. VOID
  35. PrinterFindDeviceIdKeys
  36. (
  37. PUCHAR *lppMFG,
  38. PUCHAR *lppMDL,
  39. PUCHAR *lppCLS,
  40. PUCHAR *lppDES,
  41. PUCHAR *lppAID,
  42. PUCHAR *lppCID,
  43. PUCHAR lpDeviceID
  44. );
  45. VOID
  46. GetCheckSum(
  47. PUCHAR Block,
  48. USHORT Len,
  49. PUSHORT CheckSum
  50. );
  51. PUCHAR
  52. StringChr(PCHAR string, CHAR c);
  53. VOID
  54. StringSubst
  55. (
  56. PUCHAR lpS,
  57. UCHAR chTargetChar,
  58. UCHAR chReplacementChar,
  59. USHORT cbS
  60. );
  61. NTSTATUS
  62. DriverEntry(
  63. IN PDRIVER_OBJECT DriverObject,
  64. IN PUNICODE_STRING RegistryPath
  65. );
  66. #ifdef ALLOC_PRAGMA
  67. #pragma alloc_text(INIT, DriverEntry)
  68. #pragma alloc_text(PAGE, PrinterUnload)
  69. #pragma alloc_text(PAGE, PrinterAddDevice)
  70. #pragma alloc_text(PAGE, PrinterStartDevice)
  71. #pragma alloc_text(PAGE, PrinterStartPdo)
  72. #pragma alloc_text(PAGE, PrinterCreatePdo)
  73. #pragma alloc_text(PAGE, PrinterQueryId)
  74. #pragma alloc_text(PAGE, PrinterGetId)
  75. #pragma alloc_text(PAGE, GetCheckSum)
  76. #pragma alloc_text(PAGE, PrinterEnumerateDevice)
  77. #pragma alloc_text(PAGE, PrinterRemoveDevice)
  78. #pragma alloc_text(PAGE, CreatePrinterDeviceObject)
  79. #pragma alloc_text(PAGE, PrinterInitFdo)
  80. #pragma alloc_text(PAGE, GetPortNumber)
  81. #pragma alloc_text(PAGE, PrinterRegisterPort)
  82. #pragma alloc_text(PAGE, PrinterQueryPnpCapabilities)
  83. #pragma alloc_text(PAGE, PrinterFindDeviceIdKeys)
  84. #pragma alloc_text(PAGE, StringChr)
  85. #pragma alloc_text(PAGE, StringSubst)
  86. #endif
  87. NTSTATUS
  88. DriverEntry(
  89. IN PDRIVER_OBJECT DriverObject,
  90. IN PUNICODE_STRING RegistryPath
  91. )
  92. /*++
  93. Routine Description:
  94. This routine initializes the printer class driver. The driver
  95. opens the port driver by name and then receives configuration
  96. information used to attach to the Printer devices.
  97. Arguments:
  98. DriverObject
  99. Return Value:
  100. NT Status
  101. --*/
  102. {
  103. CLASS_INIT_DATA InitializationData;
  104. PAGED_CODE();
  105. DEBUGPRINT1(("\n\nSCSI/SBP2 Printer Class Driver\n"));
  106. //
  107. // Zero InitData
  108. //
  109. RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
  110. //
  111. // Set sizes
  112. //
  113. InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
  114. InitializationData.FdoData.DeviceExtensionSize = sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(PRINTER_DATA);
  115. InitializationData.FdoData.DeviceType = FILE_DEVICE_PRINTER;
  116. InitializationData.FdoData.DeviceCharacteristics = 0;
  117. //
  118. // Set entry points
  119. //
  120. InitializationData.FdoData.ClassInitDevice = PrinterInitFdo;
  121. InitializationData.FdoData.ClassStartDevice = PrinterStartDevice;
  122. InitializationData.FdoData.ClassReadWriteVerification = PrinterReadWrite;
  123. InitializationData.FdoData.ClassDeviceControl = PrinterDeviceControl;
  124. InitializationData.FdoData.ClassRemoveDevice = PrinterRemoveDevice;
  125. InitializationData.FdoData.ClassStopDevice = PrinterStopDevice;
  126. InitializationData.FdoData.ClassShutdownFlush = NULL;
  127. InitializationData.FdoData.ClassCreateClose = PrinterOpenClose;
  128. InitializationData.PdoData.DeviceExtensionSize = sizeof(PHYSICAL_DEVICE_EXTENSION);
  129. InitializationData.PdoData.DeviceType = FILE_DEVICE_PRINTER;
  130. InitializationData.PdoData.DeviceCharacteristics = 0;
  131. InitializationData.PdoData.ClassStartDevice = PrinterStartPdo;
  132. InitializationData.PdoData.ClassInitDevice = PrinterInitPdo;
  133. InitializationData.PdoData.ClassRemoveDevice = PrinterRemoveDevice;
  134. InitializationData.PdoData.ClassStopDevice = PrinterStopDevice;
  135. InitializationData.PdoData.ClassPowerDevice = NULL;
  136. InitializationData.PdoData.ClassError = NULL;
  137. InitializationData.PdoData.ClassReadWriteVerification = PrinterReadWrite;
  138. InitializationData.PdoData.ClassCreateClose = NULL;
  139. InitializationData.PdoData.ClassDeviceControl = PrinterDeviceControl;
  140. InitializationData.PdoData.ClassQueryPnpCapabilities = PrinterQueryPnpCapabilities;
  141. InitializationData.ClassEnumerateDevice = PrinterEnumerateDevice;
  142. InitializationData.ClassQueryId = PrinterQueryId;
  143. InitializationData.ClassAddDevice = PrinterAddDevice;
  144. InitializationData.ClassUnload = PrinterUnload;
  145. //
  146. // Call the class init routine
  147. //
  148. return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
  149. } // end DriverEntry()
  150. VOID
  151. PrinterUnload(
  152. IN PDRIVER_OBJECT DriverObject
  153. )
  154. /*++
  155. Routine Description:
  156. Does nothing really...
  157. Arguments:
  158. DriverObject - the driver being unloaded
  159. Return Value:
  160. none
  161. --*/
  162. {
  163. PAGED_CODE();
  164. UNREFERENCED_PARAMETER(DriverObject);
  165. return;
  166. }
  167. NTSTATUS
  168. PrinterAddDevice(
  169. IN PDRIVER_OBJECT DriverObject,
  170. IN PDEVICE_OBJECT PhysicalDeviceObject
  171. )
  172. /*++
  173. Routine Description:
  174. This routine creates and initializes a new FDO for the corresponding
  175. PDO. It may perform property queries on the FDO but cannot do any
  176. media access operations.
  177. Arguments:
  178. DriverObject - Printer class driver object.
  179. Pdo - the physical device object we are being added to
  180. Return Value:
  181. status
  182. --*/
  183. {
  184. ULONG printerCount = 0;
  185. NTSTATUS status;
  186. PAGED_CODE();
  187. //
  188. // Get the address of the count of the number of cdroms already initialized.
  189. //
  190. do {
  191. status = CreatePrinterDeviceObject(
  192. DriverObject,
  193. PhysicalDeviceObject,
  194. &printerCount);
  195. printerCount++;
  196. } while (status == STATUS_OBJECT_NAME_COLLISION);
  197. DEBUGPRINT1(("SCSIPRNT: AddDevice, exit with status %x\n",status));
  198. return status;
  199. }
  200. NTSTATUS
  201. CreatePrinterDeviceObject(
  202. IN PDRIVER_OBJECT DriverObject,
  203. IN PDEVICE_OBJECT PhysicalDeviceObject,
  204. IN PULONG DeviceCount
  205. )
  206. /*++
  207. Routine Description:
  208. This routine creates an object for the device.
  209. Arguments:
  210. DriverObject - Pointer to driver object created by system.
  211. PortDeviceObject - to connect to the port driver.
  212. DeviceCount - Number of previously installed devices of this type.
  213. Return Value:
  214. NTSTATUS
  215. --*/
  216. {
  217. UCHAR ntNameBuffer[64];
  218. STRING ntNameString;
  219. NTSTATUS status;
  220. PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(DriverObject);
  221. PDEVICE_OBJECT lowerDevice = NULL;
  222. PDEVICE_OBJECT deviceObject = NULL;
  223. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  224. PCOMMON_DEVICE_EXTENSION commonExtension = NULL;
  225. CCHAR dosNameBuffer[64];
  226. CCHAR deviceNameBuffer[64];
  227. STRING deviceNameString;
  228. STRING dosString;
  229. UNICODE_STRING unicodeString;
  230. PCLASS_DEV_INFO devInfo;
  231. PPRINTER_DATA printerData;
  232. ULONG lptNumber;
  233. PAGED_CODE();
  234. lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  235. status = ClassClaimDevice(lowerDevice, FALSE);
  236. if(!NT_SUCCESS(status)) {
  237. DEBUGPRINT1(("SCSIPRINT!CreatePrinterDeviceObject: Failed to claim device %x\n",status));
  238. ObDereferenceObject(lowerDevice);
  239. return status;
  240. }
  241. //
  242. // initialize our driver extension..
  243. //
  244. devInfo = &(driverExtension->InitData.FdoData);
  245. devInfo->DeviceType = FILE_DEVICE_PRINTER;
  246. devInfo->DeviceCharacteristics = 0;
  247. //
  248. // Create device object for this device.
  249. //
  250. sprintf(ntNameBuffer, "\\Device\\Printer%d", *DeviceCount);
  251. status = ClassCreateDeviceObject(DriverObject,
  252. ntNameBuffer,
  253. PhysicalDeviceObject,
  254. TRUE,
  255. &deviceObject);
  256. if (!NT_SUCCESS(status)) {
  257. DEBUGPRINT1(("SCSIPRINT!CreatePrinterDeviceObjects: Can not create device %s, status %x\n",
  258. ntNameBuffer,status));
  259. goto CreateDeviceObjectExit;
  260. }
  261. deviceObject->Flags |= DO_DIRECT_IO;
  262. fdoExtension = deviceObject->DeviceExtension;
  263. commonExtension = deviceObject->DeviceExtension;
  264. printerData = (PPRINTER_DATA)(commonExtension->DriverData);
  265. RtlZeroMemory(printerData,sizeof(PRINTER_DATA));
  266. printerData->DeviceIdString = NULL;
  267. //
  268. // Back pointer to device object.
  269. //
  270. fdoExtension->CommonExtension.DeviceObject = deviceObject;
  271. //
  272. // This is the physical device.
  273. //
  274. fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
  275. //
  276. // Initialize lock count to zero. The lock count is used to
  277. // disable the ejection mechanism when media is mounted.
  278. //
  279. fdoExtension->LockCount = 0;
  280. //
  281. // Save system printer number
  282. //
  283. fdoExtension->DeviceNumber = *DeviceCount;
  284. //
  285. // Set the alignment requirements for the device based on the
  286. // host adapter requirements
  287. //
  288. if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
  289. deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
  290. }
  291. //
  292. // Save the device descriptors
  293. //
  294. fdoExtension->AdapterDescriptor = NULL;
  295. fdoExtension->DeviceDescriptor = NULL;
  296. //
  297. // Clear the SrbFlags and disable synchronous transfers
  298. //
  299. fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  300. //
  301. // Finally, attach to the PDO
  302. //
  303. fdoExtension->LowerPdo = PhysicalDeviceObject;
  304. fdoExtension->CommonExtension.LowerDeviceObject =
  305. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  306. if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
  307. DEBUGPRINT1(("SCSIPRINT!CreatePrinterDeviceObjects: Failed attach\n"));
  308. status = STATUS_UNSUCCESSFUL;
  309. goto CreateDeviceObjectExit;
  310. }
  311. //
  312. // Recreate the deviceName
  313. //
  314. sprintf(deviceNameBuffer,
  315. "\\Device\\Printer%d",
  316. fdoExtension->DeviceNumber);
  317. RtlInitString(&deviceNameString,
  318. deviceNameBuffer);
  319. status = RtlAnsiStringToUnicodeString(&unicodeString,
  320. &deviceNameString,
  321. TRUE);
  322. ASSERT(NT_SUCCESS(status));
  323. //
  324. // offset the lptnumber to avoid parallel port numbers.
  325. // note that there is an increment at the beginning of the do
  326. // loop below as well.
  327. //
  328. lptNumber = fdoExtension->DeviceNumber+1;
  329. do {
  330. lptNumber++;
  331. sprintf(dosNameBuffer,
  332. "\\DosDevices\\LPT%d",
  333. lptNumber);
  334. RtlInitString(&dosString, dosNameBuffer);
  335. status = RtlAnsiStringToUnicodeString(&printerData->UnicodeLinkName,
  336. &dosString,
  337. TRUE);
  338. if(!NT_SUCCESS(status)) {
  339. printerData->UnicodeLinkName.Buffer = NULL;
  340. break;
  341. }
  342. if ((printerData->UnicodeLinkName.Buffer != NULL) && (unicodeString.Buffer != NULL)) {
  343. status = IoAssignArcName(&printerData->UnicodeLinkName, &unicodeString);
  344. } else {
  345. status = STATUS_UNSUCCESSFUL;
  346. }
  347. if (!NT_SUCCESS(status)) {
  348. RtlFreeUnicodeString(&printerData->UnicodeLinkName);
  349. DEBUGPRINT1(("SCSIPRINT!CreatePrinterDeviceObjects: Failed creating Arc Name, status %x\n",status));
  350. }
  351. } while (status == STATUS_OBJECT_NAME_COLLISION);
  352. if (unicodeString.Buffer != NULL ) {
  353. RtlFreeUnicodeString(&unicodeString);
  354. }
  355. if (!NT_SUCCESS(status)) {
  356. goto CreateDeviceObjectExit;
  357. }
  358. printerData->LptNumber = lptNumber;
  359. ObDereferenceObject(lowerDevice);
  360. //
  361. // The device is initialized properly - mark it as such.
  362. //
  363. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  364. return status;
  365. CreateDeviceObjectExit:
  366. ClassClaimDevice(lowerDevice, TRUE);
  367. ObDereferenceObject(lowerDevice);
  368. if (deviceObject != NULL) {
  369. IoDeleteDevice(deviceObject);
  370. }
  371. DEBUGPRINT1(("SCSIPRINT!CreatePrinterDeviceObjects: Exiting with status %x\n",status));
  372. return status;
  373. } // end CreateDeviceObject()
  374. NTSTATUS
  375. PrinterInitFdo(
  376. IN PDEVICE_OBJECT Fdo
  377. )
  378. {
  379. return STATUS_SUCCESS;
  380. }
  381. NTSTATUS
  382. PrinterStartDevice(
  383. IN PDEVICE_OBJECT Fdo
  384. )
  385. /*++
  386. Routine Description:
  387. This routine will complete the cd-rom initialization. This includes
  388. allocating sense info buffers and srb s-lists, reading drive capacity
  389. and setting up Media Change Notification (autorun).
  390. This routine will not clean up allocate resources if it fails - that
  391. is left for device stop/removal
  392. Arguments:
  393. Fdo - a pointer to the functional device object for this device
  394. Return Value:
  395. status
  396. --*/
  397. {
  398. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  399. PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(Fdo->DriverObject);
  400. UNICODE_STRING dosUnicodeString;
  401. STORAGE_PROPERTY_ID propertyId;
  402. PVOID senseData = NULL;
  403. PIRP irp;
  404. PIO_STACK_LOCATION irpStack;
  405. KEVENT event;
  406. PPRINTER_DATA printerData = NULL;
  407. GUID * printerGuid;
  408. HANDLE hInterfaceKey;
  409. UCHAR rawString[256];
  410. PUCHAR vendorId, productId;
  411. ULONG timeOut;
  412. NTSTATUS status;
  413. PSBP2_REQUEST sbp2Request = NULL;
  414. //
  415. // Allocate request sense buffer.
  416. //
  417. senseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  418. SENSE_BUFFER_SIZE,
  419. PRINTER_TAG);
  420. if (senseData == NULL) {
  421. //
  422. // The buffer cannot be allocated.
  423. //
  424. status = STATUS_INSUFFICIENT_RESOURCES;
  425. return status;
  426. }
  427. //
  428. // Build the lookaside list for srb'. Should only
  429. // need a couple.
  430. //
  431. ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension), PRINTER_SRB_LIST_SIZE);
  432. //
  433. // Set the sense data pointer in the device extension.
  434. //
  435. fdoExtension->SenseData = senseData;
  436. //
  437. // printers are not partitionable so starting offset is 0.
  438. //
  439. fdoExtension->CommonExtension.StartingOffset.LowPart = 0;
  440. fdoExtension->CommonExtension.StartingOffset.HighPart = 0;
  441. //
  442. // Set timeout value in seconds.
  443. //
  444. timeOut = ClassQueryTimeOutRegistryValue(Fdo);
  445. if (timeOut) {
  446. fdoExtension->TimeOutValue = timeOut;
  447. } else {
  448. fdoExtension->TimeOutValue = PRINTER_TIMEOUT;
  449. }
  450. printerData = (PPRINTER_DATA)(fdoExtension->CommonExtension.DriverData);
  451. KeInitializeSpinLock(&printerData->SplitRequestSpinLock);
  452. //
  453. // Call port driver to get adapter capabilities.
  454. //
  455. propertyId = StorageAdapterProperty;
  456. status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
  457. &propertyId,
  458. &(fdoExtension->AdapterDescriptor));
  459. if(!NT_SUCCESS(status)) {
  460. DEBUGPRINT1(( "PrinterStartDevice: unable to retrieve adapter descriptor "
  461. "[%#08lx]\n", status));
  462. ExFreePool(senseData);
  463. return status;
  464. }
  465. //
  466. // Call port driver to get device capabilities.
  467. //
  468. propertyId = StorageDeviceProperty;
  469. status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
  470. &propertyId,
  471. &(fdoExtension->DeviceDescriptor));
  472. if(!NT_SUCCESS(status)) {
  473. DEBUGPRINT1(( "PrinterStartAddDevice: unable to retrieve device descriptor "
  474. "[%#08lx]\n", status));
  475. ExFreePool(senseData);
  476. return status;
  477. }
  478. if (printerData->DeviceIdString == NULL) {
  479. printerData->DeviceIdString = ExAllocatePool(PagedPool,256);
  480. if (!printerData->DeviceIdString) {
  481. return STATUS_INSUFFICIENT_RESOURCES;
  482. }
  483. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  484. //
  485. // to retrieve the model/vendor id from the port driver below, send a queryId
  486. // to our PDO
  487. //
  488. sbp2Request = ExAllocatePool(NonPagedPool,sizeof(SBP2_REQUEST));
  489. if (sbp2Request == NULL) {
  490. return STATUS_INSUFFICIENT_RESOURCES;
  491. }
  492. irp = IoAllocateIrp((CCHAR)(Fdo->StackSize), FALSE);
  493. if (irp == NULL) {
  494. DEBUGPRINT1(("PrinterQueryId: Can't allocate irp\n"));
  495. return STATUS_INSUFFICIENT_RESOURCES;
  496. }
  497. RtlZeroMemory(sbp2Request,sizeof(SBP2_REQUEST));
  498. //
  499. // set the sbp2 api call
  500. //
  501. sbp2Request->RequestNumber = SBP2_REQUEST_RETRIEVE_TEXT_LEAFS;
  502. sbp2Request->u.RetrieveTextLeaf.fulFlags |= SBP2REQ_RETRIEVE_TEXT_LEAF_INDIRECT;
  503. sbp2Request->u.RetrieveTextLeaf.Key = 0x14; // LUN key, followed 0x81 key w/ 1284 ID
  504. //
  505. // Construct the IRP stack for the lower level driver.
  506. //
  507. irpStack = IoGetNextIrpStackLocation(irp);
  508. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  509. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SBP2_REQUEST;
  510. irpStack->Parameters.Others.Argument1 = sbp2Request;
  511. KeInitializeEvent(&event,
  512. NotificationEvent,
  513. FALSE);
  514. IoSetCompletionRoutine(irp,
  515. PrinterCompletionRoutine,
  516. &event,
  517. TRUE,
  518. TRUE,
  519. TRUE);
  520. status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  521. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  522. if(!NT_SUCCESS(status) || !NT_SUCCESS(irp->IoStatus.Status) ||
  523. (sbp2Request->u.RetrieveTextLeaf.Buffer == NULL)) {
  524. status = irp->IoStatus.Status;
  525. DEBUGPRINT1(("PrinterStartDevice: 1284 retrieve failed status %xx\n",status));
  526. sprintf(printerData->DeviceIdString,"1394 Printer");
  527. } else {
  528. //
  529. // A pointer to the 1284 id TEXTUAL_LEAF is now stored in the
  530. // sbp2Request->u.RetrieveTextLeaf.Buffer field.
  531. //
  532. // We want to make sure it's NULL terminated before we parse
  533. // it, so we'll move contents of TL_Data (the actual string)
  534. // back to the front of the buffer (overwriting all existing
  535. // TL_Xxx fields), then zero the following 4 bytes.
  536. //
  537. // Note that sbp2Req->u.RetrTextLeaf.ulLength is the size in
  538. // bytes of the entire leaf & data, minus the TL_CRC and
  539. // TL_Length fields.
  540. //
  541. RtlMoveMemory(
  542. sbp2Request->u.RetrieveTextLeaf.Buffer,
  543. ((PUCHAR) sbp2Request->u.RetrieveTextLeaf.Buffer +
  544. FIELD_OFFSET(TEXTUAL_LEAF,TL_Data)),
  545. sbp2Request->u.RetrieveTextLeaf.ulLength -
  546. 2 * sizeof (ULONG) // TL_Spec_Id & TL_Lang_Id fields
  547. );
  548. *((PULONG) ((PUCHAR) sbp2Request->u.RetrieveTextLeaf.Buffer +
  549. sbp2Request->u.RetrieveTextLeaf.ulLength -
  550. 2 * sizeof (ULONG))) = 0;
  551. status = PrinterGetId(sbp2Request->u.RetrieveTextLeaf.Buffer,BusQueryDeviceID,rawString,NULL);
  552. if (!NT_SUCCESS(status)) {
  553. sprintf(printerData->DeviceIdString,"1394 Printer");
  554. status = STATUS_SUCCESS;
  555. } else {
  556. RtlCopyMemory(printerData->DeviceIdString,rawString,256);
  557. }
  558. ExFreePool(sbp2Request->u.RetrieveTextLeaf.Buffer);
  559. }
  560. IoFreeIrp(irp);
  561. ExFreePool(sbp2Request);
  562. //
  563. // register with the pnp GUID so the pnp printer port enumerator loads and finds us...
  564. //
  565. printerGuid=(GUID *)&PNPPRINT_GUID;
  566. status=IoRegisterDeviceInterface(fdoExtension->LowerPdo,printerGuid,NULL,&printerData->UnicodeDeviceString);
  567. if (NT_SUCCESS(status)) {
  568. status=IoSetDeviceInterfaceState(&printerData->UnicodeDeviceString,TRUE);
  569. if (!NT_SUCCESS(status)) {
  570. DEBUGPRINT1(("PrinterStartDevice: Failed setting interfaceState %x\n",status));
  571. return status;
  572. }
  573. } else {
  574. printerData->UnicodeDeviceString.Buffer = NULL;
  575. }
  576. //
  577. // retrieve available port number and write it in our registry key..
  578. // the key is closed in GetPortNumber
  579. //
  580. status = IoOpenDeviceInterfaceRegistryKey(&printerData->UnicodeDeviceString,KEY_ALL_ACCESS,&hInterfaceKey);
  581. if (NT_SUCCESS(status)) {
  582. status = GetPortNumber(hInterfaceKey, &printerData->UnicodeDeviceString, &printerData->PortNumber);
  583. } else {
  584. DEBUGPRINT1(("PrinterStartDevice Failed opening registry key%x\n",status));
  585. }
  586. } else {
  587. vendorId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
  588. productId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
  589. printerData->PortNumber = fdoExtension->DeviceNumber;
  590. sprintf(printerData->DeviceIdString,"Printer&Ven_%s&Prod_%s",
  591. vendorId,
  592. productId);
  593. }
  594. }
  595. //
  596. // If this is a 1394 printer then we want to enable blocking
  597. // writes by default (to keep USBMON.DLL happy)
  598. //
  599. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  600. printerData->WriteCompletionRoutine = PrinterWriteComplete;
  601. KeInitializeTimer (&printerData->Timer);
  602. KeInitializeDpc(
  603. &printerData->TimerDpc,
  604. PrinterWriteTimeoutDpc,
  605. fdoExtension
  606. );
  607. } else {
  608. printerData->WriteCompletionRoutine = ClassIoComplete;
  609. }
  610. ClassUpdateInformationInRegistry(Fdo, "LPT", printerData->LptNumber, NULL, 0);
  611. return status;
  612. } // end PrinterStartDevice()
  613. NTSTATUS
  614. GetPortNumber(
  615. HANDLE hFdoKey,
  616. PUNICODE_STRING fdoUnicodeString,
  617. PULONG ulReturnNumber
  618. )
  619. {
  620. UCHAR buf[sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (ULONG)];
  621. PWSTR pDeviceList;
  622. PWSTR pWalkDevice;
  623. HANDLE hInterfaceKey;
  624. UCHAR baseNameString[32];
  625. ANSI_STRING ansiBaseNameString;
  626. UNICODE_STRING uncValueName,uncLinkName,uncBaseNameValueName;
  627. UNICODE_STRING uncBaseName, uncRecyclableValueName;
  628. UNICODE_STRING uncPortDescription, uncPortDescriptionValueName;
  629. ULONG dwPortNum;
  630. ULONG ulSizeUsed;
  631. ULONG i;
  632. ULONG ulPortNumber=0;
  633. UCHAR portArray[MAX_NUM_PRINTERS] ;
  634. NTSTATUS status=STATUS_SUCCESS;
  635. NTSTATUS qStatus;
  636. PKEY_VALUE_PARTIAL_INFORMATION valueStruct;
  637. GUID *printerGuid = (GUID *) &PNPPRINT_GUID;
  638. for (i=0;i<MAX_NUM_PRINTERS;i++) {
  639. portArray[i] = 0;
  640. }
  641. RtlInitUnicodeString(&uncValueName,PORT_NUM_VALUE_NAME);
  642. RtlInitUnicodeString(&uncBaseName,BASE_1394_PORT_NAME);
  643. RtlInitUnicodeString(&uncBaseNameValueName,BASE_PORT_NAME_VALUE_NAME);
  644. RtlInitUnicodeString(&uncRecyclableValueName,RECYCLABLE_VALUE_NAME);
  645. RtlInitUnicodeString(&uncPortDescription,BASE_PORT_DESCRIPTION);
  646. RtlInitUnicodeString(&uncPortDescriptionValueName,BASE_PORT_DESCRIPTION_VALUE_NAME);
  647. ulSizeUsed = sizeof (buf); //this is a byte to much. Oh well
  648. valueStruct = (PKEY_VALUE_PARTIAL_INFORMATION) buf;
  649. //
  650. // first check if our own key, has already a port value..
  651. //
  652. status=ZwQueryValueKey(hFdoKey,&uncValueName,KeyValuePartialInformation,(PVOID)valueStruct,ulSizeUsed,&ulSizeUsed);
  653. if (NT_SUCCESS(status)) {
  654. DEBUGPRINT1(("\'PRINTER:GetPortNumber: Found existing port in our Own key\n"));
  655. ulPortNumber=*((ULONG *)&(valueStruct->Data));
  656. ZwClose(hFdoKey);
  657. } else {
  658. ZwClose (hFdoKey);
  659. //
  660. // search the registry for all ports present. If you find a hole, take it
  661. // if no holes are found, take the next available slot
  662. //
  663. status=IoGetDeviceInterfaces(printerGuid,NULL,DEVICE_INTERFACE_INCLUDE_NONACTIVE,&pDeviceList);
  664. if (!NT_SUCCESS(status)) {
  665. DEBUGPRINT1(("\'PRINTER:GetPortNumber: Failed to retrive interfaces\n"));
  666. return status;
  667. }
  668. pWalkDevice=pDeviceList;
  669. while((*pWalkDevice!=0) && (NT_SUCCESS(status))) {
  670. RtlInitUnicodeString(&uncLinkName,pWalkDevice);
  671. if (!RtlCompareUnicodeString(fdoUnicodeString,&uncLinkName,FALSE)) {
  672. //
  673. // this key is the same as ours, skip it
  674. //
  675. pWalkDevice=pWalkDevice+wcslen(pWalkDevice)+1;
  676. continue;
  677. }
  678. status=IoOpenDeviceInterfaceRegistryKey(&uncLinkName,KEY_ALL_ACCESS,&hInterfaceKey);
  679. if (NT_SUCCESS(status)) {
  680. qStatus = ZwQueryValueKey(hInterfaceKey,&uncValueName,KeyValuePartialInformation,valueStruct,ulSizeUsed,&ulSizeUsed);
  681. if (NT_SUCCESS(qStatus)) {
  682. dwPortNum = *((ULONG *)&(valueStruct->Data));
  683. qStatus = ZwQueryValueKey(hInterfaceKey,&uncRecyclableValueName,KeyValuePartialInformation,valueStruct,ulSizeUsed,&ulSizeUsed);
  684. if (!NT_SUCCESS(qStatus)) {
  685. //
  686. // port cant be recycled, mark as used so we dont try to grab it..
  687. //
  688. portArray[dwPortNum-1] = 1;
  689. } else {
  690. //
  691. // port was marked recycled so we can reuse it..
  692. //
  693. DEBUGPRINT1(("\'GetPortNumber, Recyclable value found for port number %d\n",dwPortNum));
  694. }
  695. }
  696. }
  697. pWalkDevice=pWalkDevice+wcslen(pWalkDevice)+1;
  698. ZwClose(hInterfaceKey);
  699. }
  700. ExFreePool(pDeviceList);
  701. //
  702. // now find the first hole, and use that port number as our port...
  703. //
  704. for (i=0;i<MAX_NUM_PRINTERS;i++) {
  705. if (portArray[i]) {
  706. ulPortNumber++;
  707. } else {
  708. ulPortNumber++;
  709. break;
  710. }
  711. }
  712. status = IoOpenDeviceInterfaceRegistryKey(fdoUnicodeString,KEY_ALL_ACCESS,&hFdoKey);
  713. if (NT_SUCCESS(status)) {
  714. //
  715. // write the new port we just found under our FDO reg key..
  716. //
  717. status=ZwSetValueKey(hFdoKey,&uncValueName,0,REG_DWORD,&ulPortNumber,sizeof(ulPortNumber));
  718. DEBUGPRINT1(("\'GetPortNumber, setting port number %d in fdo key status %x\n",ulPortNumber,status));
  719. //
  720. // also write our base port name
  721. //
  722. if (NT_SUCCESS(status)) {
  723. status=ZwSetValueKey(hFdoKey,
  724. &uncBaseNameValueName,
  725. 0,REG_SZ,
  726. uncBaseName.Buffer,
  727. uncBaseName.Length);
  728. DEBUGPRINT1(("\'GetPortNumber, setting port name in fdo key status %x\n",status));
  729. }
  730. //
  731. // write out our port description
  732. //
  733. if (NT_SUCCESS(status)) {
  734. status=ZwSetValueKey(hFdoKey,
  735. &uncPortDescriptionValueName,
  736. 0,REG_SZ,
  737. uncPortDescription.Buffer,
  738. uncPortDescription.Length);
  739. DEBUGPRINT1(("\'GetPortNumber, setting port description in fdo key status %x\n",status));
  740. }
  741. ZwClose(hFdoKey);
  742. }
  743. }
  744. DEBUGPRINT1(("\'GetPortNumber, grabbing port %d\n",ulPortNumber));
  745. *ulReturnNumber = ulPortNumber;
  746. return status;
  747. }
  748. NTSTATUS
  749. PrinterInitPdo(
  750. IN PDEVICE_OBJECT Fdo
  751. )
  752. {
  753. return STATUS_SUCCESS;
  754. }
  755. NTSTATUS
  756. PrinterStartPdo(
  757. IN PDEVICE_OBJECT Pdo
  758. )
  759. /*++
  760. Routine Description:
  761. This routine will create the well known names for a PDO and register
  762. it's device interfaces.
  763. --*/
  764. {
  765. return STATUS_SUCCESS;
  766. }
  767. NTSTATUS
  768. PrinterEnumerateDevice(
  769. IN PDEVICE_OBJECT Fdo
  770. )
  771. /*++
  772. Routine Description:
  773. This routine is called by the class driver to update the PDO list off
  774. of this FDO.
  775. Since we always only have one static PDO, this is pretty simple..
  776. Arguments:
  777. Fdo - a pointer to the FDO being re-enumerated
  778. Return Value:
  779. status
  780. --*/
  781. {
  782. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  783. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  784. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  785. PDEVICE_OBJECT pdo = NULL;
  786. ULONG numberListElements = 0;
  787. NTSTATUS status;
  788. ASSERT(commonExtension->IsFdo);
  789. PAGED_CODE();
  790. if (fdoExtension->AdapterDescriptor == NULL) {
  791. //
  792. // device removed..
  793. //
  794. return STATUS_UNSUCCESSFUL;
  795. }
  796. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  797. if(fdoExtension->CommonExtension.ChildList == NULL) {
  798. DebugPrint((1, "PrinterEnumerateDevice: Creating PDO\n"));
  799. status = PrinterCreatePdo(Fdo, &pdo);
  800. } else {
  801. status = STATUS_SUCCESS;
  802. }
  803. } else {
  804. status = STATUS_NOT_SUPPORTED;
  805. }
  806. return status;
  807. } // end printerEnumerateDevice()
  808. NTSTATUS
  809. PrinterCreatePdo(
  810. IN PDEVICE_OBJECT Fdo,
  811. OUT PDEVICE_OBJECT *Pdo
  812. )
  813. /*++
  814. Routine Description:
  815. This routine will create and initialize a new device object
  816. (PDO) and insert it into the FDO partition list.
  817. Note that the PDO is actually never used. We create so the printer class
  818. installer will run after the LPTENUM ids for this PDO were matched to the
  819. printer inf..
  820. Arguments:
  821. Fdo - a pointer to the functional device object this PDO will be a child
  822. of
  823. Pdo - a location to store the pdo pointer upon successful completion
  824. Return Value:
  825. status
  826. --*/
  827. {
  828. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  829. PCOMMON_DEVICE_EXTENSION commonExtension;
  830. PDEVICE_OBJECT pdo = NULL;
  831. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  832. PPRINTER_DATA printerData = fdoExtension->CommonExtension.DriverData;
  833. NTSTATUS status = STATUS_SUCCESS;
  834. PAGED_CODE();
  835. DebugPrint((2, "PrinterCreatePdo: Create device object %s\n",
  836. printerData->DeviceName));
  837. status = ClassCreateDeviceObject(Fdo->DriverObject,
  838. printerData->DeviceName,
  839. Fdo,
  840. FALSE,
  841. &pdo);
  842. if (!NT_SUCCESS(status)) {
  843. DebugPrint((1, "printerEnumerateDevice: Can't create device object for %s\n", printerData->DeviceName));
  844. return status;
  845. }
  846. //
  847. // Set up device extension fields.
  848. //
  849. pdoExtension = pdo->DeviceExtension;
  850. commonExtension = pdo->DeviceExtension;
  851. //
  852. // Set up device object fields.
  853. //
  854. pdo->Flags |= DO_DIRECT_IO;
  855. pdo->StackSize = (CCHAR)
  856. commonExtension->LowerDeviceObject->StackSize + 1;
  857. pdoExtension->IsMissing = FALSE;
  858. commonExtension->DeviceObject = pdo;
  859. commonExtension->PartitionZeroExtension = fdoExtension;
  860. pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  861. *Pdo = pdo;
  862. return status;
  863. }
  864. NTSTATUS
  865. PrinterStopDevice(
  866. IN PDEVICE_OBJECT DeviceObject,
  867. IN UCHAR Type
  868. )
  869. {
  870. DEBUGPRINT2((
  871. "SCSIPRNT: PrinterStopDevice: DevObj=x%p, Type=%d\n",
  872. DeviceObject,
  873. (ULONG) Type
  874. ));
  875. return STATUS_SUCCESS;
  876. }
  877. NTSTATUS
  878. PrinterRemoveDevice(
  879. IN PDEVICE_OBJECT DeviceObject,
  880. IN UCHAR Type
  881. )
  882. /*++
  883. Routine Description:
  884. This routine is responsible for releasing any resources in use by the
  885. driver and shutting down it's timer routine. This routine is called
  886. when all outstanding requests have been completed and the device has
  887. disappeared - no requests may be issued to the lower drivers.
  888. Arguments:
  889. DeviceObject - the device object being removed
  890. Return Value:
  891. none - this routine may not fail
  892. --*/
  893. {
  894. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  895. PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
  896. DeviceObject->DeviceExtension;
  897. PPRINTER_DATA printerData = deviceExtension->CommonExtension.DriverData;
  898. if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
  899. (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
  900. return STATUS_SUCCESS;
  901. }
  902. if (commonExtension->IsFdo) {
  903. if (printerData->DeviceIdString) {
  904. ExFreePool(printerData->DeviceIdString);
  905. printerData->DeviceIdString = NULL;
  906. }
  907. if (deviceExtension->DeviceDescriptor) {
  908. ExFreePool(deviceExtension->DeviceDescriptor);
  909. deviceExtension->DeviceDescriptor = NULL;
  910. }
  911. if (deviceExtension->AdapterDescriptor) {
  912. ExFreePool(deviceExtension->AdapterDescriptor);
  913. deviceExtension->AdapterDescriptor = NULL;
  914. }
  915. if (deviceExtension->SenseData) {
  916. ExFreePool(deviceExtension->SenseData);
  917. deviceExtension->SenseData = NULL;
  918. }
  919. if (printerData->UnicodeLinkName.Buffer != NULL ) {
  920. IoDeassignArcName(&printerData->UnicodeLinkName);
  921. RtlFreeUnicodeString(&printerData->UnicodeLinkName);
  922. printerData->UnicodeLinkName.Buffer = NULL;
  923. }
  924. if (printerData->UnicodeDeviceString.Buffer != NULL ) {
  925. IoSetDeviceInterfaceState(&printerData->UnicodeDeviceString,FALSE);
  926. RtlFreeUnicodeString(&printerData->UnicodeDeviceString);
  927. printerData->UnicodeDeviceString.Buffer = NULL;
  928. }
  929. ClassDeleteSrbLookasideList(commonExtension);
  930. }
  931. return STATUS_SUCCESS;
  932. }
  933. NTSTATUS
  934. PrinterQueryId(
  935. IN PDEVICE_OBJECT Pdo,
  936. IN BUS_QUERY_ID_TYPE IdType,
  937. IN PUNICODE_STRING UnicodeIdString
  938. )
  939. {
  940. ANSI_STRING ansiIdString;
  941. UCHAR rawString[256];
  942. UCHAR finalString[256];
  943. NTSTATUS status;
  944. PPHYSICAL_DEVICE_EXTENSION pdoExtension = Pdo->DeviceExtension;
  945. PCOMMON_DEVICE_EXTENSION commonExtension = Pdo->DeviceExtension;
  946. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  947. PPRINTER_DATA printerData;
  948. PAGED_CODE();
  949. ASSERT_PDO(Pdo);
  950. fdoExtension = commonExtension->PartitionZeroExtension;
  951. RtlZeroMemory(rawString,256);
  952. RtlZeroMemory(finalString,256);
  953. //
  954. // FDOs printer data
  955. //
  956. printerData = fdoExtension->CommonExtension.DriverData;
  957. if(IdType == BusQueryDeviceID) {
  958. if (fdoExtension->AdapterDescriptor->BusType != BusType1394) {
  959. sprintf(finalString,"SCSI\\%s",printerData->DeviceIdString);
  960. } else {
  961. //
  962. // we want to fake our ids it so we use the legacy printing inf.
  963. //
  964. sprintf(finalString,"LPTENUM\\%s",printerData->DeviceIdString);
  965. }
  966. RtlCopyMemory(printerData->DeviceName,finalString,256);
  967. DEBUGPRINT1(("\'PrinterQueryId, DeviceId =%s\n",printerData->DeviceName));
  968. RtlInitAnsiString(&ansiIdString,finalString);
  969. return RtlAnsiStringToUnicodeString(UnicodeIdString, &ansiIdString, TRUE);
  970. }
  971. if(IdType == BusQueryInstanceID) {
  972. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  973. sprintf(finalString,"1394_%03u",printerData->PortNumber);
  974. } else {
  975. sprintf(finalString,"SCSI%03u", printerData->PortNumber);
  976. }
  977. RtlInitAnsiString(&ansiIdString, finalString);
  978. return RtlAnsiStringToUnicodeString(UnicodeIdString, &ansiIdString, TRUE);
  979. }
  980. if((IdType == BusQueryHardwareIDs) || (IdType == BusQueryCompatibleIDs)) {
  981. sprintf(rawString,"%s",printerData->DeviceIdString);
  982. sprintf(finalString,"%s",printerData->DeviceIdString);
  983. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  984. status = PrinterGetId(printerData->DeviceIdString,IdType,rawString,NULL);
  985. if (IdType == BusQueryHardwareIDs) {
  986. PrinterRegisterPort(Pdo->DeviceExtension);
  987. }
  988. if (NT_SUCCESS(status)) {
  989. RtlZeroMemory(finalString,256);
  990. sprintf(finalString,"%s",rawString);
  991. }
  992. }
  993. DEBUGPRINT1(("\'PrinterQueryId, Combatible/Hw Id =%s\n",finalString));
  994. RtlInitAnsiString(&ansiIdString, finalString);
  995. UnicodeIdString->MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(&ansiIdString) + sizeof(UNICODE_NULL);
  996. UnicodeIdString->Buffer = ExAllocatePoolWithTag(PagedPool,
  997. UnicodeIdString->MaximumLength,
  998. PRINTER_TAG);
  999. if(UnicodeIdString->Buffer == NULL) {
  1000. return STATUS_INSUFFICIENT_RESOURCES;
  1001. }
  1002. RtlZeroMemory(UnicodeIdString->Buffer, UnicodeIdString->MaximumLength);
  1003. return RtlAnsiStringToUnicodeString(UnicodeIdString,
  1004. &ansiIdString,
  1005. FALSE);
  1006. }
  1007. return STATUS_NOT_IMPLEMENTED;
  1008. }
  1009. NTSTATUS
  1010. PrinterCompletionRoutine(
  1011. IN PDEVICE_OBJECT DeviceObject,
  1012. IN PIRP Irp,
  1013. IN PKEVENT Event
  1014. )
  1015. {
  1016. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  1017. return STATUS_MORE_PROCESSING_REQUIRED;
  1018. }
  1019. NTSTATUS
  1020. PrinterQueryPnpCapabilities(
  1021. IN PDEVICE_OBJECT DeviceObject,
  1022. IN PDEVICE_CAPABILITIES Capabilities
  1023. )
  1024. {
  1025. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1026. PAGED_CODE();
  1027. ASSERT(DeviceObject);
  1028. ASSERT(Capabilities);
  1029. if(commonExtension->IsFdo) {
  1030. return STATUS_NOT_IMPLEMENTED;
  1031. } else {
  1032. Capabilities->RawDeviceOK = 1;
  1033. Capabilities->SurpriseRemovalOK = 1;
  1034. }
  1035. return STATUS_SUCCESS;
  1036. }
  1037. VOID
  1038. PrinterRegisterPort(
  1039. IN PPHYSICAL_DEVICE_EXTENSION DeviceExtension
  1040. )
  1041. {
  1042. HANDLE KeyHandle;
  1043. UCHAR RawString[256];
  1044. ANSI_STRING AnsiIdString;
  1045. NTSTATUS status;
  1046. UNICODE_STRING UnicodeTemp;
  1047. UNICODE_STRING UnicodeRegValueName;
  1048. PCOMMON_DEVICE_EXTENSION commonExtension = &DeviceExtension->CommonExtension;
  1049. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
  1050. commonExtension->PartitionZeroExtension;
  1051. PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
  1052. PPRINTER_DATA printerData = fdoExtension->CommonExtension.DriverData;
  1053. //
  1054. // register with the printer guid and create a Port value in the registry
  1055. // for talking to this printer (legacy junk, because the spooler expects it..)
  1056. //
  1057. status = IoOpenDeviceRegistryKey (deviceObject,
  1058. PLUGPLAY_REGKEY_DEVICE,
  1059. KEY_ALL_ACCESS,
  1060. &KeyHandle );
  1061. if (NT_SUCCESS(status)) {
  1062. //
  1063. // Create a new value under our instance, for the port number
  1064. //
  1065. sprintf(RawString,"PortName");
  1066. RtlInitAnsiString(&AnsiIdString,RawString);
  1067. RtlAnsiStringToUnicodeString(&UnicodeRegValueName,&AnsiIdString,TRUE);
  1068. if (fdoExtension->AdapterDescriptor->BusType == BusType1394) {
  1069. sprintf(RawString,"1394_%03u",printerData->PortNumber);
  1070. } else {
  1071. sprintf(RawString,"SCSI%03u",printerData->PortNumber);
  1072. }
  1073. RtlInitAnsiString(&AnsiIdString,RawString);
  1074. RtlAnsiStringToUnicodeString(&UnicodeTemp,&AnsiIdString,TRUE);
  1075. status = ZwSetValueKey(KeyHandle,
  1076. &UnicodeRegValueName,
  1077. 0,
  1078. REG_SZ,
  1079. UnicodeTemp.Buffer,
  1080. UnicodeTemp.Length*sizeof(UCHAR));
  1081. ZwClose(KeyHandle);
  1082. RtlFreeUnicodeString(&UnicodeRegValueName);
  1083. RtlFreeUnicodeString(&UnicodeTemp);
  1084. }
  1085. }
  1086. NTSTATUS
  1087. PrinterGetId
  1088. (
  1089. IN PUCHAR DeviceIdString,
  1090. IN ULONG Type,
  1091. OUT PUCHAR resultString,
  1092. OUT PUCHAR descriptionString
  1093. )
  1094. /*
  1095. Description:
  1096. Creates Id's from the device id retrieved from the printer
  1097. Parameters:
  1098. DeviceId - String with raw device id
  1099. Type - What of id we want as a result
  1100. Id - requested id
  1101. Return Value:
  1102. NTSTATUS
  1103. */
  1104. {
  1105. NTSTATUS status;
  1106. USHORT checkSum=0; // A 16 bit check sum
  1107. UCHAR nodeName[16] = "LPTENUM\\";
  1108. // The following are used to generate sub-strings from the Device ID string
  1109. // to get the DevNode name, and to update the registry
  1110. PUCHAR MFG = NULL; // Manufature name
  1111. PUCHAR MDL = NULL; // Model name
  1112. PUCHAR CLS = NULL; // Class name
  1113. PUCHAR AID = NULL; // Hardare ID
  1114. PUCHAR CID = NULL; // Compatible IDs
  1115. PUCHAR DES = NULL; // Device Description
  1116. status = STATUS_SUCCESS;
  1117. switch(Type) {
  1118. case BusQueryDeviceID:
  1119. // Extract the usefull fields from the DeviceID string. We want
  1120. // MANUFACTURE (MFG):
  1121. // MODEL (MDL):
  1122. // AUTOMATIC ID (AID):
  1123. // COMPATIBLE ID (CID):
  1124. // DESCRIPTION (DES):
  1125. // CLASS (CLS):
  1126. PrinterFindDeviceIdKeys(&MFG, &MDL, &CLS, &DES, &AID, &CID, DeviceIdString);
  1127. // Check to make sure we got MFG and MDL as absolute minimum fields. If not
  1128. // we cannot continue.
  1129. if (!MFG || !MDL)
  1130. {
  1131. status = STATUS_NOT_FOUND;
  1132. goto GetId_Cleanup;
  1133. }
  1134. //
  1135. // Concatenate the provided MFG and MDL P1284 fields
  1136. // Checksum the entire MFG+MDL string
  1137. //
  1138. sprintf(resultString, "%s%s\0",MFG,MDL);
  1139. if (descriptionString) {
  1140. sprintf(descriptionString, "%s %s\0",MFG,MDL);
  1141. }
  1142. break;
  1143. case BusQueryHardwareIDs:
  1144. GetCheckSum(DeviceIdString, (USHORT)strlen(DeviceIdString), &checkSum);
  1145. sprintf(resultString,"%s%.20s%4X",nodeName,DeviceIdString,checkSum);
  1146. break;
  1147. case BusQueryCompatibleIDs:
  1148. //
  1149. // return only 1 id
  1150. //
  1151. GetCheckSum(DeviceIdString, (USHORT)strlen(DeviceIdString), &checkSum);
  1152. sprintf(resultString,"%.20s%4X",DeviceIdString,checkSum);
  1153. break;
  1154. }
  1155. if (Type!=BusQueryDeviceID) {
  1156. //
  1157. // Convert and spaces in the Hardware ID to underscores
  1158. //
  1159. StringSubst ((PUCHAR) resultString, ' ', '_', (USHORT)strlen(resultString));
  1160. }
  1161. GetId_Cleanup:
  1162. return(status);
  1163. }
  1164. VOID
  1165. PrinterFindDeviceIdKeys
  1166. (
  1167. PUCHAR *lppMFG,
  1168. PUCHAR *lppMDL,
  1169. PUCHAR *lppCLS,
  1170. PUCHAR *lppDES,
  1171. PUCHAR *lppAID,
  1172. PUCHAR *lppCID,
  1173. PUCHAR lpDeviceID
  1174. )
  1175. /*
  1176. Description:
  1177. This function will parse a P1284 Device ID string looking for keys
  1178. of interest to the LPT enumerator. Got it from win95 lptenum
  1179. Parameters:
  1180. lppMFG Pointer to MFG string pointer
  1181. lppMDL Pointer to MDL string pointer
  1182. lppMDL Pointer to CLS string pointer
  1183. lppDES Pointer to DES string pointer
  1184. lppCIC Pointer to CID string pointer
  1185. lppAID Pointer to AID string pointer
  1186. lpDeviceID Pointer to the Device ID string
  1187. Return Value:
  1188. no return VALUE.
  1189. If found the lpp parameters are set to the approprate portions
  1190. of the DeviceID string, and they are NULL terminated.
  1191. The actual DeviceID string is used, and the lpp Parameters just
  1192. reference sections, with appropriate null thrown in.
  1193. */
  1194. {
  1195. PUCHAR lpKey = lpDeviceID; // Pointer to the Key to look at
  1196. PUCHAR lpValue; // Pointer to the Key's value
  1197. USHORT wKeyLength; // Length for the Key (for stringcmps)
  1198. // While there are still keys to look at.
  1199. lpValue = StringChr(lpKey, '&');
  1200. if (lpValue) {
  1201. ++lpValue;
  1202. lpKey = lpValue;
  1203. }
  1204. while (lpKey != NULL)
  1205. {
  1206. while (*lpKey == ' ')
  1207. ++lpKey;
  1208. // Is there a terminating COLON character for the current key?
  1209. if (!(lpValue = StringChr(lpKey, ':')) )
  1210. {
  1211. // N: OOPS, somthing wrong with the Device ID
  1212. return;
  1213. }
  1214. // The actual start of the Key value is one past the COLON
  1215. ++lpValue;
  1216. //
  1217. // Compute the Key length for Comparison, including the COLON
  1218. // which will serve as a terminator
  1219. //
  1220. wKeyLength = (USHORT)(lpValue - lpKey);
  1221. //
  1222. // Compare the Key to the Know quantities. To speed up the comparison
  1223. // a Check is made on the first character first, to reduce the number
  1224. // of strings to compare against.
  1225. // If a match is found, the appropriate lpp parameter is set to the
  1226. // key's value, and the terminating SEMICOLON is converted to a NULL
  1227. // In all cases lpKey is advanced to the next key if there is one.
  1228. //
  1229. switch (*lpKey)
  1230. {
  1231. case 'M':
  1232. // Look for MANUFACTURE (MFG) or MODEL (MDL)
  1233. if ((RtlCompareMemory(lpKey, "MANUFACTURER", wKeyLength)>5) ||
  1234. (RtlCompareMemory(lpKey, "MFG", wKeyLength)==3) )
  1235. {
  1236. *lppMFG = lpValue;
  1237. if ((lpKey = StringChr(lpValue, ';'))!=NULL)
  1238. {
  1239. *lpKey = '\0';
  1240. ++lpKey;
  1241. }
  1242. }
  1243. else if ((RtlCompareMemory(lpKey, "MODEL", wKeyLength)==5) ||
  1244. (RtlCompareMemory(lpKey, "MDL", wKeyLength)==3) )
  1245. {
  1246. *lppMDL = lpValue;
  1247. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1248. {
  1249. *lpKey = '\0';
  1250. ++lpKey;
  1251. }
  1252. }
  1253. else
  1254. {
  1255. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1256. {
  1257. *lpKey = '\0';
  1258. ++lpKey;
  1259. }
  1260. }
  1261. break;
  1262. case 'C':
  1263. // Look for CLASS (CLS)
  1264. if ((RtlCompareMemory(lpKey, "CLASS", wKeyLength)==5) ||
  1265. (RtlCompareMemory(lpKey, "CLS", wKeyLength)==3) )
  1266. {
  1267. *lppCLS = lpValue;
  1268. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1269. {
  1270. *lpKey = '\0';
  1271. ++lpKey;
  1272. }
  1273. }
  1274. else if ((RtlCompareMemory(lpKey, "COMPATIBLEID", wKeyLength)>5) ||
  1275. (RtlCompareMemory(lpKey, "CID", wKeyLength)==3) )
  1276. {
  1277. *lppCID = lpValue;
  1278. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1279. {
  1280. *lpKey = '\0';
  1281. ++lpKey;
  1282. }
  1283. }
  1284. else
  1285. {
  1286. if ((lpKey = StringChr(lpValue,';'))!=0)
  1287. {
  1288. *lpKey = '\0';
  1289. ++lpKey;
  1290. }
  1291. }
  1292. break;
  1293. case 'D':
  1294. // Look for DESCRIPTION (DES)
  1295. if (RtlCompareMemory(lpKey, "DESCRIPTION", wKeyLength) ||
  1296. RtlCompareMemory(lpKey, "DES", wKeyLength) )
  1297. {
  1298. *lppDES = lpValue;
  1299. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1300. {
  1301. *lpKey = '\0';
  1302. ++lpKey;
  1303. }
  1304. }
  1305. else
  1306. {
  1307. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1308. {
  1309. *lpKey = '\0';
  1310. ++lpKey;
  1311. }
  1312. }
  1313. break;
  1314. case 'A':
  1315. // Look for AUTOMATIC ID (AID)
  1316. if (RtlCompareMemory(lpKey, "AUTOMATICID", wKeyLength) ||
  1317. RtlCompareMemory(lpKey, "AID", wKeyLength) )
  1318. {
  1319. *lppAID = lpValue;
  1320. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1321. {
  1322. *lpKey = '\0';
  1323. ++lpKey;
  1324. }
  1325. }
  1326. else
  1327. {
  1328. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1329. {
  1330. *lpKey = '\0';
  1331. ++lpKey;
  1332. }
  1333. }
  1334. break;
  1335. default:
  1336. // The key is uninteresting. Go to the next Key
  1337. if ((lpKey = StringChr(lpValue, ';'))!=0)
  1338. {
  1339. *lpKey = '\0';
  1340. ++lpKey;
  1341. }
  1342. break;
  1343. }
  1344. }
  1345. }
  1346. VOID
  1347. GetCheckSum(
  1348. PUCHAR Block,
  1349. USHORT Len,
  1350. PUSHORT CheckSum
  1351. )
  1352. {
  1353. USHORT i;
  1354. UCHAR lrc;
  1355. USHORT crc = 0;
  1356. unsigned short crc16a[] = {
  1357. 0000000, 0140301, 0140601, 0000500,
  1358. 0141401, 0001700, 0001200, 0141101,
  1359. 0143001, 0003300, 0003600, 0143501,
  1360. 0002400, 0142701, 0142201, 0002100,
  1361. };
  1362. unsigned short crc16b[] = {
  1363. 0000000, 0146001, 0154001, 0012000,
  1364. 0170001, 0036000, 0024000, 0162001,
  1365. 0120001, 0066000, 0074000, 0132001,
  1366. 0050000, 0116001, 0104001, 0043000,
  1367. };
  1368. //
  1369. // Calculate CRC using tables.
  1370. //
  1371. UCHAR tmp;
  1372. for ( i=0; i<Len; i++) {
  1373. tmp = Block[i] ^ (UCHAR)crc;
  1374. crc = (crc >> 8) ^ crc16a[tmp & 0x0f] ^ crc16b[tmp >> 4];
  1375. }
  1376. *CheckSum = crc;
  1377. }
  1378. PUCHAR
  1379. StringChr(PCHAR string, CHAR c)
  1380. {
  1381. ULONG i=0;
  1382. if (!string)
  1383. return(NULL);
  1384. while (*string) {
  1385. if (*string==c)
  1386. return(string);
  1387. string++;
  1388. i++;
  1389. }
  1390. return(NULL);
  1391. }
  1392. VOID
  1393. StringSubst
  1394. (
  1395. PUCHAR lpS,
  1396. UCHAR chTargetChar,
  1397. UCHAR chReplacementChar,
  1398. USHORT cbS
  1399. )
  1400. {
  1401. USHORT iCnt = 0;
  1402. while ((lpS != '\0') && (iCnt++ < cbS))
  1403. if (*lpS == chTargetChar)
  1404. *lpS++ = chReplacementChar;
  1405. else
  1406. ++lpS;
  1407. }