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

📄 usbdl.cpp

📁 at91的一个bootloader
💻 CPP
字号:
//-----------------------------------------------------------------------------
// This is the Windows-side program that you run to download code into a
// device. It is capable of loading both the application (i.e., a piece of
// code starting at address 0x00002000 in flash) or the bootrom (i.e., a
// piece of code starting at address 0x00000000 in flash).
// 
// Since the device looks like an HID device, we do not need to provide our
// own kernel-mode driver. We just get a handle to our device--which we
// can find by looking at the PID/VID--and from there we can just use the
// usual I/O functions.
//
// Jonathan Westhues, July 2005, public release May 2006
//-----------------------------------------------------------------------------

#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
extern "C" {
#include "include/hidsdi.h"
#include "include/hidpi.h"
}

#include "../include/usb_cmd.h"

// This must obviously agree with the descriptors in the ARM-side code.
#define OUR_VID             0x9ac5
#define OUR_PID             0x4b8f

// Check your datasheets! This varies depending on the part.
#define FLASH_PAGE_SIZE     256

static HANDLE UsbHandle;

static void ShowError(void)
{
    char buf[1024];
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
        buf, sizeof(buf), NULL);
    printf("ERROR: %s", buf);
}

static BOOL UsbConnect(void)
{
    typedef void (__stdcall *GetGuidProc)(GUID *);
    typedef BOOLEAN (__stdcall *GetAttrProc)(HANDLE, HIDD_ATTRIBUTES *);
    typedef BOOLEAN (__stdcall *GetPreparsedProc)(HANDLE,
                                        PHIDP_PREPARSED_DATA *);
    typedef NTSTATUS (__stdcall *GetCapsProc)(PHIDP_PREPARSED_DATA, PHIDP_CAPS);
    GetGuidProc         getGuid;
    GetAttrProc         getAttr;
    GetPreparsedProc    getPreparsed;
    GetCapsProc         getCaps;

    // I don't think you can get hid.lib without paying for the DDK; but
    // if we link dynamically, then we don't need to.
    HMODULE h = LoadLibrary("hid.dll");
    getGuid      = (GetGuidProc)GetProcAddress(h, "HidD_GetHidGuid");
    getAttr      = (GetAttrProc)GetProcAddress(h, "HidD_GetAttributes");
    getPreparsed = (GetPreparsedProc)GetProcAddress(h, "HidD_GetPreparsedData");
    getCaps      = (GetCapsProc)GetProcAddress(h, "HidP_GetCaps");

    GUID hidGuid;
    getGuid(&hidGuid);

    HDEVINFO devInfo;
    devInfo = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
        DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);

    SP_DEVICE_INTERFACE_DATA devInfoData;
    devInfoData.cbSize = sizeof(devInfoData);

    int i;
    for(i = 0;; i++) {
        if(!SetupDiEnumDeviceInterfaces(devInfo, 0, &hidGuid, i, &devInfoData))
        {
            if(GetLastError() != ERROR_NO_MORE_ITEMS) {
//                printf("SetupDiEnumDeviceInterfaces failed\n");
            }
//            printf("done list\n");
            SetupDiDestroyDeviceInfoList(devInfo);
            return FALSE;
        }

//        printf("item %d:\n", i);
    
        DWORD sizeReqd = 0;
        if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,
            NULL, 0, &sizeReqd, NULL))
        {
            if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
//                printf("SetupDiGetDeviceInterfaceDetail (0) failed\n");
                continue;
            }
        }

        SP_DEVICE_INTERFACE_DETAIL_DATA *devInfoDetailData =
            (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(sizeReqd);
        devInfoDetailData->cbSize = sizeof(*devInfoDetailData);

        if(!SetupDiGetDeviceInterfaceDetail(devInfo, &devInfoData,
            devInfoDetailData, 87, NULL, NULL))
        {
//            printf("SetupDiGetDeviceInterfaceDetail (1) failed\n");
            continue;
        }

        char *path = devInfoDetailData->DevicePath;

        UsbHandle = CreateFile(path, /*GENERIC_READ |*/ GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
            FILE_FLAG_OVERLAPPED, NULL);

        if(UsbHandle == INVALID_HANDLE_VALUE) {
            ShowError();
//            printf("CreateFile failed: for '%s'\n", path);
            continue;
        }

        HIDD_ATTRIBUTES attr;
        attr.Size = sizeof(attr);
        if(!getAttr(UsbHandle, &attr)) {
            ShowError();
//            printf("HidD_GetAttributes failed\n");
            continue;
        }

//        printf("VID: %04x PID %04x\n", attr.VendorID, attr.ProductID);

        if(attr.VendorID != OUR_VID || attr.ProductID != OUR_PID) {
            CloseHandle(UsbHandle);
//            printf("    nope, not us\n");
            continue;
        }

//        printf ("got it!\n");
        CloseHandle(UsbHandle);

        UsbHandle = CreateFile(path, GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
            FILE_FLAG_OVERLAPPED, NULL);

        if(UsbHandle == INVALID_HANDLE_VALUE) {
            ShowError();
//            printf("Error, couldn't open our own handle as desired.\n");
            return FALSE;
        }

        PHIDP_PREPARSED_DATA pp;
        getPreparsed(UsbHandle, &pp);
        HIDP_CAPS caps;

        if(getCaps(pp, &caps) != HIDP_STATUS_SUCCESS) {
//            printf("getcaps failed\n");
            return FALSE;
        }

//        printf("input/out report %d/%d\n", caps.InputReportByteLength,
//            caps.OutputReportByteLength);


        return TRUE;
    }
    return FALSE;
}

