ide_drv.c

来自「ertfs文件系统里面既有完整ucos程序」· C语言 代码 · 共 1,289 行 · 第 1/3 页

C
1,289
字号

        ide_read_register_file(pc);
        /* Report the error on all but diagnostipc-> The error bits
            are treated differently on this command. */ 
        if (pc->vo_command != IDE_CMD_DIAG)
        {
            pc->error_code = IDE_ERC_STATUS;
            goto io_done_label;
        }
    }
    /* =================================================================== */
    /* ================= Now process command completes==================== */
    /* =================================================================== */

    /* Reads and Write are treated differently from the rest of the commands.
        They may recieve multiple interrupts and the performance of this 
        routine is very important. To pick up some performance we only read
        the register file entries that we need. 
    */
/* Command::::: IDE_CMD_READM - read multiple, IDE_CMD_READS - read sector(s) */
    if((pc->vo_command == IDE_CMD_READM)||(pc->vo_command == IDE_CMD_READS))
    {
        if (pc->sectors_remaining >= (word) pc->block_size)
            utemp = (word) pc->block_size;
        else
            utemp = pc->sectors_remaining;
//BUGBUGBUG - We should compare the sector count register.

        if (!ide_in_words(pc, (word) (utemp << 8)))/* 256 times xfr size */
        {
            /* Serious problem. Bus state incorrect */
            pc->error_code = IDE_ERC_BUS;
            goto io_done_label;
        }
        pc->sectors_remaining -= utemp;

        /* see if we've completed transferring all of our blocks */
        if (pc->sectors_remaining)
            return;             /* NOPE - More to come */
        else
        {
            ide_read_register_file(pc);
            if (pc->vi_status & IDE_STB_ERROR)
                pc->error_code = IDE_ERC_STATUS;
            goto io_done_label; 
        }
    }

/* Command::::: IDE_CMD_WRITEM IDE_CMS_WRITES - write multiple, write sectors */
    if ((pc->vo_command == IDE_CMD_WRITES) ||
        (pc->vo_command == IDE_CMD_WRITES_NE) ||
        (pc->vo_command == IDE_CMD_WRITEM) ||
        (pc->vo_command == IDE_CMD_WRITEM_NE))
    {
        if (!pc->sectors_remaining)
        {
            /* Sector count reg is 0. we're done. We'll read the register
                File in case we want to look at the values */
            ide_read_register_file(pc);
            goto io_done_label; 
        }
    /* 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);
	while(alt_status & IDE_STB_BUSY)
        alt_status = ide_rd_alt_status(pc);
    return(TRUE);
    
#if 0
    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);
#endif
}


/* 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);
	while(!(alt_status & IDE_STB_READY))
        alt_status = ide_rd_alt_status(pc);
    return(TRUE);

#if 0
    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);
#endif
}




/* 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);
}

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:
        
        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);
            }
            else
                return(DEVTEST_UNKMEDIA);
//            break;
        case DEVCTL_WARMSTART:
            if (!pdr->partition_number && !pdr->logical_unit_number)    /* Only initialize the controller once */
            {
                pc->controller_number = pdr->controller_number;
                /* This is the IO address of the register file   */
                pc->register_file_address = pdr->register_file_address;

                pc->interrupt_number = pdr->interrupt_number;

                /* Clear IEN bar if interrupts are requested: Otherwise we poll   */
                if (pc->interrupt_number >= 0)
                    pc->vo_dig_out = 0;
                else
                    pc->vo_dig_out = IDE_OUT_IEN;

                /* Set up OS operating layer and interrupt service routines   */
                if (pc->interrupt_number >= 0)
                {
                    hook_ide_interrupt(pc->interrupt_number, pc->controller_number);
                    /* Clear the signal */
                    OS_IDE_SIGNAL_CLEAR(pc->controller_number);
                }
            }
           
            /* It's a fixed drive so try to open it */
            if (!ide_drive_open(pdr))
            	return(-1);
            else
                pdr->drive_flags |= DRIVE_FLAGS_VALID;

            return(0);
            /* Fall through */
        case DEVCTL_POWER_RESTORE:
            /* Fall through */
        case DEVCTL_POWER_LOSS:
            /* Fall through */
        default:
            break;
    }
    return(0);

}

#endif /* (USE_ATA) */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?