aboutsummaryrefslogtreecommitdiff
path: root/kernel/io
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/io')
-rw-r--r--kernel/io/include/io/io.h30
-rw-r--r--kernel/io/include/io/usart.h31
-rw-r--r--kernel/io/io.c25
-rw-r--r--kernel/io/mcu/atmega2560/include/mcu/io/usart.h12
-rw-r--r--kernel/io/mcu/atmega2560/usart.c148
-rw-r--r--kernel/io/usart.c103
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(&current->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");
-}
-*/