📄 dfu.c
字号:
/* * dfu.c * * DFU download utility * * Copyright Brad Hards and Bas Vermeulen * *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <usb.h>#include "dfu.h"#define DEBUG 1#define USB_DIR_IN 0x80#define USB_DIR_OUT 0x00#define STATUS_SUCCESS 1#define STATUS_UNSUCCESSFUL -1#define STATUS_INVALID_PARAMETER -9999#define USB_SUCCESS(a) (a >= 0)/* Should be read from interface functional descriptor */#define DFU_PACKETSIZE 1024#define TIMEOUT 1000int DFUDetach(usb_dev_handle * dev){ int result; printf("ATMEL - DFU Detach\n"); result = usb_control_msg(dev, USB_DIR_OUT | 0x40 | USB_RECIP_INTERFACE, DFU_DETACH, 1000, /* Value */ 0, /* Index */ NULL, /* Buffer */ 0, /* Size */ TIMEOUT); if (!USB_SUCCESS(result)) printf("ATMEL - DFU Detach FAILED (%s)!\n", usb_strerror()); return result;}int DFUDownload(usb_dev_handle * dev, unsigned char *Buffer, unsigned long Bytes, unsigned short Block){ int result;#if 0 printf("DOWNLOADING %ld Bytes (Block = %d)\n", Bytes, Block);#endif result = usb_control_msg(dev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, DFU_DNLOAD, Block, /* Value */ 0, /* Index */ Buffer, /* Buffer */ Bytes, /* Size */ TIMEOUT); if (!USB_SUCCESS(result)) printf("Write FW Block %d failed (%s)!\n", Block, usb_strerror()); return result;}int DFUGetStatus(usb_dev_handle * dev, struct dfu_status *status){ int result; unsigned char stat_buff[6]; result = usb_control_msg(dev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, DFU_GETSTATUS, 0, /* Value */ 0, /* Index */ (unsigned char *) &stat_buff, /* Buffer */ 6, /* Size */ TIMEOUT); memcpy(status, &stat_buff, 6); return result;}unsigned char DFUGetState(usb_dev_handle * dev, unsigned char *state){ int result; result = usb_control_msg(dev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, /* Request Type */ DFU_GETSTATE, /* Request */ 0, /* Value */ 0, /* Index */ state, /* Buffer */ 1, /* Size */ TIMEOUT); return result;}int DownloadFirmware(usb_dev_handle * dev, unsigned char *DfuBuffer, unsigned int DfuLen){ int status = STATUS_SUCCESS; int NeedDFUState = 1; int IsDone = 0; struct dfu_status DfuStatusBuffer; unsigned char DfuState = 0; unsigned long DfuTimeout = 0; unsigned long DfuBlockBytes, DfuBytesLeft, DfuBufferOffset; unsigned long DfuBlockCnt; int t; DfuBlockCnt = 0; DfuBytesLeft = DfuLen; DfuBlockBytes = 0; DfuBufferOffset = 0; if (DfuLen == 0) { printf("FW Buffer length invalid!\n"); return STATUS_UNSUCCESSFUL; }#if 0 printf("Start FW Downloading...\n");#endif do { if (NeedDFUState) { status = DFUGetState(dev, &DfuState); if (!USB_SUCCESS(status)) { printf ("ATMEL - DFU: Failed to get DFU state...\n"); return STATUS_UNSUCCESSFUL; } NeedDFUState = 0; } switch (DfuState) { case STATE_DFU_DOWNLOAD_SYNC:#if 0 printf("STATE_DFU_DOWNLOAD_SYNC\n");#endif if (USB_SUCCESS (DFUGetStatus(dev, &DfuStatusBuffer))) { DfuState = DfuStatusBuffer.bState; DfuTimeout = 0; DfuTimeout = (unsigned long) (DfuStatusBuffer. bwPollTimeout[2] << 16); DfuTimeout |= (unsigned long) (DfuStatusBuffer. bwPollTimeout[1] << 8); DfuTimeout |= (unsigned long) (DfuStatusBuffer. bwPollTimeout[0]); NeedDFUState = 0; } break; case STATE_DFU_DOWNLOAD_BUSY:#if 0 printf("STATE_DFU_DOWNLOAD_BUSY\n");#endif NeedDFUState = 1; if (DfuTimeout > 0) printf("ATMEL - DFU: Resetting device - Waiting ...\nDownloading FW Blocks\n"); else printf("ATMEL - DFU: In progress\n"); for (t = 1; t <= DfuTimeout / 500; t++) usleep(500 * 1000); /* Sleep for 500 ms */ break; case STATE_DFU_DOWNLOAD_IDLE:#if 0 printf("DOWNLOAD ");#endif case STATE_DFU_IDLE:#if 0 printf("DFU IDLE\n");#endif if (DfuBytesLeft <= DFU_PACKETSIZE) DfuBlockBytes = DfuBytesLeft; else DfuBlockBytes = DFU_PACKETSIZE; if (USB_SUCCESS(status)) { DfuBytesLeft -= DfuBlockBytes; status = DFUDownload(dev, DfuBuffer + DfuBufferOffset, DfuBlockBytes, DfuBlockCnt); DfuBufferOffset += DfuBlockBytes; DfuBlockCnt++; } NeedDFUState = 1; break; case STATE_DFU_MANIFEST_SYNC:#if 0 printf("STATE_DFU_MANIFEST_SYNC\n");#endif status = DFUGetStatus(dev, &DfuStatusBuffer); if (USB_SUCCESS(status)) { DfuState = DfuStatusBuffer.bState; DfuTimeout = 0; DfuTimeout = (unsigned long) (DfuStatusBuffer. bwPollTimeout[2] << 16); DfuTimeout |= (unsigned long) (DfuStatusBuffer. bwPollTimeout[1] << 8); DfuTimeout |= (unsigned long) (DfuStatusBuffer. bwPollTimeout[0]); NeedDFUState = 0; if (DfuTimeout > 0) printf("ATMEL - DFU: Resetting device - Waiting ...\n"); else printf("ATMEL - DFU: In progress\n"); for (t = 1; t <= DfuTimeout / 500; t++) usleep(500 * 1000); /* Sleep for 500 ms */ } break; case STATE_DFU_MANIFEST: printf("STATE_DFU_MANIFEST - We Are About to sleep 7 seconds\n"); sleep(7); IsDone = 1; break; case STATE_DFU_MANIFEST_WAIT_RESET: printf("STATE_DFU_MANIFEST_WAIT_RESET\n"); usb_reset(dev); break; case STATE_DFU_UPLOAD_IDLE: printf("STATE_DFU_UPLOAD_IDLE\n"); break; case STATE_DFU_ERROR: printf("STATE_DFU_ERROR\n"); usb_reset(dev); break; default: printf("DFU UNKNOWN STATE (%d)\n", DfuState); status = STATUS_INVALID_PARAMETER; break; } } while (!IsDone && USB_SUCCESS(status)); return status;}unsigned long ReadFirmware(char *file, unsigned char **buffer){ struct stat filestat; unsigned long fwsize; unsigned long bytesread; int fd; stat(file, &filestat); fwsize = filestat.st_size; if ((*buffer = malloc(fwsize)) == NULL) { printf("Unable to allocate %ld bytes!\n", fwsize); return -ENOMEM; } /* Open the firmware file */ if ((fd = open(file, O_RDONLY)) < 0) { printf("Unable to open %s!\n", file); free(*buffer); return -errno; } /* Read the firmware file into the buffer */ bytesread = read(fd, *buffer, fwsize); /* Close the firmware file */ close(fd); if (bytesread < fwsize) { printf("Short read in %s!\n", file); free(*buffer); return -EINVAL; } return fwsize;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -