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