⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bios.c

📁 nucleus 文件系统,内核和彩色图形系统,在小系统上非常好用
💻 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 + -