From b6181e4a21b1bc3b5615604e175c6a297b661687 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Thu, 3 Apr 2014 18:48:59 +0200 Subject: add uniform io interface --- kernel/io/mcu/atmega2560/usart.c | 148 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 kernel/io/mcu/atmega2560/usart.c (limited to 'kernel/io/mcu/atmega2560/usart.c') diff --git a/kernel/io/mcu/atmega2560/usart.c b/kernel/io/mcu/atmega2560/usart.c new file mode 100644 index 0000000..381f403 --- /dev/null +++ b/kernel/io/mcu/atmega2560/usart.c @@ -0,0 +1,148 @@ +#include "io/io.h" +#include "collection/list.h" +#include "collection/rbuffer.h" +#include "task/sched.h" +#include "mcu/io/usart.h" +#include "mcu/task/context.h" +#include +#include + +struct usart_private { + char __rx_buffer[USART_BUFFER_SIZE]; + char __tx_buffer[USART_BUFFER_SIZE]; + + struct rbuffer_t rx_buffer; + struct rbuffer_t tx_buffer; + + struct list_head rx_queue; + struct list_head tx_queue; + + volatile unsigned char* const ucsrxa; + volatile unsigned char* const ubrrxh; + volatile unsigned char* const ubrrxl; + volatile unsigned char* const ucsrxb; + char u2xx; + char rxenx; + char txenx; + char rxciex; + char udriex; +}; + +int usart_open(struct file* usart) { + struct usart_private* priv = (struct usart_private*) usart->private_data; + + INIT_LIST_HEAD(&priv->rx_queue); + INIT_LIST_HEAD(&priv->tx_queue); + INIT_RBUFFER(&priv->rx_buffer, priv->__rx_buffer, USART_BUFFER_SIZE); + INIT_RBUFFER(&priv->tx_buffer, priv->__tx_buffer, USART_BUFFER_SIZE); + + return 0; +} + +int usart_ioctl(struct file* usart, int cmd, long args) { + struct usart_private* priv = (struct usart_private*) usart->private_data; + + switch (cmd) { + case IOCTL_SET_BAUD: { + long baud = args; + (*priv->ucsrxa) |= (1 << priv->u2xx); + long baud_setting = (F_CPU / 4 / baud - 1) / 2; + (*priv->ubrrxh) = baud_setting >> 8; + (*priv->ubrrxl) = baud_setting; + (*priv->ucsrxb) |= (1 << priv->rxenx) | (1 << priv->txenx) | (1 << priv->rxciex); + (*priv->ucsrxb) &= ~(1 << priv->udriex); + return 0; + } + default: + return -1; + } +} + +ssize_t usart_write(struct file* usart, const char* const buffer, size_t length) { + struct usart_private* priv = (struct usart_private*) usart->private_data; + volatile unsigned char* ucsrxb = (priv->ucsrxb); + char write_enable = (1 << priv->udriex); + + ssize_t wrote = 0; + int r = 0; + do { + cli(); + r = rbuffer_write(&priv->tx_buffer, buffer[wrote]); + wrote += 1; + sei(); + *ucsrxb |= write_enable; + } while (r == 0 && wrote < length); + return wrote; +} + +ssize_t usart_read(struct file* usart, char* const buffer, size_t length) { + struct usart_private* priv = (struct usart_private*) usart->private_data; + while (rbuffer_empty(&priv->rx_buffer)) { + sleep_queue(&priv->rx_queue); + yield(); + } + size_t read = 0; + size_t r = 0; + while (!rbuffer_empty(&priv->rx_buffer) && read < length && r == 0) { + cli(); + r = rbuffer_read(&priv->rx_buffer, buffer + read); + read += 1; + sei(); + } + return read; +} + +int usart_close(struct file* usart) { + return 0; +} + +struct file_operations usart_fops = { + .open = usart_open, + .ioctl = usart_ioctl, + .read = usart_read, + .write = usart_write, + .close = usart_close +}; + +struct usart_private _usart0 = { + .ucsrxa = &UCSR0A, + .ubrrxh = &UBRR0H, + .ubrrxl = &UBRR0L, + .ucsrxb = &UCSR0B, + .u2xx = U2X0, + .rxenx = RXEN0, + .txenx = TXEN0, + .rxciex = RXCIE0, + .udriex = UDRIE0 +}; + +struct file usart0 = { + .fops = &usart_fops, + .private_data = &_usart0 +}; + +//called when data register is empty +ISR(USART0_UDRE_vect) { + struct usart_private* priv = (struct usart_private*) usart0.private_data; + char c; + + if (rbuffer_read(&priv->tx_buffer, &c) == 0) { + UDR0 = c; + } else { + UCSR0B &= ~(1 << UDRIE0); //buffer empty, disable interruot + } +} + +//called when byte is received +ISR(USART0_RX_vect, ISR_NAKED) { + context_save(); + + struct usart_private* priv = (struct usart_private*) usart0.private_data; + + char c = UDR0; + rbuffer_write(&priv->rx_buffer, c); + wake_all_queue(&priv->rx_queue); + + context_restore(); + asm volatile ("reti"); +} \ No newline at end of file -- cgit v1.2.3