388 lines
15 KiB
Plaintext
388 lines
15 KiB
Plaintext
|
|
||
|
|
||
|
MINDRVR
|
||
|
Simple ATA/ATAPI Low Level Driver for Embedded Systems
|
||
|
User's Guide
|
||
|
|
||
|
by Hale Landis
|
||
|
|
||
|
Version 0G and higher
|
||
|
|
||
|
|
||
|
INTRODUCTION
|
||
|
------------
|
||
|
|
||
|
MINDRVR is a simple version of ATADRVR. ATADRVR is Hale Landis'
|
||
|
C code that shows the low level programming required to configure
|
||
|
and execute commands on ATA and ATAPI devices. MINDRVR is
|
||
|
suitable for embedded systems that have simple ATA interface
|
||
|
hardware that is memory mapped. MINDRVR does not have some
|
||
|
features of ATADRVR, such as, the command and low level trace
|
||
|
facility, no support for ATA CHS addressing, no and checking of
|
||
|
ATAPI command protocol errors.
|
||
|
|
||
|
MINDRVR is fully contained in two files: MINDRVR.H and
|
||
|
MINDRVR.C.
|
||
|
|
||
|
MINDRVR, like ATADRVR, supports all of the ATA and ATA/ATAPI
|
||
|
standards.
|
||
|
|
||
|
The MINDRVR C code has been placed into the public domain by Hale
|
||
|
Landis. This C code has no copyright or other restrictions on
|
||
|
how it is used.
|
||
|
|
||
|
|
||
|
USING MINDRVR
|
||
|
-------------
|
||
|
|
||
|
Normally a "file system" driver would call MINDRVR to perform actual
|
||
|
phyical I/O operations on ATA or ATAPI devices using PIO or DMA data
|
||
|
transfer modes. Any program or driver that calls MINDRVR must include
|
||
|
the MINDRVR.H header file. MINDRVR.H defines all the MINDRVR public
|
||
|
functions and public data.
|
||
|
|
||
|
The basics of using MINDRVR are:
|
||
|
|
||
|
1) Review the MINDRVR.H and MINDRVR.C files. In these files look
|
||
|
for comment lines that have the string '!!!'. These comments
|
||
|
explain the information you must provide at compile time, such
|
||
|
as, the memory addresses for the ATA registers in your
|
||
|
system's memory.
|
||
|
|
||
|
2) #include "mindrvr.h" in your program or driver that will call
|
||
|
MINDRVR.
|
||
|
|
||
|
3) Call reg_config() so that MINDRVR can determine what devices
|
||
|
are attached to the ATA host adapter.
|
||
|
|
||
|
4) Call reg_reset() or any of the other "reg_" functions to issue
|
||
|
ATA or ATAPI commands in PIO data transfer mode. If your
|
||
|
system can support ATA/ATAPI DMA then call the dma_pci_"
|
||
|
functions to issue ATA or ATAPI commands in DMA data transfer
|
||
|
mode.
|
||
|
|
||
|
Note that MINDRVR is designed for systems with a single ATA
|
||
|
controller (single ATA inteface). If you system has multiple ATA
|
||
|
controllers/interfaces then you will need to either: a) make a
|
||
|
separate MINDRVR for each controller, or b) switch between
|
||
|
controllers by swapping the MINDRVR configuration information
|
||
|
between calls to MINDRVR.
|
||
|
|
||
|
|
||
|
MINDRVR REFERENCE
|
||
|
-----------------
|
||
|
|
||
|
Each of the public functions and symbols of MINDRVR are described
|
||
|
below in alphabetical order.
|
||
|
|
||
|
Note that there is no "interrupt handler" defined by MINDRVR.
|
||
|
You must supply the appropriate interrupt handler as described in
|
||
|
MINDRVR.H and MINDRVR.C.
|
||
|
|
||
|
|
||
|
Public Data
|
||
|
-----------
|
||
|
|
||
|
unsigned char int_ata_status;
|
||
|
|
||
|
When using interrupts the interrupt handler must return this
|
||
|
data. This is the interrupting device's ATA status as read by
|
||
|
interrupt handler.
|
||
|
|
||
|
unsigned char int_bmide_status;
|
||
|
|
||
|
When using interrupts the interrupt handler must return this
|
||
|
data. This is the interrupting controller's BMIDE status read
|
||
|
by interrupt handler.
|
||
|
|
||
|
unsigned char int_use_intr_flag;
|
||
|
|
||
|
MINDRVR can be switched between polling mode and interrupt
|
||
|
mode. Note that interrupt mode is required for DMA data
|
||
|
transfers.
|
||
|
|
||
|
Make this value not zero to use interrupts.
|
||
|
|
||
|
unsigned char pio_xfer_width;
|
||
|
|
||
|
This variable controls the width of PIO data transfers.
|
||
|
This variable can have the following values:
|
||
|
|
||
|
8 = 8-bits. PIO transfers will use 8-bit memory write/read
|
||
|
when accessing the ATA Data register.
|
||
|
|
||
|
16 = 16-bits. PIO transfers will use 16-bit memory write/read
|
||
|
when accessing the ATA Data register.
|
||
|
|
||
|
32 = 32-bits. PIO transfers will 32-bit memory write/read
|
||
|
when accessing the ATA Data register.
|
||
|
|
||
|
Any other value is treated the same as 16.
|
||
|
|
||
|
struct REG_CMD_INFO
|
||
|
{
|
||
|
// command code
|
||
|
unsigned char cmd; // command code
|
||
|
// command parameters
|
||
|
unsigned int fr; // feature (8 or 16 bits)
|
||
|
unsigned int sc; // sec cnt (8 or 16 bits)
|
||
|
unsigned int sn; // sec num (8 or 16 bits)
|
||
|
unsigned int cl; // cyl low (8 or 16 bits)
|
||
|
unsigned int ch; // cyl high (8 or 16 bits)
|
||
|
unsigned char dh; // device head
|
||
|
unsigned char dc; // device control
|
||
|
long ns; // actual sector count
|
||
|
int mc; // current multiple block setting
|
||
|
unsigned char lbaSize; // size of LBA used
|
||
|
#define LBACHS 0 // last command used ATA CHS (not supported by MINDRVR)
|
||
|
// -or- last command was ATAPI PACKET command
|
||
|
#define LBA28 28 // last command used ATA 28-bit LBA
|
||
|
#define LBA48 48 // last command used ATA 48-bit LBA
|
||
|
unsigned long lbaLow; // lower 32-bits of ATA LBA
|
||
|
unsigned long lbaHigh; // upper 32-bits of ATA LBA
|
||
|
// status and error regs
|
||
|
unsigned char st; // status reg
|
||
|
unsigned char as; // alt status reg
|
||
|
unsigned char er ; // error reg
|
||
|
// driver error codes
|
||
|
unsigned char ec; // detailed error code
|
||
|
unsigned char to; // not zero if time out error
|
||
|
// additional result info
|
||
|
long totalBytesXfer; // total bytes transfered
|
||
|
long drqPackets; // number of PIO DRQ packets
|
||
|
} ;
|
||
|
struct REG_CMD_INFO reg_cmd_info;
|
||
|
|
||
|
This data structure contains information about the last reset or command
|
||
|
that was executed.
|
||
|
|
||
|
int reg_config( void );
|
||
|
|
||
|
This function shoul be called so that MINDRVR can correctly
|
||
|
configure itself. reg_config() sets the values into
|
||
|
reg_config_info[2].
|
||
|
|
||
|
Note that the program calling MINDRVR may bypass calling this
|
||
|
function as long as reg_config_info[] is set appropriately
|
||
|
before attempting to execute any resets or commands.
|
||
|
|
||
|
int reg_config_info[2];
|
||
|
|
||
|
This array is set by calling reg_config(). reg_config_info[0]
|
||
|
describes device 0 and reg_config_info[1] describes device 1.
|
||
|
The possible values in these words are (see MINDRVR.H):
|
||
|
REG_CONFIG_TYPE_NONE, REG_CONFIG_TYPE_UNKN,
|
||
|
REG_CONFIG_TYPE_ATA, REG_CONFIG_TYPE_ATAPI.
|
||
|
|
||
|
Note that MINDRVR is not able to determine the type of some
|
||
|
devices. However, after issuing some commands the calling
|
||
|
program may be able to determine the exact type of a device.
|
||
|
The calling program may change the values in this array but
|
||
|
this must be done very carefully:
|
||
|
|
||
|
a) DO NOT CHANGE the value REG_CONFIG_TYPE_NONE.
|
||
|
b) DO NOT CHANGE a value to REG_CONFIG_TYPE_NONE.
|
||
|
c) The value REG_CONFIG_TYPE_UNKN can be changed to either
|
||
|
REG_CONFIG_TYPE_ATA or REG_CONFIG_TYPE_ATAPI.
|
||
|
|
||
|
int reg_non_data_lba28( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lba ); // LBA
|
||
|
|
||
|
Execute an ATA Non-Data command using LBA sector addressing.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_non_data_lba48( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lbahi, // LBA upper 16-bits
|
||
|
long lbalo ); // LBA lower 32 bits
|
||
|
|
||
|
Execute an ATA Non-Data command using LBA sector addressing.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_packet( unsigned char dev, // device (0 or 1)
|
||
|
unsigned int cpbc, // command packet size
|
||
|
unsigned char * cdbBufAddr, // CDB buffer
|
||
|
int dir, // 0 for no data or read, 1 for write
|
||
|
unsigned int dpbc, // max data packet size
|
||
|
unsigned char * dataBufAddr ); // data packet buffer
|
||
|
|
||
|
Execute an ATAPI Packet (A0H) command in PIO mode. Note that
|
||
|
the first byte of the Commmand Packet buffer is the command
|
||
|
code of the "SCSI CDB" that is to be executed by the device.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_pio_data_in_lba28( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lba, // LBA
|
||
|
unsigned char * bufAddr, // buffer address
|
||
|
int numSect, // number of sectors to transfer
|
||
|
int multiCnt ); // current multiple count
|
||
|
|
||
|
Execute an ATA PIO Data In command in LBA sector addressing
|
||
|
mode.
|
||
|
|
||
|
numSect is the actual number of sectors to be transferred.
|
||
|
This value may be different than the sc value.
|
||
|
|
||
|
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the
|
||
|
current sectors per block.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_pio_data_in_lba48( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lbahi, // LBA upper 16-bits
|
||
|
long lbalo, // LBA lower 32 bits
|
||
|
unsigned char * bufAddr, // buffer address
|
||
|
int numSect, // number of sectors to transfer
|
||
|
int multiCnt ); // current multiple count
|
||
|
|
||
|
Execute an ATA PIO Data In command in LBA sector addressing
|
||
|
mode.
|
||
|
|
||
|
numSect is the actual number of sectors to be transferred.
|
||
|
This value may be different than the sc value.
|
||
|
|
||
|
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the
|
||
|
current sectors per block.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_pio_data_out_lba28( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lba, // LBA
|
||
|
unsigned char * bufAddr, // buffer address
|
||
|
int numSect, // number of sectors to transfer
|
||
|
int multiCnt ); // current multiple count
|
||
|
|
||
|
Execute an ATA PIO Data Out command in LBA sector addressing
|
||
|
mode.
|
||
|
|
||
|
numSect is the actual number of sectors to be transferred.
|
||
|
This value may be different than the sc value.
|
||
|
|
||
|
If cmd is C5H (Write Multiple) then multiCnt MUST be set to
|
||
|
the current sectors per block.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_pio_data_out_lba48( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lbahi, // LBA upper 16-bits
|
||
|
long lbalo, // LBA lower 32 bits
|
||
|
unsigned char * bufAddr, // buffer address
|
||
|
int numSect, // number of sectors to transfer
|
||
|
int multiCnt ); // current multiple count
|
||
|
|
||
|
Execute an ATA PIO Data Out command in LBA sector addressing
|
||
|
mode.
|
||
|
|
||
|
numSect is the actual number of sectors to be transferred.
|
||
|
This value may be different than the sc value.
|
||
|
|
||
|
If cmd is C5H (Write Multiple) then multiCnt MUST be set to
|
||
|
the current sectors per block.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int reg_reset( unsigned char devRtrn ); // device's data returned
|
||
|
|
||
|
Execute an ATA Soft Reset. Set devRtrn to 0 or 1 to determine
|
||
|
which device's register contents are returned in reg_cmd_info.
|
||
|
|
||
|
|
||
|
DMA Data Transfer Functions And Data
|
||
|
------------------------------------
|
||
|
|
||
|
These functions setup PCI bus DMA (ATA Multiword or Ultra DMA)
|
||
|
and perform ATA and ATAPI commands using DMA. The function
|
||
|
dma_pci_config() MUST be called with no error before any of the
|
||
|
other functions will attempt to execute a command.
|
||
|
|
||
|
int dma_pci_config( void );
|
||
|
|
||
|
Configure MINDRVR to use PCI bus DMA (ATA Multiword or Ultra
|
||
|
DMA) on a PCI Bus Mastering ATA controller.
|
||
|
|
||
|
This function may not be needed in your system - see the MINDRVR.H
|
||
|
and MINDRVR.C files.
|
||
|
|
||
|
int dma_pci_lba28( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lba, // LBA
|
||
|
unsigned char * bufAddr ); // buffer address
|
||
|
|
||
|
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command
|
||
|
using LBA sector addressing.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int dma_pci_lba48( unsigned char dev, // device (0 or 1)
|
||
|
unsigned char cmd, // command register
|
||
|
int fr, // feature register
|
||
|
int sc, // sector count
|
||
|
long lbahi, // LBA upper 16-bits
|
||
|
long lbalo, // LBA lower 32 bits
|
||
|
unsigned char * bufAddr ); // buffer address
|
||
|
|
||
|
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command
|
||
|
using LBA sector addressing.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
int dma_pci_packet( unsigned char dev, // device (0 or 1)
|
||
|
unsigned int cpbc, // command packet size
|
||
|
unsigned char * cdbBufAddr, // CDB buffer
|
||
|
int dir, // 0 for no data or read, 1 for write
|
||
|
unsigned int dpbc, // max data packet size
|
||
|
unsigned char * dataBufAddr ); // data packet buffer
|
||
|
|
||
|
Execute an ATAPI Packet (A0H) command in DMA mode. Note that
|
||
|
the first byte of the Commmand Packet buffer is the command
|
||
|
code of the "SCSI CDB" that is to be executed by the device.
|
||
|
|
||
|
Returns 0 if no error or 1 if there is an error. See the
|
||
|
contents of reg_cmd_info.
|
||
|
|
||
|
|
||
|
QUESTIONS OR PROBLEMS?
|
||
|
----------------------
|
||
|
|
||
|
Send your question(s) or problem description(s) to Hale Landis
|
||
|
via email at this address:
|
||
|
|
||
|
hlandis@ata-atapi.com
|
||
|
|
||
|
Visit Hale's web site:
|
||
|
|
||
|
www.ata-atapi.com
|
||
|
|
||
|
/end/
|