Leaked source code of windows server 2003
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.

598 lines
15 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vdmprint.c
  5. Abstract:
  6. This module contains the support for printing ports which could be
  7. handled in kernel without going to ntvdm.exe
  8. Author:
  9. Sudeep Bharati (sudeepb) 16-Jan-1993
  10. Revision History:
  11. William Hsieh (williamh) 31-May-1996
  12. rewrote for Dongle support
  13. --*/
  14. #include "vdmp.h"
  15. #include <ntddvdm.h>
  16. NTSTATUS
  17. VdmpFlushPrinterWriteData (
  18. IN USHORT Adapter
  19. );
  20. #define DATA_PORT_OFFSET 0
  21. #define STATUS_PORT_OFFSET 1
  22. #define CONTROL_PORT_OFFSET 2
  23. #define LPT1_PORT_STATUS 0x3bd
  24. #define LPT2_PORT_STATUS 0x379
  25. #define LPT3_PORT_STATUS 0x279
  26. #define LPT_MASK 0xff0
  27. #define IRQ 0x10
  28. #define NOTBUSY 0x80
  29. #define HOST_LPT_BUSY (1 << 0)
  30. #define STATUS_REG_MASK 0x07
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(PAGE, VdmPrinterStatus)
  33. #pragma alloc_text(PAGE, VdmPrinterWriteData)
  34. #pragma alloc_text(PAGE, VdmpFlushPrinterWriteData)
  35. #pragma alloc_text(PAGE, VdmpPrinterInitialize)
  36. #pragma alloc_text(PAGE, VdmpPrinterDirectIoOpen)
  37. #pragma alloc_text(PAGE, VdmpPrinterDirectIoClose)
  38. #endif
  39. BOOLEAN
  40. VdmPrinterStatus (
  41. IN ULONG iPort,
  42. IN ULONG cbInstructionSize,
  43. IN PKTRAP_FRAME TrapFrame
  44. )
  45. /*++
  46. Routine Description:
  47. This routine handles the read operation on the printer status port
  48. Arguments:
  49. iPort - port on which the io was trapped
  50. cbInstructionSize - Instruction size to update TsEip
  51. TrapFrame - Trap Frame
  52. Return Value:
  53. True if successful, False otherwise
  54. --*/
  55. {
  56. UCHAR PrtMode;
  57. HANDLE PrintHandle;
  58. volatile PUCHAR HostStatus;
  59. volatile PUCHAR AdapterStatus;
  60. volatile PUCHAR AdapterControl;
  61. USHORT adapter;
  62. KIRQL OldIrql;
  63. PVDM_TIB VdmTib;
  64. NTSTATUS Status;
  65. PULONG printer_status;
  66. LOGICAL IssueIoControl;
  67. PVDM_PRINTER_INFO PrtInfo;
  68. PIO_STATUS_BLOCK IoStatusBlock;
  69. PVDM_PROCESS_OBJECTS VdmObjects;
  70. PAGED_CODE();
  71. Status = VdmpGetVdmTib(&VdmTib);
  72. if (!NT_SUCCESS(Status)) {
  73. return FALSE;
  74. }
  75. OldIrql = PASSIVE_LEVEL;
  76. PrintHandle = (HANDLE)-1;
  77. PrtInfo = &VdmTib->PrinterInfo;
  78. IoStatusBlock = (PIO_STATUS_BLOCK) &VdmTib->TempArea1;
  79. printer_status = &VdmTib->PrinterInfo.prt_Scratch;
  80. IssueIoControl = FALSE;
  81. try {
  82. //
  83. // First figure out which PRT we are dealing with. The
  84. // port addresses in the PrinterInfo are base address of each
  85. // PRT sorted in the adapter order.
  86. //
  87. *FIXED_NTVDMSTATE_LINEAR_PC_AT |= VDM_IDLEACTIVITY;
  88. if ((USHORT)iPort == PrtInfo->prt_PortAddr[0] + STATUS_PORT_OFFSET) {
  89. adapter = 0;
  90. }
  91. else if ((USHORT)iPort == PrtInfo->prt_PortAddr[1] + STATUS_PORT_OFFSET) {
  92. adapter = 1;
  93. }
  94. else if ((USHORT)iPort == PrtInfo->prt_PortAddr[2] + STATUS_PORT_OFFSET) {
  95. adapter = 2;
  96. }
  97. else {
  98. // something must be wrong in our code, better check it out
  99. ASSERT (FALSE);
  100. return FALSE;
  101. }
  102. PrtMode = PrtInfo->prt_Mode[adapter];
  103. VdmObjects = (PVDM_PROCESS_OBJECTS) (PsGetCurrentProcess()->VdmObjects);
  104. AdapterStatus = VdmObjects->PrinterStatus + adapter;
  105. if (PRT_MODE_SIMULATE_STATUS_PORT == PrtMode) {
  106. //
  107. // We are simulating a printer status read.
  108. // Get the current status from softpc.
  109. //
  110. HostStatus = VdmObjects->PrinterHostState + adapter;
  111. if (!(*AdapterStatus & NOTBUSY) && !(*HostStatus & HOST_LPT_BUSY)) {
  112. AdapterControl = VdmObjects->PrinterControl + adapter;
  113. if (*AdapterControl & IRQ) {
  114. return FALSE;
  115. }
  116. *AdapterStatus = (*AdapterStatus | NOTBUSY);
  117. }
  118. *printer_status = (ULONG)(*AdapterStatus | STATUS_REG_MASK);
  119. TrapFrame->Eax &= 0xffffff00;
  120. TrapFrame->Eax |= (UCHAR)*printer_status;
  121. TrapFrame->Eip += cbInstructionSize;
  122. }
  123. else if (PRT_MODE_DIRECT_IO == PrtMode) {
  124. //
  125. // We have to read the I/O directly (of course, through file system
  126. // which in turn goes to the driver).
  127. // Before performing the read, flush out all pending output data
  128. // in our buffer. This is done because the status we are about
  129. // to read may depend on the pending output data.
  130. //
  131. if (PrtInfo->prt_BytesInBuffer[adapter]) {
  132. Status = VdmpFlushPrinterWriteData (adapter);
  133. #ifdef DBG
  134. if (!NT_SUCCESS(Status)) {
  135. DbgPrint("VdmPrintStatus: failed to flush buffered data, status = %ls\n", Status);
  136. }
  137. #endif
  138. }
  139. //
  140. // Capture this argument first as this reference may cause an
  141. // exception.
  142. //
  143. PrintHandle = PrtInfo->prt_Handle[adapter];
  144. //
  145. // Lower irql to PASSIVE before doing any I/O.
  146. //
  147. OldIrql = KeGetCurrentIrql ();
  148. KeLowerIrql (PASSIVE_LEVEL);
  149. IssueIoControl = TRUE;
  150. }
  151. else {
  152. //
  153. // We don't simulate it here.
  154. //
  155. return FALSE;
  156. }
  157. } except(EXCEPTION_EXECUTE_HANDLER) {
  158. Status = GetExceptionCode();
  159. }
  160. if (IssueIoControl == TRUE) {
  161. Status = NtDeviceIoControlFile(PrintHandle,
  162. NULL, // notification event
  163. NULL, // APC routine
  164. NULL, // Apc Context
  165. IoStatusBlock,
  166. IOCTL_VDM_PAR_READ_STATUS_PORT,
  167. NULL,
  168. 0,
  169. printer_status,
  170. sizeof(ULONG));
  171. try {
  172. if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock->Status)) {
  173. //
  174. // fake a status to make it looks like the port is not connected
  175. // to a printer.
  176. //
  177. *printer_status = 0x7F;
  178. #ifdef DBG
  179. DbgPrint("VdmPrinterStatus: failed to get status from printer, status = %lx\n", Status);
  180. #endif
  181. //
  182. // Always tell the caller that we have simulated the operation.
  183. //
  184. Status = STATUS_SUCCESS;
  185. }
  186. TrapFrame->Eax &= 0xffffff00;
  187. TrapFrame->Eax |= (UCHAR)*printer_status;
  188. TrapFrame->Eip += cbInstructionSize;
  189. }
  190. except (EXCEPTION_EXECUTE_HANDLER) {
  191. Status = GetExceptionCode();
  192. }
  193. //
  194. // Regardless of any exceptions that may have occurred, we must
  195. // restore our caller's IRQL since we lowered it.
  196. //
  197. KeRaiseIrql (OldIrql, &OldIrql);
  198. }
  199. if (!NT_SUCCESS(Status)) {
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. BOOLEAN
  205. VdmPrinterWriteData (
  206. IN ULONG iPort,
  207. IN ULONG cbInstructionSize,
  208. IN PKTRAP_FRAME TrapFrame
  209. )
  210. {
  211. PVDM_PRINTER_INFO PrtInfo;
  212. USHORT adapter;
  213. PVDM_TIB VdmTib;
  214. NTSTATUS Status;
  215. PAGED_CODE();
  216. Status = VdmpGetVdmTib(&VdmTib);
  217. if (!NT_SUCCESS(Status)) {
  218. return FALSE;
  219. }
  220. PrtInfo = &VdmTib->PrinterInfo;
  221. try {
  222. //
  223. // First figure out which PRT we are dealing with. The
  224. // port addresses in the PrinterInfo are base address of each
  225. // PRT sorted in the adapter order.
  226. //
  227. *FIXED_NTVDMSTATE_LINEAR_PC_AT |= VDM_IDLEACTIVITY;
  228. if ((USHORT)iPort == PrtInfo->prt_PortAddr[0] + DATA_PORT_OFFSET) {
  229. adapter = 0;
  230. }
  231. else if ((USHORT)iPort == PrtInfo->prt_PortAddr[1] + DATA_PORT_OFFSET) {
  232. adapter = 1;
  233. }
  234. else if ((USHORT)iPort == PrtInfo->prt_PortAddr[2] + DATA_PORT_OFFSET) {
  235. adapter = 2;
  236. }
  237. else {
  238. // something must be wrong in our code, better check it out
  239. ASSERT(FALSE);
  240. return FALSE;
  241. }
  242. if (PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[adapter]) {
  243. PrtInfo->prt_Buffer[adapter][PrtInfo->prt_BytesInBuffer[adapter]] = (UCHAR)TrapFrame->Eax;
  244. //
  245. // buffer full, then flush it out
  246. //
  247. if (++PrtInfo->prt_BytesInBuffer[adapter] >= PRT_DATA_BUFFER_SIZE) {
  248. VdmpFlushPrinterWriteData(adapter);
  249. }
  250. TrapFrame->Eip += cbInstructionSize;
  251. }
  252. else {
  253. Status = STATUS_ILLEGAL_INSTRUCTION;
  254. }
  255. } except(EXCEPTION_EXECUTE_HANDLER) {
  256. Status = GetExceptionCode();
  257. }
  258. if (!NT_SUCCESS(Status)) {
  259. return FALSE;
  260. }
  261. return TRUE;
  262. }
  263. NTSTATUS
  264. VdmpFlushPrinterWriteData (
  265. IN USHORT adapter
  266. )
  267. {
  268. KIRQL OldIrql;
  269. PVDM_TIB VdmTib;
  270. HANDLE PrintHandle;
  271. NTSTATUS Status;
  272. PVDM_PRINTER_INFO PrtInfo;
  273. PIO_STATUS_BLOCK IoStatusBlock;
  274. PVOID InputBuffer;
  275. ULONG InputBufferLength;
  276. PAGED_CODE();
  277. Status = VdmpGetVdmTib (&VdmTib);
  278. if (!NT_SUCCESS(Status)) {
  279. return FALSE;
  280. }
  281. InputBuffer = NULL;
  282. InputBufferLength = 0;
  283. PrintHandle = (HANDLE)-1;
  284. PrtInfo = &VdmTib->PrinterInfo;
  285. IoStatusBlock = (PIO_STATUS_BLOCK)&VdmTib->TempArea1;
  286. try {
  287. if (PrtInfo->prt_Handle[adapter] &&
  288. PrtInfo->prt_BytesInBuffer[adapter] &&
  289. PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[adapter]) {
  290. PrintHandle = PrtInfo->prt_Handle[adapter];
  291. InputBuffer = &PrtInfo->prt_Buffer[adapter][0];
  292. InputBufferLength = PrtInfo->prt_BytesInBuffer[adapter];
  293. }
  294. else {
  295. Status = STATUS_INVALID_PARAMETER;
  296. }
  297. } except (EXCEPTION_EXECUTE_HANDLER) {
  298. Status = GetExceptionCode();
  299. }
  300. if (NT_SUCCESS(Status)) {
  301. OldIrql = KeGetCurrentIrql();
  302. KeLowerIrql(PASSIVE_LEVEL);
  303. Status = NtDeviceIoControlFile(PrintHandle,
  304. NULL, // notification event
  305. NULL, // APC routine
  306. NULL, // APC context
  307. IoStatusBlock,
  308. IOCTL_VDM_PAR_WRITE_DATA_PORT,
  309. InputBuffer,
  310. InputBufferLength,
  311. NULL,
  312. 0);
  313. try {
  314. PrtInfo->prt_BytesInBuffer[adapter] = 0;
  315. if (!NT_SUCCESS(Status)) {
  316. #ifdef DBG
  317. DbgPrint("IOCTL_VDM_PAR_WRITE_DATA_PORT failed %lx %x\n",
  318. Status, IoStatusBlock->Status);
  319. #endif
  320. Status = IoStatusBlock->Status;
  321. }
  322. } except (EXCEPTION_EXECUTE_HANDLER) {
  323. Status = GetExceptionCode();
  324. }
  325. KeRaiseIrql (OldIrql, &OldIrql);
  326. }
  327. return Status;
  328. }
  329. NTSTATUS
  330. VdmpPrinterInitialize (
  331. IN PVOID ServiceData
  332. )
  333. /*++
  334. Routine Description:
  335. This routine probes and caches the data associated with kernel
  336. mode printer emulation.
  337. Arguments:
  338. ServiceData - Not used.
  339. Return Value:
  340. --*/
  341. {
  342. PUCHAR State, PrtStatus, Control, HostState;
  343. PVDM_TIB VdmTib;
  344. PVDM_PROCESS_OBJECTS VdmObjects;
  345. NTSTATUS Status;
  346. UNREFERENCED_PARAMETER (ServiceData);
  347. //
  348. // Note: We only support two printers in the kernel.
  349. //
  350. Status = VdmpGetVdmTib(&VdmTib);
  351. if (!NT_SUCCESS(Status)) {
  352. return FALSE;
  353. }
  354. try {
  355. State = VdmTib->PrinterInfo.prt_State;
  356. PrtStatus = VdmTib->PrinterInfo.prt_Status;
  357. Control = VdmTib->PrinterInfo.prt_Control;
  358. HostState = VdmTib->PrinterInfo.prt_HostState;
  359. //
  360. // Probe the locations for two printers
  361. //
  362. ProbeForWrite(
  363. State,
  364. 2 * sizeof(UCHAR),
  365. sizeof(UCHAR)
  366. );
  367. ProbeForWrite(
  368. PrtStatus,
  369. 2 * sizeof(UCHAR),
  370. sizeof(UCHAR)
  371. );
  372. ProbeForWrite(
  373. Control,
  374. 2 * sizeof(UCHAR),
  375. sizeof(UCHAR)
  376. );
  377. ProbeForWrite(
  378. HostState,
  379. 2 * sizeof(UCHAR),
  380. sizeof(UCHAR)
  381. );
  382. } except (EXCEPTION_EXECUTE_HANDLER) {
  383. Status = GetExceptionCode();
  384. State = 0; // satisfy no_opt compilation
  385. PrtStatus = 0; // satisfy no_opt compilation
  386. Control = 0; // satisfy no_opt compilation
  387. HostState = 0; // satisfy no_opt compilation
  388. }
  389. if (NT_SUCCESS(Status)) {
  390. VdmObjects = PsGetCurrentProcess()->VdmObjects;
  391. VdmObjects->PrinterState = State;
  392. VdmObjects->PrinterStatus = PrtStatus;
  393. VdmObjects->PrinterControl = Control;
  394. VdmObjects->PrinterHostState = HostState;
  395. }
  396. return Status;
  397. }
  398. NTSTATUS
  399. VdmpPrinterDirectIoOpen (
  400. IN PVOID ServiceData
  401. )
  402. {
  403. PAGED_CODE();
  404. UNREFERENCED_PARAMETER (ServiceData);
  405. return STATUS_SUCCESS;
  406. }
  407. NTSTATUS
  408. VdmpPrinterDirectIoClose (
  409. IN PVOID ServiceData
  410. )
  411. {
  412. LOGICAL FlushData;
  413. NTSTATUS Status;
  414. PVDM_PRINTER_INFO PrtInfo;
  415. USHORT Adapter;
  416. PVDM_TIB VdmTib;
  417. PAGED_CODE();
  418. if (NULL == ServiceData) {
  419. return STATUS_ACCESS_VIOLATION;
  420. }
  421. //
  422. // First we fetch vdm tib and do some damage control in case
  423. // this is bad user-mode memory
  424. // PrtInfo points to a stricture
  425. try {
  426. VdmTib = NtCurrentTeb()->Vdm;
  427. if (VdmTib == NULL) {
  428. return STATUS_ACCESS_VIOLATION;
  429. }
  430. ProbeForWrite(VdmTib, sizeof(VDM_TIB), sizeof(UCHAR));
  431. //
  432. // Now verify that servicedata ptr is valid.
  433. //
  434. ProbeForRead(ServiceData, sizeof(USHORT), sizeof(UCHAR));
  435. Adapter = *(PUSHORT)ServiceData;
  436. } except (EXCEPTION_EXECUTE_HANDLER) {
  437. return GetExceptionCode();
  438. }
  439. Status = STATUS_SUCCESS;
  440. PrtInfo = &VdmTib->PrinterInfo;
  441. FlushData = FALSE;
  442. try {
  443. if (Adapter < VDM_NUMBER_OF_LPT) {
  444. if (PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[Adapter] &&
  445. PrtInfo->prt_BytesInBuffer[Adapter]) {
  446. FlushData = TRUE;
  447. }
  448. }
  449. else {
  450. Status = STATUS_INVALID_PARAMETER;
  451. }
  452. } except (EXCEPTION_EXECUTE_HANDLER) {
  453. Status = GetExceptionCode();
  454. }
  455. if (FlushData == TRUE) {
  456. Status = VdmpFlushPrinterWriteData (Adapter);
  457. }
  458. return Status;
  459. }