Trim CVS logs and cleanup header info.
[bertos.git] / drv / ser.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
6  * All Rights Reserved.
7  * -->
8  *
9  * \brief Buffered serial I/O driver
10  *
11  * The serial rx interrupt buffers incoming data in a software FIFO
12  * to decouple the higher level protocols from the line speed.
13  * Outgoing data is buffered as well for better performance.
14  * This driver is not optimized for best performance, but it
15  * has proved to be fast enough to handle transfer rates up to
16  * 38400bps on a 16MHz 80196.
17  *
18  * MODULE CONFIGURATION
19  *      \li \c CONFIG_SER_HWHANDSHAKE define this preprocessor symbol to enable
20  *      support for RTS/CTS handshake. Support is incomplete/untested
21  *      for 80196.
22  *  \li \c CONFIG_SER_TXTIMEOUT - Enable software serial transmission timeouts
23  *
24  *
25  * \version $Id$
26  * \author Bernardo Innocenti <bernie@develer.com>
27  */
28
29 /*
30  * $Log$
31  * Revision 1.2  2004/05/23 18:21:53  bernie
32  * Trim CVS logs and cleanup header info.
33  *
34  */
35
36 #include <mware/formatwr.h>
37 #include <drv/kdebug.h>
38 #include "ser.h"
39 #include "ser_p.h"
40 #include "hw.h"
41
42 #ifdef CONFIG_KERNEL
43         #include <kern/proc.h>
44 #endif
45 #if defined(CONFIG_SER_TXTIMEOUT) || defined(CONFIG_SER_RXTIMEOUT)
46         #include <drv/timer.h>
47 #endif
48
49
50 /* Serial configuration parameters */
51 #define SER_CTSDELAY        70  /*!< CTS line retry interval (ms) */
52 #define SER_TXPOLLDELAY      2  /*!< Transmit buffer full retry interval (ms) */
53 #define SER_RXPOLLDELAY      2  /*!< Receive buffer empty retry interval (ms) */
54
55
56 struct Serial ser_handles[SER_CNT];
57
58
59 /*!
60  * Inserisce il carattere c nel buffer di trasmissione.
61  * Questa funzione mette il processo chiamante in attesa
62  * quando il buffer e' pieno.
63  *
64  * \return EOF in caso di errore o timeout, altrimenti
65  *         il carattere inviato.
66  */
67 int ser_putchar(int c, struct Serial *port)
68 {
69         if (fifo_isfull_locked(&port->txfifo))
70         {
71 #ifdef CONFIG_SER_TXTIMEOUT
72                 time_t start_time = timer_gettick();
73 #endif
74
75                 /* Attende finche' il buffer e' pieno... */
76                 do
77                 {
78 #ifdef CONFIG_KERN_SCHED
79                         /* Give up timeslice to other processes. */
80                         proc_switch();
81 #endif
82 #ifdef CONFIG_SER_TXTIMEOUT
83                         if (timer_gettick() - start_time >= port->txtimeout)
84                         {
85                                 port->status |= SERRF_TXTIMEOUT;
86                                 return EOF;
87                         }
88 #endif /* CONFIG_SER_TXTIMEOUT */
89                 }
90                 while (fifo_isfull_locked(&port->txfifo));
91         }
92
93         fifo_push(&port->txfifo, (unsigned char)c);
94
95         /* (re)trigger tx interrupt */
96         port->hw->table->enabletxirq(port->hw);
97
98         /* Avoid returning signed estended char */
99         return (int)((unsigned char)c);
100 }
101
102
103 /*!
104  * Preleva un carattere dal buffer di ricezione.
105  * Questa funzione mette il processo chiamante in attesa
106  * quando il buffer e' vuoto. L'attesa ha un timeout
107  * di ser_rxtimeout millisecondi.
108  *
109  * \return EOF in caso di errore o timeout, altrimenti
110  *         il carattere ricevuto.
111  */
112 int ser_getchar(struct Serial *port)
113 {
114         int result;
115
116         if (fifo_isempty_locked(&port->rxfifo))
117         {
118 #ifdef CONFIG_SER_RXTIMEOUT
119                 time_t start_time = timer_gettick();
120 #endif
121                 /* Wait while buffer is empty */
122                 do
123                 {
124 #ifdef CONFIG_KERN_SCHED
125                         /* Give up timeslice to other processes. */
126                         proc_switch();
127 #endif
128 #ifdef CONFIG_SER_RXTIMEOUT
129                         if (timer_gettick() - start_time >= port->rxtimeout)
130                         {
131                                 port->status |= SERRF_RXTIMEOUT;
132                                 return EOF;
133                         }
134 #endif /* CONFIG_SER_RXTIMEOUT */
135                 }
136                 while (fifo_isempty_locked(&port->rxfifo));
137         }
138
139         /*
140          * Get a byte from the FIFO (avoiding sign-extension),
141          * re-enable RTS, then return result.
142          */
143         result = (int)(unsigned char)fifo_pop(&port->rxfifo);
144         return port->status ? EOF : result;
145 }
146
147
148 /*!
149  * Preleva un carattere dal buffer di ricezione.
150  * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
151  * immediatamente EOF.
152  */
153 int ser_getchar_nowait(struct Serial *port)
154 {
155         if (fifo_isempty_locked(&port->rxfifo))
156                 return EOF;
157
158         /* NOTE: the double cast prevents unwanted sign extension */
159         return (int)(unsigned char)fifo_pop(&port->rxfifo);
160 }
161
162
163 /*!
164  * Read a line long at most as size and puts it
165  * in buf.
166  * \return number of chars read or EOF in case
167  *         of error.
168  */
169 int ser_gets(struct Serial *port, char *buf, int size)
170 {
171         return ser_gets_echo(port, buf, size, false);
172 }
173
174
175 /*!
176  * Read a line long at most as size and puts it
177  * in buf, with optional echo.
178  * \return number of chars read or EOF in case
179  *         of error.
180  */
181 int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
182 {
183         int i = 0;
184         int c;
185
186         for (;;)
187         {
188                 if ((c = ser_getchar(port)) == EOF)
189                         return -1;
190                 /* FIXME */
191                 if (c == '\r' || c == '\n' || i >= size-1)
192                 {
193                         buf[i] = '\0';
194                         if (echo)
195                                 ser_print(port, "\r\n");
196                         break;
197                 }
198                 buf[i++] = c;
199                 if (echo)
200                         ser_putchar(c, port);
201         }
202
203         return i;
204 }
205
206
207 /*!
208  * Read at most size bytes and puts them
209  * in buf.
210  * \return number of bytes read or EOF in case
211  *         of error.
212  */
213 int ser_read(struct Serial *port, char *buf, size_t size)
214 {
215         size_t i = 0;
216         int c;
217
218         while (i < size)
219         {
220                 if ((c = ser_getchar(port)) == EOF)
221                         return EOF;
222                 buf[i++] = c;
223         }
224
225         return i;
226 }
227
228
229 /*!
230  * Write a string to serial.
231  * \return 0 if OK, EOF in case of error.
232  */
233 int ser_print(struct Serial *port, const char *s)
234 {
235         while (*s)
236         {
237                 if (ser_putchar(*s++, port) == EOF)
238                         return EOF;
239         }
240         return 0;
241 }
242
243
244 /*!
245  * \brief Write a buffer to serial.
246  *
247  * \return 0 if OK, EOF in case of error.
248  */
249 int ser_write(struct Serial *port, const void *buf, size_t len)
250 {
251         while (len--)
252         {
253                 if (ser_putchar(*((const char *)buf)++, port) == EOF)
254                         return EOF;
255         }
256         return 0;
257 }
258
259
260 /*!
261  * Formatted write
262  */
263 int ser_printf(struct Serial *port, const char *format, ...)
264 {
265         va_list ap;
266         int len;
267
268         ser_setstatus(port, 0);
269         va_start(ap, format);
270         len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
271         va_end(ap);
272
273         return len;
274 }
275
276 #if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
277 void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout)
278 {
279         port->rxtimeout = rxtimeout;
280         port->txtimeout = txtimeout;
281 }
282 #endif /* defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT) */
283
284
285 void ser_setbaudrate(struct Serial *port, unsigned long rate)
286 {
287         port->hw->table->setbaudrate(port->hw, rate);
288 }
289
290
291 void ser_setparity(struct Serial *port, int parity)
292 {
293         port->hw->table->setparity(port->hw, parity);
294 }
295
296
297 /*!
298  * Flush both the RX and TX buffers.
299  */
300 void ser_purge(struct Serial *ser)
301 {
302         fifo_flush(&ser->rxfifo);
303         fifo_flush(&ser->txfifo);
304 }
305
306
307 /*!
308  * Initialize serial
309  */
310 struct Serial *ser_open(unsigned int unit)
311 {
312         struct Serial *port;
313
314         ASSERT(unit < countof(ser_handles));
315
316         port = &ser_handles[unit];
317
318         ASSERT(!port->is_open);
319
320         port->unit = unit;
321         port->is_open = true;
322
323         /* Initialize circular buffer */
324         fifo_init(&port->rxfifo, port->rxbuffer, sizeof(port->rxbuffer));
325         fifo_init(&port->txfifo, port->txbuffer, sizeof(port->txbuffer));
326
327         port->hw = ser_hw_getdesc(unit);
328         port->hw->table->init(port->hw, port);
329
330         /* Set default values */
331 #if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
332         ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
333 #endif
334         ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
335
336         return port;
337 }
338
339
340 /*!
341  * Clean up serial port, disabling the associated hardware.
342  */
343 void ser_close(struct Serial *port)
344 {
345         ASSERT(port->is_open);
346
347         port->is_open = false;
348         port->hw->table->cleanup(port->hw);
349         port->hw = NULL;        
350 }