From 1c9feda0565eb8bddc12f01def09c35da6ad39e0 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 15 Aug 2024 13:15:45 +0300 Subject: [PATCH] serial character device --- kern/src/asmutil.h | 4 +- kern/src/file.h | 7 ++- kern/src/libc/errno.h | 12 ++++++ kern/src/ser.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++- kern/src/ser.h | 7 +++ 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 kern/src/libc/errno.h diff --git a/kern/src/asmutil.h b/kern/src/asmutil.h index 1720f5a..6c7a513 100644 --- a/kern/src/asmutil.h +++ b/kern/src/asmutil.h @@ -42,12 +42,12 @@ void getsregs(struct segregs *sregs); #define outp(p, v) \ asm volatile( \ "outb %1, %0" \ - :: "d"(p), "a"((unsigned char)v)) + :: "d"(p), "a"((unsigned char)(v))) #define outpw(p, v) \ asm volatile( \ "outw %1, %0" \ - :: "d"(p), "a"((unsigned short)v)) + :: "d"(p), "a"((unsigned short)(v))) static inline unsigned char inp(int p) { diff --git a/kern/src/file.h b/kern/src/file.h index 4bff2c6..5534135 100644 --- a/kern/src/file.h +++ b/kern/src/file.h @@ -3,20 +3,23 @@ #include "fs.h" +enum { FILE_REG, FILE_CDEV, FILE_BDEV }; + struct device; struct file { int type; + struct inode *inode; struct device *dev; int cur_rd, cur_wr; }; struct fileops { - struct file *(*open)(int inum, unsigned int flags); + int (*open)(struct file *file, struct inode *inode, unsigned int flags); int (*close)(struct file*); int (*read)(struct file*, void*, int); int (*write)(struct file*, void*, int); - int (*ioctl)(struct file*, int, void*, int); + int (*ioctl)(struct file*, int, long); }; diff --git a/kern/src/libc/errno.h b/kern/src/libc/errno.h new file mode 100644 index 0000000..ad05c53 --- /dev/null +++ b/kern/src/libc/errno.h @@ -0,0 +1,12 @@ +#ifndef ERRNO_H_ +#define ERRNO_H_ + +enum { + ENXIO = 1, + EBUSY, + EBADF, + + EBUG = 255 +}; + +#endif /* ERRNO_H_ */ diff --git a/kern/src/ser.c b/kern/src/ser.c index cfd28bd..08fb397 100644 --- a/kern/src/ser.c +++ b/kern/src/ser.c @@ -1,4 +1,9 @@ +#include +#include #include "ser.h" +#include "file.h" +#include "dev.h" +#include "asmutil.h" #define UART1_BASE 0x3f8 #define UART2_BASE 0x2f8 @@ -19,8 +24,114 @@ #define MCTL_DTR_RTS_OUT2 0x0b #define LST_TRIG_EMPTY 0x20 +static void setuart(int portidx, int baud); +static void serput(int portidx, int c); + +static int ser_open(struct file *file, struct inode *inode, unsigned int flags); +static int ser_close(struct file *file); +static int ser_read(struct file *file, void *buf, int sz); +static int ser_write(struct file *file, void *buf, int sz); +static int ser_ioctl(struct file *file, int ioc, long val); + +static unsigned int uart_addr[2] = {UART1_BASE, UART2_BASE}; +static struct device serdev[2]; +static unsigned int devopen; int ser_init(void) { - return -1; /* TODO */ + int i; + + for(i=0; i<2; i++) { + serdev[i].fop->open = ser_open; + serdev[i].fop->close = ser_close; + serdev[i].fop->read = ser_read; + serdev[i].fop->write = ser_write; + serdev[i].fop->ioctl = ser_ioctl; + } + devopen = 0; + + setuart(0, BAUD_9600); + setuart(1, BAUD_9600); + return 0; +} + +static unsigned int baud_div[] = { + 115200 / 9600, + 115200 / 19200, + 115200 / 38400, + 1 +}; + +static void setuart(int portidx, int baud) +{ + unsigned int iobase = uart_addr[portidx]; + unsigned int div = baud_div[baud]; + + /* set clock divisor */ + outp(iobase | UART_LCTL, LCTL_DLAB); + outp(iobase | UART_DIVLO, div & 0xff); + outp(iobase | UART_DIVHI, div >> 8); + /* set format 8n1 */ + outp(iobase | UART_LCTL, LCTL_8N1); + /* assert RTS and DTR */ + outp(iobase | UART_MCTL, MCTL_DTR_RTS_OUT2); +} + +static void serput(int portidx, int c) +{ + unsigned int iobase = uart_addr[portidx]; + + while((inp(iobase | UART_LSTAT) & LST_TRIG_EMPTY) == 0); + outp(iobase | UART_DATA, c); +} + +static int ser_open(struct file *file, struct inode *inode, unsigned int flags) +{ + int port = inode->dev_minor; + + if(port < 0 || port >= 2) { + return -ENXIO; + } + if(devopen & (1 << port)) { + return -EBUSY; + } + + memset(file, 0, sizeof *file); + file->type = FILE_CDEV; + file->inode = inode; + file->dev = serdev + port; + + devopen |= 1 << port; + return 0; +} + +static int ser_close(struct file *file) +{ + int port = file->inode->dev_minor; + + if(!(devopen & (1 << port))) { + return -EBADF; + } + devopen &= ~(1 << port); + return 0; +} + +static int ser_read(struct file *file, void *buf, int sz) +{ + return -EBUG; +} + +static int ser_write(struct file *file, void *buf, int sz) +{ + int port = file->inode->dev_minor; + unsigned char *ptr = buf; + while(sz > 0) { + serput(port, *ptr++); + } + return ptr - (unsigned char*)buf; +} + +static int ser_ioctl(struct file *file, int ioc, long val) +{ + return -EBUG; } diff --git a/kern/src/ser.h b/kern/src/ser.h index 0a1f418..e581971 100644 --- a/kern/src/ser.h +++ b/kern/src/ser.h @@ -1,6 +1,13 @@ #ifndef SER_H_ #define SER_H_ +enum { + BAUD_9600, + BAUD_19200, + BAUD_38400, + BAUD_115200 +}; + int ser_init(void); #endif /* SER_H_ */ -- 1.7.10.4