initial revision
[ucgine.git] / lib / uart / ucg_uart.c
1 /*
2  * Copyright (c) 2005-2015, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <string.h>
29
30 #include <ucg_irq.h>
31 #include <ucg_cirbuf.h>
32 #include <ucg_uart.h>
33
34 /* Send the next char, or disable tx interruptions if tx fifo is
35  * empty. Must be called with intrp locked and uart data register
36  * empty. */
37 static void ucg_uart_send_next_char(struct ucg_uart *uart)
38 {
39         char c;
40
41         if (ucg_cirbuf_is_empty(uart->tx_fifo)) {
42                 uart->ops->disable_tx_irq(uart);
43                 return;
44         }
45
46         c = ucg_cirbuf_get_tail(uart->tx_fifo);
47         ucg_cirbuf_del_tail(uart->tx_fifo);
48         uart->ops->set_udr(uart, c);
49         if (uart->tx_cb != NULL)
50                 uart->tx_cb(c);
51
52         uart->ops->enable_tx_irq(uart);
53
54 }
55
56 /* Receive char and put it in the fifo. If the rx fifo is full, the char
57  * is dropped. Must be called with intrp locked and uart data register
58  * empty. */
59 static void ucg_uart_recv_next_char(struct ucg_uart *uart)
60 {
61         char c;
62
63         c = uart->ops->get_udr(uart);
64
65         if (!ucg_cirbuf_is_full(uart->rx_fifo))
66                 ucg_cirbuf_add_head(uart->rx_fifo, c);
67
68         if (uart->rx_cb != NULL)
69                 uart->rx_cb(c);
70 }
71
72 /* called by user to handle the "tx register empty" interrupt */
73 void ucg_uart_tx_intr(struct ucg_uart *uart)
74 {
75         ucg_uart_send_next_char(uart);
76 }
77
78 /* called by user to handle the "rx register non empty" interrupt */
79 void ucg_uart_rx_intr(struct ucg_uart *uart)
80 {
81         ucg_uart_recv_next_char(uart);
82 }
83
84
85 /* get a char from the receive fifo */
86 static int ucg_uart_recv_nowait(struct ucg_uart *uart)
87 {
88         char c = 0;
89         ucg_irqflags_t flags;
90
91         flags = ucg_irq_lock_save();
92         if (ucg_cirbuf_is_empty(uart->rx_fifo)) {
93                 ucg_irq_unlock_restore(flags);
94                 return -1;
95         }
96
97         c = ucg_cirbuf_get_tail(uart->rx_fifo);
98         ucg_cirbuf_del_tail(uart->rx_fifo);
99         ucg_irq_unlock_restore(flags);
100
101         return (int)c;
102 }
103
104 /* get a char from the receive fifo */
105 int ucg_uart_recv(struct ucg_uart *uart, enum ucg_uart_wait wait)
106 {
107         int c = 0;
108
109         c = ucg_uart_recv_nowait(uart);
110         if (c >= 0)
111                 return c;
112
113         if (wait == NOWAIT)
114                 return -1;
115
116         if (ucg_irq_locked()) {
117                 /* if irq are masked we have to poll uart register */
118                 while (!uart->ops->rx_ready(uart))
119                         ;
120
121                 /* then receive the data, and return it */
122                 ucg_uart_recv_next_char(uart);
123                 c = ucg_uart_recv_nowait(uart);
124         } else {
125                 while ((c = ucg_uart_recv_nowait(uart)) == -1)
126                         ;
127         }
128
129         return c;
130 }
131
132 /* send a char, or put it in the fifo if uart is not ready. Return -1
133  * if fifo is full */
134 static int ucg_uart_send_nowait(struct ucg_uart *uart, char c)
135 {
136         ucg_irqflags_t flags;
137
138         flags = ucg_irq_lock_save();
139
140         if (ucg_cirbuf_is_full(uart->tx_fifo)) {
141                 ucg_irq_unlock_restore(flags);
142                 return -1;
143         }
144
145         /* uart is ready to send */
146         if (ucg_cirbuf_is_empty(uart->tx_fifo) && uart->ops->tx_ready(uart)) {
147                 uart->ops->set_udr(uart, c);
148                 if (uart->tx_cb != NULL)
149                         uart->tx_cb(c);
150                 uart->ops->enable_tx_irq(uart);
151
152         }
153         else { /* not ready, put char in fifo */
154                 ucg_cirbuf_add_head(uart->tx_fifo, c);
155         }
156
157         ucg_irq_unlock_restore(flags);
158         return 0;
159 }
160
161 /* send a byte */
162 int ucg_uart_send(struct ucg_uart *uart, char c, enum ucg_uart_wait wait)
163 {
164         /* try to send the char */
165         if (ucg_uart_send_nowait(uart, c) == 0)
166                 return 0;
167
168         if (wait == NOWAIT)
169                 return -1;
170
171         if (ucg_irq_locked()) {
172                 /* if irq are masked we have to poll uart register */
173                 while (!uart->ops->tx_ready(uart))
174                         ;
175
176                 /* then send a data to free a room in the fifo */
177                 ucg_uart_send_next_char(uart);
178                 ucg_cirbuf_add_head(uart->tx_fifo, c);
179         } else {
180                 /* if irq are not locked, we can loop to emit */
181                 while (ucg_uart_send_nowait(uart, c) != 0)
182                         ;
183         }
184         return 0;
185 }
186
187 /* flush the tx fifo */
188 void ucg_uart_flush(struct ucg_uart *uart)
189 {
190         ucg_irqflags_t flags;
191
192         if (ucg_irq_locked()) {
193                 /* poll uart register, and send next byte until tx fifo
194                  * is empty */
195                 while (1) {
196                         if (ucg_cirbuf_is_empty(uart->tx_fifo))
197                                 break;
198                         while (!uart->ops->tx_ready(uart))
199                                 ;
200                         ucg_uart_send_next_char(uart);
201                 }
202         } else {
203                 /* just wait that tx fifo is empty */
204                 while (1) {
205                         flags = ucg_irq_lock_save();
206                         if (ucg_cirbuf_is_empty(uart->tx_fifo)) {
207                                 ucg_irq_unlock_restore(flags);
208                                 break;
209                         }
210                         ucg_irq_unlock_restore(flags);
211                 }
212         }
213 }
214
215 /* read the current running configuration */
216 void ucg_uart_getconf(struct ucg_uart *uart, struct ucg_uart_config *conf)
217 {
218         memcpy(conf, &uart->conf, sizeof(*conf));
219 }
220
221 /* set a new uart config */
222 int ucg_uart_setconf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
223 {
224         int ret;
225
226         ret = uart->ops->set_conf(uart, conf);
227         if (ret < 0)
228                 return ret;
229
230         memcpy(&uart->conf, conf, sizeof(*conf));
231         return 0;
232 }
233
234 /* register the function that will be executed at each byte transmission */
235 void ucg_uart_register_tx_cb(struct ucg_uart *uart, void (*f)(char))
236 {
237         ucg_irqflags_t flags;
238
239         flags = ucg_irq_lock_save();
240         uart->tx_cb = f;
241         ucg_irq_unlock_restore(flags);
242 }
243
244 /* register the function that will be executed at each byte reception */
245 void ucg_uart_register_rx_cb(struct ucg_uart *uart, void (*f)(char))
246 {
247         ucg_irqflags_t flags;
248
249         flags = ucg_irq_lock_save();
250         uart->rx_cb = f;
251         ucg_irq_unlock_restore(flags);
252 }
253
254 /* init uart and fifos, call the per-arch initialization and set a default
255  * configuration (9600 bauds) */
256 int ucg_uart_init(struct ucg_uart *uart,
257         const struct ucg_uart_driver_ops *ops, void *driver_data,
258         struct ucg_cirbuf *rx_cbuf, char *rx_buf, unsigned rx_bufsize,
259         struct ucg_cirbuf *tx_cbuf, char *tx_buf, unsigned tx_bufsize)
260 {
261         int ret;
262
263         const struct ucg_uart_config def_conf = {
264                 .enable = 1,
265                 .parity = 0,
266                 .stop_bits = 0,
267                 .reserved = 0,
268                 .nbits = 8,
269                 .baudrate = 9600,
270         };
271
272         memset(uart, 0, sizeof(*uart));
273         ucg_cirbuf_init(rx_cbuf, rx_buf, 0, rx_bufsize);
274         ucg_cirbuf_init(tx_cbuf, tx_buf, 0, tx_bufsize);
275         uart->rx_fifo = rx_cbuf;
276         uart->tx_fifo = tx_cbuf;
277         uart->ops = ops;
278         uart->driver_data = driver_data;
279         ret = ucg_uart_setconf(uart, &def_conf);
280
281         return ret;
282 }