📄 ide_drv.c
字号:
*
* Inputs:
* drive - Drive number (0 or 1)
* heads -
* sectors
*
* Returns:
* TRUE on success else FALSE. If FALSE pc->error_no will contain the error.
*
* This routine tells the drive how many heads and sectors per track
* we will be basing our block to sector:trak:head calculations. The
* drive will map sector:trak:head to its internal geometry.
*
* This routine is portable
*/
#if (USE_SETPARMS)
static BOOLEAN ide_command_setparms(PIDE_CONTROLLER pc, int logical_unit_number, byte heads, byte sectors) /* __fn__ */
{
byte max_head;
ide_clear_voregs(pc); /* Clear virtual output registers */
/* Sectors per track go in sector count register */
pc->vo_sector_count = sectors;
/* number of heads - 1 goes in the drive head register */
max_head = (byte) (heads - 1);
pc->vo_drive_head = (byte) (max_head & 0x0f); /* bit 0-3 is head */
pc->vo_drive_head |= 0x20; /* Bit five is always one */
if (logical_unit_number) /* Bit four is drive (1 or 0) */
pc->vo_drive_head |= 0x10;
pc->vo_command = IDE_CMD_INITP;
pc->timer = (word)TIMEOUT_TYPICAL;
/* Call the processing routine */
return(ide_do_command(pc));
}
#endif
/* ide_command_read_multiple - Execute read multiple commands
*
* Inputs:
* address - Destination address for the data
* drive - Drive number (0 or 1)
* blockno - Block number to read
* nblocks - Number of blocks (legal range: 1-256)
*
* Returns:
* TRUE on success else FALSE. If FALSE pc->error_no will contain the error.
*
* This is the read worker function for the device driver. It performs a one
* or many block read operation. It calls ide_rdwr_setup() and ide_do_command
* to do most of the work.
*
* Called by ide_io
*
* This routine is portable
*/
static BOOLEAN ide_command_read_multiple(PIDE_CONTROLLER pc, int logical_unit_number, dword blockno, word nblocks) /* __fn__ */
{
/* Call set multiple */
/* 11-10=2000 - Don't call this, we did it in the open
if (!ide_command(IDE_CMD_SETM, pc, logical_unit_number, 0, 0))
return(FALSE);
*/
return(ide_command(IDE_CMD_READM, pc, logical_unit_number, blockno, nblocks));
}
/* ide_command_write_multiple - Execute write_multiple(s) command
*
* Inputs:
* address - Source address for the data
* drive - Drive number (0 or 1)
* blockno - Block number to read
* nblocks - Number of blocks (legal range: 1-256)
*
* Returns:
* TRUE on success else FALSE. If FALSE pc->error_no will contain the error.
*
* This routine performs a one or many block write operation. It calls
* ide_rdwr_setup() and ide_do_command() to do most of the work.
*
* This is the write worker function for the device driver. It performs a one
* or many block write operation. It calls ide_rdwr_setup() and ide_do_command
* to do most of the work.
*
* Called by ide_do_block
*
* This routine is portable
*/
static BOOLEAN ide_command_write_multiple(PIDE_CONTROLLER pc, int logical_unit_number, dword blockno, word nblocks) /* __fn__ */
{
/* Call set multiple */
/* 11-10=2000 - Don't call this, we did it in the open
if (!ide_command(IDE_CMD_SETM, pc, logical_unit_number, 0, 0))
return(FALSE);
*/
return(ide_command(IDE_CMD_WRITEM, pc, logical_unit_number, blockno, nblocks));
}
/* ide_rdwr_setup - Setup routine for read for read and write operations
* Inputs:
* address - Destination address for the data
* drive - Drive number (0 or 1)
* blockno - Block number to read/write
* nblocks - Number of blocks (legal range: 1-256)
*
* Outputs:
*
* Sets the following register file registers:
* vo_sector_count,vo_sector_number,vo_cyl_low,vo_cyl_high,vo_drive_head
*
*
* Returns:
* TRUE if inputs are valid else FALSE
*
* This routine performs setup operations common to read and write. The
* registers listed above are set up and the user transfer address is
* set up.
*
* This routine is portable
*
*/
static byte l_to_byte(dword l, int bit)
{
if (bit)
l >>= bit;
l &= 0xff;
return( (byte) l);
}
#if (IDE_USE_ATAPI)
static void reverse(byte *sink, byte *source, word bytes)
{
source+=bytes;
while(bytes--)
*(sink++)=*(--source);
}
#endif
static BOOLEAN ide_rdwr_setup(PIDE_CONTROLLER pc, int logical_unit_number, dword blockno, word nblocks) /* __fn__ */
{
word cylinder;
word head;
word sector;
word blk_offs_in_cyl;
/* Check against max_blocks. this is 256 for IDE. In real mode 80xx we limit
it to 128 to eliminate segment wrap. */
if ( (nblocks > MAX_BLOCKS) ||
(logical_unit_number && logical_unit_number != 1) || /* Can only be 0 or 1 */
(!pc->drive[logical_unit_number].sec_p_cyl&&(pc->drive[logical_unit_number].media_descriptor!=0xef)) ) /* Will be non zeroe if the */ /* CDROM Jerry*/
{ /* Drive is initted */
pc->error_code = IDE_ERC_ARGS;
return(FALSE); /* Drive is initted */
}
#if (IDE_USE_ATAPI)
/* In lba mode sector no = block (0.7), cyl_low = (8.15), cyl_high = (16,23)
drive_head = (24, 27) */
if(pc->drive[logical_unit_number].protocol==2)
{
reverse((byte *)&pc->drive[logical_unit_number].atapi_packet.generic.lba,(byte *)&blockno,4);
pc->drive[logical_unit_number].atapi_packet.generic.transfer_length.lsb=(byte)nblocks;
pc->drive[logical_unit_number].atapi_packet.generic.transfer_length.msb=(byte)(nblocks>>8);
}
#endif
if (pc->drive[logical_unit_number].supports_lba)
{
pc->vo_sector_number = (byte) l_to_byte(blockno, 0);
pc->vo_cyl_low = (byte) l_to_byte(blockno, 8);
pc->vo_cyl_high = (byte) l_to_byte(blockno, 16);
pc->vo_drive_head = (byte) (l_to_byte(blockno, 24) & 0x0f);
pc->vo_drive_head |= 0x40; /* Select lba mode */
}
else
{
/* Calculate block address */
cylinder = (word) (blockno/pc->drive[logical_unit_number].sec_p_cyl);
blk_offs_in_cyl = (word) (blockno%pc->drive[logical_unit_number].sec_p_cyl);
head = (word) (blk_offs_in_cyl/pc->drive[logical_unit_number].sec_p_track);
sector = (word) (blk_offs_in_cyl%pc->drive[logical_unit_number].sec_p_track);
/* Load registers */
pc->vo_sector_number = (byte) (sector + 1); /* Note in 1-N order at the controller */
pc->vo_cyl_low = (byte) (cylinder & 0xff);
pc->vo_cyl_high = (byte) (cylinder >> 8);
pc->vo_drive_head = (byte) (head & 0x0f); /* bit 0-3 is head */
}
pc->vo_sector_count = (byte) nblocks; /* 1-255. 256 becomes 0 */
return(TRUE);
}
static BOOLEAN ide_error(PIDE_CONTROLLER pc, word error_code)
{
pc->error_code = error_code;
pc->command_complete = TRUE; /* Shesssaaa hung */
return(FALSE);
}
/* ide_do_command- Execute an ide cmd and poll or block until complete
* Inputs:
* uses values in cs (the control structure)
* Outputs:
* pc->command_complete and pc->error_code are updated. As well as all the
* vi_xxx (virtual register file in) are read in.
* Returns:
* TRUE if command succeeded else look in error_code.
*
* This routine is called by all ide_command_xxx routines to begin
* command executiion. It copies the vo_xxxxx register file from the control
* structure to the drive and then polls or blocks until completion. If
* pc->vo_dig_out & IDE_OUT_IEN is true it polls waiting for completion,
* otherwise it blocks waiting for the ISR to wake it. Each command has
* a time out value in pc->timer.
*
*/
static BOOLEAN ide_do_command(PIDE_CONTROLLER pc) /* __fn__ */
{
word utemp;
#if (IDE_USE_ATAPI)
dword words_remaining;
dword words_to_transfer;
int phys_drive;
PFBYTE save_useraddress;
byte save_vo_command; /* command register see command patterns above (W) */
dword i;
word dummyWord;
#endif
int loop_count=8;
pc->error_code = 0;
pc->command_complete = FALSE;
/* The drive may be busy. If so, wait for it to complete */
if (!ide_wait_not_busy(pc, pc->timer))
return(ide_error(pc,IDE_ERC_BUS)); /* bus is hung */
/* There should be no pending interrupt complete signals
so call os_ide_clear_signal(); to be sure we aren't
signalled until after an int occurs. */
if (!(pc->vo_dig_out & IDE_OUT_IEN))
{
OS_IDE_SIGNAL_BIND(pc->controller_number);
OS_IDE_SIGNAL_CLEAR(pc->controller_number);
}
#if (IDE_USE_ATAPI)
phys_drive=(pc->vo_drive_head & 0x10)>>4; /* GET PHYSICAL DRIVE */
if( ((pc->drive[phys_drive].protocol==2) &&
(pc->vo_command!=IDE_CMD_DIAG) &&
(pc->vo_command!=IDE_CMD_IDENT) &&
(pc->vo_command!=ATAPI_CMD_IDENT) &&
(pc->vo_command!=IDE_CMD_GET_MEDIA_STATUS) &&
(pc->vo_command!=IDE_CMD_SOFT_RESET) &&
(pc->vo_command!=IDE_CMD_SETF)) ||
(pc->vo_command==ATAPI_PKT_CMD_TEST_UNIT_READY) ||
(pc->vo_command==ATAPI_PKT_CMD_REQUEST_SENSE) ||
(pc->vo_command==ATAPI_PKT_CMD_MODE_SENSE) ||
(pc->vo_command==ATAPI_PKT_CMD_START_STOP_UNIT) ||
(pc->vo_command==ATAPI_PKT_CMD_FORMAT_UNIT))
{
save_vo_command=pc->vo_command;
pc->vo_command=ATAPI_CMD_PKT;
switch(save_vo_command)
{
case IDE_CMD_READS: /* Read sector(s) */
pc->timer<<=1; /* increase the timer to allow for spin up */
pc->drive[phys_drive].atapi_packet.generic.op_code=ATAPI_PKT_CMD_READ;
break;
case IDE_CMD_WRITES: /* Write sector(s) */
pc->timer<<=1; /* increase the timer to allow for spin up */
pc->drive[phys_drive].atapi_packet.generic.op_code=ATAPI_PKT_CMD_WRITE;
break;
case ATAPI_PKT_CMD_TEST_UNIT_READY:
pc_memfill(&pc->drive[phys_drive].atapi_packet, sizeof(ATAPI_PACKET), (byte) 0);
/* fall thru */
case ATAPI_PKT_CMD_MODE_SENSE:
case ATAPI_PKT_CMD_REQUEST_SENSE:
pc->timer<<=1; /* increase the timer to allow for spin up */
pc->drive[phys_drive].atapi_packet.generic.op_code=save_vo_command;
break;
case ATAPI_PKT_CMD_START_STOP_UNIT:
/* timer should be already set for a few minutes */
pc_memfill(&pc->drive[phys_drive].atapi_packet, sizeof(ATAPI_PACKET), (byte) 0);
/* Eject the packet if possible */
pc->drive[phys_drive].atapi_packet.start_stop.op_code=ATAPI_PKT_CMD_START_STOP_UNIT;
pc->drive[phys_drive].atapi_packet.start_stop.eject = 0x02;
break;
case ATAPI_PKT_CMD_FORMAT_UNIT:
/* timer should be already set for a few minutes */
pc_memfill(&pc->drive[phys_drive].atapi_packet, sizeof(ATAPI_PACKET), (byte) 0);
switch(pc->drive[phys_drive].medium_type_code) /* Bytes/ Sectors/ */
{ /* Cyl H Sector Track Capacity */
case 0x22: /* Formatted NEC 77 2 1024 8 1.20Mb*/
case 0x23: /* Formatted Toshiba 80 2 512 15 1.20Mb*/
case 0x26: /* DMF 80 2 512 21 1.7Mb*/
case 0x27: /* NEC-DMF 77 2 512 9 720Kb*/
case 0x30: /* Formatted UHD 963 8 512 32 120Mb */
case 0x31: /* Unformatted UHD 963 8 512 32 120Mb */
pc->drive[phys_drive].atapi_packet.format.op_code=save_vo_command;
pc->drive[phys_drive].atapi_packet.format.defect_list_format=0x17;
pc->drive[phys_drive].atapi_packet.format.track_number=0x01;
break;
case 0x11: /* Formatted DD 80 2 512 9 720Kb*/
case 0x10: /* Unformatted DD 80 2 512 9 720Kb*/
pc->drive[phys_drive].atapi_packet.old_format.medium=0x11;
pc->drive[phys_drive].atapi_packet.old_format.op_code=ATAPI_PKT_CMD_OLD_FORMAT_UNIT;
pc->drive[phys_drive].atapi_packet.old_format.control_byte=0x21;
break;
case 0x20: /* Unformatted HD 80 2 512 18 1.44Mb*/
case 0x24: /* Formatted HD 80 2 512 18 1.44Mb*/
pc->drive[phys_drive].atapi_packet.old_format.medium=0x24;
pc->drive[phys_drive].atapi_packet.old_format.op_code=ATAPI_PKT_CMD_OLD_FORMAT_UNIT;
pc->drive[phys_drive].atapi_packet.old_format.control_byte=0x21;
break;
default:
return(FALSE);
}
break;
case IDE_CMD_ERASES: /* Erase sector(s) */
case IDE_CMD_WRITES_NE: /* Write sector(s) No pre-erase */
case IDE_CMD_WRITEM: /* Write multiple sectors/interrupt */
case IDE_CMD_WRITEM_NE: /* Write multiple No pre-erase */
case IDE_CMD_READM: /* Read multiple sectors/interrupt */
case IDE_CMD_SETM: /* Set multiple mode */
default:
pc->error_code=IDE_ERC_BAD_CMD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -