diff --git a/drivers/Makefile b/drivers/Makefile index 3af5bcb3d..56ac13ff5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -24,3 +24,4 @@ all install depend clean: cd ./rtl8139 && $(MAKE) $@ cd ./fxp && $(MAKE) $@ cd ./dpeth && $(MAKE) $@ + cd ./log && $(MAKE) $@ diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index 957c1ad3d..f108cb959 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -233,7 +233,11 @@ PRIVATE struct driver w_dtab = { nop_cleanup, /* nothing to clean up */ w_geometry, /* tell the geometry of the disk */ nop_stop, /* no cleanup needed on shutdown */ - nop_alarm, /* ignore leftover alarms */ + nop_alarm, /* ignore leftover alarms, function key presses, CANCELs, SELECTs */ + nop_fkey, + nop_cancel, + nop_select, + NULL }; diff --git a/drivers/floppy/floppy.c b/drivers/floppy/floppy.c index 1de97cdaf..fdfab651e 100644 --- a/drivers/floppy/floppy.c +++ b/drivers/floppy/floppy.c @@ -274,6 +274,10 @@ PRIVATE struct driver f_dtab = { f_geometry, /* tell the geometry of the diskette */ floppy_stop, /* floppy cleanup on shutdown */ f_expire_tmrs,/* expire all alarm timers */ + nop_fkey, /* ignore function keys and CANCELs */ + nop_cancel, + nop_select, + NULL }; diff --git a/drivers/libdriver/driver.c b/drivers/libdriver/driver.c index 5490b09df..adedb0a27 100644 --- a/drivers/libdriver/driver.c +++ b/drivers/libdriver/driver.c @@ -24,6 +24,8 @@ * |------------+---------+---------+---------+---------+---------| * | DEV_IOCTL | device | proc nr |func code| | buf ptr | * |------------+---------+---------+---------+---------+---------| + * | CANCEL | device | proc nr | r/w | | | + * |------------+---------+---------+---------+---------+---------| * | HARD_STOP | | | | | | * ---------------------------------------------------------------- * @@ -65,6 +67,7 @@ FORWARD _PROTOTYPE( void init_buffer, (void) ); FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp) ); FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp) ); +int device_caller; /*===========================================================================* * driver_task * @@ -74,7 +77,7 @@ struct driver *dp; /* Device dependent entry points. */ { /* Main program of any device driver task. */ - int r, caller, proc_nr; + int r, proc_nr; message mess; int s; @@ -89,7 +92,7 @@ struct driver *dp; /* Device dependent entry points. */ /* Wait for a request to read or write a disk block. */ receive(ANY, &mess); - caller = mess.m_source; + device_caller = mess.m_source; proc_nr = mess.PROC_NR; /* Now carry out the work. */ @@ -97,6 +100,8 @@ struct driver *dp; /* Device dependent entry points. */ case DEV_OPEN: r = (*dp->dr_open)(dp, &mess); break; case DEV_CLOSE: r = (*dp->dr_close)(dp, &mess); break; case DEV_IOCTL: r = (*dp->dr_ioctl)(dp, &mess); break; + case CANCEL: r = (*dp->dr_cancel)(dp, &mess);break; + case DEV_SELECT: r = (*dp->dr_select)(dp, &mess);break; case DEV_READ: case DEV_WRITE: r = do_rdwt(dp, &mess); break; @@ -111,7 +116,12 @@ struct driver *dp; /* Device dependent entry points. */ continue; /* don't reply */ case FKEY_PRESSED: (*dp->dr_fkey)(dp, &mess); continue; /* don't reply */ - default: r = EINVAL; break; + default: + if(dp->dr_other) + r = (*dp->dr_other)(dp, &mess); + else + r = EINVAL; + break; } /* Clean up leftover state. */ @@ -122,7 +132,7 @@ struct driver *dp; /* Device dependent entry points. */ mess.REP_PROC_NR = proc_nr; mess.REP_STATUS = r; /* # of bytes transferred or error code */ - send(caller, &mess); /* send reply to caller */ + send(device_caller, &mess); /* send reply to caller */ } } @@ -305,6 +315,30 @@ PUBLIC void nop_cleanup() /* Nothing to clean up. */ } +/*===========================================================================* + * nop_fkey * + *===========================================================================*/ +PUBLIC void nop_fkey(struct driver *dr, message *m) +{ +/* Nothing to do for fkey. */ +} + +/*===========================================================================* + * nop_cancel * + *===========================================================================*/ +PUBLIC int nop_cancel(struct driver *dr, message *m) +{ +/* Nothing to do for cancel. */ +} + +/*===========================================================================* + * nop_select * + *===========================================================================*/ +PUBLIC int nop_select(struct driver *dr, message *m) +{ +/* Nothing to do for select. */ +} + /*===========================================================================* * nop_task * diff --git a/drivers/libdriver/driver.h b/drivers/libdriver/driver.h index 2d963a04f..777581663 100644 --- a/drivers/libdriver/driver.h +++ b/drivers/libdriver/driver.h @@ -39,6 +39,9 @@ struct driver { _PROTOTYPE( void (*dr_stop), (struct driver *dp) ); _PROTOTYPE( void (*dr_alarm), (struct driver *dp) ); _PROTOTYPE( void (*dr_fkey), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( int (*dr_cancel), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( int (*dr_select), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( int (*dr_other), (struct driver *dp, message *m_ptr) ); }; #if (CHIP == INTEL) @@ -66,6 +69,9 @@ _PROTOTYPE( void nop_cleanup, (void) ); _PROTOTYPE( void nop_task, (void) ); _PROTOTYPE( void nop_stop, (struct driver *dp) ); _PROTOTYPE( void nop_alarm, (struct driver *dp) ); +_PROTOTYPE( void nop_fkey, (struct driver *dp, message *m_ptr) ); +_PROTOTYPE( int nop_cancel, (struct driver *dp, message *m_ptr) ); +_PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) ); _PROTOTYPE( int do_diocntl, (struct driver *dp, message *m_ptr) ); /* Parameters for the disk drive. */ diff --git a/drivers/log/Makefile b/drivers/log/Makefile new file mode 100644 index 000000000..80416e588 --- /dev/null +++ b/drivers/log/Makefile @@ -0,0 +1,46 @@ +# Makefile for log driver +DRIVER = log + +# directories +u = /usr +i = $u/include +s = $i/sys +m = $i/minix +d = .. + +# programs, flags, etc. +MAKE = exec make +CC = exec cc +CFLAGS = -I$i +LDFLAGS = -i +LIBS = -lsys -lutils + +OBJ = log.o +LIBDRIVER = $d/libdriver/driver.o + + +# build local binary +all build: $(DRIVER) +$(DRIVER): $(OBJ) $(LIBDRIVER) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBDRIVER) $(LIBS) + install -S 64w $(DRIVER) + +$(LIBDRIVER): + cd $d/libdriver && $(MAKE) + +# install with other drivers +install: /usr/sbin/drivers/$(DRIVER) +/usr/sbin/drivers/$(DRIVER): $(DRIVER) + install -o root -cs $? $@ + +# clean up local files +clean: + rm -f $(DRIVER) *.o *.bak + + +depend: + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c ../libdriver/*.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/drivers/log/log.c b/drivers/log/log.c new file mode 100644 index 000000000..3277bf29b --- /dev/null +++ b/drivers/log/log.c @@ -0,0 +1,441 @@ +/* This file contains a driver for: + * /dev/klog - system log device + * + * Changes: + * 7 july 2005 - Created (Ben Gras) + */ + +#include "../drivers.h" +#include "../libdriver/driver.h" +#include "../../kernel/const.h" +#include "../../kernel/type.h" + +#include +#include + +#define NR_DEVS 1 /* number of minor devices */ +#define KRANDOM_PERIOD 10 /* ticks between krandom calls */ + +#define LOG_DEBUG 0 + +#define MINOR_KLOG 0 /* /dev/klog */ + +#define LOG_SIZE (5*1024) +#define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0) + +#define SUSPENDABLE 1 + +PRIVATE struct logdevice { + char log_buffer[LOG_SIZE]; + int log_size, /* no. of bytes in log buffer */ + log_read, /* read mark */ + log_write; /* write mark */ +#if SUSPENDABLE + int log_proc_nr, + log_source, + log_iosize; /* proc that is blocking on read */ + vir_bytes log_user_vir; +#endif + int log_selected, log_select_proc; +} logdevices[NR_DEVS]; + +PRIVATE struct device log_geom[NR_DEVS]; /* base and size of each device */ +PRIVATE int log_device = -1; /* current device */ + +FORWARD _PROTOTYPE( char *log_name, (void) ); +FORWARD _PROTOTYPE( struct device *log_prepare, (int device) ); +FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, off_t position, + iovec_t *iov, unsigned nr_req) ); +FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) ); +FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) ); +FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) ); +FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) ); +FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) ); +FORWARD _PROTOTYPE( void log_reply, (int code, int replyee, int proc, int status) ); +FORWARD _PROTOTYPE( void log_notify, (int code, int replyee, int line, int ops) ); + +/* Entry points to this driver. */ +PRIVATE struct driver log_dtab = { + log_name, /* current device's name */ + log_do_open, /* open or mount */ + do_nop, /* nothing on a close */ + do_nop, /* ioctl nop */ + log_prepare, /* prepare for I/O on a given minor device */ + log_transfer, /* do the I/O */ + nop_cleanup, /* no need to clean up */ + log_geometry, /* geometry */ + nop_stop, /* no need to clean up on shutdown */ + nop_alarm, /* no alarm */ + nop_fkey, /* no fkey registered */ + log_cancel, /* CANCEL request */ + log_select, /* DEV_SELECT request */ + log_other /* Unrecognized messages */ +}; + +extern int device_caller; + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC void main(void) +{ + int i; + for(i = 0; i < NR_DEVS; i++) { + log_geom[i].dv_size = cvul64(LOG_SIZE); + log_geom[i].dv_base = cvul64((long)logdevices[i].log_buffer); + logdevices[i].log_size = logdevices[i].log_read = + logdevices[i].log_write = logdevices[i].log_selected = 0; +#if SUSPENDABLE + logdevices[i].log_proc_nr = 0; +#endif + } + driver_task(&log_dtab); +} + + +/*===========================================================================* + * log_name * + *===========================================================================*/ +PRIVATE char *log_name() +{ +/* Return a name for the current device. */ + static char name[] = "log"; + return name; +} + + +/*===========================================================================* + * log_prepare * + *===========================================================================*/ +PRIVATE struct device *log_prepare(device) +int device; +{ +/* Prepare for I/O on a device: check if the minor device number is ok. */ + + if (device < 0 || device >= NR_DEVS) return(NIL_DEV); + log_device = device; + + return(&log_geom[device]); +} + +/*===========================================================================* + * subwrite * + *===========================================================================*/ +PRIVATE int +subwrite(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) +{ + char *buf; + int r; + if (log->log_write + count > LOG_SIZE) + count = LOG_SIZE - log->log_write; + buf = log->log_buffer + log->log_write; + + if((r=sys_vircopy(proc_nr,D,user_vir, SELF,D,(int)buf, count)) != OK) + return r; + + LOGINC(log->log_write, count); + log->log_size += count; + + if(log->log_size > LOG_SIZE) { + int overflow; + overflow = log->log_size - LOG_SIZE; + log->log_size -= overflow; + LOGINC(log->log_read, overflow); + } + +#if SUSPENDABLE + if(log->log_size > 0 && log->log_proc_nr) { + /* Someone who was suspended on read can now + * be revived. + */ + r = subread(log, log->log_iosize, log->log_proc_nr, + log->log_user_vir); + log_reply(REVIVE, log->log_source, log->log_proc_nr, r); +#if LOG_DEBUG + printf("revived to %d (%d) with %d bytes\n", + log->log_source, log->log_proc_nr, r); +#endif + log->log_proc_nr = 0; + } + + if(log->log_size > 0 && log->log_selected) { + /* Someone(s) who was/were select()ing can now + * be awoken. If there was a blocking read (above), + * this can only happen if the blocking read didn't + * swallow all the data (log_size > 0). + */ + if(log->log_selected & SEL_RD) { + log_notify(DEV_SELECTED, + log->log_select_proc, log_device, SEL_RD); + log->log_selected &= ~SEL_RD; +#if LOG_DEBUG + printf("log notified %d\n", log->log_select_proc); +#endif + } + } +#endif + + return count; +} + +/*===========================================================================* + * subread * + *===========================================================================*/ +PRIVATE int +subread(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) +{ + char *buf; + int r; + if (count > log->log_size) + count = log->log_size; + if (log->log_read + count > LOG_SIZE) + count = LOG_SIZE - log->log_read; + + buf = log->log_buffer + log->log_read; + if((r=sys_vircopy(SELF,D,(int)buf,proc_nr,D,user_vir, count)) != OK) + return r; + + LOGINC(log->log_read, count); + log->log_size -= count; + + return count; +} + +/*===========================================================================* + * log_transfer * + *===========================================================================*/ +PRIVATE int log_transfer(proc_nr, opcode, position, iov, nr_req) +int proc_nr; /* process doing the request */ +int opcode; /* DEV_GATHER or DEV_SCATTER */ +off_t position; /* offset on device to read or write */ +iovec_t *iov; /* pointer to read or write request vector */ +unsigned nr_req; /* length of request vector */ +{ +/* Read or write one the driver's minor devices. */ + unsigned count; + vir_bytes user_vir; + struct device *dv; + unsigned long dv_size; + int s, accumulated_read = 0; + struct logdevice *log; + + if(log_device < 0 || log_device >= NR_DEVS) + return EIO; + + /* Get minor device number and check for /dev/null. */ + dv = &log_geom[log_device]; + dv_size = cv64ul(dv->dv_size); + log = &logdevices[log_device]; + + while (nr_req > 0) { + char *buf; + /* How much to transfer and where to / from. */ + count = iov->iov_size; + user_vir = iov->iov_addr; + + switch (log_device) { + + case MINOR_KLOG: + if (opcode == DEV_GATHER) { +#if SUSPENDABLE + if (log->log_proc_nr || count < 1) { + /* There's already someone hanging to read, or + * no real I/O requested. + */ +#if LOG_DEBUG + printf("someone (%d) is already blocking\n", log->log_proc_nr); +#endif + return(OK); + } + + if (!log->log_size) { + if(accumulated_read) + return OK; + /* No data available; let caller block. */ + log->log_proc_nr = proc_nr; + log->log_iosize = count; + log->log_user_vir = user_vir; + + /* Device_caller is a global in drivers library. */ + log->log_source = device_caller; +#if LOG_DEBUG + printf("blocked %d (%d)\n", + log->log_source, log->log_proc_nr); +#endif + return(SUSPEND); + } +#else + if (!log->log_size) { + return OK; + } +#endif + count = subread(log, count, proc_nr, user_vir); + if(count < 0) { + return count; + } + accumulated_read += count; + } else { + count = subwrite(log, count, proc_nr, user_vir); + if(count < 0) + return count; + } + break; + /* Unknown (illegal) minor device. */ + default: + return(EINVAL); + } + + /* Book the number of bytes transferred. */ + iov->iov_addr += count; + if ((iov->iov_size -= count) == 0) { iov++; nr_req--; } + } + return(OK); +} + +/*===========================================================================* + * log_notify * + *===========================================================================*/ +PRIVATE void log_notify(int code, int replyee, int line, int ops) +{ + message lm; + lm.NOTIFY_TYPE = code; + lm.NOTIFY_ARG = line; + lm.NOTIFY_FLAGS = ops; + notify(replyee, &lm); +} + +/*===========================================================================* + * log_reply * + *===========================================================================*/ +PRIVATE void log_reply(code, replyee, process, status) +int code; /* TASK_REPLY or REVIVE */ +int replyee; /* destination for message (normally FS) */ +int process; /* which user requested the printing */ +int status; /* number of chars printed or error code */ +{ + message mess; + + mess.m_type = code; + mess.REP_STATUS = status; + mess.REP_PROC_NR = process; + send(replyee, &mess); +} + +/*============================================================================* + * log_do_open * + *============================================================================*/ +PRIVATE int log_do_open(dp, m_ptr) +struct driver *dp; +message *m_ptr; +{ + if (log_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO); + return(OK); +} + +/*============================================================================* + * log_geometry * + *============================================================================*/ +PRIVATE void log_geometry(entry) +struct partition *entry; +{ + /* take a page from the fake memory device geometry */ + entry->heads = 64; + entry->sectors = 32; + entry->cylinders = div64u(log_geom[log_device].dv_size, SECTOR_SIZE) / + (entry->heads * entry->sectors); +} + +/*============================================================================* + * log_cancel * + *============================================================================*/ +PRIVATE int log_cancel(dp, m_ptr) +struct driver *dp; +message *m_ptr; +{ +#if SUSPENDABLE + int d; + d = m_ptr->TTY_LINE; + if(d < 0 || d >= NR_DEVS) + return EINVAL; + logdevices[d].log_proc_nr = 0; +#endif + return(OK); +} + +/*============================================================================* + * log_select * + *============================================================================*/ +PRIVATE int log_other(dp, m_ptr) +struct driver *dp; +message *m_ptr; +{ + int r; + + /* This function gets messages that the generic driver doesn't + * understand. + */ + switch(m_ptr->m_type) { + case DIAGNOSTICS: + r = subwrite(&logdevices[0], m_ptr->DIAG_BUF_COUNT, + m_ptr->m_source, (vir_bytes) m_ptr->DIAG_PRINT_BUF); + break; + default: + r = EINVAL; + break; + } + + return r; +} + +/*============================================================================* + * log_select * + *============================================================================*/ +PRIVATE int log_select(dp, m_ptr) +struct driver *dp; +message *m_ptr; +{ + int d, ready_ops = 0, ops = 0; + d = m_ptr->TTY_LINE; + if(d < 0 || d >= NR_DEVS) { +#if LOG_DEBUG + printf("line %d? EINVAL\n", d); +#endif + return EINVAL; + } + + ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR); + +#if SUSPENDABLE + /* Read blocks when there is no log. */ + if((m_ptr->PROC_NR & SEL_RD) && logdevices[d].log_size > 0) { +#if LOG_DEBUG + printf("log can read; size %d\n", logdevices[d].log_size); +#endif + ready_ops |= SEL_RD; /* writes never block */ + } +#else + /* Read never blocks. */ + if(m_ptr->PROC_NR & SEL_RD) ready_ops |= SEL_RD; +#endif + + /* Write never blocks. */ + if(m_ptr->PROC_NR & SEL_WR) ready_ops |= SEL_WR; + + /* Enable select calback if no operations were + * ready to go, but operations were requested, + * and notify was enabled. + */ + if((m_ptr->PROC_NR & SEL_NOTIFY) && ops && !ready_ops) { + logdevices[d].log_selected |= ops; + logdevices[d].log_select_proc = m_ptr->m_source; +#if LOG_DEBUG + printf("log setting selector.\n"); +#endif + } + +#if LOG_DEBUG + printf("log returning ops %d\n", ready_ops); +#endif + + return(ready_ops); +} diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index c63e898d8..18957aa2f 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -56,7 +56,11 @@ PRIVATE struct driver m_dtab = { nop_cleanup, /* no need to clean up */ m_geometry, /* memory device "geometry" */ nop_stop, /* no need to clean up on shutdown */ - m_random, /* get randomness from kernel */ + m_random, /* get randomness from kernel (alarm) */ + nop_fkey, /* ignore function key presses and CANCELs */ + nop_cancel, + nop_select, + NULL }; /* Buffer for the /dev/zero null byte feed. */