mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 03:41:10 +08:00
453 lines
12 KiB
C++
453 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2002-2013 The DOSBox Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
/* FIXME: At some point I would like to roll the Disney Sound Source emulation into this code */
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "dosbox.h"
|
|
|
|
#include "support.h"
|
|
#include "inout.h"
|
|
#include "pic.h"
|
|
#include "setup.h"
|
|
#include "timer.h"
|
|
#include "bios.h" // SetLPTPort(..)
|
|
#include "hardware.h" // OpenCaptureFile
|
|
|
|
#include "parport.h"
|
|
#include "directlpt_win32.h"
|
|
#include "directlpt_linux.h"
|
|
#include "printer_redir.h"
|
|
#include "filelpt.h"
|
|
#include "dos_inc.h"
|
|
|
|
bool device_LPT::Read(Bit8u * data,Bit16u * size) {
|
|
*size=0;
|
|
LOG(LOG_DOSMISC,LOG_NORMAL)("LPTDEVICE:Read called");
|
|
return true;
|
|
}
|
|
|
|
|
|
bool device_LPT::Write(Bit8u * data,Bit16u * size) {
|
|
for (Bit16u i=0; i<*size; i++)
|
|
{
|
|
if(!pportclass->Putchar(data[i])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool device_LPT::Seek(Bit32u * pos,Bit32u type) {
|
|
*pos = 0;
|
|
return true;
|
|
}
|
|
|
|
bool device_LPT::Close() {
|
|
return false;
|
|
}
|
|
|
|
Bit16u device_LPT::GetInformation(void) {
|
|
return 0x80A0;
|
|
};
|
|
const char* lptname[]={"LPT1","LPT2","LPT3"};
|
|
device_LPT::device_LPT(Bit8u num, class CParallel* pp) {
|
|
pportclass = pp;
|
|
SetName(lptname[num]);
|
|
this->num = num;
|
|
}
|
|
|
|
device_LPT::~device_LPT() {
|
|
/* clear reference to myself so that CParallel does not attempt to free me or ask DOS to delete me */
|
|
if (pportclass != NULL && pportclass->mydosdevice == this)
|
|
pportclass->mydosdevice = NULL;
|
|
|
|
// LOG_MSG("~device_LPT\n");
|
|
//LOG_MSG("del");
|
|
}
|
|
|
|
static void Parallel_EventHandler(Bitu val) {
|
|
Bitu serclassid=val&0x3;
|
|
if(parallelPortObjects[serclassid]!=0)
|
|
parallelPortObjects[serclassid]->handleEvent(val>>2);
|
|
}
|
|
|
|
void CParallel::setEvent(Bit16u type, float duration) {
|
|
PIC_AddEvent(Parallel_EventHandler,duration,(type<<2)|port_nr);
|
|
}
|
|
|
|
void CParallel::removeEvent(Bit16u type) {
|
|
// TODO
|
|
PIC_RemoveSpecificEvents(Parallel_EventHandler,(type<<2)|port_nr);
|
|
}
|
|
|
|
void CParallel::handleEvent(Bit16u type) {
|
|
handleUpperEvent(type);
|
|
}
|
|
|
|
static Bitu PARALLEL_Read (Bitu port, Bitu iolen) {
|
|
for(Bitu i = 0; i < 3; i++) {
|
|
if(parallel_baseaddr[i]==(port&0xfffc) && (parallelPortObjects[i]!=0)) {
|
|
Bitu retval=0xff;
|
|
switch (port & 0x7) {
|
|
case 0:
|
|
retval = parallelPortObjects[i]->Read_PR();
|
|
break;
|
|
case 1:
|
|
retval = parallelPortObjects[i]->Read_SR();
|
|
break;
|
|
case 2:
|
|
retval = parallelPortObjects[i]->Read_COM();
|
|
break;
|
|
}
|
|
|
|
#if PARALLEL_DEBUG
|
|
const char* const dbgtext[]= {"DAT","STA","COM","???"};
|
|
parallelPortObjects[i]->log_par(parallelPortObjects[i]->dbg_cregs,
|
|
"read 0x%2x from %s.",retval,dbgtext[port&3]);
|
|
#endif
|
|
return retval;
|
|
}
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
static void PARALLEL_Write (Bitu port, Bitu val, Bitu) {
|
|
for(Bitu i = 0; i < 3; i++) {
|
|
if(parallel_baseaddr[i]==(port&0xfffc) && parallelPortObjects[i]) {
|
|
#if PARALLEL_DEBUG
|
|
const char* const dbgtext[]={"DAT","IOS","CON","???"};
|
|
parallelPortObjects[i]->log_par(parallelPortObjects[i]->dbg_cregs,
|
|
"write 0x%2x to %s.",val,dbgtext[port&3]);
|
|
if(parallelPortObjects[i]->dbg_plaindr &&!(port & 0x3)) {
|
|
fprintf(parallelPortObjects[i]->debugfp,"%c",val);
|
|
}
|
|
#endif
|
|
switch (port & 0x3) {
|
|
case 0:
|
|
parallelPortObjects[i]->Write_PR (val);
|
|
return;
|
|
case 1:
|
|
parallelPortObjects[i]->Write_IOSEL (val);
|
|
return;
|
|
case 2:
|
|
parallelPortObjects[i]->Write_CON (val);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//The Functions
|
|
|
|
#if PARALLEL_DEBUG
|
|
#include <stdarg.h>
|
|
void CParallel::log_par(bool active, char const* format,...) {
|
|
if(active) {
|
|
// copied from DEBUG_SHOWMSG
|
|
char buf[512];
|
|
buf[0]=0;
|
|
sprintf(buf,"%12.3f ",PIC_FullIndex());
|
|
va_list msg;
|
|
va_start(msg,format);
|
|
vsprintf(buf+strlen(buf),format,msg);
|
|
va_end(msg);
|
|
// Add newline if not present
|
|
Bitu len=strlen(buf);
|
|
if(buf[len-1]!='\n') strcat(buf,"\r\n");
|
|
fputs(buf,debugfp);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Initialisation
|
|
CParallel::CParallel(CommandLine* cmd, Bitu portnr, Bit8u initirq) {
|
|
base = parallel_baseaddr[portnr];
|
|
irq = initirq;
|
|
port_nr = portnr;
|
|
|
|
#if PARALLEL_DEBUG
|
|
dbg_data = cmd->FindExist("dbgdata", false);
|
|
dbg_putchar = cmd->FindExist("dbgput", false);
|
|
dbg_cregs = cmd->FindExist("dbgregs", false);
|
|
dbg_plainputchar = cmd->FindExist("dbgputplain", false);
|
|
dbg_plaindr = cmd->FindExist("dbgdataplain", false);
|
|
|
|
if(cmd->FindExist("dbgall", false)) {
|
|
dbg_data=
|
|
dbg_putchar=
|
|
dbg_cregs=true;
|
|
dbg_plainputchar=dbg_plaindr=false;
|
|
}
|
|
|
|
if(dbg_data||dbg_putchar||dbg_cregs||dbg_plainputchar||dbg_plaindr)
|
|
debugfp=OpenCaptureFile("parlog",".parlog.txt");
|
|
else debugfp=0;
|
|
|
|
if(debugfp == 0) {
|
|
dbg_data=
|
|
dbg_putchar=dbg_plainputchar=
|
|
dbg_cregs=false;
|
|
} else {
|
|
std::string cleft;
|
|
cmd->GetStringRemain(cleft);
|
|
|
|
log_par(true,"Parallel%d: BASE %xh, initstring \"%s\"\r\n\r\n",
|
|
portnr+1,base,cleft.c_str());
|
|
}
|
|
#endif
|
|
LOG_MSG("Parallel%d: BASE %xh",(int)portnr+1,(int)base);
|
|
|
|
for (Bitu i = 0; i < 3; i++) {
|
|
/* bugfix: do not register I/O write handler for the status port. it's a *status* port.
|
|
* also, this is needed for ISA PnP emulation to work properly even if DOSBox
|
|
* is emulating more than one parallel port. */
|
|
if (i != 1) WriteHandler[i].Install (i + base, PARALLEL_Write, IO_MB);
|
|
ReadHandler[i].Install (i + base, PARALLEL_Read, IO_MB);
|
|
}
|
|
|
|
mydosdevice = NULL;
|
|
};
|
|
|
|
void CParallel::registerDOSDevice() {
|
|
if (mydosdevice == NULL) {
|
|
LOG(LOG_MISC,LOG_DEBUG)("LPT%d: Registering DOS device",(int)port_nr+1);
|
|
mydosdevice = new device_LPT(port_nr, this);
|
|
DOS_AddDevice(mydosdevice);
|
|
}
|
|
}
|
|
|
|
void CParallel::unregisterDOSDevice() {
|
|
if (mydosdevice != NULL) {
|
|
LOG(LOG_MISC,LOG_DEBUG)("LPT%d: Unregistering DOS device",(int)port_nr+1);
|
|
DOS_DelDevice(mydosdevice); // deletes the pointer for us!
|
|
mydosdevice=NULL;
|
|
}
|
|
}
|
|
|
|
CParallel::~CParallel(void) {
|
|
unregisterDOSDevice();
|
|
};
|
|
|
|
Bit8u CParallel::getPrinterStatus()
|
|
{
|
|
/* 7 not busy
|
|
6 acknowledge
|
|
5 out of paper
|
|
4 selected
|
|
3 I/O error
|
|
2-1 unused
|
|
0 timeout */
|
|
Bit8u statusreg=Read_SR();
|
|
|
|
//LOG_MSG("get printer status: %x",statusreg);
|
|
statusreg^=0x48;
|
|
return statusreg&~0x7;
|
|
}
|
|
|
|
#include "callback.h"
|
|
|
|
void RunIdleTime(Bitu milliseconds)
|
|
{
|
|
Bitu time=SDL_GetTicks()+milliseconds;
|
|
while(SDL_GetTicks()<time)
|
|
CALLBACK_Idle();
|
|
}
|
|
|
|
void CParallel::initialize()
|
|
{
|
|
Write_IOSEL(0x55); // output mode
|
|
Write_CON(0x08); // init low
|
|
Write_PR(0);
|
|
RunIdleTime(10);
|
|
Write_CON(0x0c); // init high
|
|
RunIdleTime(500);
|
|
//LOG_MSG("printer init");
|
|
}
|
|
|
|
|
|
|
|
CParallel* parallelPortObjects[3]={NULL,NULL,NULL};
|
|
|
|
bool DISNEY_HasInit();
|
|
Bitu DISNEY_BasePort();
|
|
bool DISNEY_ShouldInit();
|
|
void DISNEY_Init(unsigned int base_port);
|
|
|
|
Bitu bios_post_parport_count() {
|
|
Bitu count = 0;
|
|
unsigned int i;
|
|
|
|
for (i=0;i < 3;i++) {
|
|
if (parallelPortObjects[i] != NULL)
|
|
count++;
|
|
else if (DISNEY_HasInit() && parallel_baseaddr[i] == DISNEY_BasePort())
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/* at BIOS POST stage, write parallel ports to bios data area */
|
|
void BIOS_Post_register_parports() {
|
|
unsigned int i;
|
|
|
|
for (i=0;i < 3;i++) {
|
|
if (parallelPortObjects[i] != NULL)
|
|
BIOS_SetLPTPort(i,parallelPortObjects[i]->base);
|
|
else if (DISNEY_HasInit() && parallel_baseaddr[i] == DISNEY_BasePort())
|
|
BIOS_SetLPTPort(i,DISNEY_BasePort());
|
|
}
|
|
}
|
|
|
|
class PARPORTS:public Module_base {
|
|
public:
|
|
|
|
PARPORTS (Section * configuration):Module_base (configuration) {
|
|
|
|
// TODO: PC-98 does have one parallel port, if at all
|
|
if (IS_PC98_ARCH) return;
|
|
|
|
// default ports & interrupts
|
|
Bit8u defaultirq[] = { 7, 5, 12};
|
|
Section_prop *section = static_cast <Section_prop*>(configuration);
|
|
|
|
char pname[]="parallelx";
|
|
// iterate through all 3 lpt ports
|
|
for (Bitu i = 0; i < 3; i++) {
|
|
pname[8] = '1' + i;
|
|
CommandLine cmd(0,section->Get_string(pname));
|
|
|
|
std::string str;
|
|
cmd.FindCommand(1,str);
|
|
#if C_DIRECTLPT
|
|
if(str=="reallpt") {
|
|
CDirectLPT* cdlpt= new CDirectLPT(i, defaultirq[i],&cmd);
|
|
if(cdlpt->InstallationSuccessful)
|
|
parallelPortObjects[i]=cdlpt;
|
|
else {
|
|
delete cdlpt;
|
|
parallelPortObjects[i]=0;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if(!str.compare("file")) {
|
|
CFileLPT* cflpt= new CFileLPT(i, defaultirq[i], &cmd);
|
|
if(cflpt->InstallationSuccessful)
|
|
parallelPortObjects[i]=cflpt;
|
|
else {
|
|
delete cflpt;
|
|
parallelPortObjects[i]=0;
|
|
}
|
|
}
|
|
else
|
|
if(str=="disabled") {
|
|
parallelPortObjects[i] = 0;
|
|
} else if (str == "disney") {
|
|
if (!DISNEY_HasInit()) {
|
|
LOG_MSG("LPT%d: User explicitly assigned Disney Sound Source to this port",(int)i+1);
|
|
DISNEY_Init(parallel_baseaddr[i]);
|
|
}
|
|
else {
|
|
LOG_MSG("LPT%d: Disney Sound Source already initialized on a port, cannot init again",(int)i+1);
|
|
}
|
|
} else {
|
|
LOG_MSG ("Invalid type for LPT%d.",(int)i + 1);
|
|
parallelPortObjects[i] = 0;
|
|
}
|
|
} // for lpt 1-3
|
|
}
|
|
|
|
~PARPORTS () {
|
|
// LOG_MSG("Parports destructor\n");
|
|
for (Bitu i = 0; i < 3; i++) {
|
|
if (parallelPortObjects[i]) {
|
|
delete parallelPortObjects[i];
|
|
parallelPortObjects[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
static PARPORTS *testParallelPortsBaseclass = NULL;
|
|
|
|
void PARALLEL_Destroy (Section * sec) {
|
|
if (testParallelPortsBaseclass != NULL) {
|
|
delete testParallelPortsBaseclass;
|
|
testParallelPortsBaseclass = NULL;
|
|
}
|
|
}
|
|
|
|
void PARALLEL_OnPowerOn (Section * sec) {
|
|
LOG(LOG_MISC,LOG_DEBUG)("Reinitializing parallel port emulation");
|
|
|
|
if (testParallelPortsBaseclass) delete testParallelPortsBaseclass;
|
|
testParallelPortsBaseclass = new PARPORTS (control->GetSection("parallel"));
|
|
|
|
/* Mainline DOSBox 0.74 compatible support for "disney=true" setting.
|
|
* But, don't allocate the Disney Sound Source if LPT1 is already taken. */
|
|
if (!DISNEY_HasInit() && DISNEY_ShouldInit() && parallelPortObjects[0] == NULL) {
|
|
LOG_MSG("LPT: LPT1 not taken, and dosbox.conf says to emulate Disney Sound Source");
|
|
DISNEY_Init(parallel_baseaddr[0]);
|
|
}
|
|
}
|
|
|
|
void PARALLEL_OnDOSKernelInit (Section * sec) {
|
|
unsigned int i;
|
|
|
|
LOG(LOG_MISC,LOG_DEBUG)("DOS kernel initializing, creating LPTx devices");
|
|
|
|
for (i=0;i < 3;i++) {
|
|
if (parallelPortObjects[i] != NULL)
|
|
parallelPortObjects[i]->registerDOSDevice();
|
|
}
|
|
}
|
|
|
|
void PARALLEL_OnDOSKernelExit (Section * sec) {
|
|
unsigned int i;
|
|
|
|
for (i=0;i < 3;i++) {
|
|
if (parallelPortObjects[i] != NULL)
|
|
parallelPortObjects[i]->unregisterDOSDevice();
|
|
}
|
|
}
|
|
|
|
void PARALLEL_OnReset (Section * sec) {
|
|
unsigned int i;
|
|
|
|
// FIXME: Unregister/destroy the DOS devices, but consider that the DOS kernel at reset is gone.
|
|
for (i=0;i < 3;i++) {
|
|
if (parallelPortObjects[i] != NULL)
|
|
parallelPortObjects[i]->unregisterDOSDevice();
|
|
}
|
|
}
|
|
|
|
void PARALLEL_Init () {
|
|
LOG(LOG_MISC,LOG_DEBUG)("Initializing parallel port emulation");
|
|
|
|
AddExitFunction(AddExitFunctionFuncPair(PARALLEL_Destroy),true);
|
|
|
|
if (!IS_PC98_ARCH) {
|
|
AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(PARALLEL_OnReset));
|
|
AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(PARALLEL_OnPowerOn));
|
|
AddVMEventFunction(VM_EVENT_DOS_EXIT_BEGIN,AddVMEventFunctionFuncPair(PARALLEL_OnDOSKernelExit));
|
|
AddVMEventFunction(VM_EVENT_DOS_INIT_KERNEL_READY,AddVMEventFunctionFuncPair(PARALLEL_OnDOSKernelInit));
|
|
}
|
|
}
|
|
|