///////////////////////////////////////////////////////////////////////// // $Id: serial.cc,v 1.20 2002-05-31 06:54:34 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002 MandrakeSoft S.A. // // MandrakeSoft S.A. // 43, rue d'Aboukir // 75002 Paris - France // http://www.linux-mandrake.com/ // http://www.mandrakesoft.com/ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Peter Grehan (grehan@iprg.nokia.com) coded most of this // serial emulation. Here's some notes from his implementation: // New files. Implement a single 8250, and allow terminal input/output // to stdout on FreeBSD. 16550/16550a/16552 should be easy: just add code // to handle a FIFO. I only did what was needed to get console output. // define USE_TTY_HACK to connect an xterm or similar (depends on tty.c) // to the serial port /AM #include "bochs.h" #define LOG_THIS bx_serial. #if USE_RAW_SERIAL #include #endif #ifdef WIN32 #ifndef __MINGW32__ // +++ //#include #include #endif #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__GNU__) #define SERIAL_ENABLE #endif #ifdef SERIAL_ENABLE extern "C" { #include }; #endif bx_serial_c bx_serial; #if BX_USE_SER_SMF #define this (&bx_serial) #endif #ifdef SERIAL_ENABLE static struct termios term_orig, term_new; #endif static int tty_id; bx_serial_c::bx_serial_c(void) { put("SER"); settype(SERLOG); } bx_serial_c::~bx_serial_c(void) { #ifdef SERIAL_ENABLE tcsetattr(tty_id, TCSAFLUSH, &term_orig); #endif // nothing for now } void bx_serial_c::init(bx_devices_c *d) { if (!bx_options.com1.Opresent->get ()) return; #ifdef SERIAL_ENABLE tty_id = open(bx_options.com1.Odev->getptr (), O_RDWR|O_NONBLOCK,600); if (tty_id < 0) BX_PANIC(("open of %s (%s) failed\n", "com1", bx_options.com1.Odev->getptr ())); BX_DEBUG(("tty_id: %d",tty_id)); tcgetattr(tty_id, &term_orig); bcopy((caddr_t) &term_orig, (caddr_t) &term_new, sizeof(struct termios)); cfmakeraw(&term_new); term_new.c_oflag |= OPOST | ONLCR; // Enable NL to CR-NL translation #ifndef TRUE_CTLC // ctl-C will exit Bochs, or trap to the debugger term_new.c_iflag &= ~IGNBRK; term_new.c_iflag |= BRKINT; term_new.c_lflag |= ISIG; #else // ctl-C will be delivered to the serial port term_new.c_iflag |= IGNBRK; term_new.c_iflag &= ~BRKINT; #endif /* !def TRUE_CTLC */ term_new.c_iflag = 0; term_new.c_oflag = 0; term_new.c_cflag = CS8|CREAD|CLOCAL; term_new.c_lflag = 0; term_new.c_cc[VMIN] = 1; term_new.c_cc[VTIME] = 0; //term_new.c_iflag |= IXOFF; tcsetattr(tty_id, TCSAFLUSH, &term_new); #endif /* def SERIAL_ENABLE */ // nothing for now #if USE_RAW_SERIAL this->raw = new serial_raw("/dev/cua0", SIGUSR1); #endif // USE_RAW_SERIAL BX_SER_THIS devices = d; BX_SER_THIS devices->register_irq(4, "Serial Port 1"); #if defined (USE_TTY_HACK) tty_id = tty_alloc("Bx Serial Console, Your Window to the 8250"); if (tty_id > 0) BX_INFO(("TTY allocated fd = %d", tty_get_fd(tty_id))); else BX_INFO(("TTY allocation failed")); #else //BX_INFO(("TTY not used, serial port is not connected")); #endif /* * Put the UART registers into their RESET state */ for (unsigned i=0; iregister_io_read_handler(this, read_handler, addr, "Serial Port 1"); BX_SER_THIS devices->register_io_write_handler(this, write_handler, addr, "Serial Port 1"); } BX_INFO(( "com1 at 0x3f8/8 irq 4" )); } // static IO port read callback handler // redirects to non-static class handler to avoid virtual functions Bit32u bx_serial_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len) { #if !BX_USE_SER_SMF bx_serial_c *class_ptr = (bx_serial_c *) this_ptr; return( class_ptr->read(address, io_len) ); } Bit32u bx_serial_c::read(Bit32u address, unsigned io_len) { #else UNUSED(this_ptr); #endif // !BX_USE_SER_SMF //UNUSED(address); Bit8u val; /* SERIAL PORT 1 */ if (io_len > 1) BX_PANIC(("io read from port %04x, bad len=%u", (unsigned) address, (unsigned) io_len)); BX_DEBUG(("register read from address 0x%x - ", (unsigned) address)); switch (address) { case 0x03F8: /* receive buffer, or divisor latch LSB if DLAB set */ if (BX_SER_THIS s[0].line_cntl.dlab) { val = BX_SER_THIS s[0].divisor_lsb; } else { val = BX_SER_THIS s[0].rxbuffer; BX_SER_THIS s[0].line_status.rxdata_ready = 0; BX_SER_THIS s[0].rx_empty = 1; /* If there are no more ints pending, clear the irq */ if ((BX_SER_THIS s[0].tx_interrupt == 0) && (BX_SER_THIS s[0].ls_interrupt == 0) && (BX_SER_THIS s[0].ms_interrupt == 0)) { BX_SER_THIS devices->pic->lower_irq(4); } BX_SER_THIS s[0].rx_interrupt = 0; BX_SER_THIS s[0].rx_ipending = 0; } break; case 0x03F9: /* interrupt enable register, or div. latch MSB */ if (BX_SER_THIS s[0].line_cntl.dlab) { val = BX_SER_THIS s[0].divisor_msb; } else { val = BX_SER_THIS s[0].int_enable.rxdata_enable | (BX_SER_THIS s[0].int_enable.txhold_enable << 1) | (BX_SER_THIS s[0].int_enable.rxlstat_enable << 2) | (BX_SER_THIS s[0].int_enable.modstat_enable << 3); } break; case 0x03FA: /* interrupt ID register */ /* * Set the interrupt ID based on interrupt source */ if (BX_SER_THIS s[0].ls_interrupt) { BX_SER_THIS s[0].int_ident.int_ID = 0x3; BX_SER_THIS s[0].int_ident.ipending = 0; } else if (BX_SER_THIS s[0].rx_interrupt) { BX_SER_THIS s[0].int_ident.int_ID = 0x2; BX_SER_THIS s[0].int_ident.ipending = 0; } else if (BX_SER_THIS s[0].tx_interrupt) { BX_SER_THIS s[0].int_ident.int_ID = 0x1; BX_SER_THIS s[0].int_ident.ipending = 0; } else if (BX_SER_THIS s[0].ms_interrupt) { BX_SER_THIS s[0].int_ident.int_ID = 0x0; BX_SER_THIS s[0].int_ident.ipending = 0; } else { BX_SER_THIS s[0].int_ident.int_ID = 0x0; BX_SER_THIS s[0].int_ident.ipending = 1; } /* If there are no more ints pending, clear the irq */ if ((BX_SER_THIS s[0].rx_interrupt == 0) && (BX_SER_THIS s[0].ls_interrupt == 0) && (BX_SER_THIS s[0].ms_interrupt == 0)) { BX_SER_THIS devices->pic->lower_irq(4); } BX_SER_THIS s[0].tx_interrupt = 0; BX_SER_THIS s[0].tx_ipending = 0; val = BX_SER_THIS s[0].int_ident.ipending | (BX_SER_THIS s[0].int_ident.int_ID << 1) | (BX_SER_THIS s[0].int_ident.fifo_enabled << 6); break; case 0x03FB: /* Line control register */ val = BX_SER_THIS s[0].line_cntl.wordlen_sel | (BX_SER_THIS s[0].line_cntl.stopbits << 2) | (BX_SER_THIS s[0].line_cntl.parity_enable << 3) | (BX_SER_THIS s[0].line_cntl.evenparity_sel << 4) | (BX_SER_THIS s[0].line_cntl.stick_parity << 5) | (BX_SER_THIS s[0].line_cntl.break_cntl << 6) | (BX_SER_THIS s[0].line_cntl.dlab << 7); break; case 0x03FC: /* MODEM control register */ val = BX_SER_THIS s[0].modem_cntl.dtr | (BX_SER_THIS s[0].modem_cntl.rts << 1) | (BX_SER_THIS s[0].modem_cntl.out1 << 2) | (BX_SER_THIS s[0].modem_cntl.out2 << 3) | (BX_SER_THIS s[0].modem_cntl.local_loopback << 4); break; case 0x03FD: /* Line status register */ val = BX_SER_THIS s[0].line_status.rxdata_ready | (BX_SER_THIS s[0].line_status.overrun_error << 1) | (BX_SER_THIS s[0].line_status.parity_error << 2) | (BX_SER_THIS s[0].line_status.framing_error << 3) | (BX_SER_THIS s[0].line_status.break_int << 4) | (BX_SER_THIS s[0].line_status.txhold_empty << 5) | (BX_SER_THIS s[0].line_status.txtransm_empty << 6) | (BX_SER_THIS s[0].line_status.fifo_error << 7); BX_SER_THIS s[0].line_status.overrun_error = 0; BX_SER_THIS s[0].line_status.break_int = 0; /* If there are no more ints pending, clear the irq */ if ((BX_SER_THIS s[0].rx_interrupt == 0) && (BX_SER_THIS s[0].tx_interrupt == 0) && (BX_SER_THIS s[0].ms_interrupt == 0)) { BX_SER_THIS devices->pic->lower_irq(4); } BX_SER_THIS s[0].ls_interrupt = 0; BX_SER_THIS s[0].ls_ipending = 0; break; case 0x03FE: /* MODEM status register */ val = BX_SER_THIS s[0].modem_status.delta_cts | (BX_SER_THIS s[0].modem_status.delta_dsr << 1) | (BX_SER_THIS s[0].modem_status.ri_trailedge << 2) | (BX_SER_THIS s[0].modem_status.delta_dcd << 3) | (BX_SER_THIS s[0].modem_status.cts << 4) | (BX_SER_THIS s[0].modem_status.dsr << 5) | (BX_SER_THIS s[0].modem_status.ri << 6) | (BX_SER_THIS s[0].modem_status.dcd << 7); BX_SER_THIS s[0].modem_status.delta_cts = 0; BX_SER_THIS s[0].modem_status.delta_dsr = 0; BX_SER_THIS s[0].modem_status.ri_trailedge = 0; BX_SER_THIS s[0].modem_status.delta_dcd = 0; /* If there are no more ints pending, clear the irq */ if ((BX_SER_THIS s[0].rx_interrupt == 0) && (BX_SER_THIS s[0].tx_interrupt == 0) && (BX_SER_THIS s[0].ls_interrupt == 0)) { BX_SER_THIS devices->pic->lower_irq(4); } BX_SER_THIS s[0].ms_interrupt = 0; BX_SER_THIS s[0].ms_ipending = 0; break; case 0x03FF: /* scratch register */ val = BX_SER_THIS s[0].scratch; break; default: val = 0; // keep compiler happy BX_PANIC(("unsupported io read from address=%0x%x!", (unsigned) address)); break; } BX_DEBUG(("val = 0x%x", (unsigned) val)); return(val); } // static IO port write callback handler // redirects to non-static class handler to avoid virtual functions void bx_serial_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len) { #if !BX_USE_SER_SMF bx_serial_c *class_ptr = (bx_serial_c *) this_ptr; class_ptr->write(address, value, io_len); } void bx_serial_c::write(Bit32u address, Bit32u value, unsigned io_len) { #else UNUSED(this_ptr); #endif // !BX_USE_SER_SMF Boolean prev_cts, prev_dsr, prev_ri, prev_dcd; Boolean gen_int = 0; BX_DEBUG(("write: 0x%x <- %d",address,value)); /* SERIAL PORT 1 */ if (io_len > 1) BX_PANIC(("io write to address %08x len=%u", (unsigned) address, (unsigned) io_len)); BX_DEBUG(("write to address: 0x%x = 0x%x", (unsigned) address, (unsigned) value)); switch (address) { case 0x03F8: /* transmit buffer, or divisor latch LSB if DLAB set */ if (BX_SER_THIS s[0].line_cntl.dlab) { BX_SER_THIS s[0].divisor_lsb = value; if (value != 0) { BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL / (16 * ((BX_SER_THIS s[0].divisor_msb << 8) | BX_SER_THIS s[0].divisor_lsb))); #if USE_RAW_SERIAL BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate); #endif // USE_RAW_SERIAL } } else { if (BX_SER_THIS s[0].tx_empty) { BX_SER_THIS s[0].tx_empty = 0; BX_SER_THIS s[0].line_status.txtransm_empty = 0; BX_SER_THIS s[0].line_status.txhold_empty = 0; /* If there are no more ints pending, clear the irq */ if ((BX_SER_THIS s[0].rx_interrupt == 0) && (BX_SER_THIS s[0].ls_interrupt == 0) && (BX_SER_THIS s[0].ms_interrupt == 0)) { BX_SER_THIS devices->pic->lower_irq(4); } BX_SER_THIS s[0].tx_interrupt = 0; BX_SER_THIS s[0].tx_ipending = 0; Bit8u bitmask = 0xff >> (3 - BX_SER_THIS s[0].line_cntl.wordlen_sel); BX_SER_THIS s[0].txbuffer = value & bitmask; bx_pc_system.activate_timer(BX_SER_THIS s[0].tx_timer_index, (int) (1000000.0 / (BX_SER_THIS s[0].baudrate / 8)), 0); /* not continuous */ } else { BX_ERROR(("write to tx hold register when not empty")); } } break; case 0x03F9: /* interrupt enable register, or div. latch MSB */ if (BX_SER_THIS s[0].line_cntl.dlab) { BX_SER_THIS s[0].divisor_msb = value; if (BX_SER_THIS s[0].divisor_msb != 0 && value != 0) { BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL / (16 * ((BX_SER_THIS s[0].divisor_msb << 8) | BX_SER_THIS s[0].divisor_lsb))); #if USE_RAW_SERIAL BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate); #endif // USE_RAW_SERIAL } } else { BX_SER_THIS s[0].int_enable.rxdata_enable = value & 0x01; BX_SER_THIS s[0].int_enable.txhold_enable = (value & 0x02) >> 1; BX_SER_THIS s[0].int_enable.rxlstat_enable = (value & 0x04) >> 2; BX_SER_THIS s[0].int_enable.modstat_enable = (value & 0x08) >> 3; if ((BX_SER_THIS s[0].ms_ipending == 1) && (BX_SER_THIS s[0].int_enable.modstat_enable == 1)) { BX_SER_THIS s[0].ms_interrupt = 1; BX_SER_THIS s[0].ms_ipending = 0; gen_int = 1; } if ((BX_SER_THIS s[0].tx_ipending == 1) && (BX_SER_THIS s[0].int_enable.txhold_enable == 1)) { BX_SER_THIS s[0].tx_interrupt = 1; BX_SER_THIS s[0].tx_ipending = 0; gen_int = 1; } if ((BX_SER_THIS s[0].rx_ipending == 1) && (BX_SER_THIS s[0].int_enable.rxdata_enable == 1)) { BX_SER_THIS s[0].rx_interrupt = 1; BX_SER_THIS s[0].rx_ipending = 0; gen_int = 1; if ((BX_SER_THIS s[0].ls_ipending == 1) && (BX_SER_THIS s[0].int_enable.rxlstat_enable == 1)) { BX_SER_THIS s[0].ls_interrupt = 1; BX_SER_THIS s[0].ls_ipending = 0; gen_int = 1; } } if (gen_int == 1) BX_SER_THIS devices->pic->raise_irq(4); } break; case 0x03FA: /* FIFO control register */ /* Ignore until FIFO mode is supported... */ break; case 0x03FB: /* Line control register */ #if !USE_RAW_SERIAL if ((value & 0x3) != 0x3) { /* ignore this: this is set by FreeBSD when the console code wants to set DLAB */ } #endif // !USE_RAW_SERIAL #if USE_RAW_SERIAL if (BX_SER_THIS s[0].line_cntl.wordlen_sel != (value & 0x3)) { BX_SER_THIS raw->set_data_bits((value & 0x3) + 5); } if (BX_SER_THIS s[0].line_cntl.stopbits != (value & 0x4) >> 2) { BX_SER_THIS raw->set_stop_bits((value & 0x4 >> 2) ? 2 : 1); } if (BX_SER_THIS s[0].line_cntl.parity_enable != (value & 0x8) >> 3 || BX_SER_THIS s[0].line_cntl.evenparity_sel != (value & 0x10) >> 4 || BX_SER_THIS s[0].line_cntl.stick_parity != (value & 0x20) >> 5) { if (((value & 0x20) >> 5) && ((value & 0x8) >> 3)) BX_PANIC(("sticky parity set and parity enabled")); BX_SER_THIS raw->set_parity_mode(((value & 0x8) >> 3), ((value & 0x10) >> 4) ? P_EVEN : P_ODD); } if (BX_SER_THIS s[0].line_cntl.break_cntl && !((value & 0x40) >> 6)) { BX_SER_THIS raw->transmit(C_BREAK); } #endif // USE_RAW_SERIAL BX_SER_THIS s[0].line_cntl.wordlen_sel = value & 0x3; /* These are ignored, but set them up so they can be read back */ BX_SER_THIS s[0].line_cntl.stopbits = (value & 0x4) >> 2; BX_SER_THIS s[0].line_cntl.parity_enable = (value & 0x8) >> 3; BX_SER_THIS s[0].line_cntl.evenparity_sel = (value & 0x10) >> 4; BX_SER_THIS s[0].line_cntl.stick_parity = (value & 0x20) >> 5; BX_SER_THIS s[0].line_cntl.break_cntl = (value & 0x40) >> 6; /* used when doing future writes */ if (BX_SER_THIS s[0].line_cntl.dlab && !((value & 0x80) >> 7)) { // Start the receive polling process if not already started // and there is a valid baudrate. Poll every 4 bit times if (BX_SER_THIS s[0].rx_pollstate == BX_SER_RXIDLE && BX_SER_THIS s[0].baudrate != 0) { BX_SER_THIS s[0].rx_pollstate = BX_SER_RXPOLL; bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index, (int) (1000000.0 / (BX_SER_THIS s[0].baudrate / 4)), 0); /* not continuous */ } BX_DEBUG(("baud rate set - %d", BX_SER_THIS s[0].baudrate)); } BX_SER_THIS s[0].line_cntl.dlab = (value & 0x80) >> 7; break; case 0x03FC: /* MODEM control register */ if ((value & 0x01) == 0) { #if USE_RAW_SERIAL BX_SER_THIS raw->send_hangup(); #endif } BX_SER_THIS s[0].modem_cntl.dtr = value & 0x01; BX_SER_THIS s[0].modem_cntl.rts = (value & 0x02) >> 1; BX_SER_THIS s[0].modem_cntl.out1 = (value & 0x04) >> 2; BX_SER_THIS s[0].modem_cntl.out2 = (value & 0x08) >> 3; BX_SER_THIS s[0].modem_cntl.local_loopback = (value & 0x10) >> 4; if (BX_SER_THIS s[0].modem_cntl.local_loopback) { prev_cts = BX_SER_THIS s[0].modem_status.cts; prev_dsr = BX_SER_THIS s[0].modem_status.dsr; prev_ri = BX_SER_THIS s[0].modem_status.ri; prev_dcd = BX_SER_THIS s[0].modem_status.dcd; BX_SER_THIS s[0].modem_status.cts = BX_SER_THIS s[0].modem_cntl.rts; BX_SER_THIS s[0].modem_status.dsr = BX_SER_THIS s[0].modem_cntl.dtr; BX_SER_THIS s[0].modem_status.ri = BX_SER_THIS s[0].modem_cntl.out1; BX_SER_THIS s[0].modem_status.dcd = BX_SER_THIS s[0].modem_cntl.out2; if (BX_SER_THIS s[0].modem_status.cts != prev_cts) { BX_SER_THIS s[0].modem_status.delta_cts = 1; BX_SER_THIS s[0].ms_ipending = 1; } if (BX_SER_THIS s[0].modem_status.dsr != prev_dsr) { BX_SER_THIS s[0].modem_status.delta_dsr = 1; BX_SER_THIS s[0].ms_ipending = 1; } if (BX_SER_THIS s[0].modem_status.ri != prev_ri) BX_SER_THIS s[0].ms_ipending = 1; if ((BX_SER_THIS s[0].modem_status.ri == 0) && (prev_ri == 1)) BX_SER_THIS s[0].modem_status.ri_trailedge = 1; if (BX_SER_THIS s[0].modem_status.dcd != prev_dcd) { BX_SER_THIS s[0].modem_status.delta_dcd = 1; BX_SER_THIS s[0].ms_ipending = 1; } if ((BX_SER_THIS s[0].ms_ipending == 1) && (BX_SER_THIS s[0].int_enable.modstat_enable == 1)) { BX_SER_THIS s[0].ms_interrupt = 1; BX_SER_THIS s[0].ms_ipending = 0; } } else { /* set these to 0 for the time being */ BX_SER_THIS s[0].modem_status.cts = 0; BX_SER_THIS s[0].modem_status.dsr = 0; BX_SER_THIS s[0].modem_status.ri = 0; BX_SER_THIS s[0].modem_status.dcd = 0; } break; case 0x03FD: /* Line status register */ BX_ERROR(("write to line status register ignored")); break; case 0x03FE: /* MODEM status register */ BX_ERROR(("write to MODEM status register ignored")); break; case 0x03FF: /* scratch register */ BX_SER_THIS s[0].scratch = value; break; default: BX_PANIC(("unsupported io write to address=0x%x, value = 0x%x!", (unsigned) address, (unsigned) value)); break; } } void bx_serial_c::tx_timer_handler(void *this_ptr) { bx_serial_c *class_ptr = (bx_serial_c *) this_ptr; class_ptr->tx_timer(); } void bx_serial_c::tx_timer(void) { int gen_int = 0; BX_SER_THIS s[0].tx_empty = 1; BX_SER_THIS s[0].line_status.txtransm_empty = 1; BX_SER_THIS s[0].line_status.txhold_empty = 1; if (BX_SER_THIS s[0].int_enable.txhold_enable) { gen_int = 1; BX_SER_THIS s[0].tx_interrupt = 1; } else { BX_SER_THIS s[0].tx_ipending = 1; } if (BX_SER_THIS s[0].modem_cntl.local_loopback) { if (BX_SER_THIS s[0].rx_empty == 0) BX_SER_THIS s[0].line_status.overrun_error = 1; BX_SER_THIS s[0].rxbuffer = BX_SER_THIS s[0].txbuffer; BX_SER_THIS s[0].line_status.rxdata_ready = 1; BX_SER_THIS s[0].rx_empty = 0; if (BX_SER_THIS s[0].modem_cntl.out2) { if (BX_SER_THIS s[0].int_enable.rxdata_enable) { gen_int = 1; BX_SER_THIS s[0].rx_interrupt = 1; } else { BX_SER_THIS s[0].rx_ipending = 1; } if (BX_SER_THIS s[0].int_enable.rxlstat_enable) { gen_int = 1; BX_SER_THIS s[0].ls_interrupt = 1; } else { BX_SER_THIS s[0].ls_ipending = 1; } } } else { #if defined (USE_TTY_HACK) tty(tty_id, 0, & BX_SER_THIS s[0].txbuffer); #elif USE_RAW_SERIAL if (!BX_SER_THIS raw->ready_transmit()) BX_PANIC(("Not ready to transmit")); BX_SER_THIS raw->transmit(BX_SER_THIS s[0].txbuffer); #endif #if defined(SERIAL_ENABLE) { char *s = (char *)(BX_SER_THIS s[0].txbuffer); BX_DEBUG(("write: '%c'",(bx_ptr_t) & s)); } write(tty_id, (bx_ptr_t) & BX_SER_THIS s[0].txbuffer, 1); #endif } if (gen_int) { BX_SER_THIS devices->pic->raise_irq(4); } } void bx_serial_c::rx_timer_handler(void *this_ptr) { bx_serial_c *class_ptr = (bx_serial_c *) this_ptr; class_ptr->rx_timer(); } void bx_serial_c::rx_timer(void) { #if BX_HAVE_SELECT #if BX_WITH_BEOS == 0 struct timeval tval; fd_set fds; #endif #endif int bdrate = BX_SER_THIS s[0].baudrate / 8; unsigned char chbuf = 0; #if BX_HAVE_SELECT #if BX_WITH_BEOS == 0 tval.tv_sec = 0; tval.tv_usec = 0; // MacOS: I'm not sure what to do with this, since I don't know // what an fd_set is or what FD_SET() or select() do. They aren't // declared in the CodeWarrior standard library headers. I'm just // leaving it commented out for the moment. FD_ZERO(&fds); FD_SET(tty_id, &fds); if (BX_SER_THIS s[0].line_status.rxdata_ready == 0) { #if defined (USE_TTY_HACK) if (tty_prefetch_char(tty_id)) { tty(tty_id, 1, &chbuf); #elif USE_RAW_SERIAL Boolean rdy; uint16 data; if ((rdy = BX_SER_THIS raw->ready_receive())) { data = BX_SER_THIS raw->receive(); if (data == C_BREAK) { BX_DEBUG(("got BREAK")); BX_SER_THIS s[0].line_status.break_int = 1; rdy = 0; } } if (rdy) { chbuf = data; #elif defined(SERIAL_ENABLE) if (select(tty_id + 1, &fds, NULL, NULL, &tval) == 1) { (void) read(tty_id, &chbuf, 1); BX_DEBUG(("read: '%c'",chbuf)); #else if (0) { #endif if (!BX_SER_THIS s[0].modem_cntl.local_loopback) { BX_SER_THIS s[0].rxbuffer = chbuf; BX_SER_THIS s[0].line_status.rxdata_ready = 1; BX_SER_THIS s[0].rx_empty = 0; if (BX_SER_THIS s[0].int_enable.rxdata_enable) { BX_SER_THIS s[0].rx_interrupt = 1; BX_SER_THIS devices->pic->raise_irq(4); } else { BX_SER_THIS s[0].rx_ipending = 1; } } } else { bdrate = (int) (1000000.0 / 100000); // Poll frequency is 100ms } } else { // Poll at 4x baud rate to see if the next-char can // be read bdrate *= 4; } #endif #endif bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index, (int) (1000000.0 / bdrate), 0); /* not continuous */ }