📄 ide_drv.c
字号:
/* Not Done. We have to send more data */
/* Note: blocks size is 1 for write sectors */
if (pc->sectors_remaining >= (word) pc->block_size)
utemp = (word) pc->block_size;
else
utemp = pc->sectors_remaining;
ide_out_words(pc, (word) (utemp << 8));/* 256 times xfer size */
pc->sectors_remaining -= utemp;
return; /* Return from the int with the command still valid. */
}
/* all other interrupts are not as performance sensitive so load the
register file up */
ide_read_register_file(pc);
if(pc->vo_command == IDE_CMD_DIAG)
{
#if (ZERO)
/* Diagnostics return 01 on no error */
if (pc->vi_error != 0x01)
pc->error_code = IDE_ERC_DIAG;
goto io_done_label;
#else
/* Diagnostics return 01 on no error */
/* if (pc->vi_error != 0x01)*/ /* this fails if either drive fails*/
/* pc->error_code = IDE_ERC_DIAG;*/
/* the following tests to see if the relavent drive failed */
if(pc->vo_drive_head&0x10)
{
if ((pc->vi_error == 0x00)||(pc->vi_error == 0x81)) /* drive 1 failure */
pc->error_code = IDE_ERC_DIAG;
}
else
if ((pc->vi_error != 0x01)&&(pc->vi_error != 0x81)) /* drive 0 failure */
pc->error_code = IDE_ERC_DIAG;
goto io_done_label;
#endif
}
else
{
if ((pc->vo_command == IDE_CMD_IDENT) || (pc->vo_command == ATAPI_CMD_IDENT)) /* :::::- Identify drive completed */
{
if (!(pc->vi_status & IDE_STB_DRQ)) /* Drive should be requesting */
{
/* Serious problem. Bus state incorrect */
pc->error_code = IDE_ERC_BUS;
goto io_done_label;
}
ide_in_words(pc, 256); /* 256 times xfr size 1 block */
ide_read_register_file(pc);
if (pc->vi_status & IDE_STB_ERROR)
pc->error_code = IDE_ERC_STATUS;
}
}
io_done_label:
/* If it gets here the current command is complete. If pc->error_code is
zero we had success */
pc->command_complete = TRUE;
return;
}
/* void ide_clear_voregs()
*
* This routine clears the virtual output register file to a known state.
* All commands first call this routine. This is done because they all
* eventually send the vo_regs to the ide drive. We want them to be in a
* known state when sent.
*
* Note: We don't clear the digital output register. This is used to enable
* interrupts on the drive. We don't want to effect this each time.
*
* This routine is portable
*/
static void ide_clear_voregs(PIDE_CONTROLLER pc) /* __fn__ */
{
pc->vo_write_precomp =
pc->vo_sector_count =
pc->vo_sector_number =
pc->vo_cyl_low =
pc->vo_cyl_high =
pc->vo_drive_head =
pc->vo_feature =
pc->vo_command = 0;
}
/* ide_wait_not_busy - Wait for the busy bit to deassert
*
*
* This routine polls the busy bit in the alternate status register
* until is clears. It uses a watchdog timer to guard against
* latchup
*
* Returns:
* TRUE if the bit cleared
* FALSE if it timed out.
*
*/
BOOLEAN ide_wait_not_busy(PIDE_CONTROLLER pc,int ticks) /* __fn__ */
{
byte alt_status;
dword l;
dword lticks;
alt_status = ide_rd_alt_status(pc);
if (!(alt_status & IDE_STB_BUSY))
return(TRUE);
/* Set a watchdog to time out in ticks seconds */
lticks = l = ks_get_ticks();
lticks += ticks;
if (l > lticks)
lticks = ticks;
while(alt_status & IDE_STB_BUSY)
{
if (ks_get_ticks() > lticks)
break; /* timer expired. hung, */
alt_status = ide_rd_alt_status(pc);
}
if(alt_status & IDE_STB_BUSY)
{
pc->error_code = IDE_ERC_TIMEOUT;
return(FALSE);
}
else
return(TRUE);
}
/* ide_wait_ready - Wait for the ready bit to assert
*
*
* This routine polls the ready bit in the alternate status register
* until is asserts. It uses a watchdog timer to guard against
* latchup
*
* Returns:
* TRUE if the bit set
* FALSE if it timed out.
*
*/
BOOLEAN ide_wait_ready(PIDE_CONTROLLER pc,int ticks) /* __fn__ */
{
byte alt_status;
dword l;
dword lticks;
alt_status = ide_rd_alt_status(pc);
if (alt_status & IDE_STB_READY)
return(TRUE);
/* Set a watchdog to time out in ticks seconds */
lticks = l = ks_get_ticks();
lticks += ticks;
if (l > lticks)
lticks = ticks;
while(!(alt_status & IDE_STB_READY))
{
if (ks_get_ticks() > lticks)
break; /* timer expired. hung, */
alt_status = ide_rd_alt_status(pc);
}
if(!(alt_status & IDE_STB_READY))
{
pc->error_code = IDE_ERC_TIMEOUT;
return(FALSE);
}
else
return(TRUE);
}
/* ide_wait_drq - Wait for the data request bit to assert
*
*
* This routine polls the drq bit in the alternate status register
* until it asserts. It uses a watchdog timer to guard against
* latchup.
*
* If the bit never sets ERC_BUS is set
*
* Returns:
* TRUE if the bit set
* FALSE if it timed out.
*
*/
BOOLEAN ide_wait_drq(PIDE_CONTROLLER pc, int ticks) /* __fn__ */
{
byte alt_status;
dword lticks, l;
int i;
/* At first stay in a tight loop without a watch dog. This
is because DRQ should come up fast. We don't want the overhead of
setting a watchdog */
for (i =0; i < 10000; i++)
{
alt_status = ide_rd_alt_status(pc);
if (alt_status & IDE_STB_DRQ)
return(TRUE);
}
/* Set a watchdog to time out in ticks seconds */
/* Set a watchdog to time out in ticks seconds */
lticks = l = ks_get_ticks();
lticks += ticks;
if (l > lticks)
lticks = ticks;
while(!(alt_status & IDE_STB_DRQ))
{
if (ks_get_ticks() > lticks)
break; /* timer expired. hung, */
alt_status = ide_rd_alt_status(pc);
}
if(!(alt_status & IDE_STB_DRQ))
{
pc->error_code = IDE_ERC_BUS;
return(FALSE);
}
else
return(TRUE);
}
/* void ide_read_register_file(pc)
*
* This routine reads the register file into the vi_xxxx fields
* in ide control structure. It is called after a drive interrupt
* has occured and register file data is needed.
*
*/
static void ide_read_register_file(PIDE_CONTROLLER pc) /* __fn__ */
{
pc->vi_error = ide_rd_error(pc);
pc->vi_sector_count = ide_rd_sector_count(pc);
pc->vi_sector_number = ide_rd_sector_number(pc);
pc->vi_cyl_low = ide_rd_cyl_low(pc);
pc->vi_cyl_high = ide_rd_cyl_high(pc);
pc->vi_drive_head = ide_rd_drive_head(pc);
pc->vi_status = ide_rd_status(pc);
pc->vi_drive_addr = ide_rd_drive_address(pc);
}
#if (IDE_USE_ATAPI)
BOOLEAN ls120_format(DDRIVE *pdr);
#endif
int ide_perform_device_ioctl(int driveno, int opcode, PFVOID pargs)
{
DDRIVE *pdr;
DEV_GEOMETRY gc; // used by DEVCTL_GET_GEOMETRY
PIDE_CONTROLLER pc;
pdr = pc_drno_to_drive_struct(driveno);
if (!pdr)
return(-1);
pc = &controller_s[pdr->controller_number];
switch (opcode)
{
case DEVCTL_GET_GEOMETRY:
pc_memfill(&gc, sizeof(gc), '\0');
gc.dev_geometry_heads = pc->drive[pdr->logical_unit_number].num_heads;
gc.dev_geometry_cylinders = pc->drive[pdr->logical_unit_number].num_cylinders;
gc.dev_geometry_secptrack = pc->drive[pdr->logical_unit_number].sec_p_track;
gc.dev_geometry_lbas = pc->drive[pdr->logical_unit_number].total_lba;
copybuff(pargs, &gc, sizeof(gc));
return (0);
case DEVCTL_FORMAT:
#if (IDE_USE_ATAPI)
if(pc->drive[pdr->logical_unit_number].protocol==2)
{
if (!ls120_format(pdr))
return(-1);
}
#endif
return (0);
case DEVCTL_REPORT_REMOVE:
pdr->drive_flags &= ~DRIVE_FLAGS_INSERTED;
/* Close out the drive so we re-open */
pc->drive[pdr->logical_unit_number].open_count = 0;
return(0);
case DEVCTL_CHECKSTATUS:
if (!(pdr->drive_flags & DRIVE_FLAGS_REMOVABLE))
return(DEVTEST_NOCHANGE);
if (pdr->drive_flags & DRIVE_FLAGS_INSERTED)
return(DEVTEST_NOCHANGE);
/* If the drive is open but the inserted is clear
that means another partition accessed the drive
and succeed so return CHANGED to force a remount
with no low level drive initialization */
if (pc->drive[pdr->logical_unit_number].open_count)
{
pdr->drive_flags |= DRIVE_FLAGS_INSERTED;
return(DEVTEST_CHANGED);
}
#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)
{
/* Do a media status call - if it fails try it again.
needed by some LS-120 drives */
if (ide_command(IDE_CMD_GET_MEDIA_STATUS, pc, pdr->logical_unit_number, 0, 0))
if (ide_command(IDE_CMD_GET_MEDIA_STATUS, pc, pdr->logical_unit_number, 0, 0))
return(DEVTEST_NOMEDIA);
/* If the user accepted a media change.. do an eject */
if (pc->vi_error & 0x08)
ide_eject_media(pdr);
/* This isn't right. needs minor fixes */
if (pc->vi_error & 0x20)
{
pdr->drive_flags |= DRIVE_FLAGS_INSERTED;
return(DEVTEST_CHANGED);
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -