DOSBox-X
|
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