#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);
};
+#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;
}