[comp.os.minix] NYUMINIX:KERNEL\MSDISK.C

jai@lab.ultra.nyu.edu (Benchiao Jai) (02/24/91)

/* This file contains the driver for the logical disk /dev/msd*
 * which is physically an MS-DOS file MINIXDSK in the current directory
 * from where NYUMINIX was booted.  It accepts three messages, for reading,
 * writing, and control. All use message format m2 and with these parameters:
 *
 *    m_type      DEVICE   PROC_NR   COUNT  POSITION  ADDRESS
 * ------------------------------------------------------------
 * |  DISK_READ | device | proc nr | bytes | offset | buf ptr |
 * |------------+--------+---------+-------+--------+---------|
 * | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
 * |------------+--------+---------+-------+--------+---------|
 * | DISK_IOCTL | device |         |       |        |         |
 * ------------------------------------------------------------
 *
 * The file contains one entry point :
 *
 *   winchester_task:   main entry when system is brought up
 *
 */

#include "..\h\const.h"
#include "..\h\type.h"
#include "..\h\callnr.h"
#include "..\h\com.h"
#include "..\h\error.h"
#include "const.h"
#include "type.h"
#include "proc.h"

void __emit__();
void __int__(int intno);
#define int21() __int__(0x21)
#define MS_READ  0x3f
#define MS_WRITE 0x40
#define M_RESET   0
#define M_READING 1
#define M_WRITING 2
#define M_ERROR   3

#define NR_MSDS 8

extern char get_byte();
extern void put_byte();
PRIVATE message mess;
PRIVATE char *MSfilename[NR_MSDS] =
  {"MINIXDSK.0","MINIXDSK.1","MINIXDSK.2","MINIXDSK.3",
   "MINIXDSK.4","MINIXDSK.5","MINIXDSK.6","MINIXDSK.7"};
PRIVATE int f_handle[NR_MSDS] = {-1,-1,-1,-1,-1,-1,-1,-1};
PRIVATE long f_size[NR_MSDS];
PRIVATE char sp_filename[80] = "";
PRIVATE int sp_handle = -1;
PRIVATE int sp_status = M_RESET;

/*===========================================================================*
 *                              winchester_task                              *
 *===========================================================================*/
PUBLIC winchester_task()
{
/* Main program of the msdisk driver task. */

  int r, caller, proc_nr;

  /* Open the physical file. */
  for (r = 0; r < NR_MSDS; r++) do_reopen(r);

  /* Main loop. */
  while (TRUE)
  {
    /* Receive the request. */
    receive(ANY, &mess);
    caller  = mess.m_source;
    proc_nr = mess.PROC_NR;
    if ( caller < 0 ) panic("msdisk task got message from ", caller);

    /* Carry out the work. */
    switch (mess.m_type)
    {
      case DISK_READ:
      case DISK_WRITE: r = do_rdwt(&mess);              break;
      case DISK_IOCTL:/*r= do_reopen(mess.DEVICE);      break;*/
      default:         r = EINVAL;                      break;
    }

    /* Prepare and send the reply message. */
    mess.m_type      = TASK_REPLY;
    mess.REP_PROC_NR = proc_nr;
    mess.REP_STATUS  = r;
    send(caller, &mess);
  }
}

/*===========================================================================*
 *                                  do_rwdt                                  *
 *===========================================================================*/
