#include #include #include #include #include #include "insignia.h" #include "host_def.h" #include /* * Name: nt_lpt.c * Derived From: Sun 2.0 sun4_lpt.c * Author: D A Bartlett * Created On: * Purpose: NT specific parallel port functions * * (c)Copyright Insignia Solutions Ltd., 1991. All rights reserved. * * Note. This port is unlike most ports because the config system has been * removed. It was the job of the config system to validate and open the * printer ports. The only calls to the host printer system are now * make from printer.c. and consist of the following calls. * * * 1) host_print_byte * 2) host_print_auto_feed * 3) host_print_doc * 4) host_lpt_status * * * On the Microsoft model the printer ports will be opened when they are * written to. * * Modifications: * * Tim June 92. Amateur attempt at buffered output to speed things up. * */ /* Work outstanding on this module, 1) Check the usage of port_state 2) Check error handling in write function 3) host_print_doc() always flushs the port, is this correct ? 4) host_print_auto_feed - what should this function do ? 5) Error handling in host_printer_open(), UIF needed ? */ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ #ifdef PRINTER /* SoftPC include files */ #include "xt.h" #include "error.h" #include "config.h" #include "timer.h" #include "host_lpt.h" #include "hostsync.h" #include "host_rrr.h" #include "gfi.h" #include "debug.h" #include "idetect.h" #include "sas.h" #include "printer.h" #ifndef PROD #include "trace.h" #endif boolean flushBuffer IFN1(int, adapter); #ifdef MONITOR extern BOOLEAN MonitorInitializePrinterInfo(WORD, PWORD, PUCHAR, PUCHAR, PUCHAR, PUCHAR); extern BOOLEAN MonitorEnablePrinterDirectAccess(WORD, HANDLE, BOOLEAN); extern BOOLEAN MonitorPrinterWriteData(WORD Adapter, BYTE Value); extern sys_addr lp16BitPrtBuf; extern sys_addr lp16BitPrtCount; extern sys_addr lp16BitPrtId; boolean host_print_buffer(int adapter); #endif /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::: Macros ::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ #ifdef MONITOR sys_addr lpt_status_addr; #define get_lpt_status(adap) \ (sas_hw_at_no_check(lpt_status_addr+(adap))) #define set_lpt_status(adap,val) \ (sas_store_no_check(lpt_status_addr+(adap), (val))) #else /* MONITOR */ #define get_lpt_status(adap) (host_lpt[(adap)].port_status) #define set_lpt_status(adap,val) (host_lpt[(adap)].port_status = (val)) #endif /* MONITOR */ #define KBUFFER_SIZE 1024 // Buffering macros #define HIGH_WATER 1020 #define DIRECT_ACCESS_HIGH_WATER 1020 /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::: Structure for host specific state data ::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ typedef struct { ULONG port_status; // Port status HANDLE handle; // Printer handle int inactive_counter; // Inactivate counter int inactive_trigger; // When equal to inactive_counter close port int bytesInBuffer; // current size of buffer int flushThreshold; // DWORD FileType; // DISK, CHAR, PIPE etc. BOOLEAN active; // Printer open and active BOOLEAN dos_opened; // printer opened with DOS open byte *kBuffer; // output buffer BOOLEAN direct_access; BOOLEAN no_device_attached; } HOST_LPT; HOST_LPT host_lpt[NUM_PARALLEL_PORTS]; #ifdef MONITOR /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::: On x86 machines the host_lpt_status table is kept on the 16-bit ::::*/ /*:::: side in order to reduce the number of expensive BOPs. Here we ::::*/ /*:::: are passed the address of the table. ::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL void host_printer_setup_table(sys_addr table_addr, word nPorts, word * portAddr) { lpt_status_addr = table_addr + 3 * NUM_PARALLEL_PORTS; // Now fill in the TIB entries for printer_info MonitorInitializePrinterInfo (nPorts, portAddr, (LPBYTE)(table_addr + NUM_PARALLEL_PORTS), (LPBYTE)(table_addr + 2 * NUM_PARALLEL_PORTS), (LPBYTE)(table_addr), (LPBYTE)(lpt_status_addr) ); } #endif /* MONITOR */ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::: Set auto close trigger :::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ VOID host_set_inactivate_counter(int adapter) { FAST HOST_LPT *lpt = &host_lpt[adapter]; int close_in_ms; // Flush rate in milliseconds /*::::::::::::::::::::::::::::::::::::::::::::::: Is auto close enabled */ if(!config_inquire(C_AUTOFLUSH, NULL)) { lpt->inactive_trigger = 0; /* Disable auto flush */ return; /* Autoflush not active */ } /*::::::::::::::::::::::::::::::::::::::::::: Calculate closedown count */ close_in_ms = ((int) config_inquire(C_AUTOFLUSH_DELAY, NULL)) * 1000; lpt->inactive_trigger = close_in_ms / (SYSTEM_TICK_INTV/1000); lpt->inactive_counter = 0; //Reset close down counter lpt->no_device_attached = FALSE; } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::: Open printer :::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ SHORT host_lpt_open(int adapter, BOOLEAN direct_access) { DWORD BytesReturn; FAST HOST_LPT *lpt = &host_lpt[adapter]; // Adapter control structure CHAR *lptName; // Adapter filename if (!direct_access) lpt->no_device_attached = FALSE; else if (lpt->no_device_attached) return FALSE; lpt->bytesInBuffer = 0; // Init output buffer index /*::::::::::::::::::::::::::::::::::::::::: Get printer name for Config */ /* use a different device name for DONGLE support */ lptName = (CHAR *) config_inquire((UTINY)((direct_access ? C_VDMLPT1_NAME : C_LPT1_NAME) + adapter), NULL); #ifndef PROD fprintf(trace_file, "Opening printer port %s (%d)\n",lptName,adapter); #endif if ((lpt->kBuffer = (byte *)host_malloc (KBUFFER_SIZE)) == NULL) { // dont put a popup here as the caller of this routine handles it return(FALSE); } lpt->flushThreshold = HIGH_WATER; /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::: Open printer */ lpt->direct_access = FALSE; lpt->active = FALSE; lpt->handle = CreateFile(lptName, GENERIC_WRITE, direct_access ? 0 : FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); /*:::::::::::::::::::::::::::::::::::::::::::::::::: Valid open request */ if(lpt->handle == (HANDLE) -1) { host_free (lpt->kBuffer); // UIF needed to inform user that the open attempt failed #ifndef PROD fprintf(trace_file, "Failed to open printer port\n"); #endif if (direct_access && GetLastError() == ERROR_FILE_NOT_FOUND) lpt->no_device_attached = TRUE; return(FALSE); } /*::::::::::::::::::::::::::::::::::::::Activate port and reset status */ lpt->FileType = GetFileType(lpt->handle); // can not open direct_access access to a redirected device. if (direct_access && lpt->FileType != FILE_TYPE_CHAR) { CloseHandle(lpt->handle); return FALSE; } lpt->active = TRUE; set_lpt_status(adapter, 0); lpt->direct_access = direct_access; if (lpt->direct_access) { lpt->flushThreshold = DIRECT_ACCESS_HIGH_WATER; #ifdef MONITOR MonitorEnablePrinterDirectAccess((WORD)adapter, lpt->handle, TRUE); #endif } /*:::::::::::::::::::::::::::::::::::::::::: Setup auto close counters */ host_set_inactivate_counter(adapter); return(TRUE); } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::: Close all printer ports ::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL void host_lpt_close_all(void) { FAST HOST_LPT *lpt; FAST int i; /*::::::::::: Scan through printer adapters updating auto flush counters */ for(i=0, lpt = &host_lpt[0]; i < NUM_PARALLEL_PORTS; i++, lpt++) { if(lpt->active) host_lpt_close(i); /* Close printer port */ } } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::: Close printer :::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ VOID host_lpt_close(int adapter) { DWORD BytesReturn; FAST HOST_LPT *lpt = &host_lpt[adapter]; if (lpt->direct_access) printer_is_being_closed(adapter); #ifdef MONITOR if (sas_hw_at_no_check(lp16BitPrtId) == adapter){ host_print_buffer (adapter); sas_store_no_check(lp16BitPrtId,0xff); } #endif /*::::::::::::::::::::::::::::::::::::::::: Is the printer port active */ if(lpt->active) { /* ** Tim June 92. Flush output buffer to get the last output out. ** If there's an error I think we've got to ignore it. */ (void)flushBuffer(adapter); #ifndef PROD fprintf(trace_file, "Closing printer port (%d)\n",adapter); #endif #ifdef MONITOR if (lpt->direct_access) MonitorEnablePrinterDirectAccess((WORD)adapter, lpt->handle, FALSE); #endif CloseHandle(lpt->handle); /* Close printer port */ host_free (lpt->kBuffer); lpt->handle = (HANDLE) -1; /* Mark device as closed */ lpt->active = FALSE; /* Deactive printer port */ set_lpt_status(adapter, 0); /* Reset port status */ #ifndef PROD fprintf(trace_file, "Counter expired, closing LPT%d\n", adapter+1); #endif } } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::: Return the status of the lpt channel for an adapter :::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL ULONG host_lpt_status(int adapter) { return(get_lpt_status(adapter)); } GLOBAL UCHAR host_read_printer_status_port(int adapter) { FAST HOST_LPT *lpt = &host_lpt[adapter]; UCHAR PrinterStatus; DWORD BytesReturn; if(!lpt->active) { /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ if(!host_lpt_open(adapter, TRUE)) { #ifndef PROD fprintf(trace_file, "file open error %d\n", GetLastError()); #endif set_lpt_status(adapter, HOST_LPT_BUSY); return(FALSE); /* exit, printer not active !!!! */ } } if (lpt->bytesInBuffer) flushBuffer(adapter); if (!DeviceIoControl(lpt->handle, IOCTL_VDM_PAR_READ_STATUS_PORT, NULL, // no input buffer 0, &PrinterStatus, sizeof(PrinterStatus), &BytesReturn, NULL // no overlap )) { #ifndef PROD fprintf(trace_file, "host_read_printer_status_port failed, error = %ld\n", GetLastError() ); #endif PrinterStatus = 0; } return(PrinterStatus); } BOOLEAN host_set_lpt_direct_access(int adapter, BOOLEAN direct_access) { DWORD BytesReturn; FAST HOST_LPT *lpt = &host_lpt[adapter]; host_lpt_close(adapter); host_lpt_open(adapter, direct_access); if (!lpt->active) set_lpt_status(adapter, HOST_LPT_BUSY); return (lpt->active); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::: Print a byte ::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /* ** Buffer up bytes before they are printed. ** Strategy: ** Save each requested byte in the buffer. ** When the buffer gets full or there's a close request write the ** buffered stuff out. ** Don't forget about errors, eg if the write fails. What about a write ** failure during the close request though? Tough said Tim. */ /* ** flushBuffer() ** Finally write what is in the buffer to the parallel port. It could be a ** real port or a networked printer. ** Input parameter is the parallel port adapter number 0=LPT1 ** Return value of TRUE means write was OK. */ boolean flushBuffer IFN1( int, adapter ) { FAST HOST_LPT *lpt = &host_lpt[adapter]; DWORD BytesWritten; if (lpt->direct_access) { DeviceIoControl(lpt->handle, IOCTL_VDM_PAR_WRITE_DATA_PORT, lpt->kBuffer, lpt->bytesInBuffer, NULL, 0, &BytesWritten, NULL ); lpt->bytesInBuffer = 0; return TRUE; } if( !WriteFile( lpt->handle, lpt->kBuffer, lpt->bytesInBuffer, &BytesWritten, NULL ) ){ #ifndef PROD fprintf(trace_file, "lpt write error %d\n", GetLastError()); #endif lpt->bytesInBuffer = 0; return(FALSE); }else{ lpt->bytesInBuffer = 0; /* * If the print job is being spooled, the spooler can * take a long time to get started, because of the spoolers * low priority. This is especially bad for dos apps in which * idle detection fails or in full screen idle detection is * inactive. To help push the print job thru the system, * idle a bit now. */ if (lpt->FileType == FILE_TYPE_PIPE) { Sleep(10); } return( TRUE ); } } /* end of flushBuffer() */ /* ** Put another byte in to the buffer. If the buffer is full call the ** flush function. ** Return value of TRUE means OK, return FALSE means did a flush and ** it failed. */ boolean toBuffer IFN2( int, adapter, BYTE, b ) { HOST_LPT *lpt = &host_lpt[adapter]; boolean status = TRUE; lpt->kBuffer[lpt->bytesInBuffer++] = b; if( lpt->bytesInBuffer >= lpt->flushThreshold ){ status = flushBuffer( adapter ); } return( status ); } /* end of toBuffer() */ GLOBAL BOOL host_print_byte(int adapter, byte value) { FAST HOST_LPT *lpt = &host_lpt[adapter]; /*:::::::::::::::::::::::::::::::::::::::::::: Is the printer active ? */ if(!lpt->active) { /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ if(!host_lpt_open(adapter, FALSE)) { #ifndef PROD fprintf(trace_file, "file open error %d\n", GetLastError()); #endif set_lpt_status(adapter, HOST_LPT_BUSY); return(FALSE); /* exit, printer not active !!!! */ } } #if defined(MONITOR) if (lpt->direct_access) { MonitorPrinterWriteData((WORD)adapter, value); } else #endif { /*:::::::::::::::::::::::::::::::::::::::::::::::: Send byte to printer */ if(toBuffer(adapter, (BYTE) value) == FALSE) { set_lpt_status(adapter, HOST_LPT_BUSY); return(FALSE); } } /*::::::::::::::::::::::::::: Update idle and activate control variables */ lpt->inactive_counter = 0; /* Reset inactivity counter */ IDLE_comlpt(); /* Tell Idle system there is printer activate */ return(TRUE); } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::: LPT heart beat call ::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL void host_lpt_heart_beat(void) { FAST HOST_LPT *lpt = &host_lpt[0]; int i; /*::::::::::: Scan through printer adapters updating auto close counters */ for(i=0; i < NUM_PARALLEL_PORTS; i++, lpt++) { /*:::::::::::::::::::::::::::::::::::::::: Check auto close counters */ if(lpt->active && lpt->inactive_trigger && ++lpt->inactive_counter == lpt->inactive_trigger) { host_lpt_close(i); /* Close printer port */ } } } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::: Flush the printer port ::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ #if 0 GLOBAL boolean host_print_doc(int adapter) { if(host_lpt[adapter].active) host_lpt_close(adapter); /* Close printer port */ return(TRUE); } #endif /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::: Reset the printer port ::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL void host_reset_print(int adapter) { if(host_lpt[adapter].active) host_lpt_close(adapter); /* Close printer port */ } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::: host_print_auto_feed :::::::::::::::::::::::::::::::::*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ GLOBAL void host_print_auto_feed(int adapter, BOOL value) { UNREFERENCED_FORMAL_PARAMETER(adapter); UNREFERENCED_FORMAL_PARAMETER(value); } #ifdef MONITOR GLOBAL boolean host_print_buffer(int adapter) { FAST HOST_LPT *lpt = &host_lpt[adapter]; word cb; byte i,ch; cb = sas_w_at_no_check(lp16BitPrtCount); if (!cb) return (TRUE); /*:::::::::::::::::::::::::::::::::::::::::::: Is the printer active ? */ if(!lpt->active) { /*:::::::::::::::::::::::::::: Port inactive, attempt to reopen it */ if(!host_lpt_open(adapter, FALSE)) { #ifndef PROD fprintf(trace_file, "file open error %d\n", GetLastError()); #endif set_lpt_status(adapter, HOST_LPT_BUSY); return(FALSE); /* exit, printer not active !!!! */ } } if (!lpt->direct_access) { /*:::::::::::::::::::::::::::::::::::::::::::::::: Send byte to printer */ for (i=0; i inactive_counter = 0; /* Reset inactivity counter */ IDLE_comlpt(); /* Tell Idle system there is printer activate */ return(TRUE); } #endif // MONITOR GLOBAL void host_lpt_dos_open(int adapter) { FAST HOST_LPT *lpt = &host_lpt[adapter]; lpt->dos_opened = TRUE; } GLOBAL void host_lpt_dos_close(int adapter) { FAST HOST_LPT *lpt = &host_lpt[adapter]; if (lpt->active) host_lpt_close(adapter); /* Close printer port */ lpt->dos_opened = FALSE; } GLOBAL void host_lpt_flush_initialize() { FAST HOST_LPT *lpt; FAST int i; for(i=0, lpt = &host_lpt[0]; i < NUM_PARALLEL_PORTS; i++, lpt++) lpt->dos_opened = FALSE; } #endif /* PRINTER */