📄 serialport.cpp
字号:
/* * Copyright (C) 2002-2007 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. *//* $Id: serialport.cpp,v 1.7 2007/02/22 08:41:16 qbix79 Exp $ */#include <string.h>#include <ctype.h>#include "dosbox.h"#include "inout.h"#include "pic.h"#include "setup.h"#include "bios.h" // SetComPorts(..)#include "callback.h" // CALLBACK_Idle#include "serialport.h"#include "directserial_win32.h"#include "directserial_posix.h"#include "directserial_os2.h"#include "serialdummy.h"#include "softmodem.h"#include "nullmodem.h"#include "cpu.h"bool device_COM::Read(Bit8u * data,Bit16u * size) { // DTR + RTS on sclass->Write_MCR(0x03); for (Bit16u i=0; i<*size; i++) { if(!(sclass->Getchar(&data[i],true,1000))) { *size=i; return true; } } return true;}bool device_COM::Write(Bit8u * data,Bit16u * size) { // DTR + RTS on sclass->Write_MCR(0x03); for (Bit16u i=0; i<*size; i++) { if(!(sclass->Putchar(data[i],true,true,1000))) { *size=i; sclass->Write_MCR(0x01); return false; } } // RTS off sclass->Write_MCR(0x01); return true;}bool device_COM::Seek(Bit32u * pos,Bit32u type) { *pos = 0; return true;}bool device_COM::Close() { return false;}Bit16u device_COM::GetInformation(void) { return 0x80A0;};device_COM::device_COM(class CSerial* sc) { sclass = sc; SetName(serial_comname[sclass->idnumber]);}device_COM::~device_COM() {}// COM1 - COM4 objectsCSerial* serialports[4] ={0,0,0,0};static Bitu SERIAL_Read (Bitu port, Bitu iolen) { for(Bitu i = 0; i < 4; i++) { if(serial_baseaddr[i]==(port&0xfff8) && (serialports[i]!=0)) { Bitu retval=0xff; switch (port & 0x7) { case RHR_OFFSET: retval = serialports[i]->Read_RHR(); break; case IER_OFFSET: retval = serialports[i]->Read_IER(); break; case ISR_OFFSET: retval = serialports[i]->Read_ISR(); break; case LCR_OFFSET: retval = serialports[i]->Read_LCR(); break; case MCR_OFFSET: retval = serialports[i]->Read_MCR(); break; case LSR_OFFSET: retval = serialports[i]->Read_LSR(); break; case MSR_OFFSET: retval = serialports[i]->Read_MSR(); break; case SPR_OFFSET: retval = serialports[i]->Read_SPR(); break; }#if SERIAL_DEBUG const char* const dbgtext[]= {"RHR","IER","ISR","LCR","MCR","LSR","MSR","SPR"}; if(serialports[i]->dbg_register) fprintf(serialports[i]->debugfp,"%12.3f read 0x%x from %s.\r\n", PIC_FullIndex(),retval,dbgtext[port&0x7]);#endif return retval; } } return 0xff;}static void SERIAL_Write (Bitu port, Bitu val, Bitu) { for(Bitu i = 0; i < 4; i++) { if(serial_baseaddr[i]==(port&0xfff8) && serialports[i]) {#if SERIAL_DEBUG const char* const dbgtext[]={"THR","IER","FCR","LCR","MCR","!LSR","MSR","SPR"}; if(serialports[i]->dbg_register) fprintf(serialports[i]->debugfp,"%12.3f write 0x%x to %s.\r\n", PIC_FullIndex(),val,dbgtext[port&0x7]);#endif switch (port & 0x7) { case THR_OFFSET: serialports[i]->Write_THR (val); return; case IER_OFFSET: serialports[i]->Write_IER (val); return; case FCR_OFFSET: serialports[i]->Write_FCR (val); return; case LCR_OFFSET: serialports[i]->Write_LCR (val); return; case MCR_OFFSET: serialports[i]->Write_MCR (val); return; case MSR_OFFSET: serialports[i]->Write_MSR (val); return; case SPR_OFFSET: serialports[i]->Write_SPR (val); return; default: serialports[i]->Write_reserved (val, port & 0x7); } } }}void CSerial::changeLineProperties() { // update the event wait time float bitlen = (1000.0f/115200.0f)*(float)baud_divider; bytetime=bitlen*(float)(1+5+1); // startbit + minimum length + stopbit bytetime+= bitlen*(float)(LCR&0x3); // databits if(LCR&0x4) bytetime+=bitlen; // stopbit updatePortConfig (baud_divider, LCR);}static void Serial_EventHandler(Bitu val) { Bitu serclassid=val&0x3; if(serialports[serclassid]!=0) serialports[serclassid]->handleEvent(val>>2);}void CSerial::setEvent(Bit16u type, float duration) { PIC_AddEvent(Serial_EventHandler,duration,(type<<2)|idnumber);}void CSerial::removeEvent(Bit16u type) { // TODO PIC_RemoveSpecificEvents(Serial_EventHandler,(type<<2)|idnumber);}void CSerial::handleEvent(Bit16u type) { switch(type) { case SERIAL_TX_LOOPBACK_EVENT: {#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp,loopback_data<0x10? "%12.3f tx 0x%02x (%u) (loopback)\r\n": "%12.3f tx 0x%02x (%c) (loopback)\r\n", PIC_FullIndex(),loopback_data, loopback_data);#endif receiveByte (loopback_data); ByteTransmitted (); break; } case SERIAL_THR_LOOPBACK_EVENT: { ByteTransmitting(); loopback_data=THR; setEvent(SERIAL_TX_LOOPBACK_EVENT,bytetime); break; } case SERIAL_ERRMSG_EVENT: { LOG_MSG("Serial%d: Errors occured: "\ "Framing %d, Parity %d, Overrun %d (IF0:%d), Break %d", COMNUMBER, framingErrors, parityErrors, overrunErrors, overrunIF0, breakErrors); errormsg_pending=false; framingErrors=0; parityErrors=0; overrunErrors=0; overrunIF0=0; breakErrors=0; break; } default: handleUpperEvent(type); }}/*****************************************************************************//* Interrupt control routines **//*****************************************************************************/void CSerial::rise (Bit8u priority) {#if SERIAL_DEBUG if(dbg_interrupt) { if(priority&TX_PRIORITY && !(waiting_interrupts&TX_PRIORITY)) fprintf(debugfp,"%12.3f tx interrupt on.\r\n",PIC_FullIndex()); if(priority&RX_PRIORITY && !(waiting_interrupts&RX_PRIORITY)) fprintf(debugfp,"%12.3f rx interrupt on.\r\n",PIC_FullIndex()); if(priority&MSR_PRIORITY && !(waiting_interrupts&MSR_PRIORITY)) fprintf(debugfp,"%12.3f msr interrupt on.\r\n",PIC_FullIndex()); if(priority&ERROR_PRIORITY && !(waiting_interrupts&ERROR_PRIORITY)) fprintf(debugfp,"%12.3f error interrupt on.\r\n",PIC_FullIndex()); }#endif waiting_interrupts |= priority; ComputeInterrupts();}// clears the pending interrupt, triggers other waiting interruptvoid CSerial::clear (Bit8u priority) { #if SERIAL_DEBUG if(dbg_interrupt) { if(priority&TX_PRIORITY && (waiting_interrupts&TX_PRIORITY)) fprintf(debugfp,"%12.3f tx interrupt off.\r\n",PIC_FullIndex()); if(priority&RX_PRIORITY && (waiting_interrupts&RX_PRIORITY)) fprintf(debugfp,"%12.3f rx interrupt off.\r\n",PIC_FullIndex()); if(priority&MSR_PRIORITY && (waiting_interrupts&MSR_PRIORITY)) fprintf(debugfp,"%12.3f msr interrupt off.\r\n",PIC_FullIndex()); if(priority&ERROR_PRIORITY && (waiting_interrupts&ERROR_PRIORITY)) fprintf(debugfp,"%12.3f error interrupt off.\r\n",PIC_FullIndex()); }#endif waiting_interrupts &= (~priority); ComputeInterrupts();}void CSerial::ComputeInterrupts () { Bitu val = IER & waiting_interrupts; if (val & ERROR_PRIORITY) ISR = ISR_ERROR_VAL; else if (val & RX_PRIORITY) ISR = ISR_RX_VAL; else if (val & TX_PRIORITY) ISR = ISR_TX_VAL; else if (val & MSR_PRIORITY) ISR = ISR_MSR_VAL; else ISR = ISR_CLEAR_VAL; if(val && !irq_active) { irq_active=true; PIC_ActivateIRQ(irq);#if SERIAL_DEBUG if(dbg_interrupt) fprintf(debugfp,"%12.3f IRQ%d on.\r\n",PIC_FullIndex(),irq);#endif } if(!val && irq_active) { irq_active=false; PIC_DeActivateIRQ(irq);#if SERIAL_DEBUG if(dbg_interrupt) fprintf(debugfp,"%12.3f IRQ%d off.\r\n",PIC_FullIndex(),irq);#endif }}/*****************************************************************************//* Can a byte be received? **//*****************************************************************************/bool CSerial::CanReceiveByte() { return (LSR & LSR_RX_DATA_READY_MASK) == 0;}/*****************************************************************************//* A byte was received **//*****************************************************************************/void CSerial::receiveByte (Bit8u data) {#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp,loopback_data<0x10? "%12.3f rx 0x%02x (%u)\r\n": "%12.3f rx 0x%02x (%c)\r\n", PIC_FullIndex(), data, data);#endif if (LSR & LSR_RX_DATA_READY_MASK) { // Overrun error ;o if(!errormsg_pending) { errormsg_pending=true; setEvent(SERIAL_ERRMSG_EVENT,1000); } overrunErrors++; Bitu iflag= GETFLAG(IF); if(!iflag)overrunIF0++;#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp, "%12.3f rx overrun (IF=%d)\r\n", PIC_FullIndex(), iflag);#endif LSR |= LSR_OVERRUN_ERROR_MASK; rise (ERROR_PRIORITY); } else { RHR = data; LSR |= LSR_RX_DATA_READY_MASK; rise (RX_PRIORITY); }}/*****************************************************************************//* A line error was received **//*****************************************************************************/void CSerial::receiveError (Bit8u errorword) { if(!errormsg_pending) { errormsg_pending=true; setEvent(SERIAL_ERRMSG_EVENT,1000); } if(errorword&LSR_PARITY_ERROR_MASK) { parityErrors++;#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp, "%12.3f parity error\r\n", PIC_FullIndex());#endif } if(errorword&LSR_FRAMING_ERROR_MASK) { framingErrors++;#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp, "%12.3f framing error\r\n", PIC_FullIndex());#endif } if(errorword&LSR_RX_BREAK_MASK) { breakErrors++;#if SERIAL_DEBUG if(dbg_serialtraffic) fprintf(debugfp, "%12.3f break received\r\n", PIC_FullIndex());#endif } LSR |= errorword; rise (ERROR_PRIORITY);}/*****************************************************************************//* ByteTransmitting: Byte has made it from THR to TX. **//*****************************************************************************/void CSerial::ByteTransmitting() { switch(LSR&(LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -