⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 Cirrus EP9315 wince bsp
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name: ide.c

Abstract: Boot loader IDE/ATA access functions.

Functions:

    ide_reset           - Reset IDE drive.
    id_drive            - Locate/identify drive.
    lba_to_pchs         - Convert LBA address to Physical CHS.
    read_sector         - Read the contents of a disk sector.
    init_ide            - Initialize IDE drive.
    load_image_ide      - Load OS image from drive.
    OEMHDDPlatformInit  - Blcommon interface functions.
    OEMHDDPreDownload   -  "
    OEMHDDReadData      -  "
    OEMHDDLaunch        -  "

Notes:
    
     Assumptions:
     - only primary master drive is supported
     - FAT16
     - file op routines only work on a single file at a time 
     - kernel image is in the root directory with the bootloader image

--*/

#include <windows.h>
#include <memorymap.h>
#include <blcommon.h>
#include <halether.h>
#include <debugtimer.h>
#include "ide.h"
#include "fat.h"
//#include "bldr.h"


// Global variables.
//
UCHAR g_bsect[SECTOR_SIZE];
ULONG g_sectorsread=0;
UCHAR g_bstartcounting=0;
//STATUSBAR g_statbar;
BOOL  g_bLBAMode = FALSE;

// Function prototypes.
//
//int create_statusbar(PSTATUSBAR pbar, ULONG sval, ULONG eval);
//int update_statusbar(PSTATUSBAR pbar, ULONG cval);
//BOOL InitNIC(void);

// Externs.
//
extern FILEINFO g_fileinfo;

#define KIMAGE_NAME	    "nk.bin"    // Kernel image name.



int ide_reset(void)
{

    DEBUGMSG(ZONE_INFO, (TEXT("ide_reset: entered.\r\n")));

    WAIT_IDE_BUSY;
    WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, (IDE_ALT_CTRL_SRST | IDE_ALT_CTRL_DSBL_INTR));
    //WAIT_IDE_NOT_BUSY;

    //
    // The IDE specification says wait 4 Milliseconds and nothing about waiting for
    // busy.
    //
    DelayInMsec(4);
    WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, IDE_ALT_CTRL_DSBL_INTR);
    WAIT_IDE_NOT_DRDY;
    WAIT_IDE_BUSY;

    if(IS_IDE_ERROR)
    {
        RETAILMSG(1, (TEXT("WARNING: Drive reset failed.\r\n")));
    }

    DEBUGMSG(ZONE_INFO, (TEXT("ide_reset: done.\r\n")));

    return(0); 
}


int id_drive(void)
{
    USHORT cnt=0;
    drv_id_hdr hdr;

    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B6\r\n")));

    // Select the drive.
    //
    WRITE_IDE_UCHAR(IDE_DRVHD_REG, IDE_HEAD_DRIVE_1);

    // Reset the drive.
    //
    if (ide_reset())
        return(-1);
   
    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B7\r\n")));

    WAIT_IDE_BUSY;
 
    // Select the drive.
    //
    WRITE_IDE_UCHAR(IDE_DRVHD_REG, IDE_HEAD_DRIVE_1);

    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B8\r\n")));

    // Identify the drive.
    //
    memset(&hdr, 0, sizeof(drv_id_hdr));

    WAIT_IDE_BUSY;
    WAIT_IDE_NOT_DRDY;
    WRITE_IDE_UCHAR(IDE_CMD_REG, IDE_IDDRIVE_CMD);
    WAIT_IDE_BUSY;
    WAIT_IDE_NOT_DRQ;

    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B9\r\n")));

    if(IS_IDE_ERROR)
    {
        RETAILMSG(1, (TEXT("ERROR: Drive ID failed.\r\n")));         
        return(-1);
    }
   
    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B10\r\n")));

    // Read id info from IDE sector buffer
    for(cnt = 0 ; cnt < (sizeof(drv_id_hdr) / sizeof(USHORT)) ; cnt++)
        *((USHORT *)(&hdr) + cnt) = READ_IDE_USHORT(IDE_DATA_REG);

    // Read the remainder of the sector buffer and toss away...
    //
    while(READ_IDE_UCHAR(IDE_STAT_REG) & IDE_STATUS_DRQ)
    {
        READ_IDE_USHORT(IDE_DATA_REG);
    }

    // Save away P-CHS conversion information for the drive.
    g_drvparms.phy_cyls        = hdr.lcyls;
    g_drvparms.phy_heads       = hdr.lheads;
    g_drvparms.phy_sectspertrk = hdr.lsctptrk;

    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B11\r\n")));

    // In theory, only LBA drives should set the total number of 
    // user-addressable sectors in the IDE ID packet.  If we find a non-zero
    // value, assume we have a drive that wants to talk LBA else use CHS.
    //
    //if (hdr.ttladdrscts)
    if (1)	// Assume LBA mode...
    {
        g_bLBAMode = TRUE;
        DEBUGMSG(ZONE_INFO, (TEXT("LBA Mode (C:H:S = %d:%d:%d  addressable sectors = %d).\r\n"), g_drvparms.phy_cyls, g_drvparms.phy_heads, g_drvparms.phy_sectspertrk, hdr.ttladdrscts));
    }
    else
    {
        g_bLBAMode = FALSE;
        DEBUGMSG(ZONE_INFO, (TEXT("CHS Mode (C:H:S = %d:%d:%d).\r\n"), g_drvparms.phy_cyls, g_drvparms.phy_heads, g_drvparms.phy_sectspertrk));
    }

    RETAILMSG(1, (TEXT("Loading image from hard drive...\r\n")));

    return(0);
}