//-----------------------------------------------------------------------------
// Try to receive a command over USB. If we do, the copy it into *c and return
// TRUE; otherwise return FALSE.
//-----------------------------------------------------------------------------
static BOOL ReceiveCommandPoll(UsbCommand *c)
{
    static BOOL ReadInProgress = FALSE;
    static OVERLAPPED Ov;
    static BYTE Buf[65];
    static DWORD HaveRead;

    if(!ReadInProgress) {
        memset(&Ov, 0, sizeof(Ov));
        ReadFile(UsbHandle, Buf, 65, &HaveRead, &Ov);
        if(GetLastError() != ERROR_IO_PENDING) {
            ShowError();
            exit(-1);
        }
        ReadInProgress = TRUE;
    }

    if(HasOverlappedIoCompleted(&Ov)) {
        ReadInProgress = FALSE;

        if(!GetOverlappedResult(UsbHandle, &Ov, &HaveRead, FALSE)) {
            ShowError();
            exit(-1);
        }

        memcpy(c, Buf+1, 64);

        return TRUE;
    } else {
        return FALSE;
    }
}

//-----------------------------------------------------------------------------
// Block until we receive a command, and then return it in *c. Actually
// we are just spinning on ReceiveCommandPoll, but try not to chew up too
// much CPU while doing so.
//-----------------------------------------------------------------------------
static void ReceiveCommand(UsbCommand *c)
{
    while(!ReceiveCommandPoll(c)) {
        Sleep(0);
    }
}

//-----------------------------------------------------------------------------
// Send a command; if wantAck is true, then try to receive a command right
// after, and verify that it is an ACK (our higher-level ACK, not the USB
// ACK).
//-----------------------------------------------------------------------------
static void SendCommand(UsbCommand *c, BOOL wantAck)
{
    BYTE buf[65];
    buf[0] = 0;
    memcpy(buf+1, c, 64);

    DWORD written;
    OVERLAPPED ov;
    memset(&ov, 0, sizeof(ov));
    WriteFile(UsbHandle, buf, 65, &written, &ov);
    if(GetLastError() != ERROR_IO_PENDING) {
        ShowError();
        exit(-1);
    }
    
    while(!HasOverlappedIoCompleted(&ov)) {
        Sleep(0);
    }

    if(!GetOverlappedResult(UsbHandle, &ov, &written, FALSE)) {
        ShowError();
        exit(-1);
    }

    if(wantAck) {
        UsbCommand ack;
        ReceiveCommand(&ack);
        if(ack.cmd != CMD_ACK) {
            printf("bad ACK\n");
            exit(-1);
        }
    }
}


// The address at which we expect to see the next byte in the S records file;
// we are assuming that the S records are in order.
static DWORD ExpectedAddr;

// The bytes that are currently queued to send; we wait until we get a full
// page's worth.
static BYTE QueuedToSend[256];

// This is TRUE if all of the bytes currently in QueuedToSend have already
// been written to the device, else FALSE.
static BOOL AllWritten;

