Minix1.1/usr/src/fs/device.c
/* When a needed block is not in the cache, it must be fetched from the disk.
* Special character files also require I/O. The routines for these are here.
*
* The entry points in this file are:
* dev_open: called when a special file is opened
* dev_close: called when a special file is closed
* dev_io: perform a read or write on a block or character device
* do_ioctl: perform the IOCTL system call
* rw_dev: procedure that actually calls the kernel tasks
* rw_dev2: procedure that actually calls task for /dev/tty
* no_call: dummy procedure (e.g., used when device need not be opened)
*/
#include "../h/const.h"
#include "../h/type.h"
#include "../h/com.h"
#include "../h/error.h"
#include "const.h"
#include "type.h"
#include "dev.h"
#include "file.h"
#include "fproc.h"
#include "glo.h"
#include "inode.h"
#include "param.h"
PRIVATE message dev_mess;
PRIVATE major, minor, task;
extern max_major;
/*===========================================================================*
* dev_open *
*===========================================================================*/
PUBLIC int dev_open(dev, mod)
dev_nr dev; /* which device to open */
int mod; /* how to open it */
{
/* Special files may need special processing upon open. */
find_dev(dev);
(*dmap[major].dmap_open)(task, &dev_mess);
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* dev_close *
*===========================================================================*/
PUBLIC dev_close(dev)
dev_nr dev; /* which device to close */
{
/* This procedure can be used when a special file needs to be closed. */
find_dev(dev);
(*dmap[major].dmap_close)(task, &dev_mess);
}
/*===========================================================================*
* dev_io *
*===========================================================================*/
PUBLIC int dev_io(rw_flag, dev, pos, bytes, proc, buff)
int rw_flag; /* READING or WRITING */
dev_nr dev; /* major-minor device number */
long pos; /* byte position */
int bytes; /* how many bytes to transfer */
int proc; /* in whose address space is buff? */
char *buff; /* virtual address of the buffer */
{
/* Read or write from a device. The parameter 'dev' tells which one. */
find_dev(dev);
/* Set up the message passed to task. */
dev_mess.m_type = (rw_flag == READING ? DISK_READ : DISK_WRITE);
dev_mess.DEVICE = (dev >> MINOR) & BYTE;
dev_mess.POSITION = pos;
dev_mess.PROC_NR = proc;
dev_mess.ADDRESS = buff;
dev_mess.COUNT = bytes;
/* Call the task. */
(*dmap[major].dmap_rw)(task, &dev_mess);
/* Task has completed. See if call completed. */
if (dev_mess.REP_STATUS == SUSPEND) suspend(task); /* suspend user */
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* do_ioctl *
*===========================================================================*/
PUBLIC do_ioctl()
{
/* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
struct filp *f;
register struct inode *rip;
extern struct filp *get_filp();
if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
rip = f->filp_ino; /* get inode pointer */
if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) return(ENOTTY);
find_dev(rip->i_zone[0]);
dev_mess.m_type = TTY_IOCTL;
dev_mess.PROC_NR = who;
dev_mess.TTY_LINE = minor;
dev_mess.TTY_REQUEST = m.TTY_REQUEST;
dev_mess.TTY_SPEK = m.TTY_SPEK;
dev_mess.TTY_FLAGS = m.TTY_FLAGS;
/* Call the task. */
(*dmap[major].dmap_rw)(task, &dev_mess);
/* Task has completed. See if call completed. */
if (dev_mess.m_type == SUSPEND) suspend(task); /* User must be suspended. */
m1.TTY_SPEK = dev_mess.TTY_SPEK; /* erase and kill */
m1.TTY_FLAGS = dev_mess.TTY_FLAGS; /* flags */
return(dev_mess.REP_STATUS);
}
/*===========================================================================*
* find_dev *
*===========================================================================*/
PRIVATE find_dev(dev)
dev_nr dev; /* device */
{
/* Extract the major and minor device number from the parameter. */
major = (dev >> MAJOR) & BYTE; /* major device number */
minor = (dev >> MINOR) & BYTE; /* minor device number */
if (major == 0 || major >= max_major) panic("bad major dev", major);
task = dmap[major].dmap_task; /* which task services the device */
dev_mess.DEVICE = minor;
}
/*===========================================================================*
* rw_dev *
*===========================================================================*/
PUBLIC rw_dev(task_nr, mess_ptr)
int task_nr; /* which task to call */
message *mess_ptr; /* pointer to message for task */
{
/* All file system I/O ultimately comes down to I/O on major/minor device
* pairs. These lead to calls on the following routines via the dmap table.
*/
int proc_nr;
proc_nr = mess_ptr->PROC_NR;
if (sendrec(task_nr, mess_ptr) != OK) panic("rw_dev: can't send", NO_NUM);
while (mess_ptr->REP_PROC_NR != proc_nr) {
/* Instead of the reply to this request, we got a message for an
* earlier request. Handle it and go receive again.
*/
revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
receive(task_nr, mess_ptr);
}
}
/*===========================================================================*
* rw_dev2 *
*===========================================================================*/
PUBLIC rw_dev2(dummy, mess_ptr)
int dummy; /* not used - for compatibility with rw_dev() */
message *mess_ptr; /* pointer to message for task */
{
/* This routine is only called for one device, namely /dev/tty. It's job
* is to change the message to use the controlling terminal, instead of the
* major/minor pair for /dev/tty itself.
*/
int task_nr, major_device;
major_device = (fp->fs_tty >> MAJOR) & BYTE;
task_nr = dmap[major_device].dmap_task; /* task for controlling tty */
mess_ptr->DEVICE = (fp->fs_tty >> MINOR) & BYTE;
rw_dev(task_nr, mess_ptr);
}
/*===========================================================================*
* no_call *
*===========================================================================*/
PUBLIC int no_call(task_nr, m_ptr)
int task_nr; /* which task */
message *m_ptr; /* message pointer */
{
/* Null operation always succeeds. */
m_ptr->REP_STATUS = OK;
}