Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

PortAccessNt4.c

Go to the documentation of this file.
00001 /*
00002  *  This program is free software; you can redistribute it and/or
00003  *  modify it under the terms of the GNU General Public License
00004  *  as published by the Free Software Foundation; either version
00005  *  2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 2004-2006 Spiro Trikaliotis
00008  *  Copyright 1998      Wolfgang Moser
00009  *
00010  *  This file is heavily based on LPTDTC by Wolfgang Moser.
00011  */
00012 
00023 #include <initguid.h>
00024 #include <wdm.h>
00025 #include "cbm_driver.h"
00026 
00027 
00028 
00029 // Set ExtendedTests to 1, if you want to try searching for unusual EPP's
00030 // But take notice that the functionality of this test is not guaranteed!
00031 #define AdvancedEPPTests 1
00032 
00033 enum lptMode
00034 {
00035         lptN_A  = 0,
00036         lptSPP  = 1,
00037         lptPS2  = 2,
00038         lptEPP  = 3,
00039         lptECP  = 4,
00040         lptEPPc = 5,                    // EPP with special control word to enable
00041 };
00042 
00043 enum ecpMode
00044 {
00045         ecpNOECR   = 0,      // no ECP-Port found!!!
00046 
00047         ecpSTNDRD  = 1,
00048         ecpBYTE    = 2,
00049         ecpSTDFIFO = 3,
00050         ecpECPFIFO = 4,
00051         ecpEPP     = 5,
00052         ecpRESVRD  = 6,
00053         ecpFIFOTST = 7,
00054         ecpCONFIG  = 8
00055 };
00056 
00057 // set the Bidirectional-Flag to output (normal mode)
00058 static void
00059 BIDIoutp(PUCHAR port)
00060 {
00061     WRITE_PORT_UCHAR(port+2,0xC4);
00062 }
00063 
00064 // set the Bidirectional-Flag to input (reverse mode)
00065 static void
00066 BIDIinp(PUCHAR port)
00067 {
00068     WRITE_PORT_UCHAR(port+2,0xE4);
00069 }
00070 
00071 // clear the Timeout-Flag
00072 static void
00073 EPPclear(PUCHAR port)
00074 {
00075     unsigned char val=READ_PORT_UCHAR(port+1);
00076 
00077                                           // Reset Timeout-Flag by reading
00078     WRITE_PORT_UCHAR(port+1,val|0x01);    // or by writing 0
00079     WRITE_PORT_UCHAR(port+1,val&0xFE);    // or by writing 1 to it
00080 }
00081 
00082 //----------------------------------------------------------------
00083 // Port Detection Routines
00084 //----------------------------------------------------------------
00085 
00086 // ECP port detection
00087 static enum lptMode
00088 ECPdetect(PUCHAR port)
00089 {
00090     enum lptMode ret = lptN_A;
00091 
00092     unsigned char ECR = READ_PORT_UCHAR(port+0x402)&~0x07;
00093     do
00094     {
00095         WRITE_PORT_UCHAR(port+0x402,0x34);
00096         WRITE_PORT_UCHAR(port+2,0xC6);
00097         if(READ_PORT_UCHAR(port+0x402)!=0x35){
00098         ECR=0xC4;                                                       // There's no ECR,
00099         break;
00100     }
00101 
00102     WRITE_PORT_UCHAR(port+0x402,0x35);
00103     WRITE_PORT_UCHAR(port+0x402,0xd4);
00104     READ_PORT_UCHAR(port+0x400);
00105     WRITE_PORT_UCHAR(port+0x400,0xAA);
00106     if(READ_PORT_UCHAR(port+0x400)!=0xAA)
00107         break;
00108 
00109     WRITE_PORT_UCHAR(port+0x400,0x55);
00110     if(READ_PORT_UCHAR(port+0x400)!=0x55)
00111         break;
00112 
00113     ret=lptECP;
00114 
00115     } while(0);
00116 
00117     WRITE_PORT_UCHAR(port+0x402,0x35);
00118     WRITE_PORT_UCHAR(port+0x402,ECR);
00119     return ret;
00120 }
00121 
00122 // EPP port detection without Control port initialisation
00123 static enum lptMode
00124 EPPdWOC(PUCHAR port)
00125 {
00126     do
00127     {
00128         EPPclear(port);
00129         WRITE_PORT_UCHAR(port+3,0xAA);
00130         EPPclear(port);
00131         if(READ_PORT_UCHAR(port+3)!=0xAA)
00132             break;
00133 
00134         EPPclear(port);
00135         WRITE_PORT_UCHAR(port+3,0x55);
00136         EPPclear(port);
00137 
00138         if(READ_PORT_UCHAR(port+3)!=0x55)
00139             break;
00140 
00141         return lptEPP;
00142 
00143     } while(0);
00144 
00145     EPPclear(port);
00146     WRITE_PORT_UCHAR(port+3,0x00);
00147     READ_PORT_UCHAR(port+3);
00148 
00149     if(!(READ_PORT_UCHAR(port+1)&0x01))
00150         return lptN_A;
00151 
00152     EPPclear(port);
00153     if(READ_PORT_UCHAR(port+1)&0x01)
00154         return lptN_A;
00155 
00156     return lptEPP;
00157 }
00158 
00159 // set the Bidirectional-Flag to input (reverse mode) and block
00160 // the DataStrobe, AddressStrobe and Write line manually, so
00161 // that the EPP can't send any automatic handshake signal
00162 static enum lptMode
00163 EPPdetect(PUCHAR port)
00164 {
00165     WRITE_PORT_UCHAR(port+2, (UCHAR) 0xEF);
00166     return EPPdWOC(port);
00167 }
00168 
00169 // Parallel Printer Port detection (SPP or PS/2)
00170 static enum lptMode
00171 PPPdetect(PUCHAR port)
00172 {
00173     BIDIoutp(port);
00174 
00175     WRITE_PORT_UCHAR(port,0xAA);
00176     if(READ_PORT_UCHAR(port)!=0xAA)
00177         return lptN_A;
00178 
00179     WRITE_PORT_UCHAR(port,0x55);
00180     if(READ_PORT_UCHAR(port)!=0x55)
00181         return lptN_A;
00182 
00183     BIDIinp(port);
00184 
00185     WRITE_PORT_UCHAR(port,0xAA);
00186     if(READ_PORT_UCHAR(port)!=0xAA)
00187         return lptPS2;
00188 
00189     WRITE_PORT_UCHAR(port,0x55);
00190     if(READ_PORT_UCHAR(port)!=0x55)
00191         return lptPS2;
00192 
00193     return lptSPP;
00194 }
00195 
00196 // perform a parallel printer port reset
00197 static void
00198 ResetLPT(PUCHAR port)
00199 {
00200     int i;
00201 
00202     // since a port read/write command is delayed by ISA bus waitstates to
00203     // 1,6 ęs, we can use it for a simple system independent delay routine.
00204 
00205     // But it would be much better to program one of the system
00206     // timers to delay 16 micro seconds
00207     for(i=10;i>0;i--)
00208         WRITE_PORT_UCHAR(port+2,0xC0);
00209 
00210     BIDIoutp(port);
00211 }
00212 
00213 //----------------------------------------------------------------
00214 // Port Mode Resolving Routines
00215 //----------------------------------------------------------------
00216 
00217 #if AdvancedEPPTests
00218 enum lptMode AdvEPP(PUCHAR port){
00219     unsigned char EPPctrl=0;
00220 
00221     // check all control words to free up the EPP
00222     do
00223     {
00224         EPPctrl |= 0x04;        // don't do a reset
00225             // write the special Control word, for freeing up the EPP
00226         WRITE_PORT_UCHAR(port+2,EPPctrl);
00227 
00228         if (EPPdWOC(port)!=lptN_A)
00229             return lptEPPc;
00230 
00231         EPPctrl++;
00232     } while(EPPctrl);
00233 
00234     return lptN_A;
00235 }
00236 
00237 // Resolving the special Control-Word to enable an EPP
00238 static char *
00239 EPPcontrol(PUCHAR port){
00240     int ret;
00241     static char ctrlWord[8];
00242     unsigned int  done0[8], done1[8];
00243     unsigned char i,EPPctrl, OldCtrl,mask;
00244 
00245     for (i=0;i<8;i++)
00246         done0[i]=done1[i]=0;
00247 
00248     OldCtrl = READ_PORT_UCHAR(port+2)&0x1f;
00249     EPPctrl = 0;  // check all control words to free up the EPP
00250 
00251     do
00252     {
00253         EPPctrl|=0x04;  // don't do a reset
00254         // write the special Control word, for freeing up the EPP
00255         WRITE_PORT_UCHAR(port+2,EPPctrl);
00256         if(EPPdWOC(port)!=lptN_A)
00257         {
00258             // EPP is enabled with this control word
00259             // return EPPctrl;
00260             for(i=0,mask=0x80;i<8;i++,mask>>=1)
00261             {
00262                 if(EPPctrl&mask)
00263                     done1[i]++;
00264                 else 
00265                     done0[i]++;
00266             }
00267         }
00268         EPPctrl++;
00269     } while(EPPctrl);
00270 
00271     WRITE_PORT_UCHAR(port+2,OldCtrl);
00272 
00273     for (i=0;i<8;i++)
00274     {
00275         if(done0[i]==done1[i])
00276         {
00277             if(!done0[i])        ctrlWord[i]='!';       // Control-Word could not found
00278             else                                 ctrlWord[i]='X';       // This Bit cares nobody
00279         }
00280         else if(!done0[i]) ctrlWord[i]='1'; // This Bit must be 1
00281         else if(!done1[i]) ctrlWord[i]='0';     // This Bit must be 0
00282         else               ctrlWord[i]='?';     // This Bit depends on other Bits
00283     }
00284     return ctrlWord;
00285 }
00286 #else
00287 static char *
00288 EPPcontrol(PUCHAR)
00289 {
00290     return "XX0X0100";
00291 }
00292 #endif
00293 
00294 static enum lptMode
00295 LPTmode(PUCHAR port)
00296 {
00297     enum lptMode ret=lptN_A;
00298 
00299     // check for valid portaddresses (LPT 1-6)
00300     // valid port addresses only at 0x200, 0x204, 0x208, ..., 0x3fc
00301 
00302     if((((ULONG_PTR)port) & ~0x1fc)!=0x200)
00303         return lptN_A;
00304 
00305         //      if(!(port&0x07)){
00306         // test for ECP/EPP only at 0/8-bases
00307 
00308     ResetLPT(port);
00309     //  ECP test doesn't touch any data registers, so no reset is needed
00310 
00311     do
00312     {
00313         // tests for an ECP
00314         if((ret = ECPdetect(port)) != lptN_A)
00315             break;
00316 
00317         // perform a reset to prevent printers from printing unusable stuff
00318         ResetLPT(port);
00319 
00320         // tests for an EPP
00321         if ((ret = EPPdetect(port)) != lptN_A)
00322             break;
00323 
00324 #if AdvancedEPPTests
00325         // tests for an EPP with different control words
00326         if ((ret = AdvEPP(port)) != lptN_A)
00327             break;
00328 #endif
00329         // tests for a SPP or PS/2
00330         if ((ret = PPPdetect(port)) != lptN_A)
00331             break;
00332 
00333     } while(0);
00334     BIDIoutp(port);
00335     return ret;
00336 }
00337 
00338 static enum ecpMode
00339 ECPmode(PUCHAR port)
00340 {
00341     if (LPTmode(port) != lptECP)
00342         return ecpNOECR;
00343 
00344     return (enum ecpMode)(ecpSTNDRD + (READ_PORT_UCHAR(port+0x402)>>5));
00345 }
00346 
00347 static enum ecpMode
00348 SetECPmode(PUCHAR port, enum ecpMode mode)
00349 {
00350     unsigned char oldvalue;
00351 
00352     if (LPTmode(port) != lptECP)
00353         return ecpNOECR;
00354 
00355     oldvalue = READ_PORT_UCHAR(port+0x402);
00356 
00357     WRITE_PORT_UCHAR(port+0x402, (oldvalue & 0x3f) | ((mode - ecpSTNDRD) << 5));
00358 
00359     return (enum ecpMode)(ecpSTNDRD + (oldvalue>>5));
00360 }
00361 
00362 //----------------------------------------------------------------
00363 // Some helper functions
00364 //----------------------------------------------------------------
00365 
00366 static int
00367 preprprt(PUCHAR port)
00368 {
00369     enum lptMode mode;
00370     const char *modes[6]={"N/A","SPP","PS/2","EPP","ECP","EPPc"};
00371 
00372     FUNC_ENTER();
00373 
00374     mode=LPTmode(port);
00375     DBG_PRINT((DBG_PREFIX "at 0x%03X, %s", port, modes[mode]));
00376 
00377     FUNC_LEAVE_INT(mode);
00378 }
00379 
00380 static int
00381 prport(PUCHAR port)
00382 {
00383     const char *ecpM[9]={
00384         "no ECR found",
00385         "Standard Mode",
00386         "Byte Mode",
00387         "Parallel Port FIFO Mode",
00388         "ECP FIFO Mode",
00389         "EPP Mode",
00390         "Reserved",
00391         "FIFO Test Mode",
00392         "Configuration Mode"
00393     };
00394 
00395     int ret;
00396 
00397     FUNC_ENTER();
00398 
00399     ret=1;
00400 
00401     switch (preprprt(port))
00402     {
00403         case lptN_A:
00404             ret=0;
00405             break;
00406         case lptEPPc:
00407             DBG_PRINT((DBG_PREFIX ",  EPP-Enable-Timeout-Bit-Detection-Control-Word:"
00408                 " %s", EPPcontrol(port)));
00409             break;
00410 
00411         case lptECP:
00412             DBG_PRINT((DBG_PREFIX ",  ECP-Mode: %s", ecpM[ECPmode(port)]));
00413     }
00414     DBG_PRINT((DBG_PREFIX ""));
00415 
00416     FUNC_LEAVE_INT(ret);
00417 }
00418 
00419 
00432 NTSTATUS
00433 ParPortSetModeNt4(PDEVICE_EXTENSION Pdx)
00434 {
00435     NTSTATUS ntStatus = STATUS_SUCCESS;
00436     enum lptMode lptmode = Pdx->HandleEcpEppMyself & 0xFF;
00437     enum ecpMode oldecpmode = ecpNOECR;
00438 
00439     FUNC_ENTER();
00440 
00441     if (lptmode == lptN_A)
00442     {
00443         DBG_PRINT((DBG_PREFIX "Trying to find out mode of 0x%04x", Pdx->ParPortPortAddress));
00444         lptmode = LPTmode(Pdx->ParPortPortAddress);
00445         prport(Pdx->ParPortPortAddress);
00446     }
00447 
00448     if (lptmode == lptECP)
00449     {
00450         oldecpmode = ECPmode(Pdx->ParPortPortAddress);
00451 
00452         DBG_PRINT((DBG_PREFIX "Setting ECP mode to BYTE mode"));
00453         SetECPmode(Pdx->ParPortPortAddress, ecpBYTE);
00454 
00455         DBG_PRINT((DBG_PREFIX "Checking if mode has changed:"));
00456         prport(Pdx->ParPortPortAddress);
00457     }
00458 
00459     if (lptmode > lptSPP)
00460     {
00461         DBG_PRINT((DBG_PREFIX "Writing the value 0xE4 to 0x%04x", Pdx->ParPortPortAddress+2));
00462         WRITE_PORT_UCHAR(Pdx->ParPortPortAddress+2,0xE4);
00463     }
00464 
00465     Pdx->HandleEcpEppMyself = (lptmode & 0xFF) | ((oldecpmode & 0xFF) << 8);
00466 
00467     FUNC_LEAVE_NTSTATUS(ntStatus);
00468 }
00469 
00483 NTSTATUS
00484 ParPortUnsetModeNt4(PDEVICE_EXTENSION Pdx)
00485 {
00486     NTSTATUS ntStatus = STATUS_SUCCESS;
00487     enum lptMode lptmode = Pdx->HandleEcpEppMyself & 0xFF;
00488     enum ecpMode oldecpmode = (Pdx->HandleEcpEppMyself & 0xFF00) >> 8;
00489 
00490     FUNC_ENTER();
00491 
00492     if (lptmode == lptECP)
00493     {
00494         DBG_PRINT((DBG_PREFIX "Setting ECP mode back to standard mode"));
00495         SetECPmode(Pdx->ParPortPortAddress, oldecpmode);
00496 
00497         DBG_PRINT((DBG_PREFIX "Checking if mode has changed:"));
00498         prport(Pdx->ParPortPortAddress);
00499     }
00500 
00501     FUNC_LEAVE_NTSTATUS(ntStatus);
00502 }
00503 
00516 extern VOID
00517 cbmiec_udelay(IN ULONG howlong); // howlong in ms!
00518 
00519 NTSTATUS
00520 ParPortSetMode(PDEVICE_EXTENSION Pdx)
00521 {
00522     NTSTATUS ntStatus = STATUS_LOGON_FAILURE; // this is just a dummy failure value to allow falling into NT4 processing
00523 
00524     FUNC_ENTER();
00525 
00526     if (!Pdx->HandleEcpEppMyself)
00527     {
00528         // First, try to set the mode via WDM functions.
00529         // Remember: Even if we install the NT4 driver, we might be running on 2000 or up.
00530         ntStatus = ParPortSetModeWdm(Pdx);
00531     }
00532 
00533     if (Pdx->HandleEcpEppMyself || ((ntStatus == STATUS_INVALID_PARAMETER) && Pdx->IsNT4))
00534     {
00535         ntStatus = ParPortSetModeNt4(Pdx);
00536         cbmiec_udelay(1000 * 10);
00537     }
00538 
00539     FUNC_LEAVE_NTSTATUS(ntStatus);
00540 }
00541 
00555 NTSTATUS
00556 ParPortUnsetMode(PDEVICE_EXTENSION Pdx)
00557 {
00558     NTSTATUS ntStatus;
00559 
00560     FUNC_ENTER();
00561 
00562     if (Pdx->HandleEcpEppMyself == 0)
00563     {
00564         ntStatus = ParPortUnsetModeWdm(Pdx);
00565     }
00566     else
00567     {
00568         ntStatus = ParPortUnsetModeNt4(Pdx);
00569     }
00570 
00571     FUNC_LEAVE_NTSTATUS(ntStatus);
00572 }

Generated on Sun Apr 30 18:45:57 2006 for opencbm by  doxygen 1.4.2