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 */ 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 */ 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 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 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 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 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 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 */ 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 */ 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