serial character device
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 15 Aug 2024 10:15:45 +0000 (13:15 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 15 Aug 2024 10:15:45 +0000 (13:15 +0300)
kern/src/asmutil.h
kern/src/file.h
kern/src/libc/errno.h [new file with mode: 0644]
kern/src/ser.c
kern/src/ser.h

index 1720f5a..6c7a513 100644 (file)
@@ -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)
 {
index 4bff2c6..5534135 100644 (file)
@@ -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 (file)
index 0000000..ad05c53
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef ERRNO_H_
+#define ERRNO_H_
+
+enum {
+       ENXIO = 1,
+       EBUSY,
+       EBADF,
+
+       EBUG = 255
+};
+
+#endif /* ERRNO_H_ */
index cfd28bd..08fb397 100644 (file)
@@ -1,4 +1,9 @@
+#include <string.h>
+#include <errno.h>
 #include "ser.h"
+#include "file.h"
+#include "dev.h"
+#include "asmutil.h"
 
 #define UART1_BASE     0x3f8
 #define UART2_BASE     0x2f8
 #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;
 }
index 0a1f418..e581971 100644 (file)
@@ -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_ */