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

📄 bddrv.c

📁 linux1.0的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************
BDDL: Block Device Driver Library
Chris Giese <geezer@execpc.com>
http://www.execpc.com/~geezer

The ATA and ATAPI code won't run in a Windows DOS box
(the floppy code _will_ work).

If this code is configured to use the floppy, do NOT run it unless
the floppy drive light is off. A timer interrupt in the BIOS may
shut off the floppy after this code turns it on. That will, in turn,
cause this code to freeze up.

Ctrl-Break may get you out of this program if it does freeze up,
but the IDE and floppy interrupt vectors will not be restored.
You will have to reset the PC (or, if run from a Windows DOS
box, exit the DOS box).

With the current #ifdef's, this code will
- expect an ATAPI (IDE) CD-ROM drive as the slave drive
	on the primary interface (2nd drive at I/O=1F0h)
- expect a data CD-ROM inserted in the CD-ROM drive
- expect a formatted, BLANK 1.44 meg floppy inserted in drive A:
	(any data on the floppy will be overwritten)
- copy 180K (10 floppy tracks) from the CD-ROM to the floppy
- print great wads of debug information (it's probably NOT a
	good idea to redirect these messages to a file...)




to do:
- figure out a common API for the floppy, ATA, and ATAPI device drivers
- use the above API to implement a RAM disk
- add a disk cache

- finish ide_error()
- ide_enable_multmode() should also be able to disable multiple mode
- ide_enable_multmode() needs to pass a request_t struct to ide_error()
- need to call ide_select() drive? should I retry it if it fails?
- >>> finish ide_write_sectors()
- review the info retrieved from the drive in ide_identify()
- finish atapi_error()
- atapi_toc_ent() and atapi_mode_sense() request < 2048 bytes
	(less than 1 block) from atapi_cmd()
- need a floppy_select() function separate from floppy_motor_on()
- floppy_motor_on() needs to use fdev->blkdev.unit
- floppy_motor_on() has a 500 ms delay that is not interrupt-driven
- floppy_seek() has a 15 ms delay that is not interrupt-driven
- should floppy_error() seek track 1 or track 0 on disk change?
	if track 0, should it do recalibrate instead?
- finish floppy_error()
- probe geometry of inserted floppy disk (1.44M, 1.68M, other - how?)


- floppy code needs a timer interrupt to decrement dev->timeout
	and shut off the floppy motor when it reaches zero
- add code to set IDE translation? what is this function used for?
- the CD-ROM transfers only 2K on each interrupt? is this normal?
- maybe a flatter hierarchy of structures? this looks ridiculous:
	ioadr = dev->blkdev.io.adr[0];
- >>> request queues w/ validation of requests
- add code to format floppy track
- alternate floppy code that uses PIO instead of DMA?
	(the CPU will have to poll the FDC status register
	and read/write a byte every 13 us; maybe faster)

testing to do:
- WD, Conner, and Maxtor hard drives
- drives on primary interface (I/O=1F0h) and secondary (I/O=170h)
- master (unit=0xA0) and slave (unit=0xB0) drives on both interfaces
- CD-ROM as master, CD-ROM as slave w/ hard drive master, CD-ROM as
  stand-alone slave (illegal?), hard drive as stand-alone slave (illegal?)
- multiple floppy drives

notes:
- IDE/ATAPI interrupt usage:
  - irq14() and irq15() clear the IRQ at the 8259 PIC chips,
    and set _interrupt_occurred (xxx - should clear IRQ at
    the drive from the ISR, in case the IRQ is level-sensitive)
  - (ide_)await_interrupt() clears _interrupt_occurred
  - other code is responsible for clearing the interrupt
    at the drive (usu. by reading the status register)
*****************************************************************************/
#include <string.h> /* memset() */
#include <stdio.h> /* printf(), putchar() */
#include <dos.h> /* delay(), inport(), outport(), inportb(), outportb() */

#if 1
#define	DEBUG(X)	X
#else
#define	DEBUG(X)	/* nothing */
#endif

#if defined(__TURBOC__)||!defined(__cplusplus)
typedef enum
{
    false = 0, true = 1
} bool;
#endif

/* linear address of the sector buffer */
#define	LMEM		0x90000L

#if defined(__TURBOC__)
#define	INLINE		/* nothing */
//#define	_DS		_DS
/* Put the floppy track buffer at 9000h:0000 */
#define	LMEM_SEG	(LMEM >> 4)
#define	LMEM_OFF	(LMEM & 15)

#define	msleep(X)	delay(X)