int lba_to_pchs(ULONG lba, 
                USHORT *pc,
                UCHAR  *ph,
                UCHAR  *ps)
{
    USHORT temp = 0;

    // Make sure we know the drive geometry
    if (g_drvparms.phy_cyls  == 0 ||
        g_drvparms.phy_heads == 0 ||
        g_drvparms.phy_sectspertrk == 0)
        return(-1);

    if (pc == NULL || ph == NULL || ps == NULL)
        return(-1);

    // Do the math...
    *pc = (USHORT)(lba / (g_drvparms.phy_heads * g_drvparms.phy_sectspertrk));
    temp = (USHORT)(lba % (g_drvparms.phy_heads * g_drvparms.phy_sectspertrk));
    *ph = (UCHAR)(temp / g_drvparms.phy_sectspertrk);
    *ps = (UCHAR)(temp % g_drvparms.phy_sectspertrk) + 1;
   
    return(0); 
}


int read_sector(ULONG lba, unsigned char *pbuf)
{
    USHORT c = 0;
    UCHAR  h = 0;
    UCHAR  s = 0;
    USHORT i = 0;
    UCHAR *a = NULL;

    if (!pbuf)
        return(-1);

    // Convert LBA address to P-CHS for IDE controller
    if (!g_bLBAMode)
    {
        if (lba_to_pchs(lba, &c, &h, &s))
            return(-1);

        DEBUGMSG(ZONE_INFO, (TEXT("INFO: Reading sector (P-CHS = %d:%d:%d).\r\n"), c, h, s));
    }
    else
        DEBUGMSG(ZONE_INFO, (TEXT("INFO: Reading sector (LBA = 0x%x).\r\n"), lba));


    // Program the IDE controller
    WAIT_IDE_BUSY;
    WRITE_IDE_UCHAR(IDE_SECTCNT_REG, 1);

    if (!g_bLBAMode)
    {
        // CHS access...
        //
        WRITE_IDE_UCHAR(IDE_CYLL_REG, (UCHAR)(c & 0x00ff));
        WRITE_IDE_UCHAR(IDE_CYLH_REG, (UCHAR)((c & 0xff00) >> 8));
        // TODO - future drive num compensate.
        WRITE_IDE_UCHAR(IDE_DRVHD_REG, (UCHAR)(h | IDE_HEAD_DRIVE_1));
        WRITE_IDE_UCHAR(IDE_SECTNUM_REG, (UCHAR)s);
    }
    else
    {
        // LBA access...
        //
        WRITE_IDE_UCHAR(IDE_SECTNUM_REG, (UCHAR)(lba & 0xff));
        WRITE_IDE_UCHAR(IDE_CYLL_REG, (UCHAR)((lba >> 8) & 0xff));
        WRITE_IDE_UCHAR(IDE_CYLH_REG, (UCHAR)((lba >> 16) & 0xff));
        // TODO - future drive num compensate.
        WRITE_IDE_UCHAR(IDE_DRVHD_REG, (UCHAR)(((lba >> 24) & 0xff) | IDE_HEAD_DRIVE_1 | IDE_HEAD_LBA_MODE));
    }

    //
    // Make sure interrupt enable bit is off (we'll poll)
    //
    //_outp(0x3f6, 0x0a);
    WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, 0xA0);    
    
    WAIT_IDE_NOT_DRDY;

    WRITE_IDE_UCHAR(IDE_CMD_REG, IDE_RDSECT_CMD);

    WAIT_IDE_BUSY; 
    if (IS_IDE_ERROR)
    {
        RETAILMSG(1, (TEXT("ERROR: Sector read failed.\r\n")));
        return(-1);
    }
    WAIT_IDE_NOT_DRQ;

    // Copy sector buffer contents to callers buffer
    for(i=0 ; i < (SECTOR_SIZE / sizeof(USHORT)) ; i++)
       *((USHORT *)pbuf + i) = (USHORT)(READ_IDE_USHORT(IDE_DATA_REG)); 

    // Increment total number of sectors and update status bar
    if (g_bstartcounting)
    {
        ++g_sectorsread;
        //update_statusbar(&g_statbar, g_sectorsread);
    }
 
    return(0);
}


