DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/parport/directlpt_win32.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 
00022 #if C_DIRECTLPT
00023 
00024 #if defined(_MSC_VER)
00025 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00026 #endif
00027 
00028 /* Windows version */
00029 #if defined (WIN32)
00030 
00031 #include "parport.h"
00032 //#include "../../libs/porttalk/porttalk.h"
00033 #include "directlpt_win32.h"
00034 #include "callback.h"
00035 #include <SDL.h> 
00036 #include "setup.h"
00037 
00038 //********************************************************
00039 //new funct prototypes for parallel port
00040 
00041 /* prototype (function typedef) for DLL function Inp32: */
00042 
00043      typedef short (_stdcall *inpfuncPtr)(short portaddr);
00044      typedef void (_stdcall *oupfuncPtr)(short portaddr, short datum);
00045 
00046 /* After successful initialization, these 2 variables
00047    will contain function pointers.
00048  */
00049      inpfuncPtr inp32fp;
00050      oupfuncPtr oup32fp;
00051 
00052 
00053 /* Wrapper functions for the function pointers
00054     - call these functions to perform I/O.
00055  */
00056      short Inp32(short portaddr)
00057      {
00058          return inp32fp(portaddr);
00059      }
00060 
00061      void Out32(short portaddr, short datum)
00062      {
00063          oup32fp(portaddr, datum);
00064      }
00065 
00066 //********************************************************
00067 
00068 
00069 
00070 CDirectLPT::CDirectLPT (Bitu nr, Bit8u initIrq, CommandLine* cmd)
00071                               :CParallel (cmd, nr, initIrq) {
00072      HINSTANCE hLib;
00073 
00074      /* Load the library for win 64 driver */
00075      hLib = LoadLibrary("inpout32.dll");
00076 
00077      if (hLib == NULL) {
00078           LOG_MSG("LoadLibrary Failed.\n");
00079           return ;
00080      }
00081 
00082      /* get the address of the function */
00083 
00084      inp32fp = (inpfuncPtr) GetProcAddress(hLib, "Inp32");
00085 
00086      if (inp32fp == NULL) {
00087           LOG_MSG("GetProcAddress for Inp32 Failed.\n");
00088           FreeLibrary(hLib);
00089           return ;
00090      }
00091 
00092 
00093      oup32fp = (oupfuncPtr) GetProcAddress(hLib, "Out32");
00094 
00095      if (oup32fp == NULL) {
00096           LOG_MSG("GetProcAddress for Oup32 Failed.\n");
00097           FreeLibrary(hLib);
00098           return ;
00099      }
00100 
00101         
00102         // LOG_MSG("installing ok");
00103 
00104         InstallationSuccessful = false;
00105         interruptflag=true; // interrupt disabled
00106         realbaseaddress = 0x378;
00107 
00108         std::string str;
00109         if(cmd->FindStringBegin("realbase:",str,false)) {
00110                 if(sscanf(str.c_str(), "%x",&realbaseaddress)!=1) {
00111                         LOG_MSG("parallel%d: Invalid realbase parameter.",nr);
00112             FreeLibrary(hLib);
00113                         return;
00114                 } 
00115         }
00116 
00117         if(realbaseaddress>=0x10000) {
00118                 LOG_MSG("Error: Invalid base address.");
00119         FreeLibrary(hLib);
00120                 return;
00121         }
00122         /*
00123         if(!initPorttalk()) {
00124                 LOG_MSG("Error: could not open PortTalk driver.");
00125                 return;
00126         }*/
00127 /*
00128         //if(!IsInpOutDriverOpen()) {
00129         if(err=Opendriver(IsXP64Bit())) {
00130                 LOG_MSG("Error: could not open new driver, err %d.",err);
00131                 return;
00132         }
00133         */
00134 
00135         // make sure the user doesn't touch critical I/O-ports
00136         if((realbaseaddress<0x100) || (realbaseaddress&0x3) ||          // sanity + mainboard res.
00137                 ((realbaseaddress>=0x1f0)&&(realbaseaddress<=0x1f7)) || // prim. HDD controller
00138                 ((realbaseaddress>=0x170)&&(realbaseaddress<=0x177)) || // sek. HDD controller
00139                 ((realbaseaddress>=0x3f0)&&(realbaseaddress<=0x3f7)) || // floppy + prim. HDD
00140                 ((realbaseaddress>=0x370)&&(realbaseaddress<=0x377))) { // sek. hdd
00141                 LOG_MSG("Parallel Port: Invalid base address.");
00142         FreeLibrary(hLib);
00143                 return;
00144         }
00145         /*      
00146         if(realbase!=0x378 && realbase!=0x278 && realbase != 0x3bc)
00147         {
00148                 // TODO PCI ECP ports can be on funny I/O-port-addresses
00149                 LOG_MSG("Parallel Port: Invalid base address.");
00150                 return;
00151         }*/
00152         Bit32u ecpbase = 0;
00153         if(cmd->FindStringBegin("ecpbase:",str,false)) {
00154                 if(sscanf(str.c_str(), "%x",&ecpbase)!=1) {
00155                         LOG_MSG("parallel%d: Invalid realbase parameter.",nr);
00156             FreeLibrary(hLib);
00157                         return;
00158                 }
00159                 isECP=true;
00160         } else {
00161                 // 0x3bc cannot be a ECP port
00162                 isECP= ((realbaseaddress&0x7)==0);
00163                 if (isECP) ecpbase = realbaseaddress+0x402;
00164         }
00165         /*
00166         // add the standard parallel port registers
00167         addIOPermission((Bit16u)realbaseaddress);
00168         addIOPermission((Bit16u)realbaseaddress+1);
00169         addIOPermission((Bit16u)realbaseaddress+2);
00170         
00171         // if it could be a ECP port: make the extended control register accessible
00172         if(isECP)addIOPermission((Bit16u)ecpbase);
00173         
00174         // bail out if porttalk fails
00175         if(!setPermissionList())
00176         {
00177                 LOG_MSG("ERROR SET PERMLIST");
00178                 return;
00179         }
00180         if(isECP) {
00181                 // check if there is a ECP port (try to set bidir)
00182                 originalECPControlReg = inportb(ecpbase);
00183                 Bit8u new_bidir = originalECPControlReg&0x1F;
00184                 new_bidir|=0x20;
00185 
00186                 outportb(ecpbase,new_bidir);
00187                 if(inportb(ecpbase)!=new_bidir) {
00188                         // this is not a ECP port
00189                         outportb(ecpbase,originalECPControlReg);
00190                         isECP=false;
00191                 }
00192         }
00193         */
00194 
00195         // check if there is a parallel port at all: the autofeed bit
00196         /*
00197         Bit8u controlreg=inportb(realbaseaddress+2);
00198         outportb(realbaseaddress+2,controlreg|2);
00199         if(!(inportb(realbaseaddress+2)&0x2))
00200         {
00201                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00202                 // cannot remember 1
00203                 return;
00204         }
00205         */
00206         //realbaseaddress=0x378;
00207         Bit8u controlreg=Inp32(realbaseaddress+2);
00208         Out32(realbaseaddress+2,controlreg|2);
00209         if(!(Inp32(realbaseaddress+2)&0x2))
00210         {
00211                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00212                 // cannot remember 1
00213         FreeLibrary(hLib);
00214                 return;
00215         }
00216         
00217         // check 0
00218         /*
00219         outportb(realbaseaddress+2,controlreg & ~2);
00220         if(inportb(realbaseaddress+2)&0x2)
00221         {
00222                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00223                 // cannot remember 0
00224                 return;
00225         }
00226         outportb(realbaseaddress+2,controlreg);
00227         */
00228         Out32(realbaseaddress+2,controlreg & ~2);
00229         if(Inp32(realbaseaddress+2)&0x2)
00230         {
00231                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00232                 // cannot remember 0
00233         FreeLibrary(hLib);
00234                 return;
00235         }
00236         Out32(realbaseaddress+2,controlreg);
00237 
00238 
00239         if(isECP) LOG_MSG("The port at 0x%x was detected as ECP port.",realbaseaddress);
00240         else LOG_MSG("The port at 0x%x is not a ECP port.",realbaseaddress);
00241         
00242         /*
00243         // bidir test
00244         outportb(realbase+2,0x20);
00245         for(int i = 0; i < 256; i++) {
00246                 outportb(realbase, i);
00247                 if(inportb(realbase)!=i) LOG_MSG("NOT %x", i);
00248         }
00249         */
00250 
00251         // go for it
00252         ack_polarity=false;
00253         initialize();
00254 
00255         InstallationSuccessful = true;
00256         //LOG_MSG("InstSuccess");
00257 }
00258 
00259 CDirectLPT::~CDirectLPT () {
00260         if(InstallationSuccessful && isECP)
00261                 //outportb(realbaseaddress+0x402,originalECPControlReg);
00262                 Out32(realbaseaddress+0x402,originalECPControlReg);
00263 }
00264 
00265 bool CDirectLPT::Putchar(Bit8u val)
00266 {       
00267         //LOG_MSG("putchar: %x",val);
00268 
00269         // check if printer online and not busy
00270         // PE and Selected: no printer attached
00271         Bit8u sr=Read_SR();
00272         //LOG_MSG("SR: %x",sr);
00273         if((sr&0x30)==0x30)
00274         {
00275                 LOG_MSG("putchar: no printer");
00276                 return false;
00277         }
00278         // error
00279         if(sr&0x20)
00280         {
00281                 LOG_MSG("putchar: paper out");
00282                 return false;
00283         }
00284         if((sr&0x08)==0)
00285         {
00286                 LOG_MSG("putchar: printer error");
00287                 return false;
00288         }
00289 
00290         Write_PR(val);
00291         // busy
00292         Bitu timeout = 10000;
00293         Bitu time = timeout+SDL_GetTicks();
00294 
00295         while(SDL_GetTicks()<time) {
00296                 // wait for the printer to get ready
00297                 for(int i = 0; i < 500; i++) {
00298                         // do NOT run into callback_idle unless we have to (speeds things up)
00299                         sr=Read_SR();
00300                         if(sr&0x80) break;
00301                 }
00302                 if(sr&0x80) break;
00303                 CALLBACK_Idle();
00304         }
00305         if(SDL_GetTicks()>=time) {
00306                 LOG_MSG("putchar: busy timeout");
00307                 return false;
00308         }
00309         // strobe data out
00310         // I hope this creates a sufficient long pulse...
00311         // (I/O-Bus at 7.15 MHz will give some delay)
00312         
00313         for(int i = 0; i < 5; i++) Write_CON(0xd); // strobe on
00314         Write_CON(0xc); // strobe off
00315 
00316 #if PARALLEL_DEBUG
00317         log_par(dbg_putchar,"putchar  0x%2x",val);
00318         if(dbg_plainputchar) fprintf(debugfp,"%c",val);
00319 #endif
00320 
00321         return true;
00322 }
00323 Bitu CDirectLPT::Read_PR() {
00324         //return inportb(realbaseaddress);
00325         return Inp32(realbaseaddress);
00326 }
00327 Bitu CDirectLPT::Read_COM() {
00328         //Bit8u retval=inportb(realbaseaddress+2);
00329         Bit8u retval=0;
00330         retval=Inp32(realbaseaddress+2);
00331         if(!interruptflag)// interrupt activated
00332         retval&=~0x10;
00333         return retval;
00334 }
00335 Bitu CDirectLPT::Read_SR() {
00336         //return inportb(realbaseaddress+1);
00337         return Inp32(realbaseaddress+1);
00338 }
00339 
00340 void CDirectLPT::Write_PR(Bitu val) {
00341         //LOG_MSG("%c,%x",(Bit8u)val,val);
00342         //outportb(realbaseaddress,val);
00343         Out32(realbaseaddress,val);
00344 }
00345 void CDirectLPT::Write_CON(Bitu val) {
00346         //do not activate interrupt
00347         interruptflag = (val&0x10)!=0;
00348         //outportb(realbaseaddress+2,val|0x10);
00349         Out32(realbaseaddress+2,val|0x10);
00350 }
00351 void CDirectLPT::Write_IOSEL(Bitu val) {
00352         //outportb(realbaseaddress+1,val);
00353         Out32(realbaseaddress+1,val);
00354 }
00355 
00356 void CDirectLPT::handleUpperEvent(Bit16u type) { (void)type; }
00357 
00358 
00359 #endif
00360 #endif