From: Ben Gras Date: Fri, 8 Jul 2005 17:23:44 +0000 (+0000) Subject: New log driver; buffers messages and makes them available to userland. X-Git-Tag: v3.1.0~641 X-Git-Url: http://zhaoyanbai.com/repos/man.genrandom.html?a=commitdiff_plain;h=640eb73ca2b150dc074e0f73f37c7b377e9ab7a6;p=minix.git New log driver; buffers messages and makes them available to userland. Added some fields in the generic device table to support this driver using libdriver. Updated other drivers to fill these fields with nops and NULLs. --- 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. */