DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/parport/directlpt_linux.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 "config.h"
00021 #include "setup.h"
00022 
00023 #if C_DIRECTLPT
00024 
00025 /* Linux version */
00026 #if defined (LINUX)
00027 
00028 #include "parport.h"
00029 #include "directlpt_linux.h"
00030 #include "callback.h"
00031 #include <linux/ppdev.h>
00032 #include <sys/ioctl.h>
00033 #include <sys/types.h>
00034 
00035 #include <errno.h>
00036 #include <fcntl.h>
00037 #include <SDL.h>
00038 
00039 CDirectLPT::CDirectLPT (Bitu nr, Bit8u initIrq, CommandLine* cmd)
00040                               :CParallel (cmd, nr, initIrq) {
00041         InstallationSuccessful = false;
00042         interruptflag=true; // interrupt disabled
00043 
00044         std::string str;
00045 
00046         if(!cmd->FindStringBegin("realport:",str,false)) {
00047                 LOG_MSG("parallel%d: realport parameter missing.",(int)nr+1);
00048                 return;
00049         }
00050         porthandle = open(str.c_str(), O_RDWR );
00051         if(porthandle == -1) {
00052                 LOG_MSG("parallel%d: Could not open port %s.",(int)nr+1,str.c_str());
00053                 if (errno == 2) LOG_MSG ("The specified port does not exist.");
00054                 else if(errno==EBUSY) LOG_MSG("The specified port is already in use.");
00055                 else if(errno==EACCES) LOG_MSG("You are not allowed to access this port.");
00056                 else LOG_MSG("Errno %d occurred.",errno);
00057                 return;
00058         }
00059 
00060         if(ioctl( porthandle, PPCLAIM, NULL ) == -1) {
00061                 LOG_MSG("parallel%d: failed to claim port.",(int)nr+1);
00062                 return;
00063         }
00064         // TODO check return value
00065         
00066         // go for it
00067         ack_polarity=false;
00068         initialize();
00069 
00070         InstallationSuccessful = true;
00071 }
00072 
00073 CDirectLPT::~CDirectLPT () {
00074         if(porthandle > 0) close(porthandle);
00075 }
00076 
00077 bool CDirectLPT::Putchar(Bit8u val)
00078 {       
00079         //LOG_MSG("putchar: %x",val);
00080 
00081         // check if printer online and not busy
00082         // PE and Selected: no printer attached
00083         Bit8u sr=Read_SR();
00084         //LOG_MSG("SR: %x",sr);
00085         if((sr&0x30)==0x30)
00086         {
00087                 LOG_MSG("putchar: no printer");
00088                 return false;
00089         }
00090         // error
00091         if(sr&0x20)
00092         {
00093                 LOG_MSG("putchar: paper out");
00094                 return false;
00095         }
00096         if((sr&0x08)==0)
00097         {
00098                 LOG_MSG("putchar: printer error");
00099                 return false;
00100         }
00101 
00102         Write_PR(val);
00103         // busy
00104         Bitu timeout = 10000;
00105         Bitu time = timeout+SDL_GetTicks();
00106 
00107         while(SDL_GetTicks()<time) {
00108                 // wait for the printer to get ready
00109                 for(int i = 0; i < 500; i++) {
00110                         // do NOT run into callback_idle unless we have to (speeds things up)
00111                         sr=Read_SR();
00112                         if(sr&0x80) break;
00113                 }
00114                 if(sr&0x80) break;
00115                 CALLBACK_Idle();
00116         }
00117         if(SDL_GetTicks()>=time) {
00118                 LOG_MSG("putchar: busy timeout");
00119                 return false;
00120         }
00121         // strobe data out
00122         // I hope this creates a sufficient long pulse...
00123         // (I/O-Bus at 7.15 MHz will give some delay)
00124         
00125         for(int i = 0; i < 5; i++) Write_CON(0xd); // strobe on
00126         Write_CON(0xc); // strobe off
00127 
00128 #if PARALLEL_DEBUG
00129         log_par(dbg_putchar,"putchar  0x%2x",val);
00130         if(dbg_plainputchar) fprintf(debugfp,"%c",val);
00131 #endif
00132 
00133         return true;
00134 }
00135 Bitu CDirectLPT::Read_PR() {
00136         Bitu retval;
00137         ioctl(porthandle, PPRDATA, &retval);
00138         return retval;
00139 }
00140 Bitu CDirectLPT::Read_COM() {
00141         Bitu retval;
00142         ioctl(porthandle, PPRCONTROL, &retval);
00143         return retval;
00144 }
00145 Bitu CDirectLPT::Read_SR() {
00146         Bitu retval;
00147         ioctl(porthandle, PPRSTATUS, &retval);
00148         return retval;
00149 }
00150 
00151 void CDirectLPT::Write_PR(Bitu val){
00152         ioctl(porthandle, PPWDATA, &val); 
00153 }
00154 void CDirectLPT::Write_CON(Bitu val) {
00155         ioctl(porthandle, PPWCONTROL, &val); 
00156 }
00157 void CDirectLPT::Write_IOSEL(Bitu val) {
00158         // switches direction old-style TODO
00159         if((val==0xAA)||(val==0x55)) LOG_MSG("TODO implement IBM-style direction switch");
00160 }
00161 void CDirectLPT::handleUpperEvent(Bit16u type) { (void)type; }
00162 #endif
00163 #endif