00001
00002
00003 #ifndef __pc_uart_h
00004 #define __pc_uart_h
00005
00006 #include <uart.h>
00007 #include <cpu.h>
00008
00009 __BEGIN_SYS
00010
00011
00012 class NS16550AF
00013 {
00014 private:
00015 typedef CPU::IO_Port IO_Port;
00016 typedef CPU::Reg8 Reg8;
00017 typedef CPU::Reg16 Reg16;
00018
00019 public:
00020
00021 typedef Reg8 Address;
00022 enum {
00023 THR = 0,
00024 RBR = 0,
00025 IER = 1,
00026 FCR = 2,
00027 IIR = 2,
00028 LCR = 3,
00029 MCR = 4,
00030 LSR = 5,
00031
00032 MSR = 6,
00033
00034 SCR = 7,
00035 DLL = 0,
00036 DLH = 1
00037 };
00038
00039 public:
00040 NS16550AF(IO_Port p) : _port(p) {}
00041 NS16550AF(IO_Port p, unsigned int div, unsigned int dbits,
00042 unsigned int par, unsigned int sbits) : _port(p) {
00043 config(div, dbits, par, sbits);
00044 }
00045
00046 void config(unsigned int div, unsigned int dbits,
00047 unsigned int par, unsigned int sbits) {
00048
00049 reg(IER, 0);
00050
00051
00052 dlab(true);
00053 reg(DLL, div);
00054 reg(DLH, div >> 8);
00055 dlab(false);
00056
00057
00058 Reg8 lcr = dbits - 5;
00059
00060
00061 if(par) {
00062 lcr |= 1 << 3;
00063 lcr |= (par - 1) << 4;
00064 }
00065
00066
00067 lcr |= (sbits > 1) ? (1 << 2) : 0;
00068
00069 reg(LCR, lcr);
00070
00071
00072 reg(FCR, 0xc7);
00073
00074
00075 reg(MCR, reg(MCR) | 0x0b);
00076 }
00077
00078 void config(unsigned int * div, unsigned int * dbits,
00079 unsigned int * par, unsigned int * sbits) {
00080
00081 dlab(true);
00082 *div = (reg(DLH) << 8) | reg(DLL);
00083 dlab(false);
00084
00085 Reg8 lcr = reg(LCR);
00086
00087
00088 *dbits = (lcr & 0x03) + 5;
00089
00090
00091 *par = (lcr & 0x08) ? ((lcr & 0x10) ? 2 : 1 ) : 0;
00092
00093
00094 *sbits = (lcr & 0x04) ? ((*dbits == 5) ? 3 : 2 ) : 1;
00095 }
00096
00097 Reg8 rxd() { return reg(RBR); }
00098 void txd(Reg8 c) { reg(THR, c); }
00099
00100 void reset() {
00101
00102 unsigned int b, db, p, sb;
00103 config(&b, &db, &p, &sb);
00104 config(b, db, p, sb);
00105 }
00106
00107 void loopback(bool flag) { reg(MCR, reg(MCR) | (flag << 4)); }
00108
00109 void int_enable(bool receive = true, bool send = true,
00110 bool line = true, bool modem = true) {
00111 reg(IER, receive | (send << 1) | (line << 2) | (modem << 3));
00112 }
00113 void int_disable() { reg(IER, 0); }
00114
00115 bool rxd_full() { return reg(LSR) & (1 << 0); }
00116 bool txd_empty() { return reg(LSR) & (1 << 5); }
00117
00118 void dtr() { reg(MCR, reg(MCR) | (1 << 0)); }
00119 void rts() { reg(MCR, reg(MCR) | (1 << 1)); }
00120 bool cts() { return reg(MSR) & (1 << 0); }
00121 bool dsr() { return reg(MSR) & (1 << 1); }
00122 bool dcd() { return reg(MSR) & (1 << 3); }
00123 bool ri() { return reg(MSR) & (1 << 2); }
00124
00125 bool overrun_error() { return reg(LSR) & (1 << 1); }
00126 bool parity_error() { return reg(LSR) & (1 << 2); }
00127 bool framing_error() { return reg(LSR) & (1 << 3); }
00128
00129 private:
00130 Reg8 reg(Address addr) { return CPU::in8(_port + addr); }
00131 void reg(Address addr, Reg8 value) { CPU::out8(_port + addr, value); }
00132
00133 void dlab(bool f) { reg(LCR, reg(LCR) & 0x7f | (f << 7)); }
00134
00135 private:
00136 IO_Port _port;
00137 };
00138
00139 class PC_UART: public UART_Common, private NS16550AF
00140 {
00141 private:
00142 typedef CPU::IO_Port IO_Port;
00143 typedef CPU::Reg8 Reg8;
00144 typedef CPU::Reg16 Reg16;
00145
00146 static const unsigned int CLOCK = Traits<PC_UART>::CLOCK / 16;
00147
00148 public:
00149 PC_UART(unsigned int unit = 0) : NS16550AF(0x3f8) {}
00150 PC_UART(unsigned int baud, unsigned int data_bits, unsigned int parity,
00151 unsigned int stop_bits, unsigned int unit = 0)
00152 : NS16550AF(0x3f8, CLOCK / baud, data_bits, parity, stop_bits) {}
00153
00154 void config(unsigned int baud, unsigned int data_bits,
00155 unsigned int parity, unsigned int stop_bits) {
00156 NS16550AF::config(CLOCK / baud, data_bits, parity, stop_bits);
00157 }
00158 void config(unsigned int * baud, unsigned int * data_bits,
00159 unsigned int * parity, unsigned int * stop_bits) {
00160 NS16550AF::config(*baud, *data_bits, *parity, *stop_bits);
00161 *baud = CLOCK / *baud;
00162 }
00163
00164 char get() { while(!rxd_full()); return rxd(); }
00165 void put(char c) { while(!txd_empty()); txd(c); }
00166
00167 void loopback(bool flag) { NS16550AF::loopback(flag); }
00168
00169
00170 enum {
00171 FULL = 0,
00172 LIGHT = 1,
00173 STANDBY = 2,
00174 OFF = 3
00175 };
00176 void power(unsigned char ps) {}
00177 unsigned char power() { return 0; }
00178
00179 static int init(System_Info *si);
00180
00181
00182 };
00183
00184 __END_SYS
00185
00186 #endif