📄 example2.c
字号:
// Example2.c -- A program showing how to use ADVDRVR with ATAPI devices.
#if 0
Some simple instructions for those of you that would like to
compile my driver code and try it.
1) I've always used Borland C (or C++, the driver code is plain C
code). One file contains a few lines of embedded ASM code. You will
need Borland's TASM too. Currently I use Borland C/C++ 4.52 and
Borland TASM 4.1.
2) This code should work with any memory mode. See the MEMMOD
variable in the make file (EXAMPLE1.MAK).
3) The EXAMPLE2.EXE program is a DOS real mode program. It will
not execute in a DOS session (a virtual x86 session) under Windows!
You should make a DOS boot floppy and boot your system for it and
execute the EXAMPLE2.EXE program from that floppy.
4) Here is a very small program that shows how to use the
driver code to issue some ATAPI commands. This program has
one required command line parameter to specify the device to
run on: P0, P1, S0 or S1.
#endif
#define INCL_PCI_DMA 0 // set to 1 to include PCI DMA
#define BMCR_IO_ADDR 0xFF00 // YOU MUST SUPPLY THIS VALUE
// IF YOU WANT TO USE R/W DMA
// begin
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "advio.h"
//**********************************************
// Please read carefully -- To use ADVDRVR the caller (such as
// this program must provide a data area (struct ADVIO_DEVICE)
// for each device to be used and must provide the pointer
// to the current device data area (struct ADVIO_DEVICE * ADP)
// before calling any ADVDRVR function. In this program
// only a single device data area is used but 'devInfo' could
// be an array of struct - just make sure ADP is set correctly
// before calling any ADVDRVR function!
// This data area is used to configure a controller and device
// for ADVDRVR's use, to determine the result of a command and
// to implement the CHT and LLT traces. The entire device data
// area must be intiialized to zero. Note that this example
// is simple in that it uses only one device. When you have
// multiple devices, some may be on the same physical ATA
// channel. In this the calling program will need to serialize
// commands to the devices on those shared channels and may
// want to have I/O, CHT and LLT buffers that are shared.
// See the ADVDRVR.UG doc file for more information.
struct ADVIO_DEVICE devInfo; // Allocate a device data area
struct ADVIO_DEVICE * ADP; // Pointer to device data area
#define CHT_SIZE 20 // command history trace buffer
struct CHT chtTrcBuf[CHT_SIZE];
#define LLT_SIZE 100 // low level trace buffer
struct LLT lltTrcBuf[LLT_SIZE];
//**********************************************
unsigned char * devTypeStr[]
= { "no device found", "unknown type", "ATA", "ATAPI" };
#define CDB_SIZE 16 // local buffer for SCSI command blocks
unsigned char cdb[CDB_SIZE];
unsigned char far * cdbPtr;
#define BUFFER_SIZE 4096 // I/O buffer
unsigned char buffer[BUFFER_SIZE];
unsigned char far * bufferPtr;
//**********************************************
// a little function to display all the error
// and trace information from the driver
void ShowAll( void );
void ShowAll( void )
{
unsigned char * cp;
printf( "ERROR !\n" );
// display the command error information
trc_err_dump1(); // start
while ( 1 )
{
cp = trc_err_dump2(); // get and display a line
if ( cp == NULL )
break;
printf( "* %s\n", cp );
}
// display the command history
trc_cht_dump1(); // start
while ( 1 )
{
cp = trc_cht_dump2(); // get and display a line
if ( cp == NULL )
break;
printf( "* %s\n", cp );
}
// display the low level trace
trc_llt_dump1(); // start
while ( 1 )
{
cp = trc_llt_dump2(); // get and display a line
if ( cp == NULL )
break;
printf( "* %s\n", cp );
}
// now clear the command history and low level traces
trc_cht_dump0(); // zero the command history
trc_llt_dump0(); // zero the low level trace
}
//**********************************************
int main( int ac, char * av[] )
{
int base;
int dev;
int numDev;
int rc;
int ndx;
printf( "ADVDRVR EXAMPLE2 Version " ADVIO_DRIVER_VERSION ".\n" );
// initialize far pointer to the CDB buffer
cdbPtr = (unsigned char far *) cdb;
// initialize far pointer to the I/O buffer
bufferPtr = (unsigned char far *) buffer;
// process command line parameter
if ( ac == 2 )
{
if ( ! strnicmp( av[1], "p0", 2 ) )
{
base = 0x1f0;
dev = 0;
}
else
if ( ! strnicmp( av[1], "p1", 2 ) )
{
base = 0x1f0;
dev = 1;
}
else
if ( ! strnicmp( av[1], "s0", 2 ) )
{
base = 0x170;
dev = 0;
}
else
if ( ! strnicmp( av[1], "s1", 2 ) )
{
base = 0x170;
dev = 1;
}
else
{
printf( "\nInvalid command line parameter !\n" );
return 1;
}
}
else
{
printf( "\nMissing command line parameter !\n" );
return 1;
}
printf( "\nUsing I/O base addresses %04X and %04X.\n",
base, base + 0x200 );
printf( "Using device %d on this ATA interface.\n", dev );
// Step 1) set ADP to point to our device data area
ADP = & devInfo;
// Step 2) initialize data ADVDRVR needs...
ADP->devBit = dev ? 0x10 : 0x00; // DEV bit value
ADP->pio_xfer_width = 16; // PIO Data register width
ADP->reg_buffer_size = BUFFER_SIZE; // buffer size
ADP->tmr_time_out = 40; // command timeout in seconds
ADP->reg_atapi_cp_size = 12; // ATAPI CDB size in bytes
ADP->chtBuf = (struct CHT far *) & chtTrcBuf; // init the command history
ADP->chtSize = CHT_SIZE;
trc_cht_dump0();
ADP->lltBuf = (struct LLT far *) & lltTrcBuf; // init the low level trace
ADP->lltSize = LLT_SIZE;
trc_llt_dump0();
// Step 3) must tell the driver what the I/O port addresses.
pio_set_iobase_addr( base, base + 0x200, BMCR_IO_ADDR );
// Step 4) find out what devices are present -- this is the step
// many driver writers ignore. You really can't just do
// resets and commands without first knowing what is out there.
// Even if you don't care the driver does care.
numDev = reg_config();
if ( numDev )
{
printf( "\nFound a devices on this ATA interface:\n" );
printf( " The device type is %s.\n", devTypeStr[ ADP->devType ] );
}
else
{
printf( "\nNo device found !\n" );
return 1;
}
// basic setup is done, now we can issue Software Resets
// (SRST), ATA Non-Data and ATA PIO data transfer commands.
// do an ATA soft reset (SRST)
printf( "Soft Reset...\n" );
rc = reg_reset( 0 );
if ( rc )
ShowAll();
// do an ATAPI Identify command in LBA mode
printf( "ATAPI Identify...\n" );
memset( buffer, 0, sizeof( buffer ) );
rc = reg_pio_data_in_lba28(
CMD_IDENTIFY_DEVICE_PACKET,
0, 0,
0L,
FP_SEG( bufferPtr ), FP_OFF( bufferPtr ),
1L, 0 );
if ( rc )
ShowAll();
else
// you get to add the code here to display all the ID data
// display the first 16 bytes read
printf( " data read %02X%02X%02X%02X %02X%02X%02X%02X "
"%02X%02X%02X%02X %02X%02X%02X%02X\n",
buffer[ 0], buffer[ 1], buffer[ 2], buffer[ 3],
buffer[ 4], buffer[ 5], buffer[ 6], buffer[ 7],
buffer[ 8], buffer[ 9], buffer[10], buffer[11],
buffer[12], buffer[13], buffer[14], buffer[15] );
// do three ATAPI Request Sense command and display some of the data
for ( ndx = 0; ndx < 3; ndx ++ )
{
printf( "ATAPI Request Sense...\n" );
memset( cdb, 0, sizeof( cdb ) );
cdb[0] = 0x03; // RS command code
cdb[4] = 32; // allocation length
memset( buffer, 0, sizeof( buffer ) );
rc = reg_packet(
12, FP_SEG( cdbPtr ), FP_OFF( cdbPtr ),
0,
4096, FP_SEG( bufferPtr ), FP_OFF( bufferPtr ),
0L // lba for tracing
);
if ( rc )
ShowAll();
else
{
// here I'll give you some help -- lets look at the RS data
// first a problem with ATAPI device: how much data was
// really transferred? You can never really be sure...
if ( ADP->totalBytesXfer != ( 8U + buffer[7] ) )
printf( "Number of bytes transferred (%ld) does not match \n"
"8 + byte 7 in the RS data received (%u) ! \n",
ADP->totalBytesXfer,
8U + buffer[7] );
// display some of the RS data
printf( "Error code=%02X, Sense Key=%02X, ASC=%02X, ASCQ=%02X\n",
buffer[0], buffer[2] & 0x0f, buffer[12], buffer[13] );
}
}
// do an ATAPI Read TOC command and display the TOC data
printf( "ATAPI CD-ROM Read TOC...\n" );
memset( cdb, 0, sizeof( cdb ) );
cdb[0] = 0x43; // command code
cdb[1] = 0x02; // MSF flag
cdb[7] = 0x10; // allocation length
cdb[8] = 0x00; // of 4096
cdb[9] = 0x80; // TOC format
memset( buffer, 0, sizeof( buffer ) );
rc = reg_packet(
12, FP_SEG( cdbPtr ), FP_OFF( cdbPtr ),
0,
4096, FP_SEG( bufferPtr ), FP_OFF( bufferPtr ),
0L // lba for tracing
);
if ( rc )
ShowAll();
else
{
// and here too I'll give you some help looking at the TOC data
// again, check the number of bytes transferred (notice
// how every SCSI like command is different here)
if ( ADP->totalBytesXfer
!=
( 2U + ( buffer[0] * 256U ) + buffer[1] )
)
printf( "Number of bytes transferred (%ld) does not match \n"
"2 + bytes 0-1 in the TOC data received (%u) ! \n",
ADP->totalBytesXfer,
2U + ( buffer[0] * 256U ) + buffer[1] );
// display the TOC data
printf( "First Session=%02X, Last Session=%02X\n",
buffer[2], buffer[3] );
printf( "TOC entries (11 bytes each)... \n" );
rc = ( ( buffer[0] * 256U ) + buffer[1] - 2U ) / 11;
ndx = 4;
while ( rc > 0 )
{
printf( " %02X %02X %02X "
"%02X %02x %02X "
"%02X %02X %02X "
"%02X %02x \n",
buffer[ndx+0], buffer[ndx+1], buffer[ndx+2],
buffer[ndx+3], buffer[ndx+4], buffer[ndx+5],
buffer[ndx+6], buffer[ndx+7], buffer[ndx+8],
buffer[ndx+9], buffer[ndx+10], buffer[ndx+11]
);
rc -- ;
ndx = ndx + 11;
}
}
#if INCL_PCI_DMA
// If you set INCL_PCI_DMA to 1 AND you have read the Driver
// User's Guide AND you have an PCI bus ATA host adapter and
// you must know the I/O address of the Bus Master Control
// Registers (BMCR) registers. This address is
// found by scanning all the PCI bus devices and finding the
// ATA host adapter you want to use. The BMCR I/O address
// is at offset 20H of the PCI configuration space for the
// ATA host adapter.
// first, tell the driver where the BMCR is located.
dma_pci_config( BMCR_IO_ADDR );
#if 0
// DO NOT DO THIS SET FEATURES UNLESS REQUIRED!
// YOU MUST KNOW WHICH MODE THE HOST ADAPTER HAS
// BEEN PROGRAMMED TO USE!
// do a set features to turn on Ultra DMA (or MW DMA)
printf( "Set Feature, FR=03H, SC=40H...\n" );
rc = reg_non_data_chs( CMD_SET_FEATURES, 0x03, 0x40, 0, 0, 0 );
if ( rc )
ShowAll();
#endif
// do an ATAPI Read TOC command and display the TOC data
// but do it in DMA mode
printf( "ATAPI CD-ROM Read TOC in DMA...\n" );
memset( cdb, 0, sizeof( cdb ) );
cdb[0] = 0x43; // command code
cdb[1] = 0x02; // MSF flag
cdb[7] = 0x10; // allocation length
cdb[8] = 0x00; // of 4096
cdb[9] = 0x80; // TOC format
memset( buffer, 0, sizeof( buffer ) );
rc = dma_pci_packet(
12, FP_SEG( cdbPtr ), FP_OFF( cdbPtr ),
0,
4096, FP_SEG( bufferPtr ), FP_OFF( bufferPtr ),
0L // lba for tracing
);
if ( rc )
ShowAll();
else
{
// and here too I'll give you some help looking at the TOC data
// again, check the number of bytes transferred (notice
// how every SCSI like command is different here?
if ( ADP->totalBytesXfer
!=
( 2U + ( buffer[0] * 256U ) + buffer[1] )
)
printf( "Number of bytes transferred (%ld) does not match \n"
"2 + bytes 0-1 in the TOC data received (%u) ! \n",
ADP->totalBytesXfer,
2U + ( buffer[0] * 256U ) + buffer[1] );
// display the TOC data
printf( "First Session=%02X, Last Session=%02X\n",
buffer[2], buffer[3] );
printf( "TOC entries (11 bytes each)... \n" );
rc = ( ( buffer[0] * 256U ) + buffer[1] - 2U ) / 11;
ndx = 4;
while ( rc > 0 )
{
printf( " %02X %02X %02X "
"%02X %02x %02X "
"%02X %02X %02X "
"%02X %02x \n",
buffer[ndx+0], buffer[ndx+1], buffer[ndx+2],
buffer[ndx+3], buffer[ndx+4], buffer[ndx+5],
buffer[ndx+6], buffer[ndx+7], buffer[ndx+8],
buffer[ndx+9], buffer[ndx+10], buffer[ndx+11]
);
rc -- ;
ndx = ndx + 11;
}
}
#endif
return 0;
}
// end example2.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -