1 /*
2 * File : serial.c
3 * This file is part of RT-Thread RTOS
4 * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Change Logs:
21 * Date Author Notes
22 * 2013-03-16 Peng Fan Modified from sep4020
23 */
24 #include <rtthread.h>
25 #include <rthw.h>
26 #include "serial.h"
27
28 /**
29 * @addtogroup sep6200
30 */
31 /*@{*/
32
33 /* RT-Thread Device Interface */
34 /**
35 * This function initializes serial
36 */
rt_serial_init(rt_device_t dev)37 static rt_err_t rt_serial_init (rt_device_t dev)
38 {
39 struct serial_device* uart = (struct serial_device*) dev->user_data;
40
41 if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
42 {
43
44 if (dev->flag & RT_DEVICE_FLAG_INT_RX)
45 {
46 rt_memset(uart->int_rx->rx_buffer, 0,
47 sizeof(uart->int_rx->rx_buffer));
48 uart->int_rx->read_index = uart->int_rx->save_index = 0;
49 }
50
51 if (dev->flag & RT_DEVICE_FLAG_INT_TX)
52 {
53 rt_memset(uart->int_tx->tx_buffer, 0,
54 sizeof(uart->int_tx->tx_buffer));
55 uart->int_tx->write_index = uart->int_tx->save_index = 0;
56 }
57
58 dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
59 }
60
61 return RT_EOK;
62 }
63
64 /* save a char to serial buffer */
rt_serial_savechar(struct serial_device * uart,char ch)65 static void rt_serial_savechar(struct serial_device* uart, char ch)
66 {
67 rt_base_t level;
68
69 /* disable interrupt */
70 level = rt_hw_interrupt_disable();
71
72 uart->int_rx->rx_buffer[uart->int_rx->save_index] = ch;
73 uart->int_rx->save_index ++;
74 if (uart->int_rx->save_index >= UART_RX_BUFFER_SIZE)
75 uart->int_rx->save_index = 0;
76
77 /* if the next position is read index, discard this 'read char' */
78 if (uart->int_rx->save_index == uart->int_rx->read_index)
79 {
80 uart->int_rx->read_index ++;
81 if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
82 uart->int_rx->read_index = 0;
83 }
84
85 /* enable interrupt */
86 rt_hw_interrupt_enable(level);
87 }
88
rt_serial_open(rt_device_t dev,rt_uint16_t oflag)89 static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
90 {
91 RT_ASSERT(dev != RT_NULL);
92 return RT_EOK;
93 }
94
rt_serial_close(rt_device_t dev)95 static rt_err_t rt_serial_close(rt_device_t dev)
96 {
97 RT_ASSERT(dev != RT_NULL);
98 return RT_EOK;
99 }
100
rt_serial_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)101 static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
102 {
103 rt_uint8_t* ptr;
104 rt_err_t err_code;
105 struct serial_device* uart;
106
107 ptr = buffer;
108 err_code = RT_EOK;
109 uart = (struct serial_device*)dev->user_data;
110
111 if (dev->flag & RT_DEVICE_FLAG_INT_RX)
112 {
113 rt_base_t level;
114
115 /* interrupt mode Rx */
116 while (size)
117 {
118 if (uart->int_rx->read_index != uart->int_rx->save_index)
119 {
120 *ptr++ = uart->int_rx->rx_buffer[uart->int_rx->read_index];
121 size --;
122
123 /* disable interrupt */
124 level = rt_hw_interrupt_disable();
125
126 uart->int_rx->read_index ++;
127 if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
128 uart->int_rx->read_index = 0;
129
130 /* enable interrupt */
131 rt_hw_interrupt_enable(level);
132 }
133 else
134 {
135 /* set error code */
136 err_code = -RT_EEMPTY;
137 break;
138 }
139 }
140 }
141 else
142 {
143 /* polling mode */
144 while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size)
145 {
146 while (uart->uart_device->lsr & USTAT_RCV_READY)
147 {
148 *ptr = uart->uart_device->dlbl_fifo.txfifo & 0xff;
149 ptr ++;
150 }
151 }
152 }
153
154 /* set error code */
155 rt_set_errno(err_code);
156 return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
157 }
158
rt_serial_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)159 static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
160 {
161 rt_uint8_t* ptr;
162 rt_err_t err_code;
163 struct serial_device* uart;
164
165 err_code = RT_EOK;
166 ptr = (rt_uint8_t*)buffer;
167 uart = (struct serial_device*)dev->user_data;
168
169 if (dev->flag & RT_DEVICE_FLAG_INT_TX)
170 {
171 /* interrupt mode Tx */
172 while (uart->int_tx->save_index != uart->int_tx->write_index)
173 {
174 /* save on tx buffer */
175 uart->int_tx->tx_buffer[uart->int_tx->save_index] = *ptr++;
176
177 -- size;
178
179 /* move to next position */
180 uart->int_tx->save_index ++;
181
182 /* wrap save index */
183 if (uart->int_tx->save_index >= UART_TX_BUFFER_SIZE)
184 uart->int_tx->save_index = 0;
185 }
186
187 /* set error code */
188 if (size > 0)
189 err_code = -RT_EFULL;
190 }
191 else
192 {
193 /* polling mode */
194 while (size)
195 {
196 /*
197 * to be polite with serial console add a line feed
198 * to the carriage return character
199 */
200 if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM))
201 {
202 while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY));
203 uart->uart_device->dlbl_fifo.txfifo = '\r';
204 }
205
206 while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY));
207 uart->uart_device->dlbl_fifo.txfifo = (*ptr & 0x1FF);
208
209 ++ptr; --size;
210 }
211 }
212
213 /* set error code */
214 rt_set_errno(err_code);
215
216 return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
217 }
218
rt_serial_control(rt_device_t dev,int cmd,void * args)219 static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args)
220 {
221 RT_ASSERT(dev != RT_NULL);
222
223 switch (cmd)
224 {
225 case RT_DEVICE_CTRL_SUSPEND:
226 /* suspend device */
227 dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
228 break;
229
230 case RT_DEVICE_CTRL_RESUME:
231 /* resume device */
232 dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
233 break;
234 }
235
236 return RT_EOK;
237 }
238
239 /*
240 * serial register
241 */
rt_hw_serial_register(rt_device_t device,const char * name,rt_uint32_t flag,struct serial_device * serial)242 rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial)
243 {
244 RT_ASSERT(device != RT_NULL);
245
246 device->type = RT_Device_Class_Char;
247 device->rx_indicate = RT_NULL;
248 device->tx_complete = RT_NULL;
249 device->init = rt_serial_init;
250 device->open = rt_serial_open;
251 device->close = rt_serial_close;
252 device->read = rt_serial_read;
253 device->write = rt_serial_write;
254 device->control = rt_serial_control;
255 device->user_data = serial;
256
257 /* register a character device */
258 return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
259 }
260
261 /* ISR for serial interrupt */
rt_hw_serial_isr(rt_device_t device)262 void rt_hw_serial_isr(rt_device_t device)
263 {
264 struct serial_device* uart = (struct serial_device*) device->user_data;
265
266 /* interrupt mode receive */
267 RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX);
268
269 /* save on rx buffer */
270 while (uart->uart_device->lsr & USTAT_RCV_READY)
271 {
272 rt_serial_savechar(uart, uart->uart_device->dlbl_fifo.rxfifo & 0xff);
273 }
274
275 /* invoke callback */
276 if (device->rx_indicate != RT_NULL)
277 {
278 rt_size_t rx_length;
279
280 /* get rx length */
281 rx_length = uart->int_rx->read_index > uart->int_rx->save_index ?
282 UART_RX_BUFFER_SIZE - uart->int_rx->read_index + uart->int_rx->save_index :
283 uart->int_rx->save_index - uart->int_rx->read_index;
284
285 device->rx_indicate(device, rx_length);
286 }
287 }
288
289 /*@}*/
290