//-----------------------------------------------------------------------------
// Called when we have accumulated a full page's worth of bytes in
// QueuedToSend; we copy them over to the device, and then tell the device
// to write them to flash.
//-----------------------------------------------------------------------------
static void FlushPrevious(void)
{
    UsbCommand c;
    memset(&c, 0, sizeof(c));

    printf("expected = %08x flush\n", ExpectedAddr);

#if FLASH_PAGE_SIZE != 256
#error Fix download format for different page size!
#endif
    int i;
    for(i = 0; i < 240; i += 48) {
        c.cmd = CMD_SETUP_WRITE;
        memcpy(c.d.asBytes, QueuedToSend+i, 48);
        c.ext1 = (i/4);
        SendCommand(&c, TRUE);
    }

    c.cmd = CMD_FINISH_WRITE;
    c.ext1 = (ExpectedAddr-1) & (~255);
    printf("    c.ext1 = %08x\n", c.ext1);
    memcpy(c.d.asBytes, QueuedToSend+240, 16);
    SendCommand(&c, TRUE);

    AllWritten = TRUE;
}

//-----------------------------------------------------------------------------
// Called for each byte in the S records; make sure that it is at the
// address (where) where we expected it, and then tack it on to the page
// to be written that we are working on. If we have a full page of data
// ready to be written, call FlushPrevious() to write it and thus clear
// out our buffer for the next page.
//-----------------------------------------------------------------------------
static void GotByte(DWORD where, BYTE which)
{
    AllWritten = FALSE;

    if(where != ExpectedAddr) {
        printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);
        exit(-1);
    }
    QueuedToSend[where & (FLASH_PAGE_SIZE-1)] = which;
    ExpectedAddr++;

    if((where & (FLASH_PAGE_SIZE-1)) == (FLASH_PAGE_SIZE-1)) {    
        // we have completed a full page
        FlushPrevious();
    }
}

//-----------------------------------------------------------------------------
// The integer value of a hex digit 0-9a-fA-F.
//-----------------------------------------------------------------------------
static int HexVal(int c)
{
    c = tolower(c);
    if(c >= '0' && c <= '9') {
        return c - '0';
    } else if(c >= 'a' && c <= 'f') {
        return (c - 'a') + 10;
    } else {
        printf("bad hex digit '%c'\n", c);
        exit(-1);
    }
}

//-----------------------------------------------------------------------------
// The integer value of the first two characters of a string, interepreted
// as an 8-bit hex quantity.
//-----------------------------------------------------------------------------
static BYTE HexByte(char *s)
{
    return (HexVal(s[0]) << 4) | HexVal(s[1]);
}

//-----------------------------------------------------------------------------
// Read S records from a file, and write them to the device. We verify that
// the file starts at the correct address, which is why we need to know
// whether the file being loaded is a bootrom or an application.
//-----------------------------------------------------------------------------
static void LoadFlashFromSRecords(char *file, BOOL isBootrom)
{
    if(isBootrom) {
        ExpectedAddr = 0;
    } else {
        ExpectedAddr = 0x2000;
    }

    FILE *f = fopen(file, "r");
    if(!f) {
        printf("couldn't open file\n");
        exit(-1);
    }

    char line[512];
    while(fgets(line, sizeof(line), f)) {
        if(memcmp(line, "S3", 2)==0) {
            char *s = line + 2;
            int len = HexByte(s) - 5;
            s += 2;

            char addrStr[9];
            memcpy(addrStr, s, 8);
            addrStr[8] = '\0';
            DWORD addr;
            sscanf(addrStr, "%x", &addr);
            s += 8;

            int i;
            for(i = 0; i < len; i++) {
                while((addr+i) > ExpectedAddr) {
                    GotByte(ExpectedAddr, 0xff);
                }
                GotByte(addr+i, HexByte(s));
                s += 2;
            }
        }
    }

    if(!AllWritten) FlushPrevious();

    fclose(f);
    printf("done.\n");
}

int main(int argc, char **argv)
{
    int i = 0;

    for(;;) {
        if(UsbConnect()) {
            break;
        }
        if(i == 0) {
            printf("...no device connected, polling for it now\n");
        }
        if(i > 50000) {
            printf("Could not connect to USB device; exiting.\n");
            return -1;
        }
        i++;
        Sleep(5);
    }

    if(argc < 2) {
        printf("Usage: %s bootrom file.s19\n", argv[0]);
        printf("       %s load osimage.s19\n", argv[0]);
        return -1;
    }

    if(strcmp(argv[1], "bootrom")==0 || strcmp(argv[1], "load")==0) {
        if(argc != 3) {
            printf("Need filename.\n");
            return -1;
        }
        if(strcmp(argv[1], "bootrom")==0) {
            LoadFlashFromSRecords(argv[2], TRUE);
        } else {
            LoadFlashFromSRecords(argv[2], FALSE);
        }
    } else {
        printf("Command '%s' not recognized.\n", argv[1]);
        return -1;
    }

    return 0;
}

⌨️ 快捷键说明

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