📄 ide_drv.c
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1996
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* Portable IDE Device driver.
*
*
*/
// 10-24-2000 added LBA formatting. Submit to main tree
#include "pcdisk.h"
#if (INCLUDE_PCMCIA)
#include "pcmcia.h"
#endif
#define IDE_USE_SET_FEATURES 0
/* if one use the following set features call when the drive is opened:
IDE_FEATURE_SETPERF Set Perfomance Option
IDE_FEATURE_WCACHE_ON Enable the write cache
IDE_FEATURE_DEFECT_ON Enable the defect re-assignment
IDE_FEATURE_RLOOK_ON Enable read look-ahead
*/
#define IDE_USE_ATAPI 1 /* if one enable ATAPI support (for CD, LS-120, etc) */
#if (defined(ERTFS_SA))
#define OS_IDE_SIGNAL_TEST(X,Y) ks_test_ide_signal(X, Y)
#define OS_IDE_SIGNAL_CLEAR(X) ks_clear_ide_signal(X)
#define OS_IDE_SIGNAL_BIND(X)
#endif
#if (defined(ERTFS_SA))
void ks_invoke_ide_interrupt(int controller_number);
void hook_ide_interrupt(int irq, int controller_number);
void ks_clear_ide_signal(int controller);
BOOLEAN ks_test_ide_signal(int controller, word timeout);
#endif
#define ZERO 0
/* Set USE_SETPARMS to 1 to force this driver to set the drive to use its
true geometry (cyls, hds, sec/track) when this driver initializes.
This is only necessary if the IDE drive had already been set to use
a translated geometry during BIOS initialization at boot. It may also
be needed for ancient IDE drives. It should not cause any harm on
newer devices -- it just adds a little unnecessary code. */
#define USE_SETPARMS 0
#if (USE_ATA)
#if (IDE_USE_SET_FEATURES || IDE_USE_ATAPI)
static BOOLEAN ide_set_features(PIDE_CONTROLLER pc, int phys_drive, byte feature, byte config);
#endif
static BOOLEAN ide_command(byte command, PIDE_CONTROLLER pc, int phys_drive, dword blockno, word nblocks);
BOOLEAN atapi_command(byte command, PIDE_CONTROLLER pc, int phys_drive);
/*static BOOLEAN ide_reset(PIDE_CONTROLLER pc);*/
static BOOLEAN ide_command_diags(PIDE_CONTROLLER pc);
static BOOLEAN ide_command_read_multiple(PIDE_CONTROLLER pc, int phys_drive, dword blockno, word nblocks);
static BOOLEAN ide_command_write_multiple(PIDE_CONTROLLER pc, int phys_drive, dword blockno, word nblocks);
static BOOLEAN ide_rdwr_setup(PIDE_CONTROLLER pc, int phys_drive, dword blockno, word nblocks);
static BOOLEAN ide_do_command(PIDE_CONTROLLER pc);
#if (USE_SETPARMS)
static BOOLEAN ide_command_setparms(PIDE_CONTROLLER pc, int phys_drive, byte heads, byte sectors);
#endif
static void ide_clear_voregs(PIDE_CONTROLLER pc);
static void ide_read_register_file(PIDE_CONTROLLER pc);
BOOLEAN ide_in_words(PIDE_CONTROLLER pc, word nwords);
BOOLEAN ide_out_words(PIDE_CONTROLLER pc, word nwords);
extern IDE_CONTROLLER controller_s[N_ATA_CONTROLLERS];
#ifndef ide_rd_status
/* If ide_rd_status is defined it is a macro in ide_drv.h */
#define ide_inbyte(X) ((byte) INBYTE((X)))
#define ide_outbyte(X,Y) OUTBYTE((X), (byte)(Y))
byte ide_rd_status(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_STATUS));
}
byte ide_rd_sector_count(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_SECTOR_int));
}
byte ide_rd_alt_status(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_ALT_STATUS));
}
byte ide_rd_error(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_ERROR));
}
byte ide_rd_sector_number(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_SECTOR_NUMBER));
}
byte ide_rd_cyl_low(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_CYL_LOW));
}
byte ide_rd_cyl_high(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_CYL_HIGH));
}
byte ide_rd_drive_head(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_DRIVE_HEAD));
}
byte ide_rd_drive_address(PIDE_CONTROLLER pc) /* __fn__ */
{
return(ide_inbyte(pc->register_file_address + IDE_OFF_DRIVE_ADDRESS));
}
void ide_wr_dig_out(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_DIG_OUTPUT, v);
}
void ide_wr_sector_count(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_SECTOR_int, v);
}
void ide_wr_sector_number(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_SECTOR_NUMBER, v);
}
void ide_wr_cyl_low(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_CYL_LOW, v);
}
void ide_wr_cyl_high(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_CYL_HIGH, v);
}
void ide_wr_drive_head(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_DRIVE_HEAD, v);
}
void ide_wr_command(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_COMMAND, v);
}
void ide_wr_feature(PIDE_CONTROLLER pc, byte v) /* __fn__ */
{
ide_outbyte(pc->register_file_address + IDE_OFF_FEATURE, v);
}
#endif /* #ifndef ide_rd_status */
/* void ide_in_words(word nwords)
*
* This routine reads nwords 16 bit words from the IDE data register
* and places it in the buffer at user_address. It must increment the
* user_address pointer so future calls will work correctly. In the IBM
* PC port we do an equivalent operation in assembler and update
* user_offset and user_segment.
*
* This has to be FAST !!!!
*
*/
BOOLEAN ide_in_words(PIDE_CONTROLLER pc, word nwords) /* __fn__ */
{
unsigned short KS_FAR *p;
pc->vi_status = ide_rd_status(pc);
if (!(pc->vi_status & IDE_STB_DRQ)) /* Drive should have data ready */
{
/* Serious problem. Bus state incorrect */
pc->error_code = IDE_ERC_BUS;
return(FALSE);
}
/* Note: the word wide data port is at offset 0 in the register file */
p = (unsigned short KS_FAR *) pc->user_address;
insw(pc->register_file_address + IDE_OFF_DATA, p, nwords);
pc->user_address += (nwords*2);
return(TRUE);
}
/* extern void ide_out_words(word nwords)
*
* This routine writes nwords 16 bit words from the buffer at
* user_address to the IDE data register.
* It must increment the user_address pointer so future calls will work
* correctly. In the IBM PC port we do an equivalent operation in assembler
* and update user_offset and user_segment.
*
* This is just a sample. This has to be FAST !!!!
*
*/
BOOLEAN ide_out_words(PIDE_CONTROLLER pc, word nwords) /* __fn__ */
{
unsigned short KS_FAR *p;
pc->vi_status = ide_rd_status(pc);
if (!(pc->vi_status & IDE_STB_DRQ)) /* Drive should be requesting */
{
pc->error_code = IDE_ERC_BUS;
return(FALSE);
}
p = (unsigned short KS_FAR *) pc->user_address;
outsw((IOADDRESS)(pc->register_file_address + IDE_OFF_DATA), p, nwords);
pc->user_address += (nwords*2);
return(TRUE);
}
/* ide_isr() - IDE ISR routine.
*
* This routine is a portable interrupt service routine.
*
*/
void KS_FAR ide_isr(int controller_number) /*__fn__*/
{
PIDE_CONTROLLER pc;
pc = &controller_s[controller_number];
/* Read the status register. to clear the interrupt status */
pc->vi_status = ide_rd_status(pc);
/* Signal that we got an interrupt */
ks_invoke_ide_interrupt(controller_number);
}
/* Open function. This is pointed to by the bdevsw[] table */
/*
* Note: This routine is called with the drive already locked so
* in several cases there is no need for critical section code handling
*/
#if (!CDFS_ONLY)
void ide_eject_media(DDRIVE *pdr)
{
PIDE_CONTROLLER pc;
pc = &controller_s[pdr->controller_number];
#if (IDE_USE_ATAPI)
/* If its an atapi drive do a get media status and check the media changed
bit in bit 5 */
if(pc->drive[pdr->logical_unit_number].protocol==2)
{
atapi_command(ATAPI_PKT_CMD_START_STOP_UNIT, pc, pdr->logical_unit_number);
}
#endif
}
#endif
BOOLEAN ide_drive_open(DDRIVE *pdr) /*__fn__*/
{
#if (IDE_USE_ATAPI)
int i;
#endif
byte heads;
byte sectors;
dword ltemp;
dword ltemp2;
word buf[256];
PIDE_CONTROLLER pc;
pc = &controller_s[pdr->controller_number];
if (pc->drive[pdr->logical_unit_number].open_count)
return(TRUE);
/*ide_controller_reset(pc) */
ide_clear_voregs(pc); /* Clear virtual output registers */
if (!ide_wait_ready(pc, (int)TIMEOUT_RESET))
return(FALSE);
/* First issue a reset to the controller */
ide_wr_dig_out(pc, IDE_OUT_RESET);
/* sleep 2 ticks can be as little as 12 microseconds) */
ks_sleep(2);
ide_wr_dig_out(pc, 0);
/* Wait for busy to drop */
if (!ide_wait_not_busy(pc, (int)TIMEOUT_RESET))
return(FALSE);
/*DM: This check fails on CDROM. If it can't be made to work, how can we
do it only for hard disks? -- we haven't yet determined whether it's
a hard disk or ATAPI device. That's done below. That's why this is
done as a conditional, which is not great, since it means that this
call is not done for IDE drives either, if CDFS linked. */
#if (!defined(USE_CDFS))
/* Now perform drive diagnostics */
if (!ide_command_diags(pc))
return(FALSE);
#endif
/* Set the power value in case we are on a lowl power system */
/* Note: change the default value */
#if (IDE_USE_SET_FEATURES)
ide_set_features(pc, pdr->logical_unit_number, IDE_FEATURE_SETPERF, IDE_FEATURE_SETPERF_VALUE);
ide_set_features(pc, pdr->logical_unit_number, IDE_FEATURE_WCACHE_ON, 0x00);
ide_set_features(pc, pdr->logical_unit_number, IDE_FEATURE_DEFECT_ON, 0x00);
ide_set_features(pc, pdr->logical_unit_number, IDE_FEATURE_RLOOK_ON, 0x00);
#endif
/* Clear the atapi flag to start */
pc->drive[pdr->logical_unit_number].protocol = 0;
/* Use the ATA identify command. word 3 == # heads */
/* word 6 == sectors per track */
/* word 47 bits 0-7 ==s max sectors per read/write multiple */
/* word 49 bit 9 == if 1 supports logocal block addressing */
/* word 60-61 == number of user addressable LBA's in LBA mode */
pc->user_address = (PFBYTE) &buf[0];
if (!ide_command(IDE_CMD_IDENT, pc, pdr->logical_unit_number, 0, 0))
{
#if (IDE_USE_ATAPI)
pc->user_address = (PFBYTE) &buf[0];
if (ide_command(ATAPI_CMD_IDENT, pc, pdr->logical_unit_number, 0, 0))
{
{
/* CDROM JERRY START */
if((to_WORD((byte *) &buf[0])&0xdf03)==0x8500)
{
pc->drive[pdr->logical_unit_number].media_descriptor=0xef;
pc->drive[pdr->logical_unit_number].CMD_DRQ_type=(byte)(to_WORD((byte *) &buf[0])&0x60);
}
/* CDROM JERRY STOP */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -