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 <string.h> 00021 #include <ctype.h> 00022 00023 #include "dosbox.h" 00024 00025 #include "inout.h" 00026 #include "pic.h" 00027 #include "setup.h" 00028 #include "bios.h" // SetComPorts(..) 00029 #include "callback.h" // CALLBACK_Idle 00030 #include "control.h" 00031 00032 #include "serialport.h" 00033 #include "serialmouse.h" 00034 #include "directserial.h" 00035 #include "serialdummy.h" 00036 #include "softmodem.h" 00037 #include "nullmodem.h" 00038 #include "seriallog.h" 00039 #include "serialfile.h" 00040 00041 #include "cpu.h" 00042 00043 #define LOG_SER(x) log_ser 00044 00045 bool device_COM::Read(Bit8u * data,Bit16u * size) { 00046 // DTR + RTS on 00047 sclass->Write_MCR(0x03); 00048 for (Bit16u i=0; i<*size; i++) 00049 { 00050 Bit8u status; 00051 if(!(sclass->Getchar(&data[i],&status,true,1000))) { 00052 *size=i; 00053 return true; 00054 } 00055 } 00056 return true; 00057 } 00058 00059 00060 bool device_COM::Write(const Bit8u * data,Bit16u * size) { 00061 // DTR + RTS on 00062 sclass->Write_MCR(0x03); 00063 for (Bit16u i=0; i<*size; i++) 00064 { 00065 if(!(sclass->Putchar(data[i],true,true,1000))) { 00066 *size=i; 00067 sclass->Write_MCR(0x01); 00068 return false; 00069 } 00070 } 00071 // RTS off 00072 sclass->Write_MCR(0x01); 00073 return true; 00074 } 00075 00076 bool device_COM::Seek(Bit32u * pos,Bit32u type) { 00077 (void)type;//UNUSED 00078 *pos = 0; 00079 return true; 00080 } 00081 00082 bool device_COM::Close() { 00083 return false; 00084 } 00085 00086 Bit16u device_COM::GetInformation(void) { 00087 return 0x80A0; 00088 } 00089 00090 device_COM::device_COM(class CSerial* sc) { 00091 sclass = sc; 00092 SetName(serial_comname[sclass->idnumber]); 00093 } 00094 00095 device_COM::~device_COM() { 00096 /* clear reference to myself so that we're not deleted twice (once by DOS_DelDevice the other by CSerial) */ 00097 if (sclass != NULL && sclass->mydosdevice == this) 00098 sclass->mydosdevice = NULL; 00099 } 00100 00101 00102 00103 // COM1 - COM4 objects 00104 CSerial* serialports[4] ={0,0,0,0}; 00105 00106 static Bitu SERIAL_Read (Bitu port, Bitu iolen) { 00107 (void)iolen;//UNUSED 00108 Bitu i; 00109 Bitu retval; 00110 Bitu index = port & 0x7; 00111 switch(port&0xff8) { 00112 case 0x3f8: i=0; break; 00113 case 0x2f8: i=1; break; 00114 case 0x3e8: i=2; break; 00115 case 0x2e8: i=3; break; 00116 default: return 0xff; 00117 } 00118 if(serialports[i]==0) return 0xff; 00119 00120 switch (index) { 00121 case RHR_OFFSET: 00122 retval = serialports[i]->Read_RHR(); 00123 break; 00124 case IER_OFFSET: 00125 retval = serialports[i]->Read_IER(); 00126 break; 00127 case ISR_OFFSET: 00128 retval = serialports[i]->Read_ISR(); 00129 break; 00130 case LCR_OFFSET: 00131 retval = serialports[i]->Read_LCR(); 00132 break; 00133 case MCR_OFFSET: 00134 retval = serialports[i]->Read_MCR(); 00135 break; 00136 case LSR_OFFSET: 00137 retval = serialports[i]->Read_LSR(); 00138 break; 00139 case MSR_OFFSET: 00140 retval = serialports[i]->Read_MSR(); 00141 break; 00142 case SPR_OFFSET: 00143 retval = serialports[i]->Read_SPR(); 00144 break; 00145 } 00146 00147 #if SERIAL_DEBUG 00148 const char* const dbgtext[]= 00149 {"RHR","IER","ISR","LCR","MCR","LSR","MSR","SPR","DLL","DLM"}; 00150 if(serialports[i]->dbg_register) { 00151 if((index<2) && ((serialports[i]->LCR)&LCR_DIVISOR_Enable_MASK)) 00152 index += 8; 00153 serialports[i]->log_ser(serialports[i]->dbg_register, 00154 "read 0x%2x from %s.",retval,dbgtext[index]); 00155 } 00156 #endif 00157 return retval; 00158 } 00159 static void SERIAL_Write (Bitu port, Bitu val, Bitu) { 00160 Bitu i; 00161 Bitu index = port & 0x7; 00162 switch(port&0xff8) { 00163 case 0x3f8: i=0; break; 00164 case 0x2f8: i=1; break; 00165 case 0x3e8: i=2; break; 00166 case 0x2e8: i=3; break; 00167 default: return; 00168 } 00169 if(serialports[i]==0) return; 00170 00171 #if SERIAL_DEBUG 00172 const char* const dbgtext[]={"THR","IER","FCR", 00173 "LCR","MCR","!LSR","MSR","SPR","DLL","DLM"}; 00174 if(serialports[i]->dbg_register) { 00175 Bitu debugindex=index; 00176 if((index<2) && ((serialports[i]->LCR)&LCR_DIVISOR_Enable_MASK)) 00177 debugindex += 8; 00178 serialports[i]->log_ser(serialports[i]->dbg_register, 00179 "write 0x%2x to %s.",val,dbgtext[debugindex]); 00180 } 00181 #endif 00182 switch (index) { 00183 case THR_OFFSET: 00184 serialports[i]->Write_THR ((Bit8u)val); 00185 return; 00186 case IER_OFFSET: 00187 serialports[i]->Write_IER ((Bit8u)val); 00188 return; 00189 case FCR_OFFSET: 00190 serialports[i]->Write_FCR ((Bit8u)val); 00191 return; 00192 case LCR_OFFSET: 00193 serialports[i]->Write_LCR ((Bit8u)val); 00194 return; 00195 case MCR_OFFSET: 00196 serialports[i]->Write_MCR ((Bit8u)val); 00197 return; 00198 case MSR_OFFSET: 00199 serialports[i]->Write_MSR ((Bit8u)val); 00200 return; 00201 case SPR_OFFSET: 00202 serialports[i]->Write_SPR ((Bit8u)val); 00203 return; 00204 default: 00205 serialports[i]->Write_reserved ((Bit8u)val, port & 0x7); 00206 } 00207 } 00208 #if SERIAL_DEBUG 00209 void CSerial::log_ser(bool active, char const* format,...) { 00210 if(active) { 00211 // copied from DEBUG_SHOWMSG 00212 char buf[512]; 00213 buf[0]=0; 00214 sprintf(buf,"%12.3f [%7u] ",PIC_FullIndex(), SDL_GetTicks()); 00215 va_list msg; 00216 va_start(msg,format); 00217 vsprintf(buf+strlen(buf),format,msg); 00218 va_end(msg); 00219 // Add newline if not present 00220 Bitu len=(Bitu)strlen(buf); 00221 if(buf[len-1]!='\n') strcat(buf,"\r\n"); 00222 fputs(buf,debugfp); 00223 } 00224 } 00225 #endif 00226 00227 void CSerial::changeLineProperties() { 00228 // update the event wait time 00229 float bitlen; 00230 00231 if(baud_divider==0) bitlen=(1000.0f/115200.0f); 00232 else bitlen = (1000.0f/115200.0f)*(float)baud_divider; 00233 bytetime=bitlen*(float)(1+5+1); // startbit + minimum length + stopbit 00234 bytetime+= bitlen*(float)(LCR&0x3); // databits 00235 if(LCR&0x4) bytetime+=bitlen; // 2nd stopbit 00236 if(LCR&0x8) bytetime+=bitlen; // parity 00237 00238 #if SERIAL_DEBUG 00239 const char* const dbgtext[]={"none","odd","none","even","none","mark","none","space"}; 00240 log_ser(dbg_serialtraffic,"New COM parameters: baudrate %5.0f, parity %s, wordlen %d, stopbits %d", 00241 1.0/bitlen*1000.0f,dbgtext[(LCR&0x38)>>3],(LCR&0x3)+5,((LCR&0x4)>>2)+1); 00242 #endif 00243 updatePortConfig (baud_divider, LCR); 00244 } 00245 00246 static void Serial_EventHandler(Bitu val) { 00247 Bitu serclassid=val&0x3; 00248 if(serialports[serclassid]!=0) 00249 serialports[serclassid]->handleEvent((Bit16u)(val>>2)); 00250 } 00251 00252 void CSerial::setEvent(Bit16u type, float duration) { 00253 PIC_AddEvent(Serial_EventHandler,duration,(Bitu)(((unsigned int)type<<2u)|(unsigned int)idnumber)); 00254 } 00255 00256 void CSerial::removeEvent(Bit16u type) { 00257 // TODO 00258 PIC_RemoveSpecificEvents(Serial_EventHandler,(Bitu)(((unsigned int)type<<2u)|(unsigned int)idnumber)); 00259 } 00260 00261 void CSerial::handleEvent(Bit16u type) { 00262 switch(type) { 00263 case SERIAL_TX_LOOPBACK_EVENT: { 00264 00265 #if SERIAL_DEBUG 00266 log_ser(dbg_serialtraffic,loopback_data<0x10? 00267 "tx 0x%02x (%u) (loopback)":"tx 0x%02x (%c) (loopback)", 00268 loopback_data, loopback_data); 00269 #endif 00270 receiveByte (loopback_data); 00271 ByteTransmitted (); 00272 break; 00273 } 00274 case SERIAL_THR_LOOPBACK_EVENT: { 00275 loopback_data=txfifo->probeByte(); 00276 ByteTransmitting(); 00277 setEvent(SERIAL_TX_LOOPBACK_EVENT,bytetime); 00278 break; 00279 } 00280 case SERIAL_ERRMSG_EVENT: { 00281 LOG_MSG("Serial%d: Errors: "\ 00282 "Framing %d, Parity %d, Overrun RX:%d (IF0:%d), TX:%d, Break %d", 00283 (int)COMNUMBER, 00284 (int)framingErrors, 00285 (int)parityErrors, 00286 (int)overrunErrors, 00287 (int)overrunIF0, 00288 (int)txOverrunErrors, 00289 (int)breakErrors); 00290 errormsg_pending=false; 00291 framingErrors=0; 00292 parityErrors=0; 00293 overrunErrors=0; 00294 txOverrunErrors=0; 00295 overrunIF0=0; 00296 breakErrors=0; 00297 break; 00298 } 00299 case SERIAL_RX_TIMEOUT_EVENT: { 00300 rise(TIMEOUT_PRIORITY); 00301 break; 00302 } 00303 default: handleUpperEvent(type); 00304 } 00305 } 00306 00307 /*****************************************************************************/ 00308 /* Interrupt control routines **/ 00309 /*****************************************************************************/ 00310 void CSerial::rise (Bit8u priority) { 00311 #if SERIAL_DEBUG 00312 if(priority&TX_PRIORITY && !(waiting_interrupts&TX_PRIORITY)) 00313 log_ser(dbg_interrupt,"tx interrupt on."); 00314 if(priority&RX_PRIORITY && !(waiting_interrupts&RX_PRIORITY)) 00315 log_ser(dbg_interrupt,"rx interrupt on."); 00316 if(priority&MSR_PRIORITY && !(waiting_interrupts&MSR_PRIORITY)) 00317 log_ser(dbg_interrupt,"msr interrupt on."); 00318 if(priority&TIMEOUT_PRIORITY && !(waiting_interrupts&TIMEOUT_PRIORITY)) 00319 log_ser(dbg_interrupt,"fifo rx timeout interrupt on."); 00320 #endif 00321 00322 waiting_interrupts |= priority; 00323 ComputeInterrupts(); 00324 } 00325 00326 // clears the pending interrupt, triggers other waiting interrupt 00327 void CSerial::clear (Bit8u priority) { 00328 00329 #if SERIAL_DEBUG 00330 if(priority&TX_PRIORITY && (waiting_interrupts&TX_PRIORITY)) 00331 log_ser(dbg_interrupt,"tx interrupt off."); 00332 if(priority&RX_PRIORITY && (waiting_interrupts&RX_PRIORITY)) 00333 log_ser(dbg_interrupt,"rx interrupt off."); 00334 if(priority&MSR_PRIORITY && (waiting_interrupts&MSR_PRIORITY)) 00335 log_ser(dbg_interrupt,"msr interrupt off."); 00336 if(priority&ERROR_PRIORITY && (waiting_interrupts&ERROR_PRIORITY)) 00337 log_ser(dbg_interrupt,"error interrupt off."); 00338 #endif 00339 waiting_interrupts &= (~priority); 00340 ComputeInterrupts(); 00341 } 00342 00343 void CSerial::ComputeInterrupts () { 00344 00345 Bitu val = IER & waiting_interrupts; 00346 00347 if (val & ERROR_PRIORITY) ISR = ISR_ERROR_VAL; 00348 else if (val & TIMEOUT_PRIORITY) ISR = ISR_FIFOTIMEOUT_VAL; 00349 else if (val & RX_PRIORITY) ISR = ISR_RX_VAL; 00350 else if (val & TX_PRIORITY) ISR = ISR_TX_VAL; 00351 else if (val & MSR_PRIORITY) ISR = ISR_MSR_VAL; 00352 else ISR = ISR_CLEAR_VAL; 00353 00354 if(val && !irq_active) 00355 { 00356 irq_active=true; 00357 if(op2) { 00358 PIC_ActivateIRQ(irq); 00359 #if SERIAL_DEBUG 00360 log_ser(dbg_interrupt,"IRQ%d on.",irq); 00361 #endif 00362 } 00363 } else if((!val) && irq_active) { 00364 irq_active=false; 00365 if(op2) { 00366 PIC_DeActivateIRQ(irq); 00367 #if SERIAL_DEBUG 00368 log_ser(dbg_interrupt,"IRQ%d off.",irq); 00369 #endif 00370 } 00371 } 00372 } 00373 00374 /*****************************************************************************/ 00375 /* Can a byte be received? **/ 00376 /*****************************************************************************/ 00377 bool CSerial::CanReceiveByte() { 00378 return !rxfifo->isFull(); 00379 } 00380 00381 /*****************************************************************************/ 00382 /* A byte was received **/ 00383 /*****************************************************************************/ 00384 void CSerial::receiveByteEx (Bit8u data, Bit8u error) { 00385 #if SERIAL_DEBUG 00386 log_ser(dbg_serialtraffic,data<0x10 ? "\t\t\t\trx 0x%02x (%u)": 00387 "\t\t\t\trx 0x%02x (%c)", data, data); 00388 #endif 00389 if (!(rxfifo->addb(data))) { 00390 // Overrun error ;o 00391 error |= LSR_OVERRUN_ERROR_MASK; 00392 } 00393 removeEvent(SERIAL_RX_TIMEOUT_EVENT); 00394 if(rxfifo->getUsage()==rx_interrupt_threshold) rise (RX_PRIORITY); 00395 else setEvent(SERIAL_RX_TIMEOUT_EVENT,bytetime*4.0f); 00396 00397 if(error) { 00398 // A lot of UART chips generate a framing error too when receiving break 00399 if(error&LSR_RX_BREAK_MASK) error |= LSR_FRAMING_ERROR_MASK; 00400 #if SERIAL_DEBUG 00401 log_ser(dbg_serialtraffic,"with error: framing=%d,overrun=%d,break=%d,parity=%d", 00402 (error&LSR_FRAMING_ERROR_MASK)>0,(error&LSR_OVERRUN_ERROR_MASK)>0, 00403 (error&LSR_RX_BREAK_MASK)>0,(error&LSR_PARITY_ERROR_MASK)>0); 00404 #endif 00405 if(FCR&FCR_ACTIVATE) { 00406 // error and FIFO active 00407 if(!errorfifo->isFull()) { 00408 errors_in_fifo++; 00409 errorfifo->addb(error); 00410 } 00411 else { 00412 Bit8u toperror=errorfifo->getTop(); 00413 if(!toperror) errors_in_fifo++; 00414 errorfifo->addb(error|toperror); 00415 } 00416 if(errorfifo->probeByte()) { 00417 // the next byte in the error fifo has an error 00418 rise (ERROR_PRIORITY); 00419 LSR |= error; 00420 } 00421 } else { 00422 // error and FIFO inactive 00423 rise (ERROR_PRIORITY); 00424 LSR |= error; 00425 } 00426 if(error&LSR_PARITY_ERROR_MASK) { 00427 parityErrors++; 00428 } 00429 if(error&LSR_OVERRUN_ERROR_MASK) { 00430 overrunErrors++; 00431 if(!GETFLAG(IF)) overrunIF0++; 00432 #if SERIAL_DEBUG 00433 log_ser(dbg_serialtraffic,"rx overrun (IF=%d)", GETFLAG(IF)>0); 00434 #endif 00435 } 00436 if(error&LSR_FRAMING_ERROR_MASK) { 00437 framingErrors++; 00438 } 00439 if(error&LSR_RX_BREAK_MASK) { 00440 breakErrors++; 00441 } 00442 // trigger status window error notification 00443 if(!errormsg_pending) { 00444 errormsg_pending=true; 00445 setEvent(SERIAL_ERRMSG_EVENT,1000); 00446 } 00447 } else { 00448 // no error 00449 if(FCR&FCR_ACTIVATE) { 00450 errorfifo->addb(error); 00451 } 00452 } 00453 } 00454 00455 void CSerial::receiveByte (Bit8u data) { 00456 receiveByteEx(data,0); 00457 } 00458 00459 /*****************************************************************************/ 00460 /* ByteTransmitting: Byte has made it from THR to TX. **/ 00461 /*****************************************************************************/ 00462 void CSerial::ByteTransmitting() { 00463 if(sync_guardtime) { 00464 //LOG_MSG("byte transmitting after guard"); 00465 //if(txfifo->isEmpty()) LOG_MSG("Serial port: FIFO empty when it should not"); 00466 sync_guardtime=false; 00467 txfifo->getb(); 00468 } //else LOG_MSG("byte transmitting"); 00469 if(txfifo->isEmpty())rise (TX_PRIORITY); 00470 } 00471 00472 00473 /*****************************************************************************/ 00474 /* ByteTransmitted: When a byte was sent, notify here. **/ 00475 /*****************************************************************************/ 00476 void CSerial::ByteTransmitted () { 00477 if(!txfifo->isEmpty()) { 00478 // there is more data 00479 Bit8u data = txfifo->getb(); 00480 #if SERIAL_DEBUG 00481 log_ser(dbg_serialtraffic,data<0x10? 00482 "\t\t\t\t\ttx 0x%02x (%u) (from buffer)": 00483 "\t\t\t\t\ttx 0x%02x (%c) (from buffer)",data,data); 00484 #endif 00485 if (loopback) setEvent(SERIAL_TX_LOOPBACK_EVENT, bytetime); 00486 else transmitByte(data,false); 00487 if(txfifo->isEmpty())rise (TX_PRIORITY); 00488 00489 } else { 00490 #if SERIAL_DEBUG 00491 log_ser(dbg_serialtraffic,"tx buffer empty."); 00492 #endif 00493 LSR |= LSR_TX_EMPTY_MASK; 00494 } 00495 } 00496 00497 /*****************************************************************************/ 00498 /* Transmit Holding Register, also LSB of Divisor Latch (r/w) **/ 00499 /*****************************************************************************/ 00500 void CSerial::Write_THR (Bit8u data) { 00501 // 0-7 transmit data 00502 00503 if (LCR & LCR_DIVISOR_Enable_MASK) { 00504 // write to DLL 00505 baud_divider&=0xFF00; 00506 baud_divider |= data; 00507 changeLineProperties(); 00508 } else { 00509 // write to THR 00510 clear (TX_PRIORITY); 00511 00512 if(LSR & LSR_TX_EMPTY_MASK) 00513 { // we were idle before 00514 //LOG_MSG("starting new transmit cycle"); 00515 //if(sync_guardtime) LOG_MSG("Serial port internal error 1"); 00516 //if(!(LSR & LSR_TX_EMPTY_MASK)) LOG_MSG("Serial port internal error 2"); 00517 //if(txfifo->getUsage()) LOG_MSG("Serial port internal error 3"); 00518 00519 // need "warming up" time 00520 sync_guardtime=true; 00521 // block the fifo so it returns THR full (or not in case of FIFO on) 00522 txfifo->addb(data); 00523 // transmit shift register is busy 00524 LSR &= (~LSR_TX_EMPTY_MASK); 00525 if(loopback) setEvent(SERIAL_THR_LOOPBACK_EVENT, bytetime/10); 00526 else { 00527 #if SERIAL_DEBUG 00528 log_ser(dbg_serialtraffic,data<0x10? 00529 "\t\t\t\t\ttx 0x%02x (%u) [FIFO=%2d]": 00530 "\t\t\t\t\ttx 0x%02x (%c) [FIFO=%2d]",data,data,txfifo->getUsage()); 00531 #endif 00532 transmitByte (data,true); 00533 } 00534 } else { 00535 // shift register is transmitting 00536 if(!txfifo->addb(data)) { 00537 // TX overflow 00538 #if SERIAL_DEBUG 00539 log_ser(dbg_serialtraffic,"tx overflow"); 00540 #endif 00541 txOverrunErrors++; 00542 if(!errormsg_pending) { 00543 errormsg_pending=true; 00544 setEvent(SERIAL_ERRMSG_EVENT,1000); 00545 } 00546 } 00547 } 00548 } 00549 } 00550 00551 00552 /*****************************************************************************/ 00553 /* Receive Holding Register, also LSB of Divisor Latch (r/w) **/ 00554 /*****************************************************************************/ 00555 Bitu CSerial::Read_RHR () { 00556 // 0-7 received data 00557 if (LCR & LCR_DIVISOR_Enable_MASK) return baud_divider&0xff; 00558 else { 00559 Bit8u data=rxfifo->getb(); 00560 if(FCR&FCR_ACTIVATE) { 00561 Bit8u error=errorfifo->getb(); 00562 if(error) errors_in_fifo--; 00563 // new error 00564 if(!rxfifo->isEmpty()) { 00565 error=errorfifo->probeByte(); 00566 if(error) { 00567 LSR |= error; 00568 rise(ERROR_PRIORITY); 00569 } 00570 } 00571 } 00572 // Reading RHR resets the FIFO timeout 00573 clear (TIMEOUT_PRIORITY); 00574 // RX int. is cleared if the buffer holds less data than the threshold 00575 if(rxfifo->getUsage()<rx_interrupt_threshold)clear(RX_PRIORITY); 00576 removeEvent(SERIAL_RX_TIMEOUT_EVENT); 00577 if(!rxfifo->isEmpty()) setEvent(SERIAL_RX_TIMEOUT_EVENT,bytetime*4.0f); 00578 return data; 00579 } 00580 } 00581 00582 /*****************************************************************************/ 00583 /* Interrupt Enable Register, also MSB of Divisor Latch (r/w) **/ 00584 /*****************************************************************************/ 00585 // Modified by: 00586 // - writing to it. 00587 Bitu CSerial::Read_IER () { 00588 // 0 receive holding register (byte received) 00589 // 1 transmit holding register (byte sent) 00590 // 2 receive line status (overrun, parity error, frame error, break) 00591 // 3 modem status 00592 // 4-7 0 00593 00594 if (LCR & LCR_DIVISOR_Enable_MASK) return (Bitu)baud_divider>>8u; 00595 else return IER&0x0f; 00596 } 00597 00598 void CSerial::Write_IER (Bit8u data) { 00599 if (LCR & LCR_DIVISOR_Enable_MASK) { // write to DLM 00600 baud_divider&=0xff; 00601 baud_divider |= ((Bit16u)data)<<8; 00602 changeLineProperties(); 00603 } else { 00604 // Retrigger TX interrupt 00605 if (txfifo->isEmpty()&& (data&TX_PRIORITY)) 00606 waiting_interrupts |= TX_PRIORITY; 00607 00608 IER = data&0xF; 00609 if((FCR&FCR_ACTIVATE)&&data&RX_PRIORITY) IER |= TIMEOUT_PRIORITY; 00610 ComputeInterrupts(); 00611 } 00612 } 00613 00614 /*****************************************************************************/ 00615 /* Interrupt Status Register (r) **/ 00616 /*****************************************************************************/ 00617 // modified by: 00618 // - incoming interrupts 00619 // - loopback mode 00620 Bitu CSerial::Read_ISR () { 00621 // 0 0:interrupt pending 1: no interrupt 00622 // 1-3 identification 00623 // 011 LSR 00624 // 010 RXRDY 00625 // 110 RX_TIMEOUT 00626 // 001 TXRDY 00627 // 000 MSR 00628 // 4-7 0 00629 00630 if(IER&Modem_Status_INT_Enable_MASK) updateMSR(); 00631 Bit8u retval = ISR; 00632 00633 // clear changes ISR!! mean.. 00634 if(ISR==ISR_TX_VAL) clear(TX_PRIORITY); 00635 if(FCR&FCR_ACTIVATE) retval |= FIFO_STATUS_ACTIVE; 00636 00637 return retval; 00638 } 00639 00640 #define BIT_CHANGE_H(oldv,newv,bitmask) (!(oldv&bitmask) && (newv&bitmask)) 00641 #define BIT_CHANGE_L(oldv,newv,bitmask) ((oldv&bitmask) && !(newv&bitmask)) 00642 00643 void CSerial::Write_FCR (Bit8u data) { 00644 if(BIT_CHANGE_H(FCR,data,FCR_ACTIVATE)) { 00645 // FIFO was switched on 00646 errors_in_fifo=0; // should already be 0 00647 errorfifo->setSize(fifosize); 00648 rxfifo->setSize(fifosize); 00649 txfifo->setSize(fifosize); 00650 } else if(BIT_CHANGE_L(FCR,data,FCR_ACTIVATE)) { 00651 // FIFO was switched off 00652 errors_in_fifo=0; 00653 errorfifo->setSize(1); 00654 rxfifo->setSize(1); 00655 txfifo->setSize(1); 00656 rx_interrupt_threshold=1; 00657 } 00658 FCR=data&0xCF; 00659 if(FCR&FCR_CLEAR_RX) { 00660 errors_in_fifo=0; 00661 errorfifo->clear(); 00662 rxfifo->clear(); 00663 } 00664 if(FCR&FCR_CLEAR_TX) txfifo->clear(); 00665 if(FCR&FCR_ACTIVATE) { 00666 switch(FCR>>6) { 00667 case 0: rx_interrupt_threshold=1; break; 00668 case 1: rx_interrupt_threshold=4; break; 00669 case 2: rx_interrupt_threshold=8; break; 00670 case 3: rx_interrupt_threshold=14; break; 00671 } 00672 } 00673 } 00674 00675 /*****************************************************************************/ 00676 /* Line Control Register (r/w) **/ 00677 /*****************************************************************************/ 00678 // signal decoder configuration: 00679 // - parity, stopbits, word length 00680 // - send break 00681 // - switch between RHR/THR and baud rate registers 00682 // Modified by: 00683 // - writing to it. 00684 Bitu CSerial::Read_LCR () { 00685 // 0-1 word length 00686 // 2 stop bits 00687 // 3 parity enable 00688 // 4-5 parity type 00689 // 6 set break 00690 // 7 divisor latch enable 00691 return LCR; 00692 } 00693 00694 void CSerial::Write_LCR (Bit8u data) { 00695 Bit8u lcr_old = LCR; 00696 LCR = data; 00697 if (((data ^ lcr_old) & LCR_PORTCONFIG_MASK) != 0) { 00698 changeLineProperties(); 00699 } 00700 if (((data ^ lcr_old) & LCR_BREAK_MASK) != 0) { 00701 if(!loopback) setBreak ((LCR & LCR_BREAK_MASK)!=0); 00702 else { 00703 // TODO: set loopback break event to reveiveError after 00704 } 00705 #if SERIAL_DEBUG 00706 log_ser(dbg_serialtraffic,((LCR & LCR_BREAK_MASK)!=0) ? 00707 "break on.":"break off."); 00708 #endif 00709 } 00710 } 00711 00712 /*****************************************************************************/ 00713 /* Modem Control Register (r/w) **/ 00714 /*****************************************************************************/ 00715 // Set levels of RTS and DTR, as well as loopback-mode. 00716 // Modified by: 00717 // - writing to it. 00718 Bitu CSerial::Read_MCR () { 00719 // 0 -DTR 00720 // 1 -RTS 00721 // 2 -OP1 00722 // 3 -OP2 00723 // 4 loopback enable 00724 // 5-7 0 00725 Bit8u retval=0; 00726 if(dtr) retval|=MCR_DTR_MASK; 00727 if(rts) retval|=MCR_RTS_MASK; 00728 if(op1) retval|=MCR_OP1_MASK; 00729 if(op2) retval|=MCR_OP2_MASK; 00730 if(loopback) retval|=MCR_LOOPBACK_Enable_MASK; 00731 return retval; 00732 } 00733 00734 void CSerial::Write_MCR (Bit8u data) { 00735 // WARNING: At the time setRTSDTR is called rts and dsr members are still wrong. 00736 if (data&FIFO_FLOWCONTROL) LOG_MSG("Warning: tried to activate hardware handshake."); 00737 bool new_dtr = (data & MCR_DTR_MASK)? true:false; 00738 bool new_rts = (data & MCR_RTS_MASK)? true:false; 00739 bool new_op1 = (data & MCR_OP1_MASK)? true:false; 00740 bool new_op2 = (data & MCR_OP2_MASK)? true:false; 00741 bool new_loopback = (data & MCR_LOOPBACK_Enable_MASK)? true:false; 00742 if (loopback != new_loopback) { 00743 if (new_loopback) setRTSDTR(false,false); 00744 else setRTSDTR(new_rts,new_dtr); 00745 } 00746 00747 if (new_loopback) { // is on: 00748 // DTR->DSR 00749 // RTS->CTS 00750 // OP1->RI 00751 // OP2->CD 00752 if (new_dtr != dtr && !d_dsr) { 00753 d_dsr = true; 00754 rise (MSR_PRIORITY); 00755 } 00756 if (new_dtr != dtr && !d_dsr) { 00757 d_dsr = true; 00758 rise (MSR_PRIORITY); 00759 } 00760 if (new_op1 != op1 && !d_ri) { 00761 // interrupt only at trailing edge 00762 if (!new_op1) { 00763 d_ri = true; 00764 rise (MSR_PRIORITY); 00765 } 00766 } 00767 if (new_op2 != op2 && !d_cd) { 00768 d_cd = true; 00769 rise (MSR_PRIORITY); 00770 } 00771 } else { 00772 // loopback is off 00773 if (new_rts != rts) { 00774 // RTS difference 00775 if (new_dtr != dtr) { 00776 // both difference 00777 00778 #if SERIAL_DEBUG 00779 log_ser(dbg_modemcontrol,"RTS %x.",new_rts); 00780 log_ser(dbg_modemcontrol,"DTR %x.",new_dtr); 00781 #endif 00782 setRTSDTR(new_rts, new_dtr); 00783 } else { 00784 // only RTS 00785 00786 #if SERIAL_DEBUG 00787 log_ser(dbg_modemcontrol,"RTS %x.",new_rts); 00788 #endif 00789 setRTS(new_rts); 00790 } 00791 } else if (new_dtr != dtr) { 00792 // only DTR 00793 #if SERIAL_DEBUG 00794 log_ser(dbg_modemcontrol,"%DTR %x.",new_dtr); 00795 #endif 00796 setDTR(new_dtr); 00797 } 00798 } 00799 // interrupt logic: if new_OP2 is 0, the IRQ line is tristated (pulled high) 00800 // which turns off the IRQ generation. 00801 if ((!op2) && new_op2) { 00802 // irq has been enabled (tristate high -> irq level) 00803 // Generate one if ComputeInterrupts has set irq_active to true 00804 if (irq_active) PIC_ActivateIRQ(irq); 00805 } else if (op2 && (!new_op2)) { 00806 // irq has been disabled (irq level -> tristate) 00807 // Remove the IRQ signal if the irq was being generated before 00808 if (irq_active) PIC_DeActivateIRQ(irq); 00809 } 00810 00811 dtr=new_dtr; 00812 rts=new_rts; 00813 op1=new_op1; 00814 op2=new_op2; 00815 loopback=new_loopback; 00816 } 00817 00818 /*****************************************************************************/ 00819 /* Line Status Register (r) **/ 00820 /*****************************************************************************/ 00821 // errors, tx registers status, rx register status 00822 // modified by: 00823 // - event from real serial port 00824 // - loopback 00825 Bitu CSerial::Read_LSR () { 00826 Bitu retval = LSR & (LSR_ERROR_MASK|LSR_TX_EMPTY_MASK); 00827 if(txfifo->isEmpty()) retval |= LSR_TX_HOLDING_EMPTY_MASK; 00828 if(!(rxfifo->isEmpty()))retval |= LSR_RX_DATA_READY_MASK; 00829 if(errors_in_fifo) retval |= FIFO_ERROR; 00830 LSR &= (~LSR_ERROR_MASK); // clear error bits on read 00831 clear (ERROR_PRIORITY); 00832 return retval; 00833 } 00834 00835 void CSerial::Write_MSR (Bit8u val) { 00836 d_cts = (val&MSR_dCTS_MASK)?true:false; 00837 d_dsr = (val&MSR_dDSR_MASK)?true:false; 00838 d_cd = (val&MSR_dCD_MASK)?true:false; 00839 d_ri = (val&MSR_dRI_MASK)?true:false; 00840 } 00841 00842 /*****************************************************************************/ 00843 /* Modem Status Register (r) **/ 00844 /*****************************************************************************/ 00845 // Contains status of the control input lines (CD, RI, DSR, CTS) and 00846 // their "deltas": if level changed since last read delta = 1. 00847 // modified by: 00848 // - real values 00849 // - write operation to MCR in loopback mode 00850 Bitu CSerial::Read_MSR () { 00851 Bit8u retval=0; 00852 00853 if (loopback) { 00854 00855 if (rts) retval |= MSR_CTS_MASK; 00856 if (dtr) retval |= MSR_DSR_MASK; 00857 if (op1) retval |= MSR_RI_MASK; 00858 if (op2) retval |= MSR_CD_MASK; 00859 00860 } else { 00861 00862 updateMSR(); 00863 if (cd) retval |= MSR_CD_MASK; 00864 if (ri) retval |= MSR_RI_MASK; 00865 if (dsr) retval |= MSR_DSR_MASK; 00866 if (cts) retval |= MSR_CTS_MASK; 00867 00868 } 00869 // new delta flags 00870 if(d_cd) retval|=MSR_dCD_MASK; 00871 if(d_ri) retval|=MSR_dRI_MASK; 00872 if(d_cts) retval|=MSR_dCTS_MASK; 00873 if(d_dsr) retval|=MSR_dDSR_MASK; 00874 00875 d_cd = false; 00876 d_ri = false; 00877 d_cts = false; 00878 d_dsr = false; 00879 00880 clear (MSR_PRIORITY); 00881 return retval; 00882 } 00883 00884 /*****************************************************************************/ 00885 /* Scratchpad Register (r/w) **/ 00886 /*****************************************************************************/ 00887 // Just a memory register. Not much to do here. 00888 Bitu CSerial::Read_SPR () { 00889 return SPR; 00890 } 00891 00892 void CSerial::Write_SPR (Bit8u data) { 00893 SPR = data; 00894 } 00895 00896 /*****************************************************************************/ 00897 /* Write_reserved **/ 00898 /*****************************************************************************/ 00899 void CSerial::Write_reserved (Bit8u data, Bit8u address) { 00900 (void)data;//UNUSED 00901 (void)address;//UNUSED 00902 /*LOG_UART("Serial%d: Write to reserved register, value 0x%x, register %x", 00903 COMNUMBER, data, address);*/ 00904 } 00905 00906 /*****************************************************************************/ 00907 /* MCR Access: returns cirquit state as boolean. **/ 00908 /*****************************************************************************/ 00909 bool CSerial::getDTR () { 00910 if(loopback) return false; 00911 else return dtr; 00912 } 00913 00914 bool CSerial::getRTS () { 00915 if(loopback) return false; 00916 else return rts; 00917 } 00918 00919 /*****************************************************************************/ 00920 /* MSR Access **/ 00921 /*****************************************************************************/ 00922 bool CSerial::getRI () { 00923 return ri; 00924 } 00925 00926 bool CSerial::getCD () { 00927 return cd; 00928 } 00929 00930 bool CSerial::getDSR () { 00931 return dsr; 00932 } 00933 00934 bool CSerial::getCTS () { 00935 return cts; 00936 } 00937 00938 void CSerial::setRI (bool value) { 00939 if (value != ri) { 00940 00941 #if SERIAL_DEBUG 00942 log_ser(dbg_modemcontrol,"%RI %x.",value); 00943 #endif 00944 // don't change delta when in loopback mode 00945 ri=value; 00946 if(!loopback) { 00947 if(value==false) d_ri=true; 00948 rise (MSR_PRIORITY); 00949 } 00950 } 00951 //else no change 00952 } 00953 void CSerial::setDSR (bool value) { 00954 if (value != dsr) { 00955 #if SERIAL_DEBUG 00956 log_ser(dbg_modemcontrol,"DSR %x.",value); 00957 #endif 00958 // don't change delta when in loopback mode 00959 dsr=value; 00960 if(!loopback) { 00961 d_dsr=true; 00962 rise (MSR_PRIORITY); 00963 } 00964 } 00965 //else no change 00966 } 00967 void CSerial::setCD (bool value) { 00968 if (value != cd) { 00969 #if SERIAL_DEBUG 00970 log_ser(dbg_modemcontrol,"CD %x.",value); 00971 #endif 00972 // don't change delta when in loopback mode 00973 cd=value; 00974 if(!loopback) { 00975 d_cd=true; 00976 rise (MSR_PRIORITY); 00977 } 00978 } 00979 //else no change 00980 } 00981 void CSerial::setCTS (bool value) { 00982 if (value != cts) { 00983 #if SERIAL_DEBUG 00984 log_ser(dbg_modemcontrol,"CTS %x.",value); 00985 #endif 00986 // don't change delta when in loopback mode 00987 cts=value; 00988 if(!loopback) { 00989 d_cts=true; 00990 rise (MSR_PRIORITY); 00991 } 00992 } 00993 //else no change 00994 } 00995 00996 /*****************************************************************************/ 00997 /* Initialisation **/ 00998 /*****************************************************************************/ 00999 void CSerial::Init_Registers () { 01000 // The "power on" settings 01001 irq_active=false; 01002 waiting_interrupts = 0x0; 01003 01004 Bit32u initbps = 9600; 01005 Bit8u bytesize = 8; 01006 char parity = 'N'; 01007 01008 Bit8u lcrresult = 0; 01009 Bit16u baudresult = 0; 01010 01011 IER = 0; 01012 ISR = 0x1; 01013 LCR = 0; 01014 //MCR = 0xff; 01015 loopback = true; 01016 dtr=true; 01017 rts=true; 01018 op1=true; 01019 op2=true; 01020 01021 sync_guardtime=false; 01022 FCR=0xff; 01023 Write_FCR(0x00); 01024 01025 01026 LSR = 0x60; 01027 d_cts = true; 01028 d_dsr = true; 01029 d_ri = true; 01030 d_cd = true; 01031 cts = true; 01032 dsr = true; 01033 ri = true; 01034 cd = true; 01035 01036 SPR = 0xFF; 01037 01038 baud_divider=0x0; 01039 01040 // make lcr: byte size, parity, stopbits, baudrate 01041 01042 if (bytesize == 5) 01043 lcrresult |= LCR_DATABITS_5; 01044 else if (bytesize == 6) 01045 lcrresult |= LCR_DATABITS_6; 01046 else if (bytesize == 7) 01047 lcrresult |= LCR_DATABITS_7; 01048 else 01049 lcrresult |= LCR_DATABITS_8; 01050 01051 switch(parity) 01052 { 01053 case 'N': 01054 case 'n': 01055 lcrresult |= LCR_PARITY_NONE; 01056 break; 01057 case 'O': 01058 case 'o': 01059 lcrresult |= LCR_PARITY_ODD; 01060 break; 01061 case 'E': 01062 case 'e': 01063 lcrresult |= LCR_PARITY_EVEN; 01064 break; 01065 case 'M': 01066 case 'm': 01067 lcrresult |= LCR_PARITY_MARK; 01068 break; 01069 case 'S': 01070 case 's': 01071 lcrresult |= LCR_PARITY_SPACE; 01072 break; 01073 } 01074 01075 // baudrate 01076 if (initbps > 0) 01077 baudresult = (Bit16u) (115200 / initbps); 01078 else 01079 baudresult = 12; // = 9600 baud 01080 01081 Write_MCR (0); 01082 Write_LCR (LCR_DIVISOR_Enable_MASK); 01083 Write_THR ((Bit8u) baudresult & 0xff); 01084 Write_IER ((Bit8u) (baudresult >> 8)); 01085 Write_LCR (lcrresult); 01086 updateMSR(); 01087 Read_MSR(); 01088 PIC_DeActivateIRQ(irq); 01089 } 01090 01091 CSerial::CSerial(Bitu id, CommandLine* cmd) { 01092 idnumber=id; 01093 Bit16u base = serial_baseaddr[id]; 01094 InstallationSuccessful = false; 01095 bytetime = 0; 01096 waiting_interrupts = 0; 01097 baud_divider = 0; 01098 IER = 0; 01099 irq_active = false; 01100 ISR = 0; 01101 LCR = 0; 01102 dtr = false; 01103 rts = false; 01104 op1 = false; 01105 op2 = false; 01106 loopback = false; 01107 LSR = 0; 01108 SPR = 0; 01109 loopback_data = 0; 01110 errors_in_fifo = 0; 01111 rx_interrupt_threshold = 0; 01112 FCR = 0; 01113 sync_guardtime = false; 01114 01115 d_cts=false; // bit0: deltaCTS 01116 d_dsr=false; // bit1: deltaDSR 01117 d_ri=false; // bit2: deltaRI 01118 d_cd=false; // bit3: deltaCD 01119 cts=false; // bit4: CTS 01120 dsr=false; // bit5: DSR 01121 ri=false; // bit6: RI 01122 cd=false; // bit7: CD 01123 01124 irq = serial_defaultirq[id]; 01125 getBituSubstring("irq:",&irq, cmd); 01126 if (irq < 2 || irq > 15) irq = serial_defaultirq[id]; 01127 01128 #if SERIAL_DEBUG 01129 dbg_serialtraffic = cmd->FindExist("dbgtr", false); 01130 dbg_modemcontrol = cmd->FindExist("dbgmd", false); 01131 dbg_register = cmd->FindExist("dbgreg", false); 01132 dbg_interrupt = cmd->FindExist("dbgirq", false); 01133 dbg_aux = cmd->FindExist("dbgaux", false); 01134 01135 if(cmd->FindExist("dbgall", false)) { 01136 dbg_serialtraffic= 01137 dbg_modemcontrol= 01138 dbg_register= 01139 dbg_interrupt= 01140 dbg_aux= true; 01141 } 01142 01143 01144 if(dbg_serialtraffic|dbg_modemcontrol|dbg_register|dbg_interrupt|dbg_aux) 01145 debugfp=OpenCaptureFile("serlog",".serlog.txt"); 01146 else debugfp=0; 01147 01148 if(debugfp == 0) { 01149 dbg_serialtraffic= 01150 dbg_modemcontrol= 01151 dbg_register= 01152 dbg_interrupt= 01153 dbg_aux= false; 01154 } else { 01155 std::string cleft; 01156 cmd->GetStringRemain(cleft); 01157 01158 log_ser(true,"Serial%d: BASE %3x, IRQ %d, initstring \"%s\"\r\n\r\n", 01159 COMNUMBER,base,irq,cleft.c_str()); 01160 } 01161 #endif 01162 fifosize=16; 01163 01164 errorfifo = new MyFifo(fifosize); 01165 rxfifo = new MyFifo(fifosize); 01166 txfifo = new MyFifo(fifosize); 01167 01168 mydosdevice=NULL; 01169 errormsg_pending=false; 01170 framingErrors=0; 01171 parityErrors=0; 01172 overrunErrors=0; 01173 txOverrunErrors=0; 01174 overrunIF0=0; 01175 breakErrors=0; 01176 01177 for (Bitu i = 0; i <= 7; i++) { 01178 WriteHandler[i].Install (i + base, SERIAL_Write, IO_MB); 01179 ReadHandler[i].Install (i + base, SERIAL_Read, IO_MB); 01180 } 01181 } 01182 01183 bool CSerial::getBituSubstring(const char* name,Bitu* data, CommandLine* cmd) { 01184 std::string tmpstring; 01185 if(!(cmd->FindStringBegin(name,tmpstring,false))) return false; 01186 const char* tmpchar=tmpstring.c_str(); 01187 01188 unsigned int tmp; 01189 if(sscanf(tmpchar,"%u",&tmp)!=1) return false; 01190 *data = (Bitu)tmp; 01191 return true; 01192 } 01193 01194 void CSerial::registerDOSDevice() { 01195 if (mydosdevice == NULL) { 01196 LOG(LOG_MISC,LOG_DEBUG)("COM%d: Registering DOS device",(int)idnumber+1); 01197 mydosdevice = new device_COM(this); 01198 DOS_AddDevice(mydosdevice); 01199 } 01200 } 01201 01202 void CSerial::unregisterDOSDevice() { 01203 if (mydosdevice != NULL) { 01204 LOG(LOG_MISC,LOG_DEBUG)("COM%d: Unregistering DOS device",(int)idnumber+1); 01205 DOS_DelDevice(mydosdevice); // deletes the pointer for us! 01206 mydosdevice=NULL; 01207 } 01208 } 01209 01210 CSerial::~CSerial(void) { 01211 unregisterDOSDevice(); 01212 for(Bit8u i = 0; i <= SERIAL_BASE_EVENT_COUNT; i++) 01213 removeEvent(i); 01214 01215 if (rxfifo != NULL) { 01216 delete rxfifo; 01217 rxfifo = NULL; 01218 } 01219 if (txfifo != NULL) { 01220 delete txfifo; 01221 txfifo = NULL; 01222 } 01223 if (errorfifo != NULL) { 01224 delete errorfifo; 01225 errorfifo = NULL; 01226 } 01227 } 01228 01229 bool CSerial::Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout) { 01230 double starttime=PIC_FullIndex(); 01231 // wait for DSR on 01232 if(wait_dsr) { 01233 while((!(Read_MSR()&0x20))&&(starttime>PIC_FullIndex()-timeout)) 01234 CALLBACK_Idle(); 01235 if(!(starttime>PIC_FullIndex()-timeout)) { 01236 #if SERIAL_DEBUG 01237 log_ser(dbg_aux,"Getchar status timeout: MSR 0x%x",Read_MSR()); 01238 #endif 01239 return false; 01240 } 01241 } 01242 // wait for a byte to arrive 01243 while((!((*lsr=(Bit8u)Read_LSR())&0x1))&&(starttime>PIC_FullIndex()-timeout)) 01244 CALLBACK_Idle(); 01245 01246 if(!(starttime>PIC_FullIndex()-timeout)) { 01247 #if SERIAL_DEBUG 01248 log_ser(dbg_aux,"Getchar data timeout: MSR 0x%x",Read_MSR()); 01249 #endif 01250 return false; 01251 } 01252 *data=(Bit8u)Read_RHR(); 01253 01254 #if SERIAL_DEBUG 01255 log_ser(dbg_aux,"Getchar read 0x%x",*data); 01256 #endif 01257 return true; 01258 } 01259 01260 01261 bool CSerial::Putchar(Bit8u data, bool wait_dsr, bool wait_cts, Bitu timeout) { 01262 01263 double starttime=PIC_FullIndex(); 01264 // wait for it to become empty 01265 while(!(Read_LSR()&0x20)) { 01266 CALLBACK_Idle(); 01267 } 01268 // wait for DSR+CTS on 01269 if(wait_dsr||wait_cts) { 01270 if(wait_dsr||wait_cts) { 01271 while(((Read_MSR()&0x30)!=0x30)&&(starttime>PIC_FullIndex()-timeout)) 01272 CALLBACK_Idle(); 01273 } else if(wait_dsr) { 01274 while(!(Read_MSR()&0x20)&&(starttime>PIC_FullIndex()-timeout)) 01275 CALLBACK_Idle(); 01276 } else if(wait_cts) { 01277 while(!(Read_MSR()&0x10)&&(starttime>PIC_FullIndex()-timeout)) 01278 CALLBACK_Idle(); 01279 } 01280 if(!(starttime>PIC_FullIndex()-timeout)) { 01281 #if SERIAL_DEBUG 01282 log_ser(dbg_aux,"Putchar timeout: MSR 0x%x",Read_MSR()); 01283 #endif 01284 return false; 01285 } 01286 } 01287 Write_THR(data); 01288 01289 #if SERIAL_DEBUG 01290 log_ser(dbg_aux,"Putchar 0x%x",data); 01291 #endif 01292 01293 return true; 01294 } 01295 01296 void BIOS_PnP_ComPortRegister(Bitu port,Bitu irq); 01297 void BIOS_SetCOMPort(Bitu port, Bit16u baseaddr); 01298 01299 void BIOS_Post_register_comports_PNP() { 01300 unsigned int i; 01301 01302 for (i=0;i < 4;i++) { 01303 if (serialports[i] != NULL) { 01304 BIOS_PnP_ComPortRegister(serial_baseaddr[i],serialports[i]->irq); 01305 } 01306 } 01307 } 01308 01309 Bitu bios_post_comport_count() { 01310 Bitu count = 0; 01311 unsigned int i; 01312 01313 for (i=0;i < 4;i++) { 01314 if (serialports[i] != NULL) 01315 count++; 01316 } 01317 01318 return count; 01319 } 01320 01321 /* at BIOS POST stage, write serial ports to bios data area */ 01322 void BIOS_Post_register_comports() { 01323 unsigned int i; 01324 01325 for (i=0;i < 4;i++) { 01326 if (serialports[i] != NULL) 01327 BIOS_SetCOMPort(i,serial_baseaddr[i]); 01328 } 01329 } 01330 01331 class SERIALPORTS:public Module_base { 01332 public: 01333 SERIALPORTS (Section * configuration):Module_base (configuration) { 01334 Section_prop *section = static_cast <Section_prop*>(configuration); 01335 01336 // TODO: PC-98 does have serial ports, though differently. 01337 // COM1 is a 8251 UART, while COM2 and higher if they exist are 8250/16xxx UARTs 01338 if (IS_PC98_ARCH) return; 01339 01340 #if C_MODEM 01341 const Prop_path *pbFilename = section->Get_path("phonebookfile"); 01342 MODEM_ReadPhonebook(pbFilename->realpath); 01343 #endif 01344 01345 char s_property[] = "serialx"; 01346 for(Bit8u i = 0; i < 4; i++) { 01347 // get the configuration property 01348 s_property[6] = '1' + i; 01349 Prop_multival* p = section->Get_multival(s_property); 01350 std::string type = p->GetSection()->Get_string("type"); 01351 CommandLine cmd(0,p->GetSection()->Get_string("parameters")); 01352 01353 // detect the type 01354 if (type=="dummy") { 01355 serialports[i] = new CSerialDummy (i, &cmd); 01356 } 01357 else if (type=="log") { 01358 serialports[i] = new CSerialLog (i, &cmd); 01359 } 01360 else if (type=="file") { 01361 serialports[i] = new CSerialFile (i, &cmd); 01362 } 01363 else if (type=="serialmouse") { 01364 serialports[i] = new CSerialMouse (i, &cmd); 01365 } 01366 #ifdef DIRECTSERIAL_AVAILIBLE 01367 else if (type=="directserial") { 01368 serialports[i] = new CDirectSerial (i, &cmd); 01369 if (!serialports[i]->InstallationSuccessful) { 01370 // serial port name was wrong or already in use 01371 delete serialports[i]; 01372 serialports[i] = NULL; 01373 } 01374 } 01375 #endif 01376 #if C_MODEM 01377 else if(type=="modem") { 01378 serialports[i] = new CSerialModem (i, &cmd); 01379 if (!serialports[i]->InstallationSuccessful) { 01380 delete serialports[i]; 01381 serialports[i] = NULL; 01382 } 01383 } 01384 else if(type=="nullmodem") { 01385 serialports[i] = new CNullModem (i, &cmd); 01386 if (!serialports[i]->InstallationSuccessful) { 01387 delete serialports[i]; 01388 serialports[i] = NULL; 01389 } 01390 } 01391 #endif 01392 else if(type=="disabled") { 01393 serialports[i] = NULL; 01394 } else { 01395 serialports[i] = NULL; 01396 LOG_MSG("Invalid type for serial%d",(int)i+1); 01397 } 01398 } // for 1-4 01399 } 01400 01401 ~SERIALPORTS () { 01402 for (Bitu i = 0; i < 4; i++) 01403 if (serialports[i]) { 01404 delete serialports[i]; 01405 serialports[i] = 0; 01406 } 01407 } 01408 }; 01409 01410 static SERIALPORTS *testSerialPortsBaseclass; 01411 01412 void SERIAL_Destroy (Section * sec) { 01413 (void)sec;//UNUSED 01414 if (testSerialPortsBaseclass) { 01415 LOG(LOG_MISC,LOG_DEBUG)("Deleting serial port base class"); 01416 delete testSerialPortsBaseclass; 01417 testSerialPortsBaseclass = NULL; 01418 } 01419 } 01420 01421 void SERIAL_OnPowerOn (Section * sec) { 01422 (void)sec;//UNUSED 01423 // should never happen 01424 LOG(LOG_MISC,LOG_DEBUG)("Reinitializing serial emulation"); 01425 if (testSerialPortsBaseclass) delete testSerialPortsBaseclass; 01426 testSerialPortsBaseclass = new SERIALPORTS (control->GetSection("serial")); 01427 } 01428 01429 void SERIAL_OnDOSKernelInit (Section * sec) { 01430 (void)sec;//UNUSED 01431 unsigned int i; 01432 01433 LOG(LOG_MISC,LOG_DEBUG)("DOS kernel initializing, creating COMx devices"); 01434 01435 for (i=0;i < 3;i++) { 01436 if (serialports[i] != NULL) 01437 serialports[i]->registerDOSDevice(); 01438 } 01439 } 01440 01441 void SERIAL_OnDOSKernelExit (Section * sec) { 01442 (void)sec;//UNUSED 01443 unsigned int i; 01444 01445 for (i=0;i < 3;i++) { 01446 if (serialports[i] != NULL) 01447 serialports[i]->unregisterDOSDevice(); 01448 } 01449 } 01450 01451 void SERIAL_OnReset (Section * sec) { 01452 (void)sec;//UNUSED 01453 unsigned int i; 01454 01455 // FIXME: Unregister/destroy the DOS devices, but consider that the DOS kernel at reset is gone. 01456 for (i=0;i < 3;i++) { 01457 if (serialports[i] != NULL) 01458 serialports[i]->unregisterDOSDevice(); 01459 } 01460 } 01461 01462 void SERIAL_Init () { 01463 LOG(LOG_MISC,LOG_DEBUG)("Initializing serial port emulation"); 01464 01465 AddExitFunction(AddExitFunctionFuncPair(SERIAL_Destroy),true); 01466 01467 if (!IS_PC98_ARCH) { 01468 AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(SERIAL_OnPowerOn)); 01469 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(SERIAL_OnReset)); 01470 AddVMEventFunction(VM_EVENT_DOS_EXIT_BEGIN,AddVMEventFunctionFuncPair(SERIAL_OnDOSKernelExit)); 01471 AddVMEventFunction(VM_EVENT_DOS_INIT_KERNEL_READY,AddVMEventFunctionFuncPair(SERIAL_OnDOSKernelInit)); 01472 } 01473 } 01474 01475 // save state support 01476 void *Serial_EventHandler_PIC_Event = (void*)((uintptr_t)Serial_EventHandler);