xref: /nrf52832-nimble/rt-thread/libcpu/arm/s3c24x0/serial.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2006-03-13     Bernard      first version
9  * 2009-04-20     yi.qiu      modified according bernard's stm32 version
10  */
11 
12 #include <rtthread.h>
13 
14 #include "serial.h"
15 
16 /**
17  * @addtogroup S3C24X0
18  */
19 /*@{*/
20 
21 /* RT-Thread Device Interface */
22 /**
23  * This function initializes serial
24  */
rt_serial_init(rt_device_t dev)25 static rt_err_t rt_serial_init(rt_device_t dev)
26 {
27     struct serial_device* uart = (struct serial_device*) dev->user_data;
28 
29     if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
30     {
31 
32         if (dev->flag & RT_DEVICE_FLAG_INT_RX)
33         {
34             rt_memset(uart->int_rx->rx_buffer, 0,
35                       sizeof(uart->int_rx->rx_buffer));
36             uart->int_rx->read_index = uart->int_rx->save_index = 0;
37         }
38 
39         if (dev->flag & RT_DEVICE_FLAG_INT_TX)
40         {
41             rt_memset(uart->int_tx->tx_buffer, 0,
42                       sizeof(uart->int_tx->tx_buffer));
43             uart->int_tx->write_index = uart->int_tx->save_index = 0;
44         }
45 
46         dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
47     }
48 
49     return RT_EOK;
50 }
51 
52 /* save a char to serial buffer */
rt_serial_savechar(struct serial_device * uart,char ch)53 static void rt_serial_savechar(struct serial_device* uart, char ch)
54 {
55     rt_base_t level;
56 
57     /* disable interrupt */
58     level = rt_hw_interrupt_disable();
59 
60     uart->int_rx->rx_buffer[uart->int_rx->save_index] = ch;
61     uart->int_rx->save_index ++;
62     if (uart->int_rx->save_index >= UART_RX_BUFFER_SIZE)
63         uart->int_rx->save_index = 0;
64 
65     /* if the next position is read index, discard this 'read char' */
66     if (uart->int_rx->save_index == uart->int_rx->read_index)
67     {
68         uart->int_rx->read_index ++;
69         if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
70             uart->int_rx->read_index = 0;
71     }
72 
73     /* enable interrupt */
74     rt_hw_interrupt_enable(level);
75 }
76 
rt_serial_open(rt_device_t dev,rt_uint16_t oflag)77 static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
78 {
79     RT_ASSERT(dev != RT_NULL);
80 
81     return RT_EOK;
82 }
83 
rt_serial_close(rt_device_t dev)84 static rt_err_t rt_serial_close(rt_device_t dev)
85 {
86     RT_ASSERT(dev != RT_NULL);
87 
88     return RT_EOK;
89 }
90 
rt_serial_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)91 static rt_size_t rt_serial_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
92 {
93     rt_uint8_t* ptr;
94     rt_err_t err_code;
95     struct serial_device* uart;
96 
97     ptr = buffer;
98     err_code = RT_EOK;
99     uart = (struct serial_device*)dev->user_data;
100 
101     if (ptr == RT_NULL)
102     {
103         err_code = -RT_ENOMEM;
104         rt_set_errno(err_code);
105         return -RT_ENOMEM;
106     }
107     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
108     {
109         rt_base_t level;
110 
111         /* interrupt mode Rx */
112         while (size)
113         {
114             if (uart->int_rx->read_index != uart->int_rx->save_index)
115             {
116                 *ptr++ = uart->int_rx->rx_buffer[uart->int_rx->read_index];
117                 size --;
118 
119                 /* disable interrupt */
120                 level = rt_hw_interrupt_disable();
121 
122                 uart->int_rx->read_index ++;
123                 if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
124                     uart->int_rx->read_index = 0;
125 
126                 /* enable interrupt */
127                 rt_hw_interrupt_enable(level);
128             }
129             else
130             {
131                 /* set error code */
132                 err_code = -RT_EEMPTY;
133                 break;
134             }
135         }
136     }
137     else
138     {
139         /* polling mode */
140         while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size)
141         {
142             while (uart->uart_device->ustat & USTAT_RCV_READY)
143             {
144                 *ptr = uart->uart_device->urxh & 0xff;
145                 ptr ++;
146             }
147         }
148     }
149 
150     /* set error code */
151     rt_set_errno(err_code);
152     return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
153 }
154 
rt_serial_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)155 static rt_size_t rt_serial_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
156 {
157     rt_uint8_t* ptr;
158     rt_err_t err_code;
159     struct serial_device* uart;
160 
161     err_code = RT_EOK;
162     ptr = (rt_uint8_t*)buffer;
163     uart = (struct serial_device*)dev->user_data;
164 
165     if (ptr == RT_NULL)
166     {
167         err_code = -RT_ENOMEM;
168         rt_set_errno(err_code);
169         return -RT_ENOMEM;
170     }
171     if (dev->flag & RT_DEVICE_FLAG_INT_TX)
172     {
173         /* interrupt mode Tx */
174         while (uart->int_tx->save_index != uart->int_tx->write_index)
175         {
176             /* save on tx buffer */
177             uart->int_tx->tx_buffer[uart->int_tx->save_index] = *ptr++;
178 
179             -- size;
180 
181             /* move to next position */
182             uart->int_tx->save_index ++;
183 
184             /* wrap save index */
185             if (uart->int_tx->save_index >= UART_TX_BUFFER_SIZE)
186                 uart->int_tx->save_index = 0;
187         }
188 
189         /* set error code */
190         if (size > 0)
191             err_code = -RT_EFULL;
192     }
193     else
194     {
195         /* polling mode */
196         while (size)
197         {
198             /*
199              * to be polite with serial console add a line feed
200              * to the carriage return character
201              */
202             if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM))
203             {
204                 while (!(uart->uart_device->ustat & USTAT_TXB_EMPTY));
205                 uart->uart_device->utxh = '\r';
206             }
207 
208             while (!(uart->uart_device->ustat & USTAT_TXB_EMPTY));
209             uart->uart_device->utxh = (*ptr & 0xFF);
210 
211             ++ptr;
212             --size;
213         }
214     }
215 
216     /* set error code */
217     rt_set_errno(err_code);
218     return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
219 }
220 
rt_serial_control(rt_device_t dev,int cmd,void * args)221 static rt_err_t rt_serial_control(rt_device_t dev, int cmd, void *args)
222 {
223     RT_ASSERT(dev != RT_NULL);
224 
225     switch (cmd)
226     {
227     case RT_DEVICE_CTRL_SUSPEND:
228         /* suspend device */
229         dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
230         break;
231 
232     case RT_DEVICE_CTRL_RESUME:
233         /* resume device */
234         dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
235         break;
236     }
237 
238     return RT_EOK;
239 }
240 
241 /*
242  * serial register
243  */
rt_hw_serial_register(rt_device_t device,const char * name,rt_uint32_t flag,struct serial_device * serial)244 rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial)
245 {
246     RT_ASSERT(device != RT_NULL);
247 
248     device->type        = RT_Device_Class_Char;
249     device->rx_indicate = RT_NULL;
250     device->tx_complete = RT_NULL;
251     device->init        = rt_serial_init;
252     device->open        = rt_serial_open;
253     device->close       = rt_serial_close;
254     device->read        = rt_serial_read;
255     device->write       = rt_serial_write;
256     device->control     = rt_serial_control;
257     device->user_data   = serial;
258 
259     /* register a character device */
260     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
261 }
262 
263 /* ISR for serial interrupt */
rt_hw_serial_isr(rt_device_t device)264 void rt_hw_serial_isr(rt_device_t device)
265 {
266     struct serial_device* uart = (struct serial_device*) device->user_data;
267 
268     /* interrupt mode receive */
269     RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX);
270 
271     /* save on rx buffer */
272     while (uart->uart_device->ustat & USTAT_RCV_READY)
273     {
274         rt_serial_savechar(uart, uart->uart_device->urxh & 0xff);
275     }
276 
277     /* invoke callback */
278     if (device->rx_indicate != RT_NULL)
279     {
280         rt_size_t rx_length;
281 
282         /* get rx length */
283         rx_length = uart->int_rx->read_index > uart->int_rx->save_index ?
284                     UART_RX_BUFFER_SIZE - uart->int_rx->read_index + uart->int_rx->save_index :
285                     uart->int_rx->save_index - uart->int_rx->read_index;
286 
287         device->rx_indicate(device, rx_length);
288     }
289 }
290 
291 /*@}*/
292