001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/errno.h>
020 #include <hwcore/ioports.h>
021 #include <sos/klibc.h>
022 #include <hwcore/irq.h>
023 #include <drivers/devices.h>
024
025 #include "tty.h"
026
027 #define SERIAL_BAUDRATE_MAX 115200
028
029
030 #ifndef DEBUG_SERIAL_PORT
031 # define DEBUG_SERIAL_PORT 0
032 #endif
033 #ifndef DEBUG_SERIAL_SPEED
034 # define DEBUG_SERIAL_SPEED 9600
035 #endif
036
037
038 #define UART_TX 0
039 #define UART_RX 0
040 #define UART_DLL 0
041 #define UART_IER 1
042 #define UART_DLH 1
043 #define UART_IIR 2
044 #define UART_FCR 2
045 #define UART_LCR 3
046 #define UART_MCR 4
047 #define UART_LSR 5
048 #define UART_MSR 6
049 #define UART_SR 7
050
051
052 #define UART_DATA_READY 0x01
053 #define UART_EMPTY_TRANSMITTER 0x20
054
055
056 #define UART_NO_PARITY 0x00
057 #define UART_ODD_PARITY 0x08
058 #define UART_EVEN_PARITY 0x18
059
060
061 #define UART_5BITS_WORD 0x00
062 #define UART_6BITS_WORD 0x01
063 #define UART_7BITS_WORD 0x02
064 #define UART_8BITS_WORD 0x03
065
066
067 #define UART_1_STOP_BIT 0x00
068 #define UART_2_STOP_BITS 0x04
069
070
071 #define UART_DLAB 0x80
072
073
074 #define UART_ENABLE_FIFO 0xC7
075
076
077 #define UART_ENABLE_MODEM 0x0B
078
079
080 static struct
081 {
082 unsigned short iobase;
083 unsigned short is_enabled;
084 struct tty_device *tty;
085 } _serial_config [] = { { 0x3f8, FALSE },
086 { 0x2f8, FALSE },
087 { 0x3e8, FALSE },
088 { 0x2e8, FALSE } };
089
090 #define SERIAL_PORT_MAX 4
091
092 #define serial_inb inb
093 #define serial_outb(port,val) outb(val,port)
094
095 inline static int
096 serial_isready (unsigned short port)
097 {
098 unsigned char status;
099
100 status = serial_inb (port + UART_LSR);
101 return (status & UART_DATA_READY) ? : -1;
102 }
103
104
105 static char
106 serial_getchar (unsigned short unit)
107 {
108 if(unit >= SERIAL_PORT_MAX
109 || _serial_config[unit].is_enabled == FALSE)
110 return -1;
111
112
113 while ((serial_inb (_serial_config[unit].iobase + UART_LSR)
114 & UART_DATA_READY) == 0)
115 ;
116
117
118 return serial_inb (_serial_config[unit].iobase + UART_RX);
119 }
120
121
122
123 static int
124 serial_putchar (unsigned short port, char c)
125 {
126
127 int timeout = 10000;
128
129
130 while ((serial_inb (port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
131 if (--timeout == 0)
132
133 return -1;
134
135 serial_outb (port + UART_TX, c);
136 return 0;
137 }
138
139 static char serial_printk_buf[1024];
140
141 inline static int serial_prints(unsigned short unit, const char *str)
142 {
143 const char *c;
144 unsigned short port;
145
146 if(unit >= SERIAL_PORT_MAX
147 || _serial_config[unit].is_enabled == FALSE)
148 return -1;
149
150 port = _serial_config[unit].iobase;
151
152 for (c = str; *c != '\0'; c++)
153 serial_putchar(port, *c);
154
155
156 return (int) (c-str);
157 }
158
159 int sos_serial_printf(unsigned short unit, const char *format, ...)
160 {
161 va_list args;
162 int len;
163
164 va_start(args, format);
165 len=vsnprintf(serial_printk_buf,sizeof(serial_printk_buf),format,args);
166
167 return serial_prints(unit, serial_printk_buf);
168 }
169
170
171 static void serial_irq_handler (int irq_level)
172 {
173 unsigned char chr;
174
175 if (irq_level == SOS_IRQ_COM1)
176 {
177 char c[2];
178 chr = serial_inb (_serial_config[0].iobase + UART_RX);
179
180
181
182 if (chr == '\r')
183 chr = '\n';
184 else if (chr == 127)
185 chr = '\b';
186
187
188 c[0] = chr;
189 c[1] = '\0';
190
191 tty_add_chars (_serial_config[0].tty, c);
192 }
193 }
194
195 static sos_ret_t sos_serial_putchar (char c)
196 {
197 sos_ret_t ret;
198 unsigned int i;
199
200
201
202
203
204 if (c == '\b')
205 {
206 const char *str = "\e[D \e[D";
207
208 for (i = 0; i < strlen(str); i++)
209 {
210 ret = serial_putchar (_serial_config[0].iobase, str[i]);
211 if (ret != SOS_OK)
212 return ret;
213 }
214
215 return SOS_OK;
216 }
217
218 return serial_putchar (_serial_config[0].iobase, c);
219 }
220
221
222
223 sos_ret_t sos_serial_subsystem_setup (sos_bool_t enable)
224 {
225 unsigned short div = 0;
226 unsigned char status = 0;
227 unsigned short serial_port;
228
229 unsigned short unit = 0;
230 unsigned int speed = 115200;
231 int word_len = UART_8BITS_WORD;
232 int parity = UART_NO_PARITY;
233 int stop_bit_len = UART_1_STOP_BIT;
234
235 if (unit >= SERIAL_PORT_MAX)
236 return -1;
237
238 serial_port = _serial_config[unit].iobase;
239
240
241 serial_outb (serial_port + UART_IER, 0);
242
243
244 serial_outb (serial_port + UART_LCR, UART_DLAB);
245
246
247 if (speed > SERIAL_BAUDRATE_MAX)
248 return -1;
249
250 div = SERIAL_BAUDRATE_MAX / speed;
251
252 serial_outb (serial_port + UART_DLL, div & 0xFF);
253 serial_outb (serial_port + UART_DLH, div >> 8);
254
255
256 status |= parity | word_len | stop_bit_len;
257 serial_outb (serial_port + UART_LCR, status);
258
259
260 serial_outb (serial_port + UART_FCR, UART_ENABLE_FIFO);
261
262
263 serial_outb (serial_port + UART_MCR, UART_ENABLE_MODEM);
264
265
266 while (serial_isready (serial_port) != -1)
267 (void) serial_getchar (unit);
268
269 _serial_config[unit].is_enabled = TRUE;
270
271 return SOS_OK;
272 }
273
274
275
276
277 sos_ret_t sos_ttyS0_subsystem_setup (void)
278 {
279 sos_ret_t ret;
280
281 ret = tty_create (SOS_CHARDEV_SERIAL_MINOR, sos_serial_putchar,
282 & _serial_config[0].tty);
283 if (SOS_OK != ret)
284 return ret;
285
286 sos_irq_set_routine (SOS_IRQ_COM1, serial_irq_handler);
287
288
289 serial_outb (_serial_config[0].iobase + UART_IER, 1);
290
291 return SOS_OK;
292 }