int init_ide(void)
{

    // Get drive geometry info - needed for LBA -> P-CHS convertion
    if (id_drive())
        return(-1);

    return(0);
}


// TODO: Resolve with OEMHDDPreDownload.
int load_image_ide(unsigned char *pname, ULONG *pimgloc)
{
    int stat=0;
    IMGHDR imghdr;
    RECHDR rechdr;
    ULONG cnt = 0;

    DEBUGMSG(ZONE_BOOTPROG, (TEXT("B5\r\n")));

    //
    g_bstartcounting = 0;
    g_sectorsread = 0;

    // Initialize IDE
    if (init_ide())
    {
        RETAILMSG(1, (TEXT("ERROR: IDE device initialization failed.\r\n")));
        return(-1);
    }


    // Initialize FAT structs
    if (init_fat())
    {
        RETAILMSG(1, (TEXT("ERROR: FAT initialization failed.\r\n")));
        return(-1);
    }

    // Open image (finds starting LBA and size - inits structs for later ops)
    // Only read is supported
    if (file_open(pname))
    {
        RETAILMSG(1, (TEXT("ERROR: File open failed (%s)\r\n"), pname));
        return(-1);
    }

    // Display status bar
    //create_statusbar(&g_statbar, 0, (g_fileinfo.fsize / SECTOR_SIZE) - 1);
    g_bstartcounting = 1;

    // Get image header
    stat = file_read((unsigned char *)&imghdr, sizeof(IMGHDR));
    if (stat == FAT_EOF)
    {
        RETAILMSG(1, (TEXT("ERROR: EOF reading image header.\r\n")));
        return(-1);
    }
    else if (stat)
    {
        RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
        return(-1);
    }

    // Determine jump address
    *pimgloc = imghdr.imgaddr;

    // Display image header
    DEBUGMSG(ZONE_INFO, (TEXT("Image Header:\r\n")));
    DEBUGMSG(ZONE_INFO, (TEXT("-------------------------------------------\r\n")));
    DEBUGMSG(ZONE_INFO, (TEXT("Sync Bytes    = '%c%c%c%c%c%c'\r\n"), imghdr.syncbytes[0], imghdr.syncbytes[1], imghdr.syncbytes[2], imghdr.syncbytes[3], imghdr.syncbytes[4], imghdr.syncbytes[5]));
    DEBUGMSG(ZONE_INFO, (TEXT("Image Address = 0x%x\r\n"), imghdr.imgaddr));
    DEBUGMSG(ZONE_INFO, (TEXT("Image Length  = 0x%x\r\n"), imghdr.imglen));

    do
    {
	// Get record header
        stat = file_read((unsigned char *)&rechdr, sizeof(RECHDR));
        if (stat == FAT_EOF)
        {
            RETAILMSG(1, (TEXT("ERROR: EOF reading record header.\r\n")));
            return(-1);
        }
        else if (stat)
        {
            RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
            return(-1);
        } 

        // Display Record Header
        DEBUGMSG(ZONE_INFO, (TEXT("Record Header:\r\n")));
        DEBUGMSG(ZONE_INFO, (TEXT("------------------------------------------\r\n")));
        DEBUGMSG(ZONE_INFO, (TEXT("Record Address  = 0x%x\r\n"), rechdr.recaddr));
        DEBUGMSG(ZONE_INFO, (TEXT("Record Length   = 0x%x\r\n"), rechdr.reclen));
        DEBUGMSG(ZONE_INFO, (TEXT("Record CheckSum = 0x%x\r\n"), rechdr.recchksum));

        // Last Header
        if (rechdr.recaddr == 0 && rechdr.recchksum == 0)
            break;

        stat = file_read((unsigned char *)rechdr.recaddr, rechdr.reclen);
        if (stat)
        {
            if (stat == EOF)
                RETAILMSG(1, (TEXT("ERROR: EOF reading data.\r\n")));
            else
                RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
            return(-1);
        } 

    }
    while(1);

    // Close file
    file_close();

    return(0);
}


