diff options
Diffstat (limited to 'kernel/io')
-rw-r--r-- | kernel/io/include/io/io.h | 30 | ||||
-rw-r--r-- | kernel/io/include/io/usart.h | 31 | ||||
-rw-r--r-- | kernel/io/io.c | 25 | ||||
-rw-r--r-- | kernel/io/mcu/atmega2560/include/mcu/io/usart.h | 12 | ||||
-rw-r--r-- | kernel/io/mcu/atmega2560/usart.c | 148 | ||||
-rw-r--r-- | kernel/io/usart.c | 103 |
6 files changed, 215 insertions, 134 deletions
diff --git a/kernel/io/include/io/io.h b/kernel/io/include/io/io.h new file mode 100644 index 0000000..a715f1b --- /dev/null +++ b/kernel/io/include/io/io.h @@ -0,0 +1,30 @@ +#ifndef IO_H +#define IO_H + +#include <stddef.h> + +typedef long ssize_t; + +struct file; +struct file_operations; + +struct file { + struct file_operations* fops; + void* private_data; +}; + +struct file_operations { + int (*open)(struct file* file); + int (*ioctl)(struct file* file, int cmd, long args); + ssize_t (*read)(struct file* file, char* const buffer, size_t size); + ssize_t (*write)(struct file* file, const char* const buffer, size_t size); + int (*close)(struct file* file); +}; + +int open(struct file* file); +int ioctl(struct file* file, int cmd, long args); +ssize_t read(struct file* file, char* const buffer, size_t size); +ssize_t write(struct file* file, const char* const buffer, size_t size); +int close(struct file* file); + +#endif
\ No newline at end of file diff --git a/kernel/io/include/io/usart.h b/kernel/io/include/io/usart.h deleted file mode 100644 index 62e2768..0000000 --- a/kernel/io/include/io/usart.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef SERIAL_H -#define SERIAL_H - -#include "collection/rbuffer.h" -#include "collection/list.h" - -#define USARTS 1 -#define USART_BUFFER_SIZE 64 - -struct usart_device_t { - volatile char __rx_buffer[USART_BUFFER_SIZE]; - volatile 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; -}; - -#define USART_DEVICE_INIT(name) \ - { \ - .rx_buffer = RBUFFER_ARRAY_INIT(name.__rx_buffer, USART_BUFFER_SIZE), \ - .tx_buffer = RBUFFER_ARRAY_INIT(name.__tx_buffer, USART_BUFFER_SIZE), \ - .rx_queue = LIST_HEAD_INIT(name.rx_queue), \ - .tx_queue = LIST_HEAD_INIT(name.tx_queue) \ - } - -void usart_init(unsigned long baud); - -#endif
\ No newline at end of file diff --git a/kernel/io/io.c b/kernel/io/io.c new file mode 100644 index 0000000..f39168b --- /dev/null +++ b/kernel/io/io.c @@ -0,0 +1,25 @@ +#include "io/io.h" + +int open(struct file* file) { + file->fops->open(file); +} + +int ioctl(struct file* file, int cmd, long args) { + file->fops->ioctl(file, cmd, args); +} + +ssize_t read(struct file* file, char* const buffer, size_t size) { + struct file_operations* fops = file->fops; + if (fops->read == NULL) return -1; + else fops->read(file, buffer, size); +} + +ssize_t write(struct file* file, const char* const buffer, size_t size) { + struct file_operations* fops = file->fops; + if (fops->write == NULL) return -1; + else fops->write(file, buffer, size); +} + +int close(struct file* file) { + file->fops->close(file); +}
\ No newline at end of file diff --git a/kernel/io/mcu/atmega2560/include/mcu/io/usart.h b/kernel/io/mcu/atmega2560/include/mcu/io/usart.h new file mode 100644 index 0000000..6b210fe --- /dev/null +++ b/kernel/io/mcu/atmega2560/include/mcu/io/usart.h @@ -0,0 +1,12 @@ +#ifndef MCU_USART +#define MCU_USART + +#include "io/io.h" + +#define USART_BUFFER_SIZE 64 +#define IOCTL_SET_BAUD 0 + +extern struct file usart0; + + +#endif
\ No newline at end of file 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 <avr/interrupt.h> +#include <avr/io.h> + +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 diff --git a/kernel/io/usart.c b/kernel/io/usart.c deleted file mode 100644 index 2046630..0000000 --- a/kernel/io/usart.c +++ /dev/null @@ -1,103 +0,0 @@ - -#include <stddef.h> -#include <stdio.h> -#include <avr/interrupt.h> -#include "task/sched.h" -#include "io/usart.h" -#include "bug/debug.h" -#include "mcu/task/context.h" - -static struct usart_device_t umain = USART_DEVICE_INIT(umain); -static int umain_putc(char c); -static int umain_getc(); - -FILE umain_out = FDEV_SETUP_STREAM(umain_putc, NULL, _FDEV_SETUP_WRITE); -FILE umain_in = FDEV_SETUP_STREAM(NULL, umain_getc, _FDEV_SETUP_READ); - -void usart_init(unsigned long baud) { - UCSR0A |= (1 << U2X0); //enable double speed transmission - uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2; - UBRR0H = baud_setting >> 8; - UBRR0L = baud_setting; - UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // 8-bit, no parity, 1 stop bit - UCSR0B &= ~(1 << UDRIE0); - stdout = &umain_out; - stdin = &umain_in; -} - -int umain_putc(char c) { - if (c == '\n') umain_putc('\r'); - int r = 0; - do { - cli(); - r = rbuffer_write_char(&umain.tx_buffer, c); - sei(); - UCSR0B |= (1 << UDRIE0); - } while (r != 1); - return c; -} - -int umain_getc() { - while (rbuffer_empty(&umain.rx_buffer)) { - cli(); - sleep_queue(&umain.rx_queue); - yield(); - } - cli(); - char c = 0; - size_t r = rbuffer_read_char(&umain.rx_buffer, &c); - sei(); - if (r) return (int) c; - else return EOF; -} - -//called when byte is received -ISR(USART0_RX_vect, ISR_NAKED) { - context_save(); - char c = UDR0; - rbuffer_write_char(&umain.rx_buffer, c); - wake_all_queue(&umain.rx_queue); - context_restore(); - asm volatile ("reti"); -} - -//called when data register is empty -ISR(USART0_UDRE_vect) { - char c; - if (rbuffer_read_char(&umain.tx_buffer, &c)) { - UDR0 = c; - } else { - UCSR0B &= ~(1 << UDRIE0); //buffer empty, disable interruot - } -} - -/* -void serial_read() { - ENTER_CRITICAL(); - list_move_tail(¤t->list, &serial_rx_q); - EXIT_CRITICAL(); - yield(); -} -*/ -/* -void serial_write_str(const char* const str) { - for (size_t i = 0; str[i] != '\0'; ++i) { - ENTER_CRITICAL(); - rbuffer_write(&serial_dev.tx_buffer, str[i]); - EXIT_CRITICAL(); - UCSR0B |= (1 << UDRIE0); - } -}*/ - - -/* -ISR(INT3_vect, ISR_NAKED) { - SAVE_CONTEXT(); - if (!list_empty(&serial_rx_q)) { - list_move_tail(serial_rx_q.next, &ready); - } - schedule(); - RESTORE_CONTEXT(); - asm volatile ("reti"); -} -*/ |