From: Philip Homburg Date: Mon, 25 Feb 2008 10:24:46 +0000 (+0000) Subject: Copy of libdriver for asynch interface to character drivers. Has to be cleaned X-Git-Tag: v3.1.4~251 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/soc.html?a=commitdiff_plain;h=bc125e3e1c3bfd358c8a6721368ba7026360045f;p=minix.git Copy of libdriver for asynch interface to character drivers. Has to be cleaned up. --- diff --git a/drivers/libdriver_asyn/Makefile b/drivers/libdriver_asyn/Makefile new file mode 100644 index 000000000..534ac1a69 --- /dev/null +++ b/drivers/libdriver_asyn/Makefile @@ -0,0 +1,34 @@ +# Makefile for driver library + +# Directories +u = /usr +i = $u/include +s = $i/sys +b = $i/ibm +m = $i/minix + +# Programs, flags, etc. +CC = exec cc +CFLAGS = -I$i $(CPROFILE) +LDFLAGS = -i +LIBS = -lsysutil -lsys +LIB = libdriver.a + +OBJECTS = driver.o drvlib.o mq.o + +all build install: $(LIB) + +$(LIB): $(OBJECTS) + ar rc $(LIB) $(OBJECTS) + +# $(CC) -c $@ $(LDFLAGS) $(OBJ) $(LIBS) + +clean: + rm -f *.o *.bak *.a + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/drivers/libdriver_asyn/driver.c b/drivers/libdriver_asyn/driver.c new file mode 100644 index 000000000..f97173e89 --- /dev/null +++ b/drivers/libdriver_asyn/driver.c @@ -0,0 +1,646 @@ +/* This file contains device independent device driver interface. + * + * Changes: + * Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder) + * Sep 15, 2004 added SYN_ALARM type for timeouts (Jorrit N. Herder) + * Jul 23, 2004 removed kernel dependencies (Jorrit N. Herder) + * Apr 02, 1992 constructed from AT wini and floppy driver (Kees J. Bot) + * + * + * The drivers support the following operations (using message format m2): + * + * m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS + * ---------------------------------------------------------------- + * | DEV_OPEN | device | proc nr | | | | + * |------------+---------+---------+---------+---------+---------| + * | DEV_CLOSE | device | proc nr | | | | + * |------------+---------+---------+---------+---------+---------| + * | DEV_READ | device | proc nr | bytes | offset | buf ptr | + * |------------+---------+---------+---------+---------+---------| + * | DEV_WRITE | device | proc nr | bytes | offset | buf ptr | + * |------------+---------+---------+---------+---------+---------| + * | DEV_GATHER | device | proc nr | iov len | offset | iov ptr | + * |------------+---------+---------+---------+---------+---------| + * | DEV_SCATTER| device | proc nr | iov len | offset | iov ptr | + * |------------+---------+---------+---------+---------+---------| + * | DEV_IOCTL | device | proc nr |func code| | buf ptr | + * |------------+---------+---------+---------+---------+---------| + * | CANCEL | device | proc nr | r/w | | | + * |------------+---------+---------+---------+---------+---------| + * | HARD_STOP | | | | | | + * |------------+---------+---------+---------+---------+---------| + * | DEV_*_S | variants using safecopies of above | + * ---------------------------------------------------------------- + * + * The file contains one entry point: + * + * driver_task: called by the device dependent task entry + */ + + +#include "../drivers.h" +#include +#include +#include "driver.h" + +#if (CHIP == INTEL) + +#if USE_EXTRA_DMA_BUF && DMA_BUF_SIZE < 2048 +/* A bit extra scratch for the Adaptec driver. */ +#define BUF_EXTRA (2048 - DMA_BUF_SIZE) +#else +#define BUF_EXTRA 0 +#endif + +/* Claim space for variables. */ +PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA]; +u8_t *tmp_buf; /* the DMA buffer eventually */ +phys_bytes tmp_phys; /* phys address of DMA buffer */ + +#else /* CHIP != INTEL */ + +/* Claim space for variables. */ +u8_t tmp_buf[DMA_BUF_SIZE]; /* the DMA buffer */ +phys_bytes tmp_phys; /* phys address of DMA buffer */ + +#endif /* CHIP != INTEL */ + +FORWARD _PROTOTYPE( void init_buffer, (void) ); +FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp, int safe) ); +FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp, int safe) ); + +_PROTOTYPE( int asynsend, (endpoint_t dst, message *mp)); + +int device_caller; +PRIVATE mq_t *queue_head = NULL; + +/*===========================================================================* + * driver_task * + *===========================================================================*/ +PUBLIC void driver_task(dp) +struct driver *dp; /* Device dependent entry points. */ +{ +/* Main program of any device driver task. */ + + int r, proc_nr; + message mess, reply_mess; + + /* Init MQ library. */ + mq_init(); + + /* Get a DMA buffer. */ + init_buffer(); + + /* Here is the main loop of the disk task. It waits for a message, carries + * it out, and sends a reply. + */ + while (TRUE) { + /* Any queued messages? Oldest are at the head. */ + if(queue_head) { + mq_t *mq; + mq = queue_head; + memcpy(&mess, &mq->mq_mess, sizeof(mess)); + queue_head = queue_head->mq_next; + mq_free(mq); + } else { + int s; + /* Wait for a request to read or write a disk block. */ + if ((s=receive(ANY, &mess)) != OK) + panic((*dp->dr_name)(),"receive() failed", s); + } + + device_caller = mess.m_source; + proc_nr = mess.IO_ENDPT; + + if (mess.m_type != SYN_ALARM && mess.m_type != DEV_PING && + mess.m_type != 4105 /* notify from TTY */ && + mess.m_type != DEV_SELECT && + mess.m_type != DEV_READ_S && + mess.m_type != DIAGNOSTICS_S && + mess.m_type != CANCEL) + { + printf("libdriver_asyn`driver_task: message %d\n", + mess.m_type); + } + + if (mess.m_type == DEV_SELECT) + { + static int first= 1; + if (first) + { + first= 0; + printf( + "libdriver_asyn`driver_task: first DEV_SELECT: minor 0x%x, ops 0x%x\n", + mess.DEVICE, mess.IO_ENDPT); + } + } + + /* Now carry out the work. */ + switch(mess.m_type) { + case DEV_OPEN: r = (*dp->dr_open)(dp, &mess); break; + case DEV_CLOSE: r = (*dp->dr_close)(dp, &mess); break; +#ifdef DEV_IOCTL + case DEV_IOCTL: r = (*dp->dr_ioctl)(dp, &mess, 0); break; +#endif + case DEV_IOCTL_S: r = (*dp->dr_ioctl)(dp, &mess, 1); break; + case CANCEL: r = (*dp->dr_cancel)(dp, &mess);break; + case DEV_SELECT: r = (*dp->dr_select)(dp, &mess);break; +#ifdef DEV_READ + case DEV_READ: + case DEV_WRITE: r = do_rdwt(dp, &mess, 0); break; +#endif + case DEV_READ_S: + case DEV_WRITE_S: r = do_rdwt(dp, &mess, 1); break; +#ifdef DEV_GATHER + case DEV_GATHER: + case DEV_SCATTER: r = do_vrdwt(dp, &mess, 0); break; +#endif + case DEV_GATHER_S: + case DEV_SCATTER_S: r = do_vrdwt(dp, &mess, 1); break; + + case HARD_INT: /* leftover interrupt or expired timer. */ + if(dp->dr_hw_int) { + (*dp->dr_hw_int)(dp, &mess); + } + continue; + case PROC_EVENT: + case SYS_SIG: (*dp->dr_signal)(dp, &mess); + continue; /* don't reply */ + case SYN_ALARM: (*dp->dr_alarm)(dp, &mess); + continue; /* don't reply */ + case DEV_PING: notify(mess.m_source); + continue; + default: + if(dp->dr_other) + r = (*dp->dr_other)(dp, &mess, 0); + else + r = EINVAL; + break; + } + + /* Clean up leftover state. */ + (*dp->dr_cleanup)(); + + /* Finally, prepare and send the reply message. */ + if (r != EDONTREPLY) { + if (mess.m_type == DEV_OPEN) + { + reply_mess.m_type = DEV_REVIVE; + reply_mess.REP_ENDPT = proc_nr; + reply_mess.REP_STATUS = r; + } + else if (mess.m_type == DEV_CLOSE) + { + reply_mess.m_type = DEV_CLOSE_REPL; + reply_mess.REP_ENDPT = proc_nr; + reply_mess.REP_STATUS = r; + } + else if (mess.m_type == DEV_READ_S || + mess.m_type == DEV_WRITE_S) + { + if (r == SUSPEND) + { + printf( + "driver_task: reviving %d with SUSPEND\n", + proc_nr); + } + reply_mess.m_type = DEV_REVIVE; + reply_mess.REP_ENDPT = proc_nr; + reply_mess.REP_IO_GRANT = (cp_grant_id_t)mess.ADDRESS; + reply_mess.REP_STATUS = r; + } + else if (mess.m_type == CANCEL) + { + continue; /* The original request should send a + * reply. + */ + } + else if (mess.m_type == DEV_SELECT) + { + reply_mess.m_type = DEV_SEL_REPL1; + reply_mess.DEV_MINOR = mess.DEVICE; + reply_mess.DEV_SEL_OPS = r; + } + else if (mess.m_type == DIAGNOSTICS_S) + { + if (device_caller == FS_PROC_NR) + printf("driver_task: sending DIAG_REPL to FS\n"); + reply_mess.m_type = DIAG_REPL; + reply_mess.REP_STATUS = r; + } + else + { + printf("driver_task: TASK_REPLY to req %d\n", + mess.m_type); + reply_mess.m_type = TASK_REPLY; + reply_mess.REP_ENDPT = proc_nr; + /* Status is # of bytes transferred or error code. */ + reply_mess.REP_STATUS = r; + } + r= asynsend(device_caller, &reply_mess); + if (r != OK) + { + printf("driver_task: unable to asynsend to %d: %d\n", + device_caller, r); + } + } + } +} + + +/*===========================================================================* + * init_buffer * + *===========================================================================*/ +PRIVATE void init_buffer() +{ +/* Select a buffer that can safely be used for DMA transfers. It may also + * be used to read partition tables and such. Its absolute address is + * 'tmp_phys', the normal address is 'tmp_buf'. + */ + +#if (CHIP == INTEL) + unsigned left; + + tmp_buf = buffer; + sys_umap(SELF, D, (vir_bytes)buffer, (phys_bytes)sizeof(buffer), &tmp_phys); + + if ((left = dma_bytes_left(tmp_phys)) < DMA_BUF_SIZE) { + /* First half of buffer crosses a 64K boundary, can't DMA into that */ + tmp_buf += left; + tmp_phys += left; + } +#endif /* CHIP == INTEL */ +} + +/*===========================================================================* + * do_rdwt * + *===========================================================================*/ +PRIVATE int do_rdwt(dp, mp, safe) +struct driver *dp; /* device dependent entry points */ +message *mp; /* pointer to read or write message */ +int safe; /* use safecopies? */ +{ +/* Carry out a single read or write request. */ + iovec_t iovec1; + int r, opcode; + phys_bytes phys_addr; + u64_t position; + + /* Disk address? Address and length of the user buffer? */ + if (mp->COUNT < 0) return(EINVAL); + + /* Check the user buffer (not relevant for safe copies). */ + if(!safe) { + sys_umap(mp->IO_ENDPT, D, (vir_bytes) mp->ADDRESS, mp->COUNT, &phys_addr); + if (phys_addr == 0) return(EFAULT); + } + + /* Prepare for I/O. */ + if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO); + + /* Create a one element scatter/gather vector for the buffer. */ + if( +#ifdef DEV_READ + mp->m_type == DEV_READ || +#endif + mp->m_type == DEV_READ_S) opcode = DEV_GATHER_S; + else opcode = DEV_SCATTER_S; + + iovec1.iov_addr = (vir_bytes) mp->ADDRESS; + iovec1.iov_size = mp->COUNT; + + /* Transfer bytes from/to the device. */ + position= make64(mp->POSITION, mp->HIGHPOS); + r = (*dp->dr_transfer)(mp->IO_ENDPT, opcode, position, &iovec1, 1, safe); + + /* Return the number of bytes transferred or an error code. */ + return(r == OK ? (mp->COUNT - iovec1.iov_size) : r); +} + +/*==========================================================================* + * do_vrdwt * + *==========================================================================*/ +PRIVATE int do_vrdwt(dp, mp, safe) +struct driver *dp; /* device dependent entry points */ +message *mp; /* pointer to read or write message */ +int safe; /* use safecopies? */ +{ +/* Carry out an device read or write to/from a vector of user addresses. + * The "user addresses" are assumed to be safe, i.e. FS transferring to/from + * its own buffers, so they are not checked. + */ + static iovec_t iovec[NR_IOREQS]; + iovec_t *iov; + phys_bytes iovec_size; + unsigned nr_req; + int r, j, opcode; + u64_t position; + + nr_req = mp->COUNT; /* Length of I/O vector */ + + { + /* Copy the vector from the caller to kernel space. */ + if (nr_req > NR_IOREQS) nr_req = NR_IOREQS; + iovec_size = (phys_bytes) (nr_req * sizeof(iovec[0])); + + if(safe) { + if (OK != sys_safecopyfrom(mp->m_source, (vir_bytes) mp->IO_GRANT, + 0, (vir_bytes) iovec, iovec_size, D)) { + panic((*dp->dr_name)(),"bad (safe) I/O vector by", mp->m_source); + } + } else { + if (OK != sys_datacopy(mp->m_source, (vir_bytes) mp->ADDRESS, + SELF, (vir_bytes) iovec, iovec_size)) { + panic((*dp->dr_name)(),"bad I/O vector by", mp->m_source); + } + } + + iov = iovec; + } + + /* Prepare for I/O. */ + if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO); + + /* Transfer bytes from/to the device. */ + opcode = mp->m_type; + position= make64(mp->POSITION, mp->HIGHPOS); + r = (*dp->dr_transfer)(mp->IO_ENDPT, opcode, position, iov, + nr_req, safe); + + /* Copy the I/O vector back to the caller. */ + if(safe) { + if (OK != sys_safecopyto(mp->m_source, (vir_bytes) mp->IO_GRANT, + 0, (vir_bytes) iovec, iovec_size, D)) { + panic((*dp->dr_name)(),"couldn't return I/O vector", mp->m_source); + } + } else { + sys_datacopy(SELF, (vir_bytes) iovec, + mp->m_source, (vir_bytes) mp->ADDRESS, iovec_size); + } + + return(r); +} + +/*===========================================================================* + * no_name * + *===========================================================================*/ +PUBLIC char *no_name() +{ +/* Use this default name if there is no specific name for the device. This was + * originally done by fetching the name from the task table for this process: + * "return(tasktab[proc_number(proc_ptr) + NR_TASKS].name);", but currently a + * real "noname" is returned. Perhaps, some system information service can be + * queried for a name at a later time. + */ + static char name[] = "noname"; + return name; +} + +/*============================================================================* + * do_nop * + *============================================================================*/ +PUBLIC int do_nop(dp, mp) +struct driver *dp; +message *mp; +{ +/* Nothing there, or nothing to do. */ + + switch (mp->m_type) { + case DEV_OPEN: return(ENODEV); + case DEV_CLOSE: return(OK); + case DEV_IOCTL_S: +#ifdef DEV_IOCTL + case DEV_IOCTL: return(ENOTTY); +#endif + default: printf("nop: ignoring code %d\n", mp->m_type); return(EIO); + } +} + +/*============================================================================* + * nop_ioctl * + *============================================================================*/ +PUBLIC int nop_ioctl(dp, mp, safe) +struct driver *dp; +message *mp; +int safe; +{ + return(ENOTTY); +} + +/*============================================================================* + * nop_signal * + *============================================================================*/ +PUBLIC void nop_signal(dp, mp) +struct driver *dp; +message *mp; +{ +/* Default action for signal is to ignore. */ +} + +/*============================================================================* + * nop_alarm * + *============================================================================*/ +PUBLIC void nop_alarm(dp, mp) +struct driver *dp; +message *mp; +{ +/* Ignore the leftover alarm. */ +} + +/*===========================================================================* + * nop_prepare * + *===========================================================================*/ +PUBLIC struct device *nop_prepare(device) +{ +/* Nothing to prepare for. */ + return(NIL_DEV); +} + +/*===========================================================================* + * nop_cleanup * + *===========================================================================*/ +PUBLIC void nop_cleanup() +{ +/* Nothing to clean up. */ +} + +/*===========================================================================* + * nop_cancel * + *===========================================================================*/ +PUBLIC int nop_cancel(struct driver *dr, message *m) +{ +/* Nothing to do for cancel. */ + return(OK); +} + +/*===========================================================================* + * nop_select * + *===========================================================================*/ +PUBLIC int nop_select(struct driver *dr, message *m) +{ +/* Nothing to do for select. */ + return(OK); +} + +/*============================================================================* + * do_diocntl * + *============================================================================*/ +PUBLIC int do_diocntl(dp, mp, safe) +struct driver *dp; +message *mp; /* pointer to ioctl request */ +int safe; /* addresses or grants? */ +{ +/* Carry out a partition setting/getting request. */ + struct device *dv; + struct partition entry; + int s; + + if (mp->REQUEST != DIOCSETP && mp->REQUEST != DIOCGETP) { + if(dp->dr_other) { + return dp->dr_other(dp, mp, safe); + } else return(ENOTTY); + } + + /* Decode the message parameters. */ + if ((dv = (*dp->dr_prepare)(mp->DEVICE)) == NIL_DEV) return(ENXIO); + + if (mp->REQUEST == DIOCSETP) { + /* Copy just this one partition table entry. */ + if(safe) { + s=sys_safecopyfrom(mp->IO_ENDPT, (vir_bytes) mp->IO_GRANT, + 0, (vir_bytes) &entry, sizeof(entry), D); + } else{ + s=sys_datacopy(mp->IO_ENDPT, (vir_bytes) mp->ADDRESS, + SELF, (vir_bytes) &entry, sizeof(entry)); + } + if(s != OK) + return s; + dv->dv_base = entry.base; + dv->dv_size = entry.size; + } else { + /* Return a partition table entry and the geometry of the drive. */ + entry.base = dv->dv_base; + entry.size = dv->dv_size; + (*dp->dr_geometry)(&entry); + if(safe) { + s=sys_safecopyto(mp->IO_ENDPT, (vir_bytes) mp->IO_GRANT, + 0, (vir_bytes) &entry, sizeof(entry), D); + } else { + s=sys_datacopy(SELF, (vir_bytes) &entry, + mp->IO_ENDPT, (vir_bytes) mp->ADDRESS, sizeof(entry)); + } + if (OK != s) + return s; + } + return(OK); +} + +/*===========================================================================* + * mq_queue * + *===========================================================================*/ +PUBLIC int mq_queue(message *m) +{ + mq_t *mq, *mi; + + if(!(mq = mq_get())) + panic("libdriver","mq_queue: mq_get failed", NO_NUM); + memcpy(&mq->mq_mess, m, sizeof(mq->mq_mess)); + mq->mq_next = NULL; + if(!queue_head) { + queue_head = mq; + } else { + for(mi = queue_head; mi->mq_next; mi = mi->mq_next) + ; + mi->mq_next = mq; + } + + return OK; +} + +#define ASYN_NR 100 +PRIVATE asynmsg_t msgtable[ASYN_NR]; +PRIVATE int first_slot= 0, next_slot= 0; + +PUBLIC int asynsend(dst, mp) +endpoint_t dst; +message *mp; +{ + int r, src_ind, dst_ind; + unsigned flags; + + /* Update first_slot */ + for (; first_slot < next_slot; first_slot++) + { + flags= msgtable[first_slot].flags; + if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE)) + { + if (msgtable[first_slot].result != OK) + { + printf( + "asynsend: found completed entry %d with error %d\n", + first_slot, + msgtable[first_slot].result); + } + continue; + } + if (flags != AMF_EMPTY) + break; + } + + if (first_slot >= next_slot) + { + /* Reset first_slot and next_slot */ + next_slot= first_slot= 0; + } + + if (next_slot >= ASYN_NR) + { + /* Tell the kernel to stop processing */ + r= senda(NULL, 0); + if (r != OK) + panic(__FILE__, "asynsend: senda failed", r); + + dst_ind= 0; + for (src_ind= first_slot; src_ind= ASYN_NR) + panic(__FILE__, "asynsend: msgtable full", NO_NUM); + } + + msgtable[next_slot].dst= dst; + msgtable[next_slot].msg= *mp; + msgtable[next_slot].flags= AMF_VALID; /* Has to be last. The kernel + * scans this table while we + * are sleeping. + */ + next_slot++; + + /* Tell the kernel to rescan the table */ + return senda(msgtable+first_slot, next_slot-first_slot); +} + diff --git a/drivers/libdriver_asyn/driver.h b/drivers/libdriver_asyn/driver.h new file mode 100644 index 000000000..8c019e92e --- /dev/null +++ b/drivers/libdriver_asyn/driver.h @@ -0,0 +1,93 @@ +/* Types and constants shared between the generic and device dependent + * device driver code. + */ + +#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */ +#define _MINIX 1 /* tell headers to include MINIX stuff */ +#define _SYSTEM 1 /* get negative error number in */ + +/* The following are so basic, all the *.c files get them automatically. */ +#include /* MUST be first */ +#include /* MUST be second */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* Info about and entry points into the device dependent code. */ +struct driver { + _PROTOTYPE( char *(*dr_name), (void) ); + _PROTOTYPE( int (*dr_open), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( int (*dr_close), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( int (*dr_ioctl), (struct driver *dp, message *m_ptr, int safe) ); + _PROTOTYPE( struct device *(*dr_prepare), (int device) ); + _PROTOTYPE( int (*dr_transfer), (int proc_nr, int opcode, u64_t position, + iovec_t *iov, unsigned nr_req, int safe) ); + _PROTOTYPE( void (*dr_cleanup), (void) ); + _PROTOTYPE( void (*dr_geometry), (struct partition *entry) ); + _PROTOTYPE( void (*dr_signal), (struct driver *dp, message *m_ptr) ); + _PROTOTYPE( void (*dr_alarm), (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, int safe) ); + _PROTOTYPE( int (*dr_hw_int), (struct driver *dp, message *m_ptr) ); +}; + +#if (CHIP == INTEL) + +/* Number of bytes you can DMA before hitting a 64K boundary: */ +#define dma_bytes_left(phys) \ + ((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF)) + +#endif /* CHIP == INTEL */ + +/* Base and size of a partition in bytes. */ +struct device { + u64_t dv_base; + u64_t dv_size; +}; + +#define NIL_DEV ((struct device *) 0) + +/* Functions defined by driver.c: */ +_PROTOTYPE( void driver_task, (struct driver *dr) ); +_PROTOTYPE( char *no_name, (void) ); +_PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) ); +_PROTOTYPE( struct device *nop_prepare, (int device) ); +_PROTOTYPE( void nop_cleanup, (void) ); +_PROTOTYPE( void nop_task, (void) ); +_PROTOTYPE( void nop_signal, (struct driver *dp, message *m_ptr) ); +_PROTOTYPE( void nop_alarm, (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, int safe) ); +_PROTOTYPE( int nop_ioctl, (struct driver *dp, message *m_ptr, int safe) ); +_PROTOTYPE( int mq_queue, (message *m_ptr) ); + +/* Parameters for the disk drive. */ +#define SECTOR_SIZE 512 /* physical sector size in bytes */ +#define SECTOR_SHIFT 9 /* for division */ +#define SECTOR_MASK 511 /* and remainder */ + +/* Size of the DMA buffer buffer in bytes. */ +#define USE_EXTRA_DMA_BUF 0 /* usually not needed */ +#define DMA_BUF_SIZE (DMA_SECTORS * SECTOR_SIZE) + +#if (CHIP == INTEL) +extern u8_t *tmp_buf; /* the DMA buffer */ +#else +extern u8_t tmp_buf[]; /* the DMA buffer */ +#endif +extern phys_bytes tmp_phys; /* phys address of DMA buffer */ diff --git a/drivers/libdriver_asyn/drvlib.c b/drivers/libdriver_asyn/drvlib.c new file mode 100644 index 000000000..57d7dfe65 --- /dev/null +++ b/drivers/libdriver_asyn/drvlib.c @@ -0,0 +1,199 @@ +/* IBM device driver utility functions. Author: Kees J. Bot + * 7 Dec 1995 + * Entry point: + * partition: partition a disk to the partition table(s) on it. + */ + +#include "driver.h" +#include "drvlib.h" +#include + +/* Extended partition? */ +#define ext_part(s) ((s) == 0x05 || (s) == 0x0F) + +FORWARD _PROTOTYPE( void extpartition, (struct driver *dp, int extdev, + unsigned long extbase) ); +FORWARD _PROTOTYPE( int get_part_table, (struct driver *dp, int device, + unsigned long offset, struct part_entry *table)); +FORWARD _PROTOTYPE( void sort, (struct part_entry *table) ); + +#ifndef CD_SECTOR_SIZE +#define CD_SECTOR_SIZE 2048 +#endif + +/*============================================================================* + * partition * + *============================================================================*/ +PUBLIC void partition(dp, device, style, atapi) +struct driver *dp; /* device dependent entry points */ +int device; /* device to partition */ +int style; /* partitioning style: floppy, primary, sub. */ +int atapi; /* atapi device */ +{ +/* This routine is called on first open to initialize the partition tables + * of a device. It makes sure that each partition falls safely within the + * device's limits. Depending on the partition style we are either making + * floppy partitions, primary partitions or subpartitions. Only primary + * partitions are sorted, because they are shared with other operating + * systems that expect this. + */ + struct part_entry table[NR_PARTITIONS], *pe; + int disk, par; + struct device *dv; + unsigned long base, limit, part_limit; + + /* Get the geometry of the device to partition */ + if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV + || cmp64u(dv->dv_size, 0) == 0) return; + base = div64u(dv->dv_base, SECTOR_SIZE); + limit = base + div64u(dv->dv_size, SECTOR_SIZE); + + /* Read the partition table for the device. */ + if(!get_part_table(dp, device, 0L, table)) { + return; + } + + /* Compute the device number of the first partition. */ + switch (style) { + case P_FLOPPY: + device += MINOR_fd0p0; + break; + case P_PRIMARY: + sort(table); /* sort a primary partition table */ + device += 1; + break; + case P_SUB: + disk = device / DEV_PER_DRIVE; + par = device % DEV_PER_DRIVE - 1; + device = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS; + } + + /* Find an array of devices. */ + if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV) return; + + /* Set the geometry of the partitions from the partition table. */ + for (par = 0; par < NR_PARTITIONS; par++, dv++) { + /* Shrink the partition to fit within the device. */ + pe = &table[par]; + part_limit = pe->lowsec + pe->size; + if (part_limit < pe->lowsec) part_limit = limit; + if (part_limit > limit) part_limit = limit; + if (pe->lowsec < base) pe->lowsec = base; + if (part_limit < pe->lowsec) part_limit = pe->lowsec; + + dv->dv_base = mul64u(pe->lowsec, SECTOR_SIZE); + dv->dv_size = mul64u(part_limit - pe->lowsec, SECTOR_SIZE); + + if (style == P_PRIMARY) { + /* Each Minix primary partition can be subpartitioned. */ + if (pe->sysind == MINIX_PART) + partition(dp, device + par, P_SUB, atapi); + + /* An extended partition has logical partitions. */ + if (ext_part(pe->sysind)) + extpartition(dp, device + par, pe->lowsec); + } + } +} + +/*============================================================================* + * extpartition * + *============================================================================*/ +PRIVATE void extpartition(dp, extdev, extbase) +struct driver *dp; /* device dependent entry points */ +int extdev; /* extended partition to scan */ +unsigned long extbase; /* sector offset of the base extended partition */ +{ +/* Extended partitions cannot be ignored alas, because people like to move + * files to and from DOS partitions. Avoid reading this code, it's no fun. + */ + struct part_entry table[NR_PARTITIONS], *pe; + int subdev, disk, par; + struct device *dv; + unsigned long offset, nextoffset; + + disk = extdev / DEV_PER_DRIVE; + par = extdev % DEV_PER_DRIVE - 1; + subdev = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS; + + offset = 0; + do { + if (!get_part_table(dp, extdev, offset, table)) return; + sort(table); + + /* The table should contain one logical partition and optionally + * another extended partition. (It's a linked list.) + */ + nextoffset = 0; + for (par = 0; par < NR_PARTITIONS; par++) { + pe = &table[par]; + if (ext_part(pe->sysind)) { + nextoffset = pe->lowsec; + } else + if (pe->sysind != NO_PART) { + if ((dv = (*dp->dr_prepare)(subdev)) == NIL_DEV) return; + + dv->dv_base = mul64u(extbase + offset + pe->lowsec, + SECTOR_SIZE); + dv->dv_size = mul64u(pe->size, SECTOR_SIZE); + + /* Out of devices? */ + if (++subdev % NR_PARTITIONS == 0) return; + } + } + } while ((offset = nextoffset) != 0); +} + +/*============================================================================* + * get_part_table * + *============================================================================*/ +PRIVATE int get_part_table(dp, device, offset, table) +struct driver *dp; +int device; +unsigned long offset; /* sector offset to the table */ +struct part_entry *table; /* four entries */ +{ +/* Read the partition table for the device, return true iff there were no + * errors. + */ + iovec_t iovec1; + u64_t position; + static unsigned char partbuf[CD_SECTOR_SIZE]; + + position = mul64u(offset, SECTOR_SIZE); + iovec1.iov_addr = (vir_bytes) partbuf; + iovec1.iov_size = CD_SECTOR_SIZE; + if ((*dp->dr_prepare)(device) != NIL_DEV) { + (void) (*dp->dr_transfer)(SELF, DEV_GATHER_S, position, &iovec1, 1, 0); + } + if (iovec1.iov_size != 0) { + return 0; + } + if (partbuf[510] != 0x55 || partbuf[511] != 0xAA) { + /* Invalid partition table. */ + return 0; + } + memcpy(table, (partbuf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0])); + return 1; +} + +/*===========================================================================* + * sort * + *===========================================================================*/ +PRIVATE void sort(table) +struct part_entry *table; +{ +/* Sort a partition table. */ + struct part_entry *pe, tmp; + int n = NR_PARTITIONS; + + do { + for (pe = table; pe < table + NR_PARTITIONS-1; pe++) { + if (pe[0].sysind == NO_PART + || (pe[0].lowsec > pe[1].lowsec + && pe[1].sysind != NO_PART)) { + tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp; + } + } + } while (--n > 0); +} diff --git a/drivers/libdriver_asyn/drvlib.h b/drivers/libdriver_asyn/drvlib.h new file mode 100644 index 000000000..1986cab05 --- /dev/null +++ b/drivers/libdriver_asyn/drvlib.h @@ -0,0 +1,27 @@ +/* IBM device driver definitions Author: Kees J. Bot + * 7 Dec 1995 + */ + +#include + +_PROTOTYPE( void partition, (struct driver *dr, int device, int style, int atapi) ); + +/* BIOS parameter table layout. */ +#define bp_cylinders(t) (* (u16_t *) (&(t)[0])) +#define bp_heads(t) (* (u8_t *) (&(t)[2])) +#define bp_reduced_wr(t) (* (u16_t *) (&(t)[3])) +#define bp_precomp(t) (* (u16_t *) (&(t)[5])) +#define bp_max_ecc(t) (* (u8_t *) (&(t)[7])) +#define bp_ctlbyte(t) (* (u8_t *) (&(t)[8])) +#define bp_landingzone(t) (* (u16_t *) (&(t)[12])) +#define bp_sectors(t) (* (u8_t *) (&(t)[14])) + +/* Miscellaneous. */ +#define DEV_PER_DRIVE (1 + NR_PARTITIONS) +#define MINOR_t0 64 +#define MINOR_r0 120 +#define MINOR_d0p0s0 128 +#define MINOR_fd0p0 (28<<2) +#define P_FLOPPY 0 +#define P_PRIMARY 1 +#define P_SUB 2 diff --git a/drivers/libdriver_asyn/mq.c b/drivers/libdriver_asyn/mq.c new file mode 100644 index 000000000..a80900d83 --- /dev/null +++ b/drivers/libdriver_asyn/mq.c @@ -0,0 +1,61 @@ +/* +inet/mq.c + +Created: Jan 3, 1992 by Philip Homburg + +Copyright 1995 Philip Homburg +*/ + +#include +#include + +#include +#include +#include +#include +#include + +#define MQ_SIZE 128 + +PRIVATE mq_t mq_list[MQ_SIZE]; +PRIVATE mq_t *mq_freelist; + +void mq_init() +{ + int i; + + mq_freelist= NULL; + for (i= 0; imq_next; + mq->mq_next= NULL; + assert(mq->mq_allocated == 0); + mq->mq_allocated= 1; + return mq; +} + +void mq_free(mq) +mq_t *mq; +{ + mq->mq_next= mq_freelist; + mq_freelist= mq; + assert(mq->mq_allocated == 1); + mq->mq_allocated= 0; +} + +/* + * $PchId: mq.c,v 1.7 1998/10/23 20:10:47 philip Exp $ + */