BOOL OEMHDDPlatformInit(VOID)
{

    // For now, the RTL8139 product NIC driver requires an ILR in the PCI 
    // config space header otherwise it isn't able to get interrupts...
    //
    //InitNIC();


    return(TRUE);
}


DWORD OEMHDDPreDownload(VOID)
{
    UCHAR pName[] = KIMAGE_NAME;

    //
    g_bstartcounting = 0;
    g_sectorsread = 0;

    RETAILMSG(1, (TEXT("Initializing IDE drive (may take a second)...\r\n")));


    //
    // Set the IDE pcmcia cards attribute space to use memory and reset the PCMCIA card.
    //
    //*CF_CONFIG = CONFIG_LEVIRQ | CONFIG_SRESET;
    *CF_CONFIG = CONFIG_LEVIRQ | 1;


    // Initialize IDE
    if (init_ide())
    {
        RETAILMSG(1, (TEXT("ERROR: IDE device initialization failed.\r\n")));
        return(-1);
    }

    // Initialize FAT structs
    if (init_fat())
    {
        RETAILMSG(1, (TEXT("ERROR: FAT initialization failed.\r\n")));
        return(-1);
    }

    // Open image (finds starting LBA and size - inits structs for later ops)
    // Only read is supported
    if (file_open(pName))
    {
        RETAILMSG(1, (TEXT("ERROR: File open failed (%s).\r\n"), pName));
        return(-1);
    }

    // Display status bar
    //create_statusbar(&g_statbar, 0, (g_fileinfo.fsize / SECTOR_SIZE) - 1);
    g_bstartcounting = 1;

    return(BL_DOWNLOAD);
}


BOOL OEMHDDReadData(DWORD cbData, LPBYTE pbData)
{
    int stat=0;

    stat = file_read((unsigned char *)pbData, cbData);
    if (stat == FAT_EOF)
    {
        RETAILMSG(1, (TEXT("ERROR: EOF reading record header.\r\n")));
        return(FALSE);
    }
    else if (stat)
    {
        RETAILMSG(1, (TEXT("ERROR: File read failed.\r\n")));
        return(FALSE);
    } 

    return(TRUE);
}

#if 0

VOID OEMHDDLaunch(DWORD dwImageStart,
                  DWORD dwImageLength,
                  DWORD dwLaunchAddr,
                  const ROMHDR *pRomHdr)
{
    ((PFN_LAUNCH)(dwLaunchAddr))();

    // Should never be reached.
    SpinForever();
}

#endif // 0

⌨️ 快捷键说明

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