// Copyright Notice
// ================
// BOCHS is Copyright 1994-1999 by Kevin P. Lawton.
//
// BOCHS is commercial software.
//
// For more information, read the file 'LICENSE' included in the bochs
// distribution.  If you don't have access to this file, or have questions
// regarding the licensing policy, the author may be contacted via:
//
//     US Mail:  Kevin Lawton
//               439 Marrett Rd.
//               Lexington, MA 02421-7714
//
//     EMail:    bochs@world.std.com


// Peter Grehan (grehan@iprg.nokia.com) coded most of this
// serial emulation.

#if USE_RAW_SERIAL
#include "serial_raw.h"
#endif // USE_RAW_SERIAL

#if BX_USE_SER_SMF
#  define BX_SER_SMF  static
#  define BX_SER_THIS bx_serial.
#else
#  define BX_SER_SMF
#  define BX_SER_THIS this->
#endif

#define BX_SERIAL_MAXDEV   4
#define BX_SERIAL_CONFDEV  1   /* only 1 serial port currently */

#define  BX_PC_CLOCK_XTL   1843200.0

#define  BX_SER_RXIDLE  0
#define  BX_SER_RXPOLL  1
#define  BX_SER_RXWAIT  2

typedef struct {
  /*
   * UART internal state
   */
  Boolean  rx_empty;
  Boolean  tx_empty;
  Boolean  rx_interrupt;
  Boolean  tx_interrupt;

  int  baudrate;
  int  tx_timer_index;

  int  rx_pollstate;
  int  rx_timer_index;

#define RX_CB_SIZE  80
  int  rx_cb_start;
  int  rx_cb_end;
  unsigned char rx_cbuf[RX_CB_SIZE];

  /*
   * Register definitions
   */
  Bit8u     rxbuffer;     /* receiver buffer register (r/o) */
  Bit8u     txbuffer;     /* transmit holding register (w/o) */
  /* Interrupt Enable Register */
  struct {
    Boolean    rxdata_enable;      /* 1=enable receive data interrupts */
    Boolean    txhold_enable;      /* 1=enable tx. holding reg. empty ints */
    Boolean    rxlstat_enable;     /* 1=enable rx line status interrupts */
    Boolean    modstat_enable;     /* 1=enable modem status interrupts */
  } int_enable;
  /* Interrupt Identification Register (r/o) */
  struct {
    Boolean    ipending;           /* 0=interrupt pending */
    Bit8u      int_ID;             /* 3-bit interrupt ID */
    Bit8u      fifo_enabled;       /* 2-bit, set to b11 when FCR0 enabled */
  } int_ident;
  /* FIFO Control Register (w/o) */
  struct {
    Boolean    enable;             /* 1=enable tx and rx FIFOs */
    Boolean    rxreset;            /* 1=clear rx fifo. self-clearing */
    Boolean    txreset;            /* 1=clear tx fifo. self-clearing */
    Boolean    dmamode;            /* 1=DMA mode 1 (unused on PC ?) */
    Bit8u      rxtrigger;          /* 2-bit code for rx fifo trigger level */
  } fifo_cntl;
  /* Line Control Register (r/w) */
  struct {
    Bit8u      wordlen_sel;        /* 2-bit code for char length */
    Boolean    stopbits;           /* select stop bit len */
    Boolean    parity_enable;      /* ... */
    Boolean    evenparity_sel;     /* ... */
    Boolean    stick_parity;       /* ... */
    Boolean    break_cntl;         /* 1=send break signal */
    Boolean    dlab;               /* divisor latch access bit */
  } line_cntl;
  /* MODEM Control Register (r/w) */
  struct {
    Boolean    dtr;                /* DTR output value */
    Boolean    rts;                /* RTS output value */
    Boolean    out1;               /* OUTPUT1 value */
    Boolean    out2;               /* OUTPUT2 value */
    Boolean    local_loopback;     /* 1=loopback mode */
  } modem_cntl;
  /* Line Status Register (r/w) */
  struct {
    Boolean    rxdata_ready;       /* 1=receiver data ready */
    Boolean    overrun_error;      /* 1=receive overrun detected */
    Boolean    parity_error;       /* 1=rx char has a bad parity bit */
    Boolean    framing_error;      /* 1=no stop bit detected for rx char */
    Boolean    break_int;          /* 1=break signal detected */
    Boolean    txhold_empty;       /* 1=tx hold register (or fifo) is empty */
    Boolean    txtransm_empty;     /* 1=shift reg and hold reg empty */
    Boolean    fifo_error;         /* 1=at least 1 err condition in fifo */
  } line_status;
  /* Modem Status Register (r/w) */
  struct {
    Boolean    delta_cts;          /* 1=CTS changed since last read */
    Boolean    delta_dsr;          /* 1=DSR changed since last read */
    Boolean    ri_trailedge;       /* 1=RI moved from low->high */
    Boolean    delta_dcd;          /* 1=CD changed since last read */
    Boolean    cts;                /* CTS input value */
    Boolean    dsr;                /* DSR input value */
    Boolean    ri;                 /* RI input value */
    Boolean    dcd;                /* DCD input value */
  } modem_status;

  Bit8u  scratch;       /* Scratch Register (r/w) */
  Bit8u  divisor_lsb;   /* Divisor latch, least-sig. byte */
  Bit8u  divisor_msb;   /* Divisor latch, most-sig. byte */
} bx_serial_t;



class bx_serial_c {
public:
  bx_serial_c(void);
  ~bx_serial_c(void);
  BX_SER_SMF void   init(bx_devices_c *);

private:
    bx_serial_t s[BX_SERIAL_MAXDEV];

  bx_devices_c *devices;

  static void tx_timer_handler(void *);
  BX_SER_SMF void tx_timer(void);

  static void rx_timer_handler(void *);
  BX_SER_SMF void rx_timer(void);

  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_SER_SMF
  Bit32u read(Bit32u address, unsigned io_len);
  void   write(Bit32u address, Bit32u value, unsigned io_len);
#endif
#if USE_RAW_SERIAL
  serial_raw* raw;
#endif // USE_RAW_SERIAL
  };


#if BX_USE_SER_SMF
extern bx_serial_c bx_serial;
#endif
