test: vdmprint.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# vdmprint.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     vdmprint.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the support for printing ports which could be
    00012     handled in kernel without going to ntvdm.exe
    00013
    00014 Author:
    00015
    00016     Sudeep Bharati (sudeepb) 16-Jan-1993
    00017
    00018 Revision History:
    00019     William Hsieh (williamh) 31-May-1996
    00020         rewrote for Dongle support
    00021
    00022 --*/
    00023
    00024
    00025 #include "vdmp.h"
    00026 #include "vdmprint.h"
    00027 #include <i386.h>
    00028 #include <v86emul.h>
    00029 #include "..\..\..\..\inc\ntddvdm.h"
    00030
    00031 #ifdef ALLOC_PRAGMA
    00032 #pragma alloc_text(PAGE, VdmPrinterStatus)
    00033 #pragma alloc_text(PAGE, VdmPrinterWriteData)
    00034 #pragma alloc_text(PAGE, VdmFlushPrinterWriteData)
    00035 #pragma alloc_text(PAGE, VdmpPrinterDirectIoOpen)
    00036 #pragma alloc_text(PAGE, VdmpPrinterDirectIoClose)
    00037 #endif
    00038
    00039
    00040
    00041 BOOLEAN
    00042 VdmPrinterStatus(
    00043     ULONG iPort,
    00044     ULONG cbInstructionSize,
    00045     PKTRAP_FRAME TrapFrame
    00046     )
    00047
    00048 /*++
    00049
    00050 Routine Description:
    00051
    00052     This routine handles the read operation on the printer status port
    00053
    00054 Arguments:
    00055     iPort              - port on which the io was trapped
    00056     cbInstructionSize  - Instruction size to update TsEip
    00057     TrapFrame          - Trap Frame
    00058
    00059 Return Value:
    00060
    00061     True if successfull, False otherwise
    00062
    00063 --*/
    00064 {
    00065     UCHAR    PrtMode;
    00066     USHORT   adapter;
    00067     ULONG *  printer_status;
    00068     KIRQL    OldIrql;
    00069     PIO_STATUS_BLOCK IoStatusBlock;
    00070     PVDM_PRINTER_INFO   PrtInfo;
    00071     PVDM_TIB    VdmTib;
    00072     NTSTATUS Status = STATUS_SUCCESS;
    00073
    00074     PAGED_CODE();
    00075
    00076     // why we have printer stuff in TIB? It would be more appropriate
    00077     // if we have them in the process object. The main reason(I think)
    00078     // is that we can get rid of synchronization.
    00079     //
    00080
    00081     Status = VdmpGetVdmTib(&VdmTib, VDMTIB_KMODE);
    00082     if (!NT_SUCCESS(Status)) {
    00083        return(FALSE);
    00084     }
    00085
    00086     PrtInfo = &VdmTib->PrinterInfo;
    00087     IoStatusBlock = (PIO_STATUS_BLOCK) &VdmTib->TempArea1;
    00088     printer_status = &VdmTib->PrinterInfo.prt_Scratch;
    00089
    00090     *pNtVDMState |= VDM_IDLEACTIVITY;
    00091     try {
    00092         // first, figure out which PRT we are dealing with. The
    00093         // port addresses in the PrinterInfo are base address of each
    00094         // PRT sorted in the adapter order.
    00095
    00096         if ((USHORT)iPort == PrtInfo->prt_PortAddr[0] + STATUS_PORT_OFFSET)
    00097             adapter = 0;
    00098         else if ((USHORT)iPort == PrtInfo->prt_PortAddr[1] + STATUS_PORT_OFFSET)
    00099             adapter = 1;
    00100         else if ((USHORT)iPort == PrtInfo->prt_PortAddr[2] + STATUS_PORT_OFFSET)
    00101             adapter = 2;
    00102         else {
    00103             // something must be wrong in our code, better check it out
    00104             ASSERT(FALSE);
    00105             return FALSE;
    00106         }
    00107         PrtMode = PrtInfo->prt_Mode[adapter];
    00108
    00109
    00110         if(PRT_MODE_SIMULATE_STATUS_PORT == PrtMode) {
    00111             // we are simulating printer status read.
    00112             // get the current status from softpc.
    00113             if (!(get_status(adapter) & NOTBUSY) &&
    00114                 !(host_lpt_status(adapter) & HOST_LPT_BUSY)) {
    00115                 if (get_control(adapter) & IRQ)
    00116                     return FALSE;
    00117                 set_status(adapter, get_status(adapter) | NOTBUSY);
    00118             }
    00119             *printer_status = (ULONG)(get_status(adapter) | STATUS_REG_MASK);
    00120         }
    00121         else if (PRT_MODE_DIRECT_IO ==  PrtMode) {
    00122             // we have to read the i/o directly(of course, through file system
    00123             // which in turn goes to the driver).
    00124             // Before performing read, flush out all pending output data in our
    00125             // buffer. This is done because the status we are about to read
    00126             // may depend on those pending output data.
    00127             //
    00128             if (PrtInfo->prt_BytesInBuffer[adapter]) {
    00129                 Status = VdmFlushPrinterWriteData(adapter);
    00130 #ifdef DBG
    00131                 if (!NT_SUCCESS(Status)) {
    00132                     DbgPrint("VdmPrintStatus: failed to flush buffered data, status = %ls\n", Status);
    00133                 }
    00134 #endif
    00135             }
    00136             OldIrql = KeGetCurrentIrql();
    00137             // lower irql to passive before doing any IO
    00138             KeLowerIrql(PASSIVE_LEVEL);
    00139             Status = NtDeviceIoControlFile(PrtInfo->prt_Handle[adapter],
    00140                                            NULL,        // notification event
    00141                                            NULL,        // APC routine
    00142                                            NULL,        // Apc Context
    00143                                            IoStatusBlock,
    00144                                            IOCTL_VDM_PAR_READ_STATUS_PORT,
    00145                                            NULL,
    00146                                            0,
    00147                                            printer_status,
    00148                                            sizeof(ULONG)
    00149                                            );
    00150
    00151             if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock->Status)) {
    00152                 // fake a status to make it looks like the port is not connected
    00153                 // to a printer.
    00154                 *printer_status = 0x7F;
    00155 #ifdef DBG
    00156                 DbgPrint("VdmPrinterStatus: failed to get status from printer, status = %lx\n", Status);
    00157 #endif
    00158                 // always tell the caller that we have simulated the operation.
    00159                 Status = STATUS_SUCCESS;
    00160             }
    00161             KeRaiseIrql(OldIrql, &OldIrql);
    00162         }
    00163         else
    00164             // we don't simulate it here
    00165             return FALSE;
    00166
    00167         TrapFrame->Eax &= 0xffffff00;
    00168         TrapFrame->Eax |= (UCHAR)*printer_status;
    00169         TrapFrame->Eip += cbInstructionSize;
    00170
    00171     } except(EXCEPTION_EXECUTE_HANDLER) {
    00172         Status = GetExceptionCode();
    00173     }
    00174     return (NT_SUCCESS(Status));
    00175 }
    00176
    00177 BOOLEAN VdmPrinterWriteData(
    00178     ULONG iPort,
    00179     ULONG cbInstructionSize,
    00180     PKTRAP_FRAME TrapFrame
    00181     )
    00182 {
    00183     UCHAR    PrtMode;
    00184     PVDM_PRINTER_INFO   PrtInfo;
    00185     USHORT   adapter;
    00186     PVDM_TIB VdmTib;
    00187     NTSTATUS Status = STATUS_SUCCESS;
    00188
    00189     PAGED_CODE();
    00190
    00191     Status = VdmpGetVdmTib(&VdmTib, VDMTIB_KMODE);
    00192     if (!NT_SUCCESS(Status)) {
    00193        return(FALSE);
    00194     }
    00195
    00196     PrtInfo = &VdmTib->PrinterInfo;
    00197     *pNtVDMState |= VDM_IDLEACTIVITY;
    00198
    00199     try {
    00200         // first, figure out which PRT we are dealing with. The
    00201         // port addresses in the PrinterInfo are base address of each
    00202         // PRT sorted in the adapter order
    00203         if ((USHORT)iPort == PrtInfo->prt_PortAddr[0] + DATA_PORT_OFFSET)
    00204             adapter = 0;
    00205         else if ((USHORT)iPort == PrtInfo->prt_PortAddr[1] + DATA_PORT_OFFSET)
    00206             adapter = 1;
    00207         else if ((USHORT)iPort == PrtInfo->prt_PortAddr[2] + DATA_PORT_OFFSET)
    00208             adapter = 2;
    00209         else {
    00210             // something must be wrong in our code, better check it out
    00211             ASSERT(FALSE);
    00212             return FALSE;
    00213         }
    00214         if (PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[adapter]){
    00215             PrtInfo->prt_Buffer[adapter][PrtInfo->prt_BytesInBuffer[adapter]] = (UCHAR)TrapFrame->Eax;
    00216             // buffer full, then flush it out
    00217             if (++PrtInfo->prt_BytesInBuffer[adapter] >= PRT_DATA_BUFFER_SIZE){
    00218
    00219                 VdmFlushPrinterWriteData(adapter);
    00220             }
    00221
    00222             TrapFrame->Eip += cbInstructionSize;
    00223
    00224         }
    00225         else
    00226             Status = STATUS_ILLEGAL_INSTRUCTION;
    00227     } except(EXCEPTION_EXECUTE_HANDLER) {
    00228         Status = GetExceptionCode();
    00229     }
    00230     return(NT_SUCCESS(Status));
    00231
    00232 }
    00233
    00234
    00235 NTSTATUS
    00236 VdmFlushPrinterWriteData(USHORT adapter)
    00237 {
    00238     KIRQL    OldIrql;
    00239     PVDM_TIB    VdmTib;
    00240     PVDM_PRINTER_INFO PrtInfo;
    00241     PIO_STATUS_BLOCK IoStatusBlock;
    00242     NTSTATUS Status;
    00243
    00244
    00245     PAGED_CODE();
    00246
    00247
    00248     Status = VdmpGetVdmTib(&VdmTib, VDMTIB_KMODE);
    00249     if (!NT_SUCCESS(Status)) {
    00250        return(FALSE);
    00251     }
    00252
    00253     PrtInfo = &VdmTib->PrinterInfo;
    00254     IoStatusBlock = (PIO_STATUS_BLOCK)&VdmTib->TempArea1;
    00255     try {
    00256         if (PrtInfo->prt_Handle[adapter] &&
    00257             PrtInfo->prt_BytesInBuffer[adapter] &&
    00258             PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[adapter]) {
    00259
    00260             OldIrql = KeGetCurrentIrql();
    00261             KeLowerIrql(PASSIVE_LEVEL);
    00262             Status = NtDeviceIoControlFile(PrtInfo->prt_Handle[adapter],
    00263                                            NULL,        // notification event
    00264                                            NULL,        // APC routine
    00265                                            NULL,        // APC context
    00266                                            IoStatusBlock,
    00267                                            IOCTL_VDM_PAR_WRITE_DATA_PORT,
    00268                                            &PrtInfo->prt_Buffer[adapter][0],
    00269                                            PrtInfo->prt_BytesInBuffer[adapter],
    00270                                            NULL,
    00271                                            0
    00272                                            );
    00273             PrtInfo->prt_BytesInBuffer[adapter] = 0;
    00274             KeRaiseIrql(OldIrql, &OldIrql);
    00275             if (!NT_SUCCESS(Status)) {
    00276 #ifdef DBG
    00277                 DbgPrint("IOCTL_VDM_PAR_WRITE_DATA_PORT failed %lx %x\n",
    00278                          Status, IoStatusBlock->Status);
    00279 #endif
    00280                 Status = IoStatusBlock->Status;
    00281
    00282             }
    00283         }
    00284         else
    00285             Status = STATUS_INVALID_PARAMETER;
    00286     } except (EXCEPTION_EXECUTE_HANDLER) {
    00287         Status = GetExceptionCode();
    00288     }
    00289     return Status;
    00290
    00291 }
    00292
    00293
    00294 NTSTATUS
    00295 VdmpPrinterInitialize(
    00296     PVOID ServiceData
    00297     )
    00298 /*++
    00299
    00300 Routine Description:
    00301
    00302     This routine probes and caches the data associated with kernel
    00303     mode printer emulation.
    00304
    00305 Arguments:
    00306
    00307     ServiceData - Not used.
    00308
    00309 Return Value:
    00310
    00311
    00312 --*/
    00313 {
    00314     PUCHAR State, PrtStatus, Control, HostState;
    00315     PVDM_TIB VdmTib;
    00316     PVDM_PROCESS_OBJECTS VdmObjects;
    00317     NTSTATUS Status;
    00318
    00319     Status = STATUS_SUCCESS;
    00320
    00321     //
    00322     // Note:  We only support two printers in the kernel.
    00323     //
    00324
    00325     Status = VdmpGetVdmTib(&VdmTib, VDMTIB_KMODE);
    00326     if (!NT_SUCCESS(Status)) {
    00327        return(FALSE);
    00328     }
    00329
    00330
    00331     try {
    00332         State = VdmTib->PrinterInfo.prt_State;
    00333         PrtStatus = VdmTib->PrinterInfo.prt_Status;
    00334         Control = VdmTib->PrinterInfo.prt_Control;
    00335         HostState = VdmTib->PrinterInfo.prt_HostState;
    00336
    00337         //
    00338         // Probe the locations for two printers
    00339         //
    00340         ProbeForWrite(
    00341             State,
    00342             2 * sizeof(UCHAR),
    00343             sizeof(UCHAR)
    00344             );
    00345
    00346         ProbeForWrite(
    00347             PrtStatus,
    00348             2 * sizeof(UCHAR),
    00349             sizeof(UCHAR)
    00350             );
    00351
    00352         ProbeForWrite(
    00353             Control,
    00354             2 * sizeof(UCHAR),
    00355             sizeof(UCHAR)
    00356             );
    00357
    00358         ProbeForWrite(
    00359             HostState,
    00360             2 * sizeof(UCHAR),
    00361             sizeof(UCHAR)
    00362             );
    00363
    00364     } except (EXCEPTION_EXECUTE_HANDLER) {
    00365         Status = GetExceptionCode();
    00366     }
    00367
    00368     if (NT_SUCCESS(Status)) {
    00369         VdmObjects = PsGetCurrentProcess()->VdmObjects;
    00370         VdmObjects->PrinterState = State;
    00371         VdmObjects->PrinterStatus = PrtStatus;
    00372         VdmObjects->PrinterControl = Control;
    00373         VdmObjects->PrinterHostState = HostState;
    00374     }
    00375
    00376     return Status;
    00377 }
    00378
    00379 NTSTATUS
    00380 VdmpPrinterDirectIoOpen(PVOID ServiceData)
    00381 {
    00382     PAGED_CODE();
    00383
    00384     return STATUS_SUCCESS;
    00385
    00386 }
    00387 NTSTATUS
    00388 VdmpPrinterDirectIoClose(PVOID ServiceData)
    00389 {
    00390     NTSTATUS    Status;
    00391     PVDM_PRINTER_INFO PrtInfo;
    00392     USHORT Adapter;
    00393     PVDM_TIB VdmTib;
    00394
    00395     PAGED_CODE();
    00396
    00397     Status = STATUS_SUCCESS;
    00398
    00399     // first we fetch vdm tib and do some damage control in case
    00400     // this is bad user-mode memory
    00401     // PrtInfo points to a stricture
    00402
    00403     try {
    00404         VdmTib = NtCurrentTeb()->Vdm;
    00405         ProbeForWrite(VdmTib, sizeof(VDM_TIB), sizeof(UCHAR));
    00406
    00407         // now verify that servicedata ptr is valid
    00408         ProbeForRead(ServiceData, sizeof(USHORT), sizeof(UCHAR));
    00409         Adapter = *(USHORT *)ServiceData;
    00410
    00411     } except (ExSystemExceptionFilter()) {
    00412         Status = GetExceptionCode();
    00413     }
    00414
    00415     if (NULL == VdmTib || NULL == ServiceData) {
    00416        Status = STATUS_ACCESS_VIOLATION;
    00417     }
    00418
    00419     if (!NT_SUCCESS(Status)) {
    00420        return(Status);
    00421     }
    00422
    00423     PrtInfo =&VdmTib->PrinterInfo;
    00424
    00425     try {
    00426              if (Adapter < VDM_NUMBER_OF_LPT) {
    00427                 if (PRT_MODE_DIRECT_IO == PrtInfo->prt_Mode[Adapter] &&
    00428                          PrtInfo->prt_BytesInBuffer[Adapter]) {
    00429                         Status = VdmFlushPrinterWriteData(Adapter);
    00430                 }
    00431              }
    00432         else {
    00433                 Status = STATUS_INVALID_PARAMETER;
    00434         }
    00435     } except (EXCEPTION_EXECUTE_HANDLER) {
    00436              Status     = GetExceptionCode();
    00437     }
    00438     return Status;
    00439 }