📄 bios.c
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/*
*****************************************************************************
BIOS - "Device driver Using The PC Bios."
Summary
#include <posix.h>
BOOL bios_open(driveno)
UCOUNT driveno
BOOL bios_close(driveno)
UCOUNT driveno
BOOL bios_io(driveno, sector, buffer, count, reading)
UCOUNT driveno;
ULONG sector;
VOID *buffer;
UCOUNT count;
BOOL reading;
Description
This is a model device driver for RTFS. It provide the device driver
services for disks A:, B:, C: and D: on a PC with a bios.
These routines are pointed to by the table pc_devsw[] in devtable.c
bios_open's job is to prepare for calls to bios_io. It manages the
device open count, it detects drive parameters, and on drives C:
and D: Calls the partition code to find the base of the DOS partition.
bios_close's job is to manage the device open count and shut the drive
down if the open count drops to zero.
bios_io's job is to read and write blocks from/to the partition managed
by driveno. Before accessing the block(s) it converts the logical block
to a physical block.
*****************************************************************************
*/
#include "pcdisk.h"
#include <bios.h>
#include <dos.h>
typedef struct disk_table {
BOOL valid;
COUNT drive_type; /* For floppies, 1 = 360, 2 = 1.2, 3 = 720, 4 = 1.44 */
UCOUNT num_heads;
UCOUNT num_cyls;
UCOUNT secp_track;
UCOUNT secp_cyl;
ULONG max_sector;
} DISK_TABLE;
BOOL bios_t_init = NO;
LOCAL DISK_TABLE disk_chars[4]; /* For #heads, secptrack etc */
/* Count of times device is physically open */
LOCAL COUNT phys_drv_open_count[4];
/* If true device is open raw. Logical == physical in both device and block mapping */
LOCAL COUNT phys_raw_open[4];
/* Bios logical unit */
LOCAL COUNT drv_luns[4];
/* For the reference port the highest drive is a ramdisk so we set NUM_LOGICAL
to NDRIVES -1, leaving room the ramdisk at the top */
#define NUM_LOGICAL_DRIVES (NDRIVES-1)
/* Partition map per logical drive. Floppies will always be from 0 to ~0 */
LOCAL ULONG drv_start[NUM_LOGICAL_DRIVES];
LOCAL ULONG drv_end[NUM_LOGICAL_DRIVES];
/* Logical open count per partition. */
LOCAL COUNT bios_drv_open_count[NUM_LOGICAL_DRIVES];
/* Logical to physical drive mapping */
LOCAL COUNT bios_drv_map[NUM_LOGICAL_DRIVES];
BOOL bios_ioctl(COUNT driveno, UCOUNT command, VOID *buffer);
BOOL bios_init_drive(COUNT driveno);
BOOL bios_open(COUNT driveno);
BOOL bios_raw_open(COUNT driveno);
BOOL bios_close(COUNT driveno);
BOOL bios_io(COUNT driveno, ULONG sector, VOID *buffer, UCOUNT count, BOOL reading);
/* Initialize driver mapping tables */
LOCAL VOID bios_table_init() /*__fn__ */
{
COUNT i;
if (bios_t_init)
return;
bios_t_init = YES;
/* Physical device open counts an open flags */
for (i = 0; i < 4; i++)
{
phys_drv_open_count[i] = 0;
phys_raw_open[i] = NO;
}
/* Physical device to BIOS logical unit mapping */
drv_luns[0] = 0;
drv_luns[1] = 1;
drv_luns[2] = 0x80;
drv_luns[3] = 0x81;
/* Set up logical device map (for partitioned drives) */
for (i = 0; i < NUM_LOGICAL_DRIVES;i++)
{
drv_start[i] = 0L; /* Partition start/end */
drv_end[i] = 0L;
bios_drv_open_count[i] = 0; /* Logical drive open count */
bios_drv_map[i] = 0; /* Physical drive where partition
resides */
}
}
/* IOCTL Call. Does nothing */
BOOL bios_ioctl(COUNT driveno, UCOUNT command, VOID *buffer)
{
driveno = driveno;
command = command;
buffer = buffer;
return(YES);
}
/* Physical Open function. This is pointed to by the bdevsw[] table */
BOOL bios_open(COUNT driveno)
{
COUNT nparts;
COUNT i;
COUNT phys_drive;
COUNT log_driveno;
/* Make sure the tables are set up */
bios_table_init();
/* Fail if a raw device is mounted on driveno */
if ( (driveno < 4) && (phys_raw_open[driveno]))
return(NO);
/* Re-open ? of a logical drive ? */
if (bios_drv_open_count[driveno])
{
bios_drv_open_count[driveno] += 1;
return(YES);
}
if (driveno < 2)
{
/* Floppy disk. No partitions, logical == physical */
if (!bios_init_drive(driveno))
return(NO);
bios_drv_open_count[driveno] = 1;
phys_drv_open_count[driveno] = 1;
bios_drv_map[driveno] = driveno;
drv_start[driveno] = (ULONG) 0L;
drv_end[driveno] = (ULONG) ~0L; /* Infinity */
return(YES);
}
/* Okay - It is a hard disk partition -
open drives and map partition until our logical partition is mapped. */
for (phys_drive = 2; phys_drive < 4; phys_drive++)
{
if (!phys_drv_open_count[phys_drive])
{
if (bios_init_drive(phys_drive))
{
/* Find the next available logical drive */
log_driveno = 0;
for (i = phys_drive; i < NUM_LOGICAL_DRIVES; i++)
{
if (!bios_drv_map[i])
{
log_driveno = i;
break;
}
}
if (!log_driveno) /* Out of drive slots ?? */
return(NO);
/* Set it to raw open so we don't do any partition mapping while
we are reading partition tables */
phys_raw_open[phys_drive] = YES;
/* Now call partition init. It fills in start and end for
every partition on the drive and then return the number of
found partitions. */
nparts = ext_partition_init(phys_drive, &drv_start[log_driveno], &drv_end[log_driveno],(COUNT) (NUM_LOGICAL_DRIVES-log_driveno));
/* Clear the raw condition */
phys_raw_open[phys_drive] = NO;
if (nparts)
{
/* Map all locical drives to the physical */
for (i = 0; i < nparts; i++)
{
bios_drv_map[log_driveno+i] = phys_drive;
bios_drv_open_count[log_driveno+i] = 1;
}
phys_drv_open_count[phys_drive] = 1;
}
}
}
/* After mapping a physical disk see if our logical disk was found */
if (bios_drv_open_count[driveno])
return(YES);
} /* Loop to the next physical drive */
return(NO);
}
/* Raw Open Function. Open Device as raw block device. No partitions */
BOOL bios_raw_open(COUNT phys_drive)
{
/* Make sure the tables are set up */
bios_table_init();
if (!phys_drv_open_count[phys_drive])
if (!bios_init_drive(phys_drive))
return(NO);
phys_drv_open_count[phys_drive] += 1;
phys_raw_open[phys_drive] = YES;
return(YES);
}
/* Close function. This is pointed to by the bdevsw[] table */
BOOL bios_close(COUNT driveno)
{
COUNT phys_drive;
COUNT n_open;
COUNT i;
if (driveno < 4 && phys_raw_open[driveno])
{
phys_raw_open[driveno] = NO;
phys_drv_open_count[driveno] -= 1;
}
else
{
phys_drive = bios_drv_map[driveno];
if (bios_drv_open_count[driveno])
bios_drv_open_count[driveno] -= 1;
if (!bios_drv_open_count[driveno])
{
n_open = 0;
phys_drive = bios_drv_map[driveno];
drv_start[driveno] = 0L;
drv_end[driveno] = 0L;
bios_drv_map[driveno] = 0;
if (driveno >= 2)
{
/* If a hard disk partition see if all partitions are unmounted.
if so set the physical device open to 0 */
bios_drv_map[driveno] = 0;
for (i = phys_drive; i < NUM_LOGICAL_DRIVES; i++)
{
if (bios_drv_map[i] == phys_drive)
{
n_open = 1;
break;
}
}
}
/* No logical drives open. Mark the physical drive closed */
if (!n_open)
phys_drv_open_count[phys_drive] = 0;
}
}
return(YES);
}
/* Read/write function: This is in the bdevsw[] table. It is also called by
ext_partion_init() to establish the partition */
BOOL bios_io(COUNT driveno, ULONG sector, VOID FAR *buffer, UCOUNT count, BOOL reading)
{
union REGS in_regs;
union REGS out_regs;
struct SREGS sregs;
char FAR *tbuffer;
ULONG ltemp;
UCOUNT cyl;
UCOUNT head;
UCOUNT sec;
UCOUNT utemp;
ULONG ltemp1;
UCOUNT nleft_track;
UCOUNT n_todo;
COUNT phys_drive;
if (!count) /* Must have a count */
return(NO);
if ( (driveno < 4) && phys_raw_open[driveno] )
phys_drive = driveno;
else
phys_drive = bios_drv_map[driveno];
tbuffer = (char FAR *) buffer;
if (!phys_raw_open[phys_drive])
sector += drv_start[driveno]; /* Add in the start of partition */
/* Check the range of blocks */
ltemp = sector+count-1;
/* Check the physical drive end */
if (ltemp > disk_chars[phys_drive].max_sector)
return(NO);
/* Check the partition end. this wil be ~0 on a floppy */
if (!phys_raw_open[phys_drive] && (ltemp > drv_end[driveno]))
return(NO);
/* cylinder == sector / sectors/cyl */
ltemp = sector/disk_chars[phys_drive].secp_cyl;
cyl = (UCOUNT) ltemp;
ltemp = sector%disk_chars[phys_drive].secp_cyl;
ltemp1 = ltemp/disk_chars[phys_drive].secp_track;
head = (UCOUNT) ltemp1;
ltemp1 = ltemp%disk_chars[phys_drive].secp_track;
sec = (UCOUNT) ltemp1;
nleft_track = (UCOUNT) (disk_chars[phys_drive].secp_track - sec);
if (count > nleft_track)
n_todo = nleft_track;
else
n_todo = count;
while (count)
{
in_regs.h.al = (unsigned char) n_todo;
in_regs.h.ch = (unsigned char) (cyl & 0xff);
/* bits 8 and 9 of the cylinder become bits 6 & 7 of cl. */
utemp = (UCOUNT) ( (UCOUNT)(cyl >> 2) & 0xc0);
/* the first 6 bits are the sector */
utemp |= (UCOUNT)(sec+1);
in_regs.h.cl = (unsigned char) utemp;
in_regs.h.dh = (unsigned char) head;
in_regs.h.dl = (unsigned char) drv_luns[phys_drive];
in_regs.x.bx = FP_OFF(tbuffer);
sregs.es = FP_SEG(tbuffer);
if(reading)
in_regs.h.ah = (unsigned char) 0x02;
else
in_regs.h.ah = (unsigned char) 0x03;
int86x(0x13,&in_regs,&out_regs,&sregs);
if (out_regs.x.cflag) /* Retry once on failure */
int86x(0x13,&in_regs,&out_regs,&sregs);
if (out_regs.x.cflag)
{
return(NO);
}
sec = 0;
head += 1;
if (head == disk_chars[phys_drive].num_heads)
{
head = 0;
cyl += 1;
}
count -= n_todo;
if (!count)
break;
tbuffer += n_todo*512;
if (count < disk_chars[phys_drive].secp_track)
n_todo = count;
else
n_todo = disk_chars[phys_drive].secp_track;
}
return (YES);
}
/* init_drive: called by bios_open. Determines drive characteristics for the
drive (# heads, secptrack etc. */
BOOL bios_init_drive(COUNT phys_drive) /* __fn__ */
{
union REGS in_regs;
union REGS out_regs;
ULONG ltemp;
/* Int x13 service 8. get disk params */
in_regs.h.ah = 0x8;
in_regs.h.dl = (UTINY) drv_luns[phys_drive];
int86(0x13, &in_regs, &out_regs);
if (out_regs.x.cflag)
{
return(NO);
}
disk_chars[phys_drive].valid = 1;
/* Drive type for floppies */
disk_chars[phys_drive].drive_type = out_regs.h.bl;
/* Max head + 1 == num_heads (heads = 0-n */
disk_chars[phys_drive].num_heads = (UCOUNT) (out_regs.h.dh + 1);
/* Max sec == max_sec (sectors = 1-n */
disk_chars[phys_drive].secp_track = (UCOUNT) (out_regs.h.cl & 0x3f);
/* Bits 7&6 of cl are bits 9&8 of number of cyls. so we mask them
in and shift left twice <<(7&6,2) -> 9&8 */
disk_chars[phys_drive].num_cyls = (UCOUNT) (out_regs.h.cl & 0xc0);
disk_chars[phys_drive].num_cyls <<= 2;
/* Now or in the low seven bits. */
disk_chars[phys_drive].num_cyls |= out_regs.h.ch;
/* cyls go 0 to n so add 1 */
disk_chars[phys_drive].num_cyls += 1;
disk_chars[phys_drive].secp_cyl = (UCOUNT) (disk_chars[phys_drive].num_heads * disk_chars[phys_drive].secp_track);
ltemp = (ULONG)((ULONG) disk_chars[phys_drive].secp_cyl *
(ULONG) disk_chars[phys_drive].num_cyls);
disk_chars[phys_drive].max_sector = ltemp;
return(YES);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -