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.

1204 lines
29 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. parvdm.c
  5. Abstract:
  6. This module contains the code for a simple parallel class driver.
  7. Unload and Cleanup are supported. The model for grabing and
  8. releasing the parallel port is embodied in the code for IRP_MJ_READ.
  9. Other IRP requests could be implemented similarly.
  10. Basically, every READ requests that comes in gets
  11. passed down to the port driver as a parallel port allocate
  12. request. This IRP will return to this driver when the driver
  13. Environment:
  14. Kernel mode
  15. Revision History :
  16. --*/
  17. #include "ntosp.h"
  18. #include "parallel.h"
  19. #include "ntddvdm.h"
  20. #include "parvdm.h"
  21. #include "parlog.h"
  22. static const PHYSICAL_ADDRESS PhysicalZero = {0};
  23. NTSTATUS
  24. DriverEntry(
  25. IN PDRIVER_OBJECT DriverObject,
  26. IN PUNICODE_STRING RegistryPath
  27. );
  28. BOOLEAN
  29. ParMakeNames(
  30. IN ULONG ParallelPortNumber,
  31. OUT PUNICODE_STRING PortName,
  32. OUT PUNICODE_STRING ClassName,
  33. OUT PUNICODE_STRING LinkName
  34. );
  35. VOID
  36. ParInitializeDeviceObject(
  37. IN PDRIVER_OBJECT DriverObject,
  38. IN ULONG ParallelPortNumber
  39. );
  40. NTSTATUS
  41. ParGetPortInfoFromPortDevice(
  42. IN OUT PDEVICE_EXTENSION Extension
  43. );
  44. VOID
  45. ParReleasePortInfoToPortDevice(
  46. IN OUT PDEVICE_EXTENSION Extension
  47. );
  48. NTSTATUS
  49. ParAllocPort(
  50. IN PDEVICE_EXTENSION Extension,
  51. IN PIRP Irp
  52. );
  53. VOID
  54. ParLogError(
  55. IN PDRIVER_OBJECT DriverObject,
  56. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  57. IN PHYSICAL_ADDRESS P1,
  58. IN PHYSICAL_ADDRESS P2,
  59. IN ULONG SequenceNumber,
  60. IN UCHAR MajorFunctionCode,
  61. IN UCHAR RetryCount,
  62. IN ULONG UniqueErrorValue,
  63. IN NTSTATUS FinalStatus,
  64. IN NTSTATUS SpecificIOStatus
  65. );
  66. #ifdef ALLOC_PRAGMA
  67. #pragma alloc_text(INIT,DriverEntry)
  68. #pragma alloc_text(INIT,ParInitializeDeviceObject)
  69. #pragma alloc_text(INIT,ParMakeNames)
  70. #endif
  71. //
  72. // Keep track of OPEN and CLOSE.
  73. //
  74. ULONG OpenCloseReferenceCount = 1;
  75. PFAST_MUTEX OpenCloseMutex = NULL;
  76. #define ParClaimDriver() \
  77. ExAcquireFastMutex(OpenCloseMutex); \
  78. if(++OpenCloseReferenceCount == 1) { \
  79. MmResetDriverPaging(DriverEntry); \
  80. } \
  81. ExReleaseFastMutex(OpenCloseMutex); \
  82. #define ParReleaseDriver() \
  83. ExAcquireFastMutex(OpenCloseMutex); \
  84. if(--OpenCloseReferenceCount == 0) { \
  85. MmPageEntireDriver(DriverEntry); \
  86. } \
  87. ExReleaseFastMutex(OpenCloseMutex); \
  88. NTSTATUS
  89. DriverEntry(
  90. IN PDRIVER_OBJECT DriverObject,
  91. IN PUNICODE_STRING RegistryPath
  92. )
  93. /*++
  94. Routine Description:
  95. This routine is called at system initialization time to initialize
  96. this driver.
  97. Arguments:
  98. DriverObject - Supplies the driver object.
  99. RegistryPath - Supplies the registry path for this driver.
  100. Return Value:
  101. STATUS_SUCCESS - We could initialize at least one device.
  102. STATUS_NO_SUCH_DEVICE - We could not initialize even one device.
  103. --*/
  104. {
  105. ULONG i;
  106. PAGED_CODE();
  107. //
  108. // allocate the mutex to protect driver reference count
  109. //
  110. OpenCloseMutex = ExAllocatePool(NonPagedPool, sizeof(FAST_MUTEX));
  111. if (!OpenCloseMutex) {
  112. //
  113. // NOTE - we could probably do without bailing here and just
  114. // leave a note for ourselves to never page out, but since we
  115. // don't have enough memory to allocate a mutex we should probably
  116. // avoid leaving the driver paged in at all times
  117. //
  118. return STATUS_INSUFFICIENT_RESOURCES;
  119. }
  120. ExInitializeFastMutex(OpenCloseMutex);
  121. for (i = 0; i < IoGetConfigurationInformation()->ParallelCount; i++) {
  122. ParInitializeDeviceObject(DriverObject, i);
  123. }
  124. if (!DriverObject->DeviceObject) {
  125. if( OpenCloseMutex ) {
  126. ExFreePool( OpenCloseMutex );
  127. OpenCloseMutex = NULL;
  128. }
  129. return STATUS_NO_SUCH_DEVICE;
  130. }
  131. //
  132. // Initialize the Driver Object with driver's entry points
  133. //
  134. DriverObject->MajorFunction[IRP_MJ_CREATE] = ParCreateOpen;
  135. DriverObject->MajorFunction[IRP_MJ_CLOSE] = ParClose;
  136. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ParDeviceControl;
  137. DriverObject->DriverUnload = ParUnload;
  138. //
  139. // page out the driver if we can
  140. //
  141. ParReleaseDriver();
  142. return STATUS_SUCCESS;
  143. }
  144. NTSTATUS
  145. ParOpenFileAgainstParport(PDEVICE_EXTENSION extension)
  146. {
  147. NTSTATUS status;
  148. status = IoGetDeviceObjectPointer(&extension->ParPortName, FILE_READ_ATTRIBUTES,
  149. &extension->ParPortFileObject,
  150. &extension->PortDeviceObject);
  151. return status;
  152. }
  153. VOID
  154. ParCloseFileAgainstParport(PDEVICE_EXTENSION extension)
  155. {
  156. if( extension->ParPortFileObject ) {
  157. ObDereferenceObject( extension->ParPortFileObject );
  158. extension->ParPortFileObject = NULL;
  159. }
  160. }
  161. VOID
  162. ParLogError(
  163. IN PDRIVER_OBJECT DriverObject,
  164. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  165. IN PHYSICAL_ADDRESS P1,
  166. IN PHYSICAL_ADDRESS P2,
  167. IN ULONG SequenceNumber,
  168. IN UCHAR MajorFunctionCode,
  169. IN UCHAR RetryCount,
  170. IN ULONG UniqueErrorValue,
  171. IN NTSTATUS FinalStatus,
  172. IN NTSTATUS SpecificIOStatus
  173. )
  174. /*++
  175. Routine Description:
  176. This routine allocates an error log entry, copies the supplied data
  177. to it, and requests that it be written to the error log file.
  178. Arguments:
  179. DriverObject - Supplies a pointer to the driver object for the
  180. device.
  181. DeviceObject - Supplies a pointer to the device object associated
  182. with the device that had the error, early in
  183. initialization, one may not yet exist.
  184. P1,P2 - Supplies the physical addresses for the controller
  185. ports involved with the error if they are available
  186. and puts them through as dump data.
  187. SequenceNumber - Supplies a ulong value that is unique to an IRP over
  188. the life of the irp in this driver - 0 generally
  189. means an error not associated with an irp.
  190. MajorFunctionCode - Supplies the major function code of the irp if there
  191. is an error associated with it.
  192. RetryCount - Supplies the number of times a particular operation
  193. has been retried.
  194. UniqueErrorValue - Supplies a unique long word that identifies the
  195. particular call to this function.
  196. FinalStatus - Supplies the final status given to the irp that was
  197. associated with this error. If this log entry is
  198. being made during one of the retries this value
  199. will be STATUS_SUCCESS.
  200. SpecificIOStatus - Supplies the IO status for this particular error.
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. PIO_ERROR_LOG_PACKET errorLogEntry;
  206. PVOID objectToUse;
  207. SHORT dumpToAllocate;
  208. if (ARGUMENT_PRESENT(DeviceObject)) {
  209. objectToUse = DeviceObject;
  210. } else {
  211. objectToUse = DriverObject;
  212. }
  213. dumpToAllocate = 0;
  214. if (P1.LowPart != 0 || P1.HighPart != 0) {
  215. dumpToAllocate = (SHORT) sizeof(PHYSICAL_ADDRESS);
  216. }
  217. if (P2.LowPart != 0 || P2.HighPart != 0) {
  218. dumpToAllocate += (SHORT) sizeof(PHYSICAL_ADDRESS);
  219. }
  220. errorLogEntry = IoAllocateErrorLogEntry(objectToUse,
  221. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate));
  222. if (!errorLogEntry) {
  223. return;
  224. }
  225. errorLogEntry->ErrorCode = SpecificIOStatus;
  226. errorLogEntry->SequenceNumber = SequenceNumber;
  227. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  228. errorLogEntry->RetryCount = RetryCount;
  229. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  230. errorLogEntry->FinalStatus = FinalStatus;
  231. errorLogEntry->DumpDataSize = dumpToAllocate;
  232. if (dumpToAllocate) {
  233. RtlCopyMemory(errorLogEntry->DumpData, &P1, sizeof(PHYSICAL_ADDRESS));
  234. if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
  235. RtlCopyMemory(((PUCHAR) errorLogEntry->DumpData) +
  236. sizeof(PHYSICAL_ADDRESS), &P2,
  237. sizeof(PHYSICAL_ADDRESS));
  238. }
  239. }
  240. IoWriteErrorLogEntry(errorLogEntry);
  241. }
  242. VOID
  243. ParInitializeDeviceObject(
  244. IN PDRIVER_OBJECT DriverObject,
  245. IN ULONG ParallelPortNumber
  246. )
  247. /*++
  248. Routine Description:
  249. This routine is called for every parallel port in the system. It
  250. will create a class device upon connecting to the port device
  251. corresponding to it.
  252. Arguments:
  253. DriverObject - Supplies the driver object.
  254. ParallelPortNumber - Supplies the number for this port.
  255. Return Value:
  256. None.
  257. --*/
  258. {
  259. UNICODE_STRING portName, className, linkName;
  260. NTSTATUS status;
  261. PDEVICE_OBJECT deviceObject;
  262. PDEVICE_EXTENSION extension;
  263. PFILE_OBJECT fileObject;
  264. PAGED_CODE();
  265. // Cobble together the port and class device names.
  266. if (!ParMakeNames(ParallelPortNumber, &portName, &className, &linkName)) {
  267. ParLogError(DriverObject, NULL, PhysicalZero, PhysicalZero, 0, 0, 0, 1,
  268. STATUS_SUCCESS, PAR_INSUFFICIENT_RESOURCES);
  269. return;
  270. }
  271. // Create the device object.
  272. status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
  273. &className, FILE_DEVICE_PARALLEL_PORT, 0, FALSE,
  274. &deviceObject);
  275. if (!NT_SUCCESS(status)) {
  276. ParLogError(DriverObject, NULL, PhysicalZero, PhysicalZero, 0, 0, 0, 2,
  277. STATUS_SUCCESS, PAR_INSUFFICIENT_RESOURCES);
  278. ExFreePool(linkName.Buffer);
  279. ExFreePool(portName.Buffer);
  280. ExFreePool(className.Buffer);
  281. return;
  282. }
  283. // Now that the device has been created,
  284. // set up the device extension.
  285. extension = deviceObject->DeviceExtension;
  286. RtlZeroMemory(extension, sizeof(DEVICE_EXTENSION));
  287. extension->DeviceObject = deviceObject;
  288. deviceObject->Flags |= DO_BUFFERED_IO;
  289. status = IoGetDeviceObjectPointer(&portName, FILE_READ_ATTRIBUTES,
  290. &fileObject,
  291. &extension->PortDeviceObject);
  292. if (!NT_SUCCESS(status)) {
  293. ParLogError(DriverObject, deviceObject, PhysicalZero, PhysicalZero,
  294. 0, 0, 0, 3, STATUS_SUCCESS, PAR_CANT_FIND_PORT_DRIVER);
  295. IoDeleteDevice(deviceObject);
  296. ExFreePool(linkName.Buffer);
  297. ExFreePool(portName.Buffer);
  298. ExFreePool(className.Buffer);
  299. return;
  300. }
  301. ObDereferenceObject(fileObject);
  302. extension->DeviceObject->StackSize =
  303. extension->PortDeviceObject->StackSize + 1;
  304. // We don't own parallel ports initially
  305. extension->PortOwned = FALSE;
  306. // Get the port information from the port device object.
  307. status = ParGetPortInfoFromPortDevice(extension);
  308. if (!NT_SUCCESS(status)) {
  309. ParLogError(DriverObject, deviceObject, PhysicalZero, PhysicalZero,
  310. 0, 0, 0, 4, STATUS_SUCCESS, PAR_CANT_FIND_PORT_DRIVER);
  311. IoDeleteDevice(deviceObject);
  312. ExFreePool(linkName.Buffer);
  313. ExFreePool(portName.Buffer);
  314. ExFreePool(className.Buffer);
  315. return;
  316. }
  317. // Set up the symbolic link for windows apps.
  318. status = IoCreateUnprotectedSymbolicLink(&linkName, &className);
  319. if (!NT_SUCCESS(status)) {
  320. ParLogError(DriverObject, deviceObject, extension->OriginalController,
  321. PhysicalZero, 0, 0, 0, 5, STATUS_SUCCESS,
  322. PAR_NO_SYMLINK_CREATED);
  323. extension->CreatedSymbolicLink = FALSE;
  324. ExFreePool(linkName.Buffer);
  325. goto Cleanup;
  326. }
  327. // We were able to create the symbolic link, so record this
  328. // value in the extension for cleanup at unload time.
  329. extension->CreatedSymbolicLink = TRUE;
  330. extension->SymbolicLinkName = linkName;
  331. Cleanup:
  332. // release the port info so the port driver can be paged out
  333. ParReleasePortInfoToPortDevice(extension);
  334. // ExFreePool(portName.Buffer); - save this in extension for
  335. // future CreateFiles against parport
  336. if( portName.Buffer ) {
  337. RtlInitUnicodeString( &extension->ParPortName, portName.Buffer );
  338. }
  339. ExFreePool(className.Buffer);
  340. }
  341. BOOLEAN
  342. ParMakeNames(
  343. IN ULONG ParallelPortNumber,
  344. OUT PUNICODE_STRING PortName,
  345. OUT PUNICODE_STRING ClassName,
  346. OUT PUNICODE_STRING LinkName
  347. )
  348. /*++
  349. Routine Description:
  350. This routine generates the names \Device\ParallelPortN and
  351. \Device\ParallelVdmN, \DosDevices\PARVDMN.
  352. Arguments:
  353. ParallelPortNumber - Supplies the port number.
  354. PortName - Returns the port name.
  355. ClassName - Returns the class name.
  356. LinkName - Returns the symbolic link name.
  357. Return Value:
  358. FALSE - Failure.
  359. TRUE - Success.
  360. --*/
  361. {
  362. UNICODE_STRING prefix, digits, linkPrefix, linkDigits;
  363. WCHAR digitsBuffer[10], linkDigitsBuffer[10];
  364. UNICODE_STRING portSuffix, classSuffix, linkSuffix;
  365. NTSTATUS status;
  366. // Put together local variables for constructing names.
  367. RtlInitUnicodeString(&prefix, L"\\Device\\");
  368. RtlInitUnicodeString(&linkPrefix, L"\\DosDevices\\");
  369. RtlInitUnicodeString(&portSuffix, DD_PARALLEL_PORT_BASE_NAME_U);
  370. RtlInitUnicodeString(&classSuffix, L"ParallelVdm");
  371. RtlInitUnicodeString(&linkSuffix, L"$VDMLPT");
  372. digits.Length = 0;
  373. digits.MaximumLength = 20;
  374. digits.Buffer = digitsBuffer;
  375. linkDigits.Length = 0;
  376. linkDigits.MaximumLength = 20;
  377. linkDigits.Buffer = linkDigitsBuffer;
  378. status = RtlIntegerToUnicodeString(ParallelPortNumber, 10, &digits);
  379. if (!NT_SUCCESS(status)) {
  380. return FALSE;
  381. }
  382. status = RtlIntegerToUnicodeString(ParallelPortNumber + 1, 10, &linkDigits);
  383. if (!NT_SUCCESS(status)) {
  384. return FALSE;
  385. }
  386. // Make the port name.
  387. PortName->Length = 0;
  388. PortName->MaximumLength = prefix.Length + portSuffix.Length +
  389. digits.Length + sizeof(WCHAR);
  390. PortName->Buffer = ExAllocatePool(PagedPool, PortName->MaximumLength);
  391. if (!PortName->Buffer) {
  392. return FALSE;
  393. }
  394. RtlZeroMemory(PortName->Buffer, PortName->MaximumLength);
  395. RtlAppendUnicodeStringToString(PortName, &prefix);
  396. RtlAppendUnicodeStringToString(PortName, &portSuffix);
  397. RtlAppendUnicodeStringToString(PortName, &digits);
  398. // Make the class name.
  399. ClassName->Length = 0;
  400. ClassName->MaximumLength = prefix.Length + classSuffix.Length +
  401. digits.Length + sizeof(WCHAR);
  402. ClassName->Buffer = ExAllocatePool(PagedPool, ClassName->MaximumLength);
  403. if (!ClassName->Buffer) {
  404. ExFreePool(PortName->Buffer);
  405. return FALSE;
  406. }
  407. RtlZeroMemory(ClassName->Buffer, ClassName->MaximumLength);
  408. RtlAppendUnicodeStringToString(ClassName, &prefix);
  409. RtlAppendUnicodeStringToString(ClassName, &classSuffix);
  410. RtlAppendUnicodeStringToString(ClassName, &digits);
  411. // Make the link name.
  412. LinkName->Length = 0;
  413. LinkName->MaximumLength = linkPrefix.Length + linkSuffix.Length +
  414. linkDigits.Length + sizeof(WCHAR);
  415. LinkName->Buffer = ExAllocatePool(PagedPool, LinkName->MaximumLength);
  416. if (!LinkName->Buffer) {
  417. ExFreePool(PortName->Buffer);
  418. ExFreePool(ClassName->Buffer);
  419. return FALSE;
  420. }
  421. RtlZeroMemory(LinkName->Buffer, LinkName->MaximumLength);
  422. RtlAppendUnicodeStringToString(LinkName, &linkPrefix);
  423. RtlAppendUnicodeStringToString(LinkName, &linkSuffix);
  424. RtlAppendUnicodeStringToString(LinkName, &linkDigits);
  425. return TRUE;
  426. }
  427. VOID
  428. ParReleasePortInfoToPortDevice(
  429. IN PDEVICE_EXTENSION Extension
  430. )
  431. /*++
  432. Routine Description:
  433. This routine will release the port information back to the port driver.
  434. Arguments:
  435. Extension - Supplies the device extension.
  436. Return Value:
  437. None.
  438. --*/
  439. {
  440. KEVENT event;
  441. PIRP irp;
  442. IO_STATUS_BLOCK ioStatus;
  443. NTSTATUS status;
  444. KeInitializeEvent(&event, NotificationEvent, FALSE);
  445. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO,
  446. Extension->PortDeviceObject,
  447. NULL, 0, NULL, 0,
  448. TRUE, &event, &ioStatus);
  449. if (!irp) {
  450. return;
  451. }
  452. status = IoCallDriver(Extension->PortDeviceObject, irp);
  453. if (!NT_SUCCESS(status)) {
  454. return;
  455. }
  456. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  457. }
  458. NTSTATUS
  459. ParGetPortInfoFromPortDevice(
  460. IN OUT PDEVICE_EXTENSION Extension
  461. )
  462. /*++
  463. Routine Description:
  464. This routine will request the port information from the port driver
  465. and fill it in the device extension.
  466. Arguments:
  467. Extension - Supplies the device extension.
  468. Return Value:
  469. STATUS_SUCCESS - Success.
  470. !STATUS_SUCCESS - Failure.
  471. --*/
  472. {
  473. KEVENT event;
  474. PIRP irp;
  475. PARALLEL_PORT_INFORMATION portInfo;
  476. IO_STATUS_BLOCK ioStatus;
  477. NTSTATUS status;
  478. KeInitializeEvent(&event, NotificationEvent, FALSE);
  479. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO,
  480. Extension->PortDeviceObject,
  481. NULL, 0, &portInfo,
  482. sizeof(PARALLEL_PORT_INFORMATION),
  483. TRUE, &event, &ioStatus);
  484. if (!irp) {
  485. return STATUS_INSUFFICIENT_RESOURCES;
  486. }
  487. status = IoCallDriver(Extension->PortDeviceObject, irp);
  488. if (!NT_SUCCESS(status)) {
  489. return status;
  490. }
  491. status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  492. if (!NT_SUCCESS(status)) {
  493. return status;
  494. }
  495. Extension->OriginalController = portInfo.OriginalController;
  496. Extension->Controller = portInfo.Controller;
  497. Extension->SpanOfController = portInfo.SpanOfController;
  498. Extension->FreePort = portInfo.FreePort;
  499. Extension->FreePortContext = portInfo.Context;
  500. if (Extension->SpanOfController < PARALLEL_REGISTER_SPAN) {
  501. return STATUS_INSUFFICIENT_RESOURCES;
  502. }
  503. return status;
  504. }
  505. VOID
  506. ParCompleteRequest(
  507. IN PDEVICE_EXTENSION Extension,
  508. IN PIRP Irp
  509. )
  510. /*++
  511. Routine Description:
  512. This routine completes the 'CurrentIrp' after it was returned
  513. from the port driver.
  514. Arguments:
  515. Extension - Supplies the device extension.
  516. Return Value:
  517. None.
  518. --*/
  519. {
  520. // DbgPrint("ParVDMCompleteRequest: Enter with irp = %#08x\n", Irp);
  521. //
  522. // If the allocate failed, then fail this request
  523. //
  524. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  525. // failed to allocate port, release port info back to port driver
  526. // and paged ourselves out.
  527. ParReleasePortInfoToPortDevice(Extension);
  528. ParReleaseDriver();
  529. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  530. Extension->CreateOpenLock = 0;
  531. return;
  532. }
  533. //
  534. // This is where the driver specific stuff should go. The driver
  535. // has exclusive access to the parallel port in this space.
  536. //
  537. // DbgPrint("ParVDMCompleteRequest: We own the port\n");
  538. Extension->PortOwned = TRUE;
  539. //
  540. // Complete the IRP, free the port, and start up the next IRP in
  541. // the queue.
  542. //
  543. Irp->IoStatus.Status = STATUS_SUCCESS;
  544. Irp->IoStatus.Information = 0;
  545. IoCompleteRequest(Irp, IO_PARALLEL_INCREMENT);
  546. return;
  547. }
  548. VOID
  549. ParCancel(
  550. IN PDEVICE_OBJECT DeviceObject,
  551. IN PIRP Irp
  552. )
  553. /*++
  554. Routine Description:
  555. This is the cancel routine for this driver.
  556. Arguments:
  557. DeviceObject - Supplies the device object.
  558. Irp - Supplies the I/O request packet.
  559. Return Value:
  560. None.
  561. --*/
  562. {
  563. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  564. IoReleaseCancelSpinLock(Irp->CancelIrql);
  565. Irp->IoStatus.Information = 0;
  566. Irp->IoStatus.Status = STATUS_CANCELLED;
  567. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  568. }
  569. NTSTATUS
  570. ParCreateOpen(
  571. IN PDEVICE_OBJECT DeviceObject,
  572. IN PIRP Irp
  573. )
  574. /*++
  575. Routine Description:
  576. This routine is the dispatch for create requests.
  577. Arguments:
  578. DeviceObject - Supplies the device object.
  579. Irp - Supplies the I/O request packet.
  580. Return Value:
  581. STATUS_SUCCESS - Success.
  582. STATUS_NOT_A_DIRECTORY - This device is not a directory.
  583. --*/
  584. {
  585. PIO_STACK_LOCATION irpSp;
  586. NTSTATUS status;
  587. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  588. //
  589. // Enforce exclusive access to this device
  590. //
  591. if( InterlockedExchange( &extension->CreateOpenLock, 1 ) ) {
  592. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  593. Irp->IoStatus.Information = 0;
  594. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  595. return STATUS_ACCESS_DENIED;
  596. }
  597. if(extension->PortOwned) {
  598. //
  599. // Do an early exit if we can detect that another client has
  600. // already acquired the port for exclusive use.
  601. //
  602. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  603. Irp->IoStatus.Information = 0;
  604. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  605. extension->CreateOpenLock = 0;
  606. return STATUS_ACCESS_DENIED;
  607. }
  608. irpSp = IoGetCurrentIrpStackLocation(Irp);
  609. if (irpSp->MajorFunction == IRP_MJ_CREATE &&
  610. irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) {
  611. //
  612. // Bail out if client thinks that we are a directory.
  613. //
  614. Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
  615. Irp->IoStatus.Information = 0;
  616. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  617. extension->CreateOpenLock = 0;
  618. return STATUS_NOT_A_DIRECTORY;
  619. }
  620. // DVDF - open FILE against parport device
  621. status = ParOpenFileAgainstParport( extension );
  622. if( !NT_SUCCESS( status ) ) {
  623. //
  624. // We couldn't open a handle to the parport device - bail out
  625. //
  626. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  627. Irp->IoStatus.Information = 0;
  628. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  629. extension->CreateOpenLock = 0;
  630. return STATUS_ACCESS_DENIED;
  631. }
  632. //Lock in driver code
  633. ParClaimDriver();
  634. // lock in ParPort driver
  635. ParGetPortInfoFromPortDevice(extension);
  636. // try to allocate the port for our exclusive use
  637. status = ParAllocPort(extension, Irp);
  638. // DbgPrint("ParVDMDeviceControl: ParAllocPort returned %#08lx\n");
  639. if( !NT_SUCCESS( status ) ) {
  640. extension->CreateOpenLock = 0;
  641. }
  642. return status;
  643. }
  644. NTSTATUS
  645. ParClose(
  646. IN PDEVICE_OBJECT DeviceObject,
  647. IN PIRP Irp
  648. )
  649. /*++
  650. Routine Description:
  651. This routine is the dispatch for a close requests.
  652. Arguments:
  653. DeviceObject - Supplies the device object.
  654. Irp - Supplies the I/O request packet.
  655. Return Value:
  656. STATUS_SUCCESS - Success.
  657. --*/
  658. {
  659. PDEVICE_EXTENSION extension;
  660. NTSTATUS statusOfWait;
  661. extension = DeviceObject->DeviceExtension;
  662. if (!extension->PortOwned)
  663. return STATUS_ACCESS_DENIED;
  664. // free the port for other uses
  665. extension->FreePort(extension->FreePortContext);
  666. extension->PortOwned = FALSE;
  667. // Allow the port driver to be paged.
  668. ParReleasePortInfoToPortDevice(extension);
  669. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  670. // DVDF - close our FILE
  671. ParCloseFileAgainstParport(extension);
  672. // Unlock the code that was locked during the open.
  673. ParReleaseDriver();
  674. // DbgPrint("ParVDMClose: Close device, we no longer own the port\n");
  675. extension->CreateOpenLock = 0;
  676. return STATUS_SUCCESS;
  677. }
  678. NTSTATUS
  679. ParAllocateCompletionRoutine(
  680. IN PDEVICE_OBJECT DeviceObject,
  681. IN PIRP Irp,
  682. IN PVOID Extension
  683. )
  684. /*++
  685. Routine Description:
  686. This is the completion routine for the device control request.
  687. This driver has exclusive access to the parallel port in this
  688. routine.
  689. Arguments:
  690. DeviceObject - Supplies the device object.
  691. Irp - Supplies the I/O request packet.
  692. Extension - Supplies the device extension.
  693. Return Value:
  694. STATUS_MORE_PROCESSING_REQUIRED
  695. --*/
  696. {
  697. KIRQL oldIrql;
  698. LONG irpRef;
  699. if( Irp->PendingReturned ) {
  700. IoMarkIrpPending( Irp );
  701. }
  702. ParCompleteRequest(Extension, Irp);
  703. // If the IRP was completed. It was completed with 'IoCompleteRequest'.
  704. return STATUS_MORE_PROCESSING_REQUIRED;
  705. }
  706. NTSTATUS
  707. ParAllocPort(
  708. IN PDEVICE_EXTENSION Extension,
  709. IN PIRP Irp
  710. )
  711. /*++
  712. Routine Description:
  713. This routine takes the 'CurrentIrp' and sends it down to the
  714. port driver as an allocate parallel port request.
  715. Arguments:
  716. Extension - Supplies the device extension.
  717. Return Value:
  718. None.
  719. --*/
  720. {
  721. PIO_STACK_LOCATION nextSp;
  722. // DbgPrint("ParVDMAllocPort: Entry\n");
  723. nextSp = IoGetNextIrpStackLocation(Irp);
  724. nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  725. nextSp->Parameters.DeviceIoControl.IoControlCode =
  726. IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE;
  727. IoSetCompletionRoutine(Irp,
  728. ParAllocateCompletionRoutine,
  729. Extension, TRUE, TRUE, TRUE);
  730. // DbgPrint("ParVDMAllocPort: Sending Request and exiting\n");
  731. return IoCallDriver(Extension->PortDeviceObject, Irp);
  732. }
  733. NTSTATUS
  734. ParDeviceControl(
  735. IN PDEVICE_OBJECT DeviceObject,
  736. IN PIRP Irp
  737. )
  738. /*++
  739. Routine Description:
  740. This routine is the dispatch for device control requests.
  741. Arguments:
  742. DeviceObject - Supplies the device object.
  743. Irp - Supplies the I/O request packet.
  744. Return Value:
  745. STATUS_PENDING - Request pending.
  746. --*/
  747. {
  748. PDEVICE_EXTENSION extension;
  749. PIO_STACK_LOCATION currentStack;
  750. NTSTATUS status = STATUS_INVALID_PARAMETER;
  751. extension = DeviceObject->DeviceExtension;
  752. currentStack = IoGetCurrentIrpStackLocation(Irp);
  753. switch(currentStack->Parameters.DeviceIoControl.IoControlCode) {
  754. case IOCTL_VDM_PAR_WRITE_DATA_PORT: {
  755. // DbgPrint("ParVDMDeviceControl: IOCTL_VDM_PAR_WRITE_DATA_PORT\n");
  756. if(extension->PortOwned) {
  757. UCHAR *data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
  758. ULONG length = currentStack->Parameters.DeviceIoControl.InputBufferLength;
  759. Irp->IoStatus.Information = 0;
  760. if (length == 1) {
  761. WRITE_PORT_UCHAR(extension->Controller +
  762. PARALLEL_DATA_OFFSET,
  763. *data);
  764. } else {
  765. for(; length != 0; length--, data++) {
  766. WRITE_PORT_UCHAR(extension->Controller +
  767. PARALLEL_DATA_OFFSET,
  768. *data);
  769. // KeStallExecutionProcessor(1);
  770. }
  771. }
  772. status = STATUS_SUCCESS;
  773. } else {
  774. status = STATUS_ACCESS_DENIED;
  775. }
  776. break;
  777. }
  778. case IOCTL_VDM_PAR_READ_STATUS_PORT: {
  779. // DbgPrint("ParVDMDeviceControl: IOCTL_VDM_PAR_READ_STATUS_PORT\n");
  780. if (extension->PortOwned) {
  781. if(currentStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(UCHAR)) {
  782. *(PUCHAR)(Irp->AssociatedIrp.SystemBuffer) =
  783. READ_PORT_UCHAR(extension->Controller +
  784. PARALLEL_STATUS_OFFSET);
  785. status = STATUS_SUCCESS;
  786. Irp->IoStatus.Information = sizeof(UCHAR);
  787. } else {
  788. status = STATUS_INVALID_PARAMETER;
  789. }
  790. } else {
  791. status = STATUS_ACCESS_DENIED;
  792. }
  793. break;
  794. }
  795. case IOCTL_VDM_PAR_WRITE_CONTROL_PORT: {
  796. // DbgPrint("ParVDMDeviceControl: IOCTL_VDM_PAR_WRITE_CONTROL_PORT\n");
  797. if(extension->PortOwned) {
  798. if(currentStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(UCHAR)) {
  799. WRITE_PORT_UCHAR(
  800. extension->Controller + PARALLEL_CONTROL_OFFSET,
  801. *(PUCHAR)(Irp->AssociatedIrp.SystemBuffer)
  802. );
  803. status = STATUS_SUCCESS;
  804. Irp->IoStatus.Information = sizeof(UCHAR);
  805. } else {
  806. status = STATUS_INVALID_PARAMETER;
  807. }
  808. } else {
  809. status = STATUS_ACCESS_DENIED;
  810. }
  811. break;
  812. }
  813. default: {
  814. // DbgPrint("ParVDMDeviceControl: Unknown IOCTL\n");
  815. status = STATUS_INVALID_PARAMETER;
  816. break;
  817. }
  818. }
  819. // DbgPrint("ParVDMDeviceControl: Exit with status %#08lx\n", status);
  820. Irp->IoStatus.Status = status;
  821. IoCompleteRequest(Irp, IO_PARALLEL_INCREMENT);
  822. return status;
  823. }
  824. VOID
  825. ParUnload(
  826. IN PDRIVER_OBJECT DriverObject
  827. )
  828. /*++
  829. Routine Description:
  830. This routine loops through the device list and cleans up after
  831. each of the devices.
  832. Arguments:
  833. DriverObject - Supplies the driver object.
  834. Return Value:
  835. None.
  836. --*/
  837. {
  838. PDEVICE_OBJECT currentDevice;
  839. PDEVICE_EXTENSION extension;
  840. KEVENT event;
  841. PARALLEL_INTERRUPT_SERVICE_ROUTINE interruptService;
  842. PIRP irp;
  843. IO_STATUS_BLOCK ioStatus;
  844. while (currentDevice = DriverObject->DeviceObject) {
  845. extension = currentDevice->DeviceExtension;
  846. if (extension->CreatedSymbolicLink) {
  847. IoDeleteSymbolicLink(&extension->SymbolicLinkName);
  848. ExFreePool(extension->SymbolicLinkName.Buffer);
  849. }
  850. if( extension->ParPortName.Buffer ) {
  851. RtlFreeUnicodeString( &extension->ParPortName );
  852. }
  853. IoDeleteDevice(currentDevice);
  854. }
  855. if( OpenCloseMutex ) {
  856. ExFreePool( OpenCloseMutex );
  857. OpenCloseMutex = NULL;
  858. }
  859. }