]> Zhao Yanbai Git Server - minix.git/commitdiff
New log driver; buffers messages and makes them available to userland.
authorBen Gras <ben@minix3.org>
Fri, 8 Jul 2005 17:23:44 +0000 (17:23 +0000)
committerBen Gras <ben@minix3.org>
Fri, 8 Jul 2005 17:23:44 +0000 (17:23 +0000)
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.

drivers/Makefile
drivers/at_wini/at_wini.c
drivers/floppy/floppy.c
drivers/libdriver/driver.c
drivers/libdriver/driver.h
drivers/log/Makefile [new file with mode: 0644]
drivers/log/log.c [new file with mode: 0644]
drivers/memory/memory.c

index 3af5bcb3dfd4679019898d110e08887575bd27a4..56ac13ff541af3e078869083a8fc32c08869c3da 100644 (file)
@@ -24,3 +24,4 @@ all install depend clean:
        cd ./rtl8139 && $(MAKE) $@
        cd ./fxp && $(MAKE) $@
        cd ./dpeth && $(MAKE) $@
+       cd ./log && $(MAKE) $@
index 957c1ad3d9ce8d672385c7cd5c774ae1ee6e7bcf..f108cb959e7c73994d3ee891d1a5f03aec758d92 100644 (file)
@@ -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
 };
 
 
index 1de97cdaf2fd2576fa24fb8de56d4782f312d475..fdfab651e3cdef3d9500b5e8258d1e97abe6d2a1 100644 (file)
@@ -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
 };
 
 
index 5490b09df87ac76fa04b4857e02738e0818518a3..adedb0a27da05796e2c86e5a00c91ad6c11696d2 100644 (file)
@@ -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                                     *
index 2d963a04ffa5ed8751db03a424021ad99d40162c..777581663f5bcfdee52e77d77fc19fa542df4025 100644 (file)
@@ -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 (file)
index 0000000..80416e5
--- /dev/null
@@ -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 (file)
index 0000000..3277bf2
--- /dev/null
@@ -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 <sys/time.h>
+#include <sys/select.h>
+
+#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);
+}
index c63e898d8dccc61708f1b5424f0996d08c664625..18957aa2f39aa8d2a9630fcfcd1f5dba1ab2f46d 100644 (file)
@@ -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. */