#elif defined(__DJGPP__)
#define	INLINE		__inline__
#define	_DS		_my_ds()
/* Floppy track buffer at linear address 90000h */
#define	LMEM_SEG	_dos_ds
#define	LMEM_OFF	LMEM

#define	msleep(X)	delay(X)
/* The nice thing about standards is... */
#define	inport(P)	inportw(P)
#define	outport(P,V)	outportw(P,V)

#else
#error Not Turbo C, not DJGPP. Sorry.
#endif

/* geezer's Portable Interrupt Macros (tm) */
#if defined(__TURBOC__)
/* getvect(), setvect() in dos.h */

#define	INTERRUPT	interrupt

#define SAVE_VECT(num, vec)	vec = getvect(num)
#define	SET_VECT(num, fn)	setvect(num, fn)
#define	RESTORE_VECT(num, vec)	setvect(num, vec)

typedef void interrupt(*vector_t)(void);

#elif defined(__DJGPP__)
#include <dpmi.h>	/* _go32_dpmi_... */
#include <go32.h>	/* _my_cs() */

#define	INTERRUPT	/* nothing */

#define	SAVE_VECT(num, vec)	\
	_go32_dpmi_get_protected_mode_interrupt_vector(num, &vec)
#define	SET_VECT(num, fn)					\
	{							\
		_go32_dpmi_seginfo new_vector;			\
								\
		new_vector.pm_selector = _my_cs();		\
		new_vector.pm_offset = (unsigned long)fn;	\
		_go32_dpmi_allocate_iret_wrapper(&new_vector);	\
		_go32_dpmi_set_protected_mode_interrupt_vector	\
			(num, &new_vector);			\
	}
#define	RESTORE_VECT(num, vec)	\
	_go32_dpmi_set_protected_mode_interrupt_vector(num, &vec)

typedef _go32_dpmi_seginfo vector_t;

#endif

/* hardware resources used by a device */
#define	NUM_IO_SPANS	2
typedef struct
{
    unsigned char dma;			/* 8-bit DMA mask */
    unsigned short irq;			/* 16-bit IRQ mask */
    unsigned short adr[NUM_IO_SPANS];	/* start of I/O range */
    unsigned short span[NUM_IO_SPANS];	/* length of I/O range */
} io_t;

typedef struct
{
    /* hardware interface (hwif; or "bus") */
    io_t io;
    /* which drive on the hwif? 2 for IDE, 4 for floppy, 7 for SCSI */
    unsigned char unit;
    /* generic info (i.e. used by ALL types of block device) */
    unsigned long num_blks;
    unsigned short bytes_per_blk;
    /* floppy and CHS IDE only */
    unsigned short sectors, heads, cyls;
} blkdev_t;

struct _request
{
    // sem_t semaphore;
    enum
    {
        BLK_CMD_READ = 1, BLK_CMD_WRITE = 2
    } cmd;			/* read or write? */
    void *dev;		/* from/to which device? */
    unsigned long blk;	/* starting at which block? */
    unsigned num_blks;	/* how many blocks? */
    // unsigned current_num_blks;
    unsigned char *buf;	/* from/to what memory location? */
    unsigned errors;	/* status */
    // struct _request *next;
};
typedef struct _request request_t;
//////////////////////////////////////////////////////////////////////////////
// MISC/HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////////
static volatile unsigned short _interrupt_occurred;
/*****************************************************************************
*****************************************************************************/
static unsigned short await_interrupt(unsigned short irq_mask,
                                      unsigned timeout)
{
    unsigned short intr = 0, time;

    DEBUG(printf("await_interrupt: irq_mask=0x%04X, timeout=%u\n",
                 irq_mask, timeout);)
    for(time = timeout; time != 0; time--)
    {
        intr = _interrupt_occurred & irq_mask;
        if(intr != 0)
            break;
        msleep(1);
    }
    DEBUG(printf("await_interrupt: waited %3u ms\n", timeout - time);)
    if(time == 0)
        return 0;
    _interrupt_occurred &= ~intr;
    return intr;
}
/*****************************************************************************
*****************************************************************************/
#pragma argsused
static void nsleep(unsigned nanosecs)
{
}
/*****************************************************************************
*****************************************************************************/
static INLINE void insw(short port, unsigned short *data, unsigned count)
{
    for(; count != 0; count--)
    {
        *data = inport(port);
        data++;
    }
}
/*****************************************************************************
*****************************************************************************/
static INLINE void outsw(short port, unsigned short *data, unsigned count)
{
    for(; count != 0; count--)
    {
        outport(port, *data);
        data++;
    }
}
/*****************************************************************************
*****************************************************************************/
#define BPERL		16	/* byte/line for dump */