PRIVATE do_rdwt(m_ptr)
message *m_ptr;
{
  struct proc *rp;
  phys_bytes user_phys;
  int count, dssave, fn_num, device, seg, ofs, i;
  long offset;
  extern phys_bytes umap();

  device = m_ptr->DEVICE;
  if (device < 0 || device >= NR_MSDS+2) return(ENXIO); /* bad minor device */
  if ( device < NR_MSDS && f_handle[device] < 0 ) return(EIO);
  offset = m_ptr->POSITION;
  if ( offset < 0 ) return(ENXIO);
  count = m_ptr->COUNT;
  if ( device < NR_MSDS && offset + count > f_size[device] )
    count = (int)(f_size[device] - offset);
  rp = proc_addr(m_ptr->PROC_NR);
  user_phys = umap(rp, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) count);
  if ( user_phys == 0 ) return(E_BAD_ADDR);
  fn_num = (m_ptr->m_type == DISK_READ) ? MS_READ : MS_WRITE;
  dssave = _DS;
  if ( device < NR_MSDS )
  {
    _BX = f_handle[device];
    _CX = *((int *)(&offset)+1);
    _DX = (int)offset;
    _AX = 0x4200;
    int21();            /* Lseek from head. */
    _BX = f_handle[device];
    _DS = ((unsigned)user_phys >> 4) + (*((int *)(&user_phys)+1) << 12);
    _DX = (int)user_phys & 0xF;
    _CX = count;
    _AH = fn_num;
    int21();            /* Read or write. */
    _DS = dssave;
    if ( fn_num == MS_WRITE ) do_reopen(device);
    return(count);
  }
  else if ( device == NR_MSDS )
  {
    seg = (int)(user_phys >> 4);
    ofs = (int)user_phys & 0xF;
    if ( fn_num == MS_READ )
    {
      if ( sp_status == M_RESET ) return(0);
      put_byte(seg, ofs, sp_status);
      if ( sp_status == M_ERROR ) sp_status = M_RESET;
      return(1);
    }
    else
    {
      if (count > 79) count = 79;
      for ( i=0; i<count; i++, ofs++)
      {
        sp_filename[i] = get_byte(seg, ofs);
        if ( sp_filename[i] == '/' ) sp_filename[i] = '\\';
      }
      if ( sp_filename[i-1] == '\n' ) --i;
      sp_filename[i] = '\0';
      switch (sp_status)
      {
        case M_RESET:
          if ( sp_filename[0] == 'R' || sp_filename[0] == 'W' )
          {
            if ( sp_filename[0] == 'R' )
            {
              fn_num = 0x3d00;
              sp_status = M_READING;
            }
            else
            {
              fn_num = 0x3c00;
              sp_status = M_WRITING;
            }
            _DX = (int)(sp_filename+1);
            _CX = 0;
            _AX = fn_num;
            int21();              /* Create file. */
            __emit__(0x19,0xd2);  /* sbb dx,dx */
            __emit__(0x09,0xd0);  /* or ax,dx */
            sp_handle = _AX;
            if ( sp_handle >= 0 ) return(count);
          }
          sp_status = M_ERROR;
          return(EIO);
        case M_READING:
        case M_WRITING:
          if ( sp_filename[0] == 'C' )
          {
            _BX = sp_handle;
            _AH = 0x3e;
            int21();        /* Close file. */
            sp_status = M_RESET;
            return(count);
          }
        default:
          return(EIO);
      }
    }
  }
  else
  {
    if ( sp_status != (fn_num==MS_READ ? M_READING : M_WRITING) ) return(EIO);
    _BX = sp_handle;
    _DS = ((unsigned)user_phys >> 4) + (*((int *)(&user_phys)+1) << 12);
    _DX = ((int)user_phys & 0xF);
    _CX = count;
    _AH = fn_num;
    int21();            /* Read or write. */
    count = _AX;
    _DS = dssave;
    return(count);
  }
}

/*===========================================================================*
 *                                 do_reopen                                 *
 *===========================================================================*/
PRIVATE do_reopen(device)
int device;
{
  int i,j;

  if ( f_handle[device] >= 0 )
  {
    _BX = f_handle[device];
    _AH = 0x3e;
    int21();            /* Close file. */
  }
  _DX = (int)(MSfilename[device]);
  _AX = 0x3d02;
  int21();              /* Open file for read/write. */
  __emit__(0x19,0xd2);  /* sbb dx,dx */
  __emit__(0x09,0xd0);  /* or ax,dx */
  i = _AX;
  f_handle[device] = i;
  if ( i < 0 ) return(EIO);
  else
  {
    _BX = i;
    _CX = 0;
    _DX = 0;
    _AX = 0x4202;
    int21();            /* Lseek from end. */
    i = _AX;
    j = _DX;
    *((int *)(&f_size[device])) = i;
    *((int *)(&f_size[device])+1) = j;
  }
  return(OK);
}