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 }

Generated on Sat May 15 19:42:22 2004 for test by doxygen 1.3.7