static void dump(unsigned char *data, unsigned count)
{
    unsigned char byte1, byte2;

    while(count != 0)
    {
        for(byte1 = 0; byte1 < BPERL; byte1++)
        {
            if(count == 0)
                break;
            printf("%02X ", data[byte1]);
            count--;
        }
        printf("\t");
        for(byte2 = 0; byte2 < byte1; byte2++)
        {
            if(data[byte2] < ' ')
                putchar('.');
            else
                putchar(data[byte2]);
        }
        printf("\n");
        data += BPERL;
    }
}
/****************************************************************************
****************************************************************************/
static unsigned short bswap16(unsigned short arg)
{
    return ((arg << 8) & 0xFF00) |
           ((arg >> 8) & 0xFF00);
}

/* these assume little-endian CPU (e.g. x86) and sizeof(short)==2 */
#define	read_le16(X)	*(unsigned short *)(X)
#define	read_be16(X)	bswap16(*(unsigned short *)(X))
//////////////////////////////////////////////////////////////////////////////
// IDE (ATA) HARD DRIVES
//////////////////////////////////////////////////////////////////////////////
/* ATA register file (offsets from 0x1F0 or 0x170) */
#define	ATA_REG_DATA		0	/* data (16-bit) */
#define	ATA_REG_FEAT		1	/* write: feature reg */
#define	ATA_REG_ERROR	ATA_REG_FEAT	/* read: error */
#define	ATA_REG_COUNT		2	/* sector count */
#define	ATA_REG_SECTOR		3	/* sector */
#define	ATA_REG_LOCYL		4	/* LSB of cylinder */
#define	ATA_REG_HICYL		5	/* MSB of cylinder */
#define	ATA_REG_DRVHD		6	/* drive select; head */
#define	ATA_REG_CMD		7	/* write: drive command */
#define	ATA_REG_STATUS		7	/* read: status and error flags */
#define	ATA_REG_DEVCTRL		0x206	/* write: device control */
//efine	ATA_REG_ALTSTAT		0x206	/* read: alternate status/error */

/* a few of the ATA registers are used differently by ATAPI... */
#define	ATAPI_REG_REASON	2	/* interrupt reason */
#define	ATAPI_REG_LOCNT		4	/* LSB of transfer count */
#define	ATAPI_REG_HICNT		5	/* MSB of transfer count */

/* ATA command bytes */
#define	ATA_CMD_READ		0x20	/* read sectors */
#define	ATA_CMD_PKT		0xA0	/* signals ATAPI packet command */
#define	ATA_CMD_PID		0xA1	/* identify ATAPI device */
#define	ATA_CMD_READMULT	0xC4	/* read sectors, one interrupt */
#define	ATA_CMD_MULTMODE	0xC6
#define	ATA_CMD_ID		0xEC	/* identify ATA device */

typedef struct
{
    /* generic block device info */
    blkdev_t blkdev;
    /* information specific to IDE drive */
unsigned has_lba : 1;
unsigned use_lba : 1;
unsigned has_dma : 1;
unsigned use_dma : 1;
unsigned has_multmode : 1;
unsigned use_multmode : 1;
    unsigned short mult_count;
} ide_t;
/*****************************************************************************
BUSY  READY  DF  DSC		DRQ1  CORR  IDX  ERR
*****************************************************************************/
static int ide_poll_status(unsigned short ioadr, unsigned timeout,
                           unsigned char stat_mask, unsigned char stat_bits)
{
    unsigned time, decr;
    unsigned char stat = 0;

    DEBUG(printf("ide_poll_status: ioadr=0x%X, stat mask=0x%X, "
                 "stat bits=0x%X\n", ioadr, stat_mask, stat_bits);)
    /* if short timeout, poll every 1 millisecond, else every 50 ms.
    If the host OS has a real-time scheduler, and that scheudler runs
    every 50 ms, you could do yield() instead of msleep(50) */
    decr = (timeout < 500) ? 1 : 50;
    for(time = timeout; time != 0; time -= decr)
    {
        stat = inportb(ioadr + ATA_REG_STATUS);
        if((stat & stat_mask) == stat_bits)
            break;
        msleep(decr);
    }
    DEBUG(printf("ide_poll_status: waited %3u ms, got stat=0x%X\n",
                 timeout - time, stat);)
    if(time == 0)
    {
        printf("ide_poll_status: error: timeout, stat=0x%X\n", stat);
        return -1;
    }
    return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -