SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2000  David Decotigny, The KOS Team
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
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 /* Default parameters */
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 /* The offsets of UART registers.  */
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 /* For LSR bits.  */
052 #define UART_DATA_READY         0x01
053 #define UART_EMPTY_TRANSMITTER  0x20
054 
055 /* The type of parity.  */
056 #define UART_NO_PARITY          0x00
057 #define UART_ODD_PARITY         0x08
058 #define UART_EVEN_PARITY        0x18
059 
060 /* The type of word length.  */
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 /* The type of the length of stop bit.  */
067 #define UART_1_STOP_BIT         0x00
068 #define UART_2_STOP_BITS        0x04
069 
070 /* the switch of DLAB.  */
071 #define UART_DLAB               0x80
072 
073 /* Enable the FIFO.  */
074 #define UART_ENABLE_FIFO        0xC7
075 
076 /* Turn on DTR, RTS, and OUT2.  */
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   /* Wait until data is ready.  */
113   while ((serial_inb (_serial_config[unit].iobase + UART_LSR)
114           & UART_DATA_READY) == 0)
115     ;
116 
117   /* Read and return the data.  */
118   return serial_inb (_serial_config[unit].iobase + UART_RX);
119 }
120 
121 
122 /* 0 on success */
123 static int
124 serial_putchar (unsigned short port, char c)
125 {
126   /* Perhaps a timeout is necessary.  */
127   int timeout = 10000;
128 
129   /* Wait until the transmitter holding register is empty.  */
130   while ((serial_inb (port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
131     if (--timeout == 0)
132       /* There is something wrong. But what can I do?  */
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       /* Little hacks to get it to work with Qemu serial port
181          emulation. */
182       if (chr == '\r')
183         chr = '\n';
184       else if (chr == 127)
185         chr = '\b';
186 
187       /* Build a null-terminated string */
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   int i;
199 
200   /* The serial port doesn't understand '\b', but requires ANSI
201      commands instead. So we emulate '\b' by outputing "\e[D \e[D"
202      which basically goes backward one character, prints a space and
203      goes backward one character again. */
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 /* OK On success */
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   /* Turn off the interrupt.  */
241   serial_outb (serial_port + UART_IER, 0);
242 
243   /* Set DLAB.  */
244   serial_outb (serial_port + UART_LCR, UART_DLAB);
245 
246   /* Set the baud rate.  */
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   /* Set the line status.  */
256   status |= parity | word_len | stop_bit_len;
257   serial_outb (serial_port + UART_LCR, status);
258 
259   /* Enable the FIFO.  */
260   serial_outb (serial_port + UART_FCR, UART_ENABLE_FIFO);
261 
262   /* Turn on DTR, RTS, and OUT2.  */
263   serial_outb (serial_port + UART_MCR, UART_ENABLE_MODEM);
264 
265   /* Drain the input buffer.  */
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 /* Cannot be placed in sos_serial_subsystem_init() because when it
276    gets called, the IRQ handling subsystem is not yet initialized */
277 sos_ret_t sos_ttyS0_subsystem_setup (void)
278 {
279   sos_ret_t ret;
280 
281   /* FIXME */
282   ret = tty_create (SOS_CHARDEV_SERIAL_MINOR, sos_serial_putchar,
283                     & _serial_config[0].tty);
284   if (SOS_OK != ret)
285     return ret;
286 
287   sos_irq_set_routine (SOS_IRQ_COM1, serial_irq_handler);
288 
289   /* Enable interrupts */
290   serial_outb (_serial_config[0].iobase + UART_IER, 1);
291 
292   return SOS_OK;
293 }

source navigation ] diff markup ] identifier search ] general search ]