4 * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
5 * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
9 * \brief Buffered serial I/O driver
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.
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
22 * \li \c CONFIG_SER_TXTIMEOUT - Enable software serial transmission timeouts
26 * \author Bernardo Innocenti <bernie@develer.com>
31 * Revision 1.3 2004/06/02 21:35:24 aleph
32 * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
34 * Revision 1.2 2004/05/23 18:21:53 bernie
35 * Trim CVS logs and cleanup header info.
39 #include <mware/formatwr.h>
40 #include <drv/kdebug.h>
46 #include <kern/proc.h>
48 #if defined(CONFIG_SER_TXTIMEOUT) || defined(CONFIG_SER_RXTIMEOUT)
49 #include <drv/timer.h>
53 /* Serial configuration parameters */
54 #define SER_CTSDELAY 70 /*!< CTS line retry interval (ms) */
55 #define SER_TXPOLLDELAY 2 /*!< Transmit buffer full retry interval (ms) */
56 #define SER_RXPOLLDELAY 2 /*!< Receive buffer empty retry interval (ms) */
59 struct Serial ser_handles[SER_CNT];
63 * Inserisce il carattere c nel buffer di trasmissione.
64 * Questa funzione mette il processo chiamante in attesa
65 * quando il buffer e' pieno.
67 * \return EOF in caso di errore o timeout, altrimenti
68 * il carattere inviato.
70 int ser_putchar(int c, struct Serial *port)
72 if (fifo_isfull_locked(&port->txfifo))
74 #ifdef CONFIG_SER_TXTIMEOUT
75 time_t start_time = timer_gettick();
78 /* Attende finche' il buffer e' pieno... */
81 #ifdef CONFIG_KERN_SCHED
82 /* Give up timeslice to other processes. */
85 #ifdef CONFIG_SER_TXTIMEOUT
86 if (timer_gettick() - start_time >= port->txtimeout)
88 port->status |= SERRF_TXTIMEOUT;
91 #endif /* CONFIG_SER_TXTIMEOUT */
93 while (fifo_isfull_locked(&port->txfifo));
96 fifo_push(&port->txfifo, (unsigned char)c);
98 /* (re)trigger tx interrupt */
99 port->hw->table->enabletxirq(port->hw);
101 /* Avoid returning signed estended char */
102 return (int)((unsigned char)c);
107 * Preleva un carattere dal buffer di ricezione.
108 * Questa funzione mette il processo chiamante in attesa
109 * quando il buffer e' vuoto. L'attesa ha un timeout
110 * di ser_rxtimeout millisecondi.
112 * \return EOF in caso di errore o timeout, altrimenti
113 * il carattere ricevuto.
115 int ser_getchar(struct Serial *port)
119 if (fifo_isempty_locked(&port->rxfifo))
121 #ifdef CONFIG_SER_RXTIMEOUT
122 time_t start_time = timer_gettick();
124 /* Wait while buffer is empty */
127 #ifdef CONFIG_KERN_SCHED
128 /* Give up timeslice to other processes. */
131 #ifdef CONFIG_SER_RXTIMEOUT
132 if (timer_gettick() - start_time >= port->rxtimeout)
134 port->status |= SERRF_RXTIMEOUT;
137 #endif /* CONFIG_SER_RXTIMEOUT */
139 while (fifo_isempty_locked(&port->rxfifo));
143 * Get a byte from the FIFO (avoiding sign-extension),
144 * re-enable RTS, then return result.
146 result = (int)(unsigned char)fifo_pop(&port->rxfifo);
147 return port->status ? EOF : result;
152 * Preleva un carattere dal buffer di ricezione.
153 * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
154 * immediatamente EOF.
156 int ser_getchar_nowait(struct Serial *port)
158 if (fifo_isempty_locked(&port->rxfifo))
161 /* NOTE: the double cast prevents unwanted sign extension */
162 return (int)(unsigned char)fifo_pop(&port->rxfifo);
167 * Read a line long at most as size and puts it
169 * \return number of chars read or EOF in case
172 int ser_gets(struct Serial *port, char *buf, int size)
174 return ser_gets_echo(port, buf, size, false);
179 * Read a line long at most as size and puts it
180 * in buf, with optional echo.
181 * \return number of chars read or EOF in case
184 int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
191 if ((c = ser_getchar(port)) == EOF)
194 if (c == '\r' || c == '\n' || i >= size-1)
198 ser_print(port, "\r\n");
203 ser_putchar(c, port);
211 * Read at most size bytes and puts them
213 * \return number of bytes read or EOF in case
216 int ser_read(struct Serial *port, char *buf, size_t size)
223 if ((c = ser_getchar(port)) == EOF)
233 * Write a string to serial.
234 * \return 0 if OK, EOF in case of error.
236 int ser_print(struct Serial *port, const char *s)
240 if (ser_putchar(*s++, port) == EOF)
248 * \brief Write a buffer to serial.
250 * \return 0 if OK, EOF in case of error.
252 int ser_write(struct Serial *port, const void *buf, size_t len)
256 if (ser_putchar(*((const char *)buf)++, port) == EOF)
266 int ser_printf(struct Serial *port, const char *format, ...)
271 ser_setstatus(port, 0);
272 va_start(ap, format);
273 len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
279 #if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
280 void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout)
282 port->rxtimeout = rxtimeout;
283 port->txtimeout = txtimeout;
285 #endif /* defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT) */
288 void ser_setbaudrate(struct Serial *port, unsigned long rate)
290 port->hw->table->setbaudrate(port->hw, rate);
294 void ser_setparity(struct Serial *port, int parity)
296 port->hw->table->setparity(port->hw, parity);
301 * Flush both the RX and TX buffers.
303 void ser_purge(struct Serial *ser)
305 fifo_flush(&ser->rxfifo);
306 fifo_flush(&ser->txfifo);
313 struct Serial *ser_open(unsigned int unit)
317 ASSERT(unit < countof(ser_handles));
319 port = &ser_handles[unit];
321 ASSERT(!port->is_open);
324 port->is_open = true;
326 /* Initialize circular buffer */
327 fifo_init(&port->rxfifo, port->rxbuffer, sizeof(port->rxbuffer));
328 fifo_init(&port->txfifo, port->txbuffer, sizeof(port->txbuffer));
330 port->hw = ser_hw_getdesc(unit);
331 port->hw->table->init(port->hw, port);
333 /* Set default values */
334 #if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
335 ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
337 ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
344 * Clean up serial port, disabling the associated hardware.
346 void ser_close(struct Serial *port)
348 ASSERT(port->is_open);
350 port->is_open = false;
351 port->hw->table->cleanup(port->hw);