DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/hardware/parport/directlpt_win32.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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           return ;
00089      }
00090 
00091 
00092      oup32fp = (oupfuncPtr) GetProcAddress(hLib, "Out32");
00093 
00094      if (oup32fp == NULL) {
00095           LOG_MSG("GetProcAddress for Oup32 Failed.\n");
00096           return ;
00097      }
00098 
00099         
00100         // LOG_MSG("installing ok");
00101 
00102         InstallationSuccessful = false;
00103         interruptflag=true; // interrupt disabled
00104         realbaseaddress = 0x378;
00105 
00106         std::string str;
00107         if(cmd->FindStringBegin("realbase:",str,false)) {
00108                 if(sscanf(str.c_str(), "%x",&realbaseaddress)!=1) {
00109                         LOG_MSG("parallel%d: Invalid realbase parameter.",nr);
00110                         return;
00111                 } 
00112         }
00113 
00114         if(realbaseaddress>=0x10000) {
00115                 LOG_MSG("Error: Invalid base address.");
00116                 return;
00117         }
00118         /*
00119         if(!initPorttalk()) {
00120                 LOG_MSG("Error: could not open PortTalk driver.");
00121                 return;
00122         }*/
00123 /*
00124         //if(!IsInpOutDriverOpen()) {
00125         if(err=Opendriver(IsXP64Bit())) {
00126                 LOG_MSG("Error: could not open new driver, err %d.",err);
00127                 return;
00128         }
00129         */
00130 
00131         // make sure the user doesn't touch critical I/O-ports
00132         if((realbaseaddress<0x100) || (realbaseaddress&0x3) ||          // sanity + mainboard res.
00133                 ((realbaseaddress>=0x1f0)&&(realbaseaddress<=0x1f7)) || // prim. HDD controller
00134                 ((realbaseaddress>=0x170)&&(realbaseaddress<=0x177)) || // sek. HDD controller
00135                 ((realbaseaddress>=0x3f0)&&(realbaseaddress<=0x3f7)) || // floppy + prim. HDD
00136                 ((realbaseaddress>=0x370)&&(realbaseaddress<=0x377))) { // sek. hdd
00137                 LOG_MSG("Parallel Port: Invalid base address.");
00138                 return;
00139         }
00140         /*      
00141         if(realbase!=0x378 && realbase!=0x278 && realbase != 0x3bc)
00142         {
00143                 // TODO PCI ECP ports can be on funny I/O-port-addresses
00144                 LOG_MSG("Parallel Port: Invalid base address.");
00145                 return;
00146         }*/
00147         Bit32u ecpbase = 0;
00148         if(cmd->FindStringBegin("ecpbase:",str,false)) {
00149                 if(sscanf(str.c_str(), "%x",&ecpbase)!=1) {
00150                         LOG_MSG("parallel%d: Invalid realbase parameter.",nr);
00151                         return;
00152                 }
00153                 isECP=true;
00154         } else {
00155                 // 0x3bc cannot be a ECP port
00156                 isECP= ((realbaseaddress&0x7)==0);
00157                 if (isECP) ecpbase = realbaseaddress+0x402;
00158         }
00159         /*
00160         // add the standard parallel port registers
00161         addIOPermission((Bit16u)realbaseaddress);
00162         addIOPermission((Bit16u)realbaseaddress+1);
00163         addIOPermission((Bit16u)realbaseaddress+2);
00164         
00165         // if it could be a ECP port: make the extended control register accessible
00166         if(isECP)addIOPermission((Bit16u)ecpbase);
00167         
00168         // bail out if porttalk fails
00169         if(!setPermissionList())
00170         {
00171                 LOG_MSG("ERROR SET PERMLIST");
00172                 return;
00173         }
00174         if(isECP) {
00175                 // check if there is a ECP port (try to set bidir)
00176                 originalECPControlReg = inportb(ecpbase);
00177                 Bit8u new_bidir = originalECPControlReg&0x1F;
00178                 new_bidir|=0x20;
00179 
00180                 outportb(ecpbase,new_bidir);
00181                 if(inportb(ecpbase)!=new_bidir) {
00182                         // this is not a ECP port
00183                         outportb(ecpbase,originalECPControlReg);
00184                         isECP=false;
00185                 }
00186         }
00187         */
00188 
00189         // check if there is a parallel port at all: the autofeed bit
00190         /*
00191         Bit8u controlreg=inportb(realbaseaddress+2);
00192         outportb(realbaseaddress+2,controlreg|2);
00193         if(!(inportb(realbaseaddress+2)&0x2))
00194         {
00195                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00196                 // cannot remember 1
00197                 return;
00198         }
00199         */
00200         //realbaseaddress=0x378;
00201         Bit8u controlreg=Inp32(realbaseaddress+2);
00202         Out32(realbaseaddress+2,controlreg|2);
00203         if(!(Inp32(realbaseaddress+2)&0x2))
00204         {
00205                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00206                 // cannot remember 1
00207                 return;
00208         }
00209         
00210         // check 0
00211         /*
00212         outportb(realbaseaddress+2,controlreg & ~2);
00213         if(inportb(realbaseaddress+2)&0x2)
00214         {
00215                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00216                 // cannot remember 0
00217                 return;
00218         }
00219         outportb(realbaseaddress+2,controlreg);
00220         */
00221         Out32(realbaseaddress+2,controlreg & ~2);
00222         if(Inp32(realbaseaddress+2)&0x2)
00223         {
00224                 LOG_MSG("No parallel port detected at 0x%x!",realbaseaddress);
00225                 // cannot remember 0
00226                 return;
00227         }
00228         Out32(realbaseaddress+2,controlreg);
00229 
00230 
00231         if(isECP) LOG_MSG("The port at 0x%x was detected as ECP port.",realbaseaddress);
00232         else LOG_MSG("The port at 0x%x is not a ECP port.",realbaseaddress);
00233         
00234         /*
00235         // bidir test
00236         outportb(realbase+2,0x20);
00237         for(int i = 0; i < 256; i++) {
00238                 outportb(realbase, i);
00239                 if(inportb(realbase)!=i) LOG_MSG("NOT %x", i);
00240         }
00241         */
00242 
00243         // go for it
00244         ack_polarity=false;
00245         initialize();
00246 
00247         InstallationSuccessful = true;
00248         //LOG_MSG("InstSuccess");
00249 }
00250 
00251 CDirectLPT::~CDirectLPT () {
00252         if(InstallationSuccessful && isECP)
00253                 //outportb(realbaseaddress+0x402,originalECPControlReg);
00254                 Out32(realbaseaddress+0x402,originalECPControlReg);
00255 }
00256 
00257 bool CDirectLPT::Putchar(Bit8u val)
00258 {       
00259         //LOG_MSG("putchar: %x",val);
00260 
00261         // check if printer online and not busy
00262         // PE and Selected: no printer attached
00263         Bit8u sr=Read_SR();
00264         //LOG_MSG("SR: %x",sr);
00265         if((sr&0x30)==0x30)
00266         {
00267                 LOG_MSG("putchar: no printer");
00268                 return false;
00269         }
00270         // error
00271         if(sr&0x20)
00272         {
00273                 LOG_MSG("putchar: paper out");
00274                 return false;
00275         }
00276         if((sr&0x08)==0)
00277         {
00278                 LOG_MSG("putchar: printer error");
00279                 return false;
00280         }
00281 
00282         Write_PR(val);
00283         // busy
00284         Bitu timeout = 10000;
00285         Bitu time = timeout+SDL_GetTicks();
00286 
00287         while(SDL_GetTicks()<time) {
00288                 // wait for the printer to get ready
00289                 for(int i = 0; i < 500; i++) {
00290                         // do NOT run into callback_idle unless we have to (speeds things up)
00291                         sr=Read_SR();
00292                         if(sr&0x80) break;
00293                 }
00294                 if(sr&0x80) break;
00295                 CALLBACK_Idle();
00296         }
00297         if(SDL_GetTicks()>=time) {
00298                 LOG_MSG("putchar: busy timeout");
00299                 return false;
00300         }
00301         // strobe data out
00302         // I hope this creates a sufficient long pulse...
00303         // (I/O-Bus at 7.15 MHz will give some delay)
00304         
00305         for(int i = 0; i < 5; i++) Write_CON(0xd); // strobe on
00306         Write_CON(0xc); // strobe off
00307 
00308 #if PARALLEL_DEBUG
00309         log_par(dbg_putchar,"putchar  0x%2x",val);
00310         if(dbg_plainputchar) fprintf(debugfp,"%c",val);
00311 #endif
00312 
00313         return true;
00314 }
00315 Bitu CDirectLPT::Read_PR() {
00316         //return inportb(realbaseaddress);
00317         return Inp32(realbaseaddress);
00318 }
00319 Bitu CDirectLPT::Read_COM() {
00320         //Bit8u retval=inportb(realbaseaddress+2);
00321         Bit8u retval=0;
00322         retval=Inp32(realbaseaddress+2);
00323         if(!interruptflag)// interrupt activated
00324         retval&=~0x10;
00325         return retval;
00326 }
00327 Bitu CDirectLPT::Read_SR() {
00328         //return inportb(realbaseaddress+1);
00329         return Inp32(realbaseaddress+1);
00330 }
00331 
00332 void CDirectLPT::Write_PR(Bitu val) {
00333         //LOG_MSG("%c,%x",(Bit8u)val,val);
00334         //outportb(realbaseaddress,val);
00335         Out32(realbaseaddress,val);
00336 }
00337 void CDirectLPT::Write_CON(Bitu val) {
00338         //do not activate interrupt
00339         interruptflag = (val&0x10)!=0;
00340         //outportb(realbaseaddress+2,val|0x10);
00341         Out32(realbaseaddress+2,val|0x10);
00342 }
00343 void CDirectLPT::Write_IOSEL(Bitu val) {
00344         //outportb(realbaseaddress+1,val);
00345         Out32(realbaseaddress+1,val);
00346 }
00347 
00348 void CDirectLPT::handleUpperEvent(Bit16u type) { (void)type; }
00349 
00350 
00351 #endif
00352 #endif