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.
This commit is contained in:
Ben Gras 2005-07-08 17:23:44 +00:00
parent c021dafe27
commit 640eb73ca2
8 changed files with 546 additions and 6 deletions

View file

@ -24,3 +24,4 @@ all install depend clean:
cd ./rtl8139 && $(MAKE) $@
cd ./fxp && $(MAKE) $@
cd ./dpeth && $(MAKE) $@
cd ./log && $(MAKE) $@

View 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
};

View 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
};

View 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 *

View 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. */

46
drivers/log/Makefile Normal file
View file

@ -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

441
drivers/log/log.c Normal file
View file

@ -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);
}

View 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. */