imx_usb_loader/0000755000175000017500000000000013203242133013753 5ustar paulliupaulliuimx_usb_loader/imx_uart.c0000644000175000017500000002332113203242133015750 0ustar paulliupaulliu/* * imx_uart: * * Program to download and execute an image over the serial boot protocol * on i.MX series processors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #include #include #endif #include "portable.h" #include "imx_sdp.h" extern int debugmode; #define get_min(a, b) (((a) < (b)) ? (a) : (b)) int transfer_uart(struct sdp_dev *dev, int report, unsigned char *p, unsigned size, unsigned int expected, int* last_trans) { int fd = *(int *)dev->priv; if (report < 3) { *last_trans = write(fd, p, size); } else { // Read... int ret; *last_trans = 0; while (*last_trans < (int)expected) { ret = read(fd, p, expected - *last_trans); if (ret < 0) return ret; // err is transfered bytes... *last_trans += ret; p += ret; } } return 0; } #ifndef WIN32 int uart_connect(int *uart_fd, char const *tty, int usertscts, int associate, struct termios *orig) #else int uart_connect(int *uart_fd, char const *tty, int usertscts, int associate, DCB* orig) #endif { int err = 0, count = 0; int retry = 10; #ifndef WIN32 int flags = O_RDWR | O_NOCTTY | O_SYNC; struct termios key; #else int flags = O_RDWR | _O_BINARY; DCB dcb; COMMTIMEOUTS timeouts; HANDLE handle; #endif char magic[] = { 0x23, 0x45, 0x45, 0x23 }; char magic_response[4]; char *buf; #ifndef WIN32 memset(&key,0,sizeof(key)); #endif memset(&magic_response,0,sizeof(magic_response)); *uart_fd = open(tty, flags); if (*uart_fd < 0) { printf("tty %s\n", tty); fprintf(stdout, "open() failed: %s\n", strerror(errno)); return *uart_fd; } #ifndef WIN32 // Get original terminal settings err = tcgetattr(*uart_fd, orig); // 8 data bits key.c_cflag |= CS8; key.c_cflag |= CLOCAL | CREAD; if (usertscts) key.c_cflag |= CRTSCTS; key.c_cflag |= B115200; // Enable blocking read, 0.5s timeout... key.c_lflag &= ~ICANON; // Set non-canonical mode key.c_cc[VTIME] = 5; err = tcsetattr(*uart_fd, TCSANOW, &key); if (err < 0) { fprintf(stdout, "tcsetattr() failed: %s\n", strerror(errno)); close(*uart_fd); return err; } err = tcflush(*uart_fd, TCIOFLUSH); #else handle=(HANDLE)_get_osfhandle(*uart_fd); orig->DCBlength=sizeof(DCB); GetCommState(handle,orig); memset(&dcb,0,sizeof(DCB)); dcb.DCBlength=sizeof(DCB); dcb.fBinary=TRUE; dcb.fParity=FALSE; dcb.BaudRate=CBR_115200; dcb.ByteSize=8; if (usertscts) { dcb.fRtsControl=RTS_CONTROL_ENABLE; dcb.fOutxCtsFlow=TRUE; } if (!SetCommState(handle,&dcb)) { fprintf(stdout, "SetCommState() failed: %d\n", GetLastError()); close(*uart_fd); return err; } memset(&timeouts,0,sizeof(COMMTIMEOUTS)); timeouts.ReadIntervalTimeout=MAXDWORD; timeouts.ReadTotalTimeoutMultiplier=MAXDWORD; timeouts.ReadTotalTimeoutConstant=500; if (!SetCommTimeouts(handle,&timeouts)) { fprintf(stdout, "SetCommTimeouts() failed: %d\n", GetLastError()); close(*uart_fd); return err; } if (!PurgeComm(handle,PURGE_TXABORT|PURGE_RXABORT)) { fprintf(stdout, "PurgeComm() failed: %d\n", GetLastError()); close(*uart_fd); return err; } #endif if (!associate) return err; // Association phase, send and receive 0x23454523 printf("starting associating phase"); while(retry--) { #ifndef WIN32 // Flush again before retrying err = tcflush(*uart_fd, TCIOFLUSH); #endif write(*uart_fd, magic, sizeof(magic)); buf = magic_response; count = 0; while (count < 4) { err = read(*uart_fd, buf, 4 - count); /* read timeout.. */ if (err <= 0) break; count += err; buf += err; } if (!memcmp(magic, magic_response, sizeof(magic_response))) break; printf("."); fflush(stdout); #ifndef WIN32 err = tcflush(*uart_fd, TCIOFLUSH); #endif msleep(1000); } printf("\n"); fflush(stdout); if (!retry) { fprintf(stderr, "associating phase failed, make sure the device" " is in recovery mode\n"); close(*uart_fd); return -2; } if (memcmp(magic, magic_response, sizeof(magic_response))) { fprintf(stderr, "magic missmatch, response was 0x%08x\n", *(uint32_t *)magic_response); close(*uart_fd); return -3; } fprintf(stderr, "association phase succeeded, response was 0x%08x\n", *(uint32_t *)magic_response); return 0; } #ifndef WIN32 void uart_close(int *uart_fd, struct termios *orig) #else void uart_close(int *uart_fd, DCB* orig) #endif { #ifndef WIN32 int err; // Restore original terminal settings err = tcsetattr(*uart_fd, TCSAFLUSH, orig); if (err < 0) fprintf(stdout, "tcsetattr() failed: %s\n", strerror(errno)); #else HANDLE handle; handle=(HANDLE)_get_osfhandle(*uart_fd); SetCommState(handle,orig); #endif close(*uart_fd); } void print_usage(void) { printf("Usage: imx_uart [OPTIONS...] UART CONFIG [JOBS...]\n" #ifndef WIN32 " e.g. imx_uart -n /dev/ttyUSB0 vybrid_usb_work.conf u-boot.imx\n" #else " e.g. imx_uart -n COM1: vybrid_uart_work.conf eboot.img\n" #endif "Load data on target connected to UART using serial download protocol as\n" "configured in CONFIG file.\n" "\n" "Where OPTIONS are\n" " -h --help Show this help\n" " -v --verify Verify downloaded data\n" " -n --no-rtscts Do not use RTS/CTS flow control\n" " Default is to use RTS/CTS, Vybrid requires them\n" " -N --no-association Do not do serial Association Phase\n" " -d --debugmode Enable debug logs\n" "\n" "And where [JOBS...] are\n" " FILE [-lLOADADDR] [-sSIZE] ...\n" "Multiple jobs can be configured. The first job is treated special, load\n" "address, jump address, and length are read from the IVT header. If no job\n" "is specified, the jobs definied in the target specific configuration file\n" "is being used.\n"); } int parse_opts(int argc, char * const *argv, char const **ttyfile, char const **conffile, int *verify, int *usertscts, int *associate, struct sdp_work **cmd_head) { char c; *conffile = NULL; *ttyfile = NULL; static struct option long_options[] = { {"help", no_argument, 0, 'h' }, {"verify", no_argument, 0, 'v' }, {"debugmode", no_argument, 0, 'd' }, {"no-rtscts", no_argument, 0, 'n' }, {"no-association", no_argument, 0, 'N' }, {0, 0, 0, 0 }, }; while ((c = getopt_long(argc, argv, "+hdvnN", long_options, NULL)) != -1) { switch (c) { case 'h': case '?': print_usage(); return -1; case 'd': debugmode = 1; /* global extern */ break; case 'n': *usertscts = 0; break; case 'N': *associate = 0; break; case 'v': *verify = 1; break; } } // Options parsed, get mandatory arguments... if (optind >= argc) { fprintf(stderr, "non optional argument UART is missing\n"); return -1; } *ttyfile = argv[optind]; optind++; if (optind >= argc) { fprintf(stderr, "non optional argument CONFIG is missing\n"); return -1; } *conffile = argv[optind]; optind++; if (optind < argc) { // Parse optional job arguments... *cmd_head = parse_cmd_args(argc - optind, &argv[optind]); } return 0; } #define ARRAY_SIZE(w) sizeof(w)/sizeof(w[0]) int main(int argc, char * const argv[]) { struct sdp_dev *p_id; int err = 0; int verify = 0; int usertscts = 1; int associate = 1; int uart_fd; struct sdp_work *curr; char const *conf; char const *ttyfile; char const *conffilepath; char const *conffile; char const *basepath; #ifndef WIN32 struct termios orig; #else DCB orig; #endif curr=NULL; err = parse_opts(argc, argv, &ttyfile, &conffilepath, &verify, &usertscts, &associate, &curr); if (err < 0) return err; // Get machine specific configuration file.. if ((conffile = strrchr(conffilepath, PATH_SEPARATOR)) == NULL) { // Only a file was given as configuration basepath = get_base_path(argv[0]); conffile = conffilepath; } else { // A whole path is given as configuration basepath = get_base_path(conffilepath); conffile++; // Filename starts after slash } conf = conf_file_name(conffile, basepath, get_global_conf_path()); if (conf == NULL) return -1; p_id = parse_conf(conf); if (!p_id) return -1; // Open UART and start associating phase... err = uart_connect(&uart_fd, ttyfile, usertscts, associate, &orig); if (err < 0) return EXIT_FAILURE; p_id->transfer = &transfer_uart; // UART private pointer is TTY file descriptor... p_id->priv = &uart_fd; err = do_status(p_id); if (err) { printf("status failed\n"); goto out; } // By default, use work from config file... if (curr == NULL) curr = p_id->work; while (curr) { if (curr->mem) perform_mem_work(p_id, curr->mem); // printf("jump_mode %x\n", curr->jump_mode); if (curr->filename[0]) { err = DoIRomDownload(p_id, curr, verify); } if (err) { err = do_status(p_id); break; } if (!curr->next && !curr->plug) break; err = do_status(p_id); printf("jump_mode %x plug=%i err=%i\n", curr->jump_mode, curr->plug, err); if (err) goto out; if (curr->plug) { curr->plug = 0; continue; } curr = curr->next; } out: uart_close(&uart_fd, &orig); return err; } imx_usb_loader/imx_sdp.c0000644000175000017500000012251613203242133015571 0ustar paulliupaulliu/* * imx_sdp: * Implementation of the Serial Download Protocol (SDP) for i.MX/Vybrid * series processors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "portable.h" #include "imx_sdp.h" #include "image.h" int debugmode = 0; #ifdef __GNUC__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define BE32(x) __builtin_bswap32(x) #else #define BE32(x) x #endif #elif _MSC_VER // assume little endian... #define BE32(x) _byteswap_ulong(x) #endif #define get_min(a, b) (((a) < (b)) ? (a) : (b)) int get_val(const char** pp, int base) { int val = 0; const char *p = *pp; while (*p==' ') p++; if (*p=='0') { p++; if ((*p=='x')||(*p=='X')) { p++; base = 16; } } while (*p) { char c = *p++; if ((c >= '0')&&(c <= '9')) { c -= '0'; } else { c &= ~('a'-'A'); if ((c >= 'A')&&(c <= 'F')) c -= ('A'-10); else { p--; break; } } if (c >= base) { printf("Syntax error: %s\n", p-1); val = -1; break; } val = (val * base) + c; } while (*p==' ') p++; *pp = p; return val; } const char *move_string(char *dest, const char *src, unsigned cnt) { unsigned i = 0; while (i < cnt) { char c = *src++; if ((!c) || (c == ' ') || (c == 0x0d) || (c == '\n') || (c == '#') || (c == ':') || (c == ',')) { src--; break; } dest[i++] = c; } dest[i] = '\0'; return src; } char const *get_base_path(char const *argv0) { static char base_path[PATH_MAX]; char *e; strncpy(base_path, argv0, sizeof(base_path)); e = strrchr(base_path, PATH_SEPARATOR); #ifdef __unix__ if (!e) { readlink("/proc/self/exe", base_path,sizeof(base_path)); e = strrchr(base_path, PATH_SEPARATOR); } #endif if (e) { dbg_printf( "trailing slash == %p:%s\n", e, e); e[1] = 0; } else { dbg_printf( "no trailing slash\n"); } return base_path; } char const *get_global_conf_path() { #ifdef WIN32 static char conf[PATH_MAX]; static char sep = PATH_SEPARATOR; const char *subdir = "imx_loader"; char const *progdata = getenv("ProgramData"); strncpy(conf, progdata, sizeof(conf)); strncat(conf, &sep, sizeof(conf)); strncat(conf, subdir, sizeof(conf)); return conf; #else char const *global_conf_path = SYSCONFDIR "/imx-loader.d/"; return global_conf_path; #endif } char const *conf_path_ok(char const *conf_path, char const *conf_file) { static char conf[PATH_MAX]; static char sep = PATH_SEPARATOR; strncpy(conf, conf_path, sizeof(conf)); strncat(conf, &sep, sizeof(conf) - strlen(conf) - 1); strncat(conf, conf_file, sizeof(conf) - strlen(conf) - 1); if (access(conf, R_OK) != -1) { printf("config file <%s>\n", conf); return conf; } return NULL; } char const *conf_file_name(char const *file, char const *base_path, char const *conf_path) { char const *conf; char cwd[PATH_MAX]; // First priority, conf path... (either -c, binary or /etc/imx-loader.d/) dbg_printf("checking with conf_path %s\n", conf_path); conf = conf_path_ok(conf_path, file); if (conf != NULL) return conf; // Second priority, base path, relative path of binary... dbg_printf("checking with base_path %s\n", base_path); conf = conf_path_ok(base_path, file); if (conf != NULL) return conf; // Third priority, working directory... getcwd(cwd, PATH_MAX); dbg_printf("checking with cwd %s\n", cwd); conf = conf_path_ok(cwd, file); if (conf != NULL) return conf; printf("%s not found\n", file); return NULL; } char const *skip(const char *p, char c) { while (*p==' ') p++; if (*p == c) { p++; } while (*p==' ') p++; return p; } int end_of_line(const char *p) { while (*p == ' ') p++; if ((!p[0]) || (*p == '#') || (*p == '\n') || (*p == '\r')) return 1; return 0; } void parse_mem_work(struct sdp_work *curr, const char *filename, const char *p) { struct mem_work *wp; struct mem_work **link; struct mem_work w; unsigned int i; const char *start = p; p = skip(p,':'); memset(&w, 0, sizeof(w)); if (strncmp(p, "read", 4) == 0) { p += 4; p = skip(p,','); i = MEM_TYPE_READ; } else if (strncmp(p, "write", 5) == 0) { p += 5; p = skip(p,','); i = MEM_TYPE_WRITE; } else if (strncmp(p, "modify", 6) == 0) { p += 6; p = skip(p,','); i = MEM_TYPE_MODIFY; } else { printf("%s: syntax error: %s {%s}\n", filename, p, start); } w.type = i; i = 0; for (;;) { w.vals[i] = get_val(&p, 16); if (i >= w.type) break; p = skip(p,','); if ((*p == 0) || (*p == '#')) { printf("%s: missing argment: %s {%s}\n", filename, p, start); return; } i++; } if (!end_of_line(p)) { printf("%s: syntax error: %s {%s}\n", filename, p, start); return; } wp = (struct mem_work *)malloc(sizeof(struct mem_work)); if (!wp) return; link = &curr->mem; while (*link) link = &(*link)->next; *wp = w; *link = wp; } void parse_file_work(struct sdp_work *curr, const char *filename, const char *p) { const char *start = p; p = move_string(curr->filename, p, sizeof(curr->filename) - 1); p = skip(p,':'); for (;;) { const char *q = p; if ((!*p) || (*p == '#') || (*p == '\n') || (*p == 0x0d)) break; if (strncmp(p, "dcd", 3) == 0) { p += 3; p = skip(p,','); curr->dcd = 1; } if (strncmp(p, "clear_dcd", 9) == 0) { p += 9; p = skip(p,','); curr->clear_dcd = 1; // printf("clear_dcd\n"); } if (strncmp(p, "clear_boot_data", 15) == 0) { p += 15; p = skip(p,','); curr->clear_boot_data = 1; // printf("clear_dcd\n"); } if (strncmp(p, "plug", 4) == 0) { p += 4; p = skip(p,','); curr->plug = 1; // printf("plug\n"); } if (strncmp(p, "load", 4) == 0) { p += 4; curr->load_addr = get_val(&p, 16); p = skip(p,','); } if (strncmp(p, "jump", 4) == 0) { p += 4; curr->jump_mode = J_ADDR; curr->jump_addr = get_val(&p, 16); if (strncmp(p, "header2", 7) == 0) { p += 7; p = skip(p,','); curr->jump_mode = J_HEADER2; } else if (strncmp(p, "header", 6) == 0) { p += 6; p = skip(p,','); curr->jump_mode = J_HEADER; } p = skip(p,','); // printf("jump\n"); } if (q == p) { printf("%s: syntax error: %s {%s}\n", filename, p, start); break; } } } /* * #hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas) *hid,1024,0x10000000,1G,0x00907000,0x31000 * */ void parse_transfer_type(struct sdp_dev *usb, const char *filename, const char *p) { int i; if (strncmp(p, "hid", 3) == 0) { p += 3; p = skip(p,','); usb->mode = MODE_HID; } else if (strncmp(p, "bulk", 4) == 0) { p += 4; p = skip(p,','); usb->mode = MODE_BULK; } else { printf("%s: hid/bulk expected\n", filename); } if (strncmp(p, "old_header", 10) == 0) { p += 10; p = skip(p,','); usb->header_type = HDR_MX51; } else if (strncmp(p, "uboot_header", 12) == 0) { p += 12; p = skip(p,','); usb->header_type = HDR_UBOOT; } else { usb->header_type = HDR_MX53; } usb->max_transfer = get_val(&p, 10); p = skip(p,','); usb->dcd_addr = get_val(&p, 16); p = skip(p,','); for (i = 0; i < 8; i++) { usb->ram[i].start = get_val(&p, 10); p = skip(p,','); usb->ram[i].size = get_val(&p, 10); if ((*p == 'G') || (*p == 'g')) { usb->ram[i].size <<= 30; p++; } else if ((*p == 'M') || (*p == 'm')) { usb->ram[i].size <<= 20; p++; } else if ((*p == 'K') || (*p == 'k')) { usb->ram[i].size <<= 10; p++; } p = skip(p,','); if ((*p == '#') || (*p == '\n') || (!*p)) break; } } struct sdp_dev *parse_conf(const char *filename) { char line[512]; FILE *xfile; const char *p; struct sdp_work *tail = NULL; struct sdp_work *curr = NULL; struct sdp_dev *usb = (struct sdp_dev *)malloc(sizeof(struct sdp_dev)); if (!usb) return NULL; memset(usb, 0, sizeof(struct sdp_dev)); xfile = fopen(filename, "rb" ); if (!xfile) { printf("Could not open file: {%s}\n", filename); free(usb); return NULL; } printf("parse %s\n", filename); while (fgets(line, sizeof(line), xfile) != NULL) { p = line; while (*p==' ') p++; if (p[0] == '#') continue; if (p[0] == 0) continue; if (p[0] == '\n') continue; if (p[0] == 0x0d) continue; if (!usb->name[0]) { p = move_string(usb->name, p, sizeof(usb->name) - 1); continue; } if (!usb->max_transfer) { parse_transfer_type(usb, filename, p); continue; } /* * #file:dcd,plug,load nnn,jump [nnn/header/header2] */ if (!curr) { curr = (struct sdp_work *)malloc(sizeof(struct sdp_work)); if (!curr) break; memset(curr, 0, sizeof(struct sdp_work)); if (!usb->work) usb->work = curr; if (tail) tail->next = curr; tail = curr; curr->load_addr = usb->ram[0].start + 0x03f00000; /* default */ } if (p[0] == ':') { parse_mem_work(curr, filename, p); } else { parse_file_work(curr, filename, p); curr = NULL; } } return usb; } struct sdp_work *parse_cmd_args(int argc, char * const *argv) { int i = 0; struct sdp_work *prev = NULL; struct sdp_work *w = NULL; struct sdp_work *head = NULL; while (argc > i) { const char *p = argv[i]; if (*p == '-') { char c; p++; c = *p++; if (w == NULL) { printf("specify file first\n"); exit(1); } if (!*p) { i++; p = argv[i]; } if (c == 's') { w->load_size = get_val(&p, 10); if (!w->load_addr) w->load_addr = 0x10800000; w->plug = 0; w->jump_mode = 0; i++; continue; } if (c == 'l') { w->load_addr = get_val(&p, 16); w->plug = 0; w->jump_mode = 0; i++; continue; } fprintf(stderr, "Unknown option %s\n", p); exit(1); } // Initialize work structure.. w = malloc(sizeof(struct sdp_work)); memset(w, 0, sizeof(struct sdp_work)); strncpy(w->filename, argv[i], sizeof(w->filename) - 1); if (access(w->filename, R_OK) == -1) { fprintf(stderr, "cannot read from file %s\n", w->filename); exit(1); } if (head == NULL) { // Special settings for first work... w->dcd = 1; w->plug = 1; w->jump_mode = J_HEADER; head = w; } if (prev != NULL) prev->next = w; prev = w; i++; } return head; } void print_sdp_work(struct sdp_work *curr) { printf("== work item\n"); printf("filename %s\n", curr->filename); printf("load_size %d bytes\n", curr->load_size); printf("load_addr 0x%08x\n", curr->load_addr); printf("dcd %u\n", curr->dcd); printf("clear_dcd %u\n", curr->clear_dcd); printf("plug %u\n", curr->plug); printf("jump_mode %d\n", curr->jump_mode); printf("jump_addr 0x%08x\n", curr->jump_addr); printf("== end work item\n"); return; } long get_file_size(FILE *xfile) { long size; fseek(xfile, 0, SEEK_END); size = ftell(xfile); rewind(xfile); // printf("filesize=%lx\n", size); return size; } struct boot_data { uint32_t dest; uint32_t image_len; uint32_t plugin; }; struct ivt_header { #define IVT_BARKER 0x402000d1 uint32_t barker; uint32_t start_addr; uint32_t reserv1; uint32_t dcd_ptr; uint32_t boot_data_ptr; /* struct boot_data * */ uint32_t self_ptr; /* struct ivt_header *, this - boot_data.start = offset linked at */ uint32_t app_code_csf; uint32_t reserv2; }; /* * MX51 header type */ struct old_app_header { uint32_t app_start_addr; #define APP_BARKER 0xb1 #define DCD_BARKER 0xb17219e9 uint32_t app_barker; uint32_t csf_ptr; uint32_t dcd_ptr_ptr; uint32_t srk_ptr; uint32_t dcd_ptr; uint32_t app_dest_ptr; }; static int read_memory(struct sdp_dev *dev, unsigned addr, unsigned char *dest, unsigned cnt) { struct sdp_command read_reg_command = { .cmd = SDP_READ_REG, .addr = BE32(addr), .format = 0x20, .cnt = BE32(cnt), .data = BE32(0), .rsvd = 0x00}; int retry = 0; int last_trans; int err; int rem; unsigned char tmp[64]; for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&read_reg_command, sizeof(read_reg_command), 0, &last_trans); if (!err) break; printf("read_reg_command err=%i, last_trans=%i\n", err, last_trans); if (retry > 5) { return -4; } retry++; } err = dev->transfer(dev, 3, tmp, 4, 4, &last_trans); if (err) { printf("r3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); return err; } rem = cnt; retry = 0; while (rem) { tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; err = dev->transfer(dev, 4, tmp, 64, rem > 64 ? 64 : rem, &last_trans); if (err) { printf("r4 in err=%i, last_trans=%i %02x %02x %02x %02x cnt=%d rem=%d\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem); if (retry++ > 8) break; continue; } retry = 0; if ((last_trans > rem) || (last_trans > 64)) { if ((last_trans == 64) && (cnt == rem)) { /* Last transfer is expected to be too large for HID */ } else { printf("err: %02x %02x %02x %02x cnt=%d rem=%d last_trans=%i\n", tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem, last_trans); } last_trans = rem; if (last_trans > 64) last_trans = 64; } memcpy(dest, tmp, last_trans); dest += last_trans; rem -= last_trans; } dbg_printf("%s: %d addr=%08x, val=%02x %02x %02x %02x\n", __func__, err, addr, dest[0], dest[1], dest[2], dest[3]); return err; } static int write_memory(struct sdp_dev *dev, unsigned addr, unsigned val) { struct sdp_command write_reg_command = { .cmd = SDP_WRITE_REG, .addr = BE32(addr), .format = 0x20, .cnt = BE32(0x00000004), .data = BE32(val), .rsvd = 0x00}; int retry = 0; int last_trans; int err = 0; unsigned char tmp[64]; dbg_printf("%s: addr=%08x, val=%08x\n", __func__, addr, val); for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&write_reg_command, sizeof(write_reg_command), 0, &last_trans); if (!err) break; printf("write_reg_command err=%i, last_trans=%i\n", err, last_trans); if (retry > 5) { return -4; } retry++; } memset(tmp, 0, sizeof(tmp)); err = dev->transfer(dev, 3, tmp, sizeof(tmp), 4, &last_trans); dbg_printf("report 3, err=%i, last_trans=%i %02x %02x %02x %02x %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]); if (err) { printf("w3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); printf("addr=0x%08x, val=0x%08x\n", addr, val); } memset(tmp, 0, sizeof(tmp)); err = dev->transfer(dev, 4, tmp, sizeof(tmp), 4, &last_trans); dbg_printf("report 4, err=%i, last_trans=%i %02x %02x %02x %02x %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7]); if (err) printf("w4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); return err; } void perform_mem_work(struct sdp_dev *dev, struct mem_work *mem) { unsigned tmp, tmp2; while (mem) { switch (mem->type) { case MEM_TYPE_READ: read_memory(dev, mem->vals[0], (unsigned char *)&tmp, 4); printf("*%x is %x\n", mem->vals[0], tmp); break; case MEM_TYPE_WRITE: write_memory(dev, mem->vals[0], mem->vals[1]); printf("%x write %x\n", mem->vals[0], mem->vals[1]); break; case MEM_TYPE_MODIFY: read_memory(dev, mem->vals[0], (unsigned char *)&tmp, 4); tmp2 = (tmp & ~mem->vals[1]) | mem->vals[2]; printf("%x = %x to %x\n", mem->vals[0], tmp, tmp2); write_memory(dev, mem->vals[0], tmp2); break; } mem = mem->next; } } static int write_dcd(struct sdp_dev *dev, struct ivt_header *hdr, unsigned char *file_start, unsigned cnt) { struct sdp_command dl_command = { .cmd = SDP_WRITE_DCD, .addr = BE32(dev->dcd_addr), .format = 0, .cnt = 0, .data = 0, .rsvd = 0}; int length; #define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self_ptr) unsigned char* dcd, *dcd_end; unsigned char* file_end = file_start + cnt; unsigned int *status; int last_trans, err; int retry = 0; unsigned transferSize=0; unsigned int max = dev->max_transfer; unsigned char tmp[64]; if (!hdr->dcd_ptr) { printf("No dcd table, barker=%x\n", hdr->barker); return 0; //nothing to do } dcd = hdr->dcd_ptr + cvt_dest_to_src; if ((dcd < file_start) || ((dcd + 4) > file_end)) { printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); return -1; } if ((dcd[0] != 0xd2) || (dcd[3] != 0x40)) { printf("Unknown tag\n"); return -1; } length = (dcd[1] << 8) + dcd[2]; if (length > HAB_MAX_DCD_SIZE) { printf("DCD is too big (%d bytes)\n", length); return -1; } if (length == 0) { printf("No DCD table, skip\n"); return 0; } dl_command.cnt = BE32(length); dcd_end = dcd + length; if (dcd_end > file_end) { printf("bad dcd length %08x\n", length); return -1; } printf("loading DCD table @%#x\n", dev->dcd_addr); for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&dl_command, sizeof(dl_command), 0, &last_trans); if (!err) break; printf("dl_command err=%i, last_trans=%i\n", err, last_trans); if (retry > 5) return -4; retry++; } retry = 0; while (length > 0) { err = dev->transfer(dev, 2, dcd, get_min(length, max), 0, &last_trans); if (err) { printf("out err=%i, last_trans=%i cnt=0x%x max=0x%x transferSize=0x%X retry=%i\n", err, last_trans, length, max, transferSize, retry); if (retry >= 10) { printf("Giving up\n"); return err; } if (max >= 16) max >>= 1; else max <<= 1; /* Wait a few ms before retrying transfer */ msleep(10); retry++; continue; } max = dev->max_transfer; retry = 0; if (!last_trans) { printf("Nothing last_trans, err=%i\n", err); break; } dcd += last_trans; length -= last_trans; transferSize += last_trans; } printf("\r\n<<<%i, %i bytes>>>\r\n", length, transferSize); if (dev->mode == MODE_HID) { err = dev->transfer(dev, 3, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("report 3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); err = dev->transfer(dev, 4, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("report 4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); status = (unsigned int*)tmp; if (*status == 0x128a8a12UL) printf("succeeded (status 0x%08x)\n", *status); else printf("failed (status 0x%08x)\n", *status); } else { do_status(dev); } return transferSize; } static int write_dcd_table_ivt(struct sdp_dev *dev, struct ivt_header *hdr, unsigned char *file_start, unsigned cnt) { unsigned char *dcd_end; unsigned m_length; #define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self_ptr) unsigned char* dcd; unsigned char* file_end = file_start + cnt; int err = 0; if (!hdr->dcd_ptr) { printf("No dcd table, barker=%x\n", hdr->barker); return 0; //nothing to do } dcd = hdr->dcd_ptr + cvt_dest_to_src; if ((dcd < file_start) || ((dcd + 4) > file_end)) { printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); return -1; } m_length = (dcd[1] << 8) + dcd[2]; printf("main dcd length %x\n", m_length); if ((dcd[0] != 0xd2) || (dcd[3] != 0x40)) { printf("Unknown tag\n"); return -1; } dcd_end = dcd + m_length; if (dcd_end > file_end) { printf("bad dcd length %08x\n", m_length); return -1; } dcd += 4; while (dcd < dcd_end) { unsigned s_length = (dcd[1] << 8) + dcd[2]; unsigned sub_tag = (dcd[0] << 24) + (dcd[3] & 0x7); unsigned flags = (dcd[3] & 0xf8); unsigned char *s_end = dcd + s_length; printf("sub dcd length %x\n", s_length); switch(sub_tag) { /* Write Data Command */ case 0xcc000004: if (flags & 0xe8) { printf("error: Write Data Command with unsupported flags, flags %x.\n", flags); return -1; } dcd += 4; if (s_end > dcd_end) { printf("error s_end(%p) > dcd_end(%p)\n", s_end, dcd_end); return -1; } while (dcd < s_end) { unsigned addr = (dcd[0] << 24) + (dcd[1] << 16) + (dcd[2] << 8) + dcd[3]; unsigned val = (dcd[4] << 24) + (dcd[5] << 16) + (dcd[6] << 8) + dcd[7]; dcd += 8; dbg_printf("write data *0x%08x = 0x%08x\n", addr, val); err = write_memory(dev, addr, val); if (err < 0) return err; } break; /* Check Data Command */ case 0xcf000004: { unsigned addr, count, mask, val; dcd += 4; addr = (dcd[0] << 24) + (dcd[1] << 16) + (dcd[2] << 8) + dcd[3]; mask = (dcd[4] << 24) + (dcd[5] << 16) + (dcd[6] << 8) + dcd[7]; count = 10000; switch (s_length) { case 12: dcd += 8; break; case 16: count = (dcd[8] << 24) + (dcd[9] << 16) + (dcd[10] << 8) + dcd[11]; dcd += 12; break; default: printf("error s_end(%p) > dcd_end(%p)\n", s_end, dcd_end); return -1; } dbg_printf("Check Data Command, at addr %x, mask %x\n",addr, mask); while (count) { val = 0; err = read_memory(dev, addr, (unsigned char*)&val, 4); if (err < 0) { printf("Check Data Command(%x) error(%d) @%x=%x mask %x\n", flags, err, addr, val, mask); return err; } if ((flags == 0x00) && ((val & mask) == 0) ) break; else if ((flags == 0x08) && ((val & mask) != mask) ) break; else if ((flags == 0x10) && ((val & mask) == mask) ) break; else if ((flags == 0x18) && ((val & mask) != 0) ) break; else if (flags & 0xe0) { printf("error: Check Data Command with unsupported flags, flags %x.\n", flags); return -1; } count--; } if (!count) printf("!!!Check Data Command(%x) expired without condition met @%x=%x mask %x\n", flags, addr, val, mask); else printf("Check Data Command(%x) success @%x=%x mask %x\n", flags, addr, val, mask); break; } default: printf("Unknown sub tag, dcd[0] 0x%2x, dcd[3] 0x%2x\n", dcd[0], dcd[3]); return -1; } } return err; } static int get_dcd_range_old(struct old_app_header *hdr, unsigned char *file_start, unsigned cnt, unsigned char **pstart, unsigned char **pend) { unsigned char *dcd_end; unsigned m_length; #define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd_ptr) - hdr->dcd_ptr_ptr) unsigned char* dcd; unsigned val; unsigned char* file_end = file_start + cnt; if (!hdr->dcd_ptr) { printf("No dcd table, barker=%x\n", hdr->app_barker); *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct old_app_header); return 0; //nothing to do } dcd = hdr->dcd_ptr + cvt_dest_to_src_old; if ((dcd < file_start) || ((dcd + 8) > file_end)) { printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); return -1; } val = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); if (val != DCD_BARKER) { printf("Unknown tag\n"); return -1; } dcd += 4; m_length = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); printf("main dcd length %x\n", m_length); dcd += 4; dcd_end = dcd + m_length; if (dcd_end > file_end) { printf("bad dcd length %08x\n", m_length); return -1; } *pstart = dcd; *pend = dcd_end; return 0; } static int write_dcd_table_old(struct sdp_dev *dev, struct old_app_header *hdr, unsigned char *file_start, unsigned cnt) { unsigned val; unsigned char *dcd_end; unsigned char* dcd; int err = get_dcd_range_old(hdr, file_start, cnt, &dcd, &dcd_end); if (err < 0) return err; while (dcd < dcd_end) { unsigned type = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); unsigned addr = (dcd[4] << 0) + (dcd[5] << 8) + (dcd[6] << 16) + (dcd[7] << 24); val = (dcd[8] << 0) + (dcd[9] << 8) + (dcd[10] << 16) + (dcd[11] << 24); dcd += 12; if (type!=4) { printf("!!!unknown type=%08x *0x%08x = 0x%08x\n", type, addr, val); } else { printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); err = write_memory(dev, addr, val); if (err < 0) return err; } } return err; } void diff_long(unsigned char *src1, unsigned char *src2, unsigned cnt, unsigned skip) { unsigned char buf[8*9 + 2]; unsigned *s1 = (unsigned *)src1; unsigned *s2 = (unsigned *)src2; unsigned i, j; while (cnt >= 4) { unsigned char *p = buf; unsigned max = get_min(cnt >> 2, 8); for (i = 0; i < (skip >> 2); i++) { for (j=0; j < 9; j++) *p++ = ' '; } for (; i < max; i++) { unsigned s1v = *s1++; unsigned diff = s1v ^ *s2++; unsigned c; *p++ = ' '; if (i == 4) *p++ = ' '; for (j = 0; j < 8; j++) { unsigned changed = diff & 0xf0000000; c = ' '; if (changed) { if ((s1v & changed) == 0) c = '^'; else if ((s1v & changed) == changed) c = 'v'; else c = '-'; } *p++ = c; diff <<= 4; s1v <<= 4; } } *p = 0; printf(" %s\n", buf); cnt -= max << 2; } } void dump_long(unsigned char *src, unsigned cnt, unsigned addr, unsigned skip) { unsigned *p = (unsigned *)src; int i = skip >> 2; while (cnt >= 4) { printf("%08x:", addr); while (skip >= 4) { printf(" "); skip -= 4; } while (cnt >= 4) { printf((i==4) ? " %08x":" %08x", p[0]); p++; cnt -= 4; addr += 4; i++; if (i==8) break; } printf("\n"); i = 0; } } void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr) { unsigned char *p = src; int i; while (cnt >= 16) { printf("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", addr, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); p += 16; cnt -= 16; addr += 16; } if (cnt) { printf("%08x:", addr); i = 0; while (cnt) { printf(" %02x", p[0]); p++; cnt--; i++; if (cnt) if (i == 4) { i = 0; printf(" "); } } printf("\n"); } } int verify_memory(struct sdp_dev *dev, FILE *xfile, unsigned offset, unsigned addr, unsigned size, unsigned char *verify_buffer, unsigned verify_cnt) { int mismatch = 0; unsigned char file_buf[1024]; unsigned verified = 0; unsigned total = size; fseek(xfile, offset + verify_cnt, SEEK_SET); while (size) { unsigned char mem_buf[64]; unsigned char *p = file_buf; int cnt = addr & 0x3f; int request = get_min(size, sizeof(file_buf)); if (cnt) { cnt = 64 - cnt; if (request > cnt) request = cnt; } if (verify_cnt) { p = verify_buffer; cnt = (int)get_min(request, (int)verify_cnt); verify_buffer += cnt; verify_cnt -= cnt; } else { cnt = fread(p, 1, request, xfile); if (cnt <= 0) { printf("Unexpected end of file, request=0x%0x, size=0x%x, cnt=%i\n", request, size, cnt); return -1; } } size -= cnt; while (cnt) { int ret; request = get_min(cnt, sizeof(mem_buf)); ret = read_memory(dev, addr, mem_buf, request); if (ret < 0) { printf("verified 0x%x of 0x%x before usb error\n", verified, total); return ret; } if (memcmp(p, mem_buf, request)) { unsigned char * m = mem_buf; if (!mismatch) printf("!!!!mismatch\n"); mismatch++; while (request) { unsigned skip = addr & 0x1f; unsigned max = 0x20 - skip; unsigned req = get_min(request, (int)max); if (memcmp(p, m, req)) { dump_long(p, req, offset, skip); dump_long(m, req, addr, skip); diff_long(p, m, req, skip); } p += req; m+= req; offset += req; addr += req; cnt -= req; request -= req; } if (mismatch >= 5) return -1; } p += request; offset += request; addr += request; cnt -= request; verified += request; } } if (!mismatch) printf("Verify success\n"); return mismatch ? -1 : 0; } int is_header(struct sdp_dev *dev, unsigned char *p) { switch (dev->header_type) { case HDR_MX51: { struct old_app_header *ohdr = (struct old_app_header *)p; if (ohdr->app_barker == 0xb1) return 1; break; } case HDR_MX53: { struct ivt_header *hdr = (struct ivt_header *)p; if (hdr->barker == IVT_BARKER) return 1; } case HDR_UBOOT: { image_header_t *image = (image_header_t *)p; if (BE32(image->ih_magic) == IH_MAGIC) return 1; } } return 0; } int perform_dcd(struct sdp_dev *dev, unsigned char *p, unsigned char *file_start, unsigned cnt) { int ret = 0; switch (dev->header_type) { case HDR_MX51: { struct old_app_header *ohdr = (struct old_app_header *)p; ret = write_dcd_table_old(dev, ohdr, file_start, cnt); dbg_printf("dcd_ptr=0x%08x\n", ohdr->dcd_ptr); #if 1 ohdr->dcd_ptr = 0; #endif if (ret < 0) return ret; break; } case HDR_MX53: { struct ivt_header *hdr = (struct ivt_header *)p; if (dev->mode == MODE_HID) { ret = write_dcd(dev, hdr, file_start, cnt); } else { // For processors that don't support the WRITE_DCD command (i.MX5x) ret = write_dcd_table_ivt(dev, hdr, file_start, cnt); } dbg_printf("dcd_ptr=0x%08x\n", hdr->dcd_ptr); #if 1 hdr->dcd_ptr = 0; #endif if (ret < 0) return ret; break; } } return 0; } int clear_dcd_ptr(struct sdp_dev *dev, unsigned char *p, unsigned char *file_start, unsigned cnt) { switch (dev->header_type) { case HDR_MX51: { struct old_app_header *ohdr = (struct old_app_header *)p; printf("clear dcd_ptr=0x%08x\n", ohdr->dcd_ptr); ohdr->dcd_ptr = 0; break; } case HDR_MX53: { struct ivt_header *hdr = (struct ivt_header *)p; printf("clear dcd_ptr=0x%08x\n", hdr->dcd_ptr); hdr->dcd_ptr = 0; break; } } return 0; } #ifndef offsetof #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif int get_dl_start(struct sdp_dev *dev, unsigned char *p, unsigned char *file_start, unsigned cnt, unsigned *dladdr, unsigned *max_length, unsigned *plugin, unsigned *header_addr, unsigned int clear_boot_data) { unsigned char* file_end = file_start + cnt; switch (dev->header_type) { case HDR_MX51: { struct old_app_header *ohdr = (struct old_app_header *)p; unsigned char *dcd_end; unsigned char* dcd; int err = get_dcd_range_old(ohdr, file_start, cnt, &dcd, &dcd_end); *dladdr = ohdr->app_dest_ptr; *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct old_app_header, dcd_ptr); *plugin = 0; if (err >= 0) { *max_length = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); } break; } case HDR_MX53: { unsigned char *bd; struct ivt_header *hdr = (struct ivt_header *)p; *dladdr = hdr->self_ptr; *header_addr = hdr->self_ptr; bd = hdr->boot_data_ptr + cvt_dest_to_src; if ((bd < file_start) || ((bd + 4) > file_end)) { printf("bad boot_data_ptr %08x\n", hdr->boot_data_ptr); return -1; } *dladdr = ((struct boot_data *)bd)->dest; *max_length = ((struct boot_data *)bd)->image_len; *plugin = ((struct boot_data *)bd)->plugin; ((struct boot_data *)bd)->plugin = 0; if (clear_boot_data) { printf("Setting boot_data_ptr to 0\n"); hdr->boot_data_ptr = 0; } break; } case HDR_UBOOT: { image_header_t *hdr = (image_header_t *)p; *dladdr = BE32(hdr->ih_load) - sizeof(image_header_t); *header_addr = *dladdr; } } return 0; } int do_status(struct sdp_dev *dev) { struct sdp_command status_command = { .cmd = SDP_ERROR_STATUS, .addr = 0, .format = 0, .cnt = 0, .data = 0, .rsvd = 0}; int last_trans; unsigned int *hab_security; unsigned char tmp[64]; int retry = 0; int err; int cnt = 64; for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&status_command, sizeof(status_command), 0, &last_trans); dbg_printf("report 1, wrote %i bytes, err=%i\n", last_trans, err); memset(tmp, 0, sizeof(tmp)); err = dev->transfer(dev, 3, tmp, cnt, 4, &last_trans); dbg_printf("report 3, read %i bytes, err=%i\n", last_trans, err); dbg_printf("read=%02x %02x %02x %02x\n", tmp[0], tmp[1], tmp[2], tmp[3]); if (!err) break; retry++; if (retry > 5) break; } hab_security = (unsigned int *)tmp; printf("HAB security state: %s (0x%08x)\n", *hab_security == HAB_SECMODE_PROD ? "production mode" : "development mode", *hab_security); if (dev->mode == MODE_HID) { err = dev->transfer(dev, 4, tmp, cnt, 4, &last_trans); dbg_printf("report 4, read %i bytes, err=%i\n", last_trans, err); dbg_printf("read=%02x %02x %02x %02x\n", tmp[0], tmp[1], tmp[2], tmp[3]); } return err; } int process_header(struct sdp_dev *dev, struct sdp_work *curr, unsigned char *buf, int cnt, unsigned *p_dladdr, unsigned *p_max_length, unsigned *p_plugin, unsigned *p_header_addr) { int ret; unsigned header_max = 0x800; unsigned header_inc = 0x400; unsigned header_offset = 0; int header_cnt = 0; unsigned char *p = buf; while (header_offset < header_max) { // printf("header_offset=%x\n", header_offset); if (is_header(dev, p)) { ret = get_dl_start(dev, p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr, curr->clear_boot_data); if (ret < 0) { printf("!!get_dl_start returned %i\n", ret); return ret; } if (curr->dcd) { ret = perform_dcd(dev, p, buf, cnt); if (ret < 0) { printf("!!perform_dcd returned %i\n", ret); return ret; } curr->dcd = 0; if ((!curr->jump_mode) && (!curr->plug)) { printf("!!dcd done, nothing else requested\n"); return 0; } } if (curr->clear_dcd) { ret = clear_dcd_ptr(dev, p, buf, cnt); if (ret < 0) { printf("!!clear_dcd returned %i\n", ret); return ret; } } if (*p_plugin && (!curr->plug) && (!header_cnt)) { header_cnt++; header_max = header_offset + *p_max_length + 0x400; if (header_max > (unsigned)(cnt - 32)) header_max = (unsigned)(cnt - 32); printf("header_max=%x\n", header_max); header_inc = 4; } else { if (!*p_plugin) curr->plug = 0; break; } } header_offset += header_inc; p += header_inc; } return header_offset; } int load_file(struct sdp_dev *dev, unsigned char *p, int cnt, unsigned char *buf, unsigned buf_cnt, unsigned dladdr, unsigned fsize, unsigned char type, FILE* xfile) { struct sdp_command dl_command = { .cmd = SDP_WRITE_FILE, .addr = BE32(dladdr), .format = 0, .cnt = BE32(fsize), .data = 0, .rsvd = type}; unsigned int *status; int last_trans, err; int retry = 0; unsigned transferSize=0; int max = dev->max_transfer; unsigned char tmp[64]; for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&dl_command, sizeof(dl_command), 0, &last_trans); if (!err) break; printf("dl_command err=%i, last_trans=%i\n", err, last_trans); if (retry > 5) return -4; retry++; } retry = 0; if (dev->mode == MODE_BULK) { err = dev->transfer(dev, 3, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); } while (1) { int retry; if (cnt > (int)(fsize-transferSize)) cnt = (fsize-transferSize); if (cnt <= 0) break; retry = 0; while (cnt) { err = dev->transfer(dev, 2, p, get_min(cnt, max), 0, &last_trans); // printf("err=%i, last_trans=0x%x, cnt=0x%x, max=0x%x\n", err, last_trans, cnt, max); if (err) { printf("out err=%i, last_trans=%i cnt=0x%x max=0x%x transferSize=0x%X retry=%i\n", err, last_trans, cnt, max, transferSize, retry); if (retry >= 10) { printf("Giving up\n"); return err; } if (max >= 16) max >>= 1; else max <<= 1; msleep(10); retry++; continue; } max = dev->max_transfer; retry = 0; if (cnt < last_trans) { dbg_printf("note: last_trans=0x%x, attempted only=0%x\n", last_trans, cnt); cnt = last_trans; } if (!last_trans) { printf("Nothing last_trans, err=%i\n", err); break; } p += last_trans; cnt -= last_trans; transferSize += last_trans; } if (!last_trans) break; if (feof(xfile)) break; cnt = fsize - transferSize; if (cnt <= 0) break; cnt = fread(buf, 1 , get_min(cnt, (int)buf_cnt), xfile); p = buf; } printf("\r\n<<<%i, %i bytes>>>\r\n", fsize, transferSize); if (dev->mode == MODE_HID) { err = dev->transfer(dev, 3, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("report 3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); err = dev->transfer(dev, 4, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("report 4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); status = (unsigned int*)tmp; if (*status == 0x88888888UL) printf("succeeded (status 0x%08x)\n", *status); else printf("failed (status 0x%08x)\n", *status); } else { do_status(dev); } return transferSize; } #define MAX_IN_LENGTH 100 // max length for user input strings #define FT_APP 0xaa #define FT_CSF 0xcc #define FT_DCD 0xee #define FT_LOAD_ONLY 0x00 int DoIRomDownload(struct sdp_dev *dev, struct sdp_work *curr, int verify) { // address, format, data count, data, type //static unsigned char jump_command[] = {0x0b,0x0b, V(0), 0x00, V(0x00000000), V(0), 0x00}; struct sdp_command jump_command = { .cmd = SDP_JUMP_ADDRESS, .addr = 0, .format = 0, .cnt = 0, .data = 0, .rsvd = 0x00}; int ret; FILE* xfile; unsigned char type; unsigned fsize; unsigned header_offset; int cnt; unsigned file_base; int last_trans, err; #define BUF_SIZE (1024*16) unsigned char *buf = NULL; unsigned char *verify_buffer = NULL; unsigned verify_cnt; unsigned char *p; unsigned char tmp[64]; unsigned dladdr = 0; unsigned max_length; unsigned plugin = 0; unsigned header_addr = 0; unsigned skip = 0; unsigned transferSize=0; int retry = 0; print_sdp_work(curr); xfile = fopen(curr->filename, "rb" ); if (!xfile) { printf("\r\nerror, can not open input file: %s\r\n", curr->filename); return -5; } buf = malloc(BUF_SIZE); if (!buf) { printf("\r\nerror, out of memory\r\n"); ret = -2; goto cleanup; } fsize = get_file_size(xfile); if (curr->load_size && (fsize > curr->load_size)) fsize = curr->load_size; cnt = fread(buf, 1 , BUF_SIZE, xfile); if (cnt < 0x20) { printf("\r\nerror, file: %s is too small\r\n", curr->filename); ret = -2; goto cleanup; } max_length = fsize; if (curr->dcd || curr->clear_dcd || curr->plug || (curr->jump_mode >= J_HEADER)) { ret = process_header(dev, curr, buf, cnt, &dladdr, &max_length, &plugin, &header_addr); if (ret < 0) goto cleanup; header_offset = ret; if ((!curr->jump_mode) && (!curr->plug)) { /* nothing else requested */ ret = 0; goto cleanup; } } else { dladdr = curr->load_addr; printf("load_addr=%x\n", curr->load_addr); header_addr = dladdr; header_offset = 0; } if (plugin && (!curr->plug)) { printf("Only plugin header found\n"); ret = -1; goto cleanup; } if (!dladdr) { printf("\nunknown load address\r\n"); ret = -3; goto cleanup; } file_base = header_addr - header_offset; type = (curr->plug || curr->jump_mode) ? FT_APP : FT_LOAD_ONLY; if (dev->mode == MODE_BULK) if (type == FT_APP) { /* No jump command, dladdr should point to header */ dladdr = header_addr; } if (file_base > dladdr) { max_length -= (file_base - dladdr); dladdr = file_base; } skip = dladdr - file_base; if ((int)skip > cnt) { if (skip > fsize) { printf("skip(0x%08x) > fsize(0x%08x) file_base=0x%08x, header_offset=0x%x\n", skip, fsize, file_base, header_offset); ret = -4; goto cleanup; } fseek(xfile, skip, SEEK_SET); cnt -= skip; fsize -= skip; skip = 0; cnt = fread(buf, 1 , BUF_SIZE, xfile); } p = &buf[skip]; cnt -= skip; fsize -= skip; if (fsize > max_length) fsize = max_length; if (verify) { /* * we need to save header for verification * because some of the file is changed * before download */ verify_buffer = malloc(cnt); verify_cnt = cnt; if (!verify_buffer) { printf("\r\nerror, out of memory\r\n"); ret = -2; goto cleanup; } memcpy(verify_buffer, p, cnt); if ((type == FT_APP) && (dev->mode != MODE_HID)) { type = FT_LOAD_ONLY; verify = 2; } } printf("\nloading binary file(%s) to %08x, skip=%x, fsize=%x type=%x\r\n", curr->filename, dladdr, skip, fsize, type); ret = load_file(dev, p, cnt, buf, BUF_SIZE, dladdr, fsize, type, xfile); if (ret < 0) goto cleanup; transferSize = ret; if (verify) { ret = verify_memory(dev, xfile, skip, dladdr, fsize, verify_buffer, verify_cnt); if (ret < 0) goto cleanup; if (verify == 2) { if (verify_cnt > 64) verify_cnt = 64; ret = load_file(dev, verify_buffer, verify_cnt, buf, BUF_SIZE, dladdr, verify_cnt, FT_APP, xfile); if (ret < 0) goto cleanup; } } if (dev->mode == MODE_HID) if (type == FT_APP) { printf("jumping to 0x%08x\n", header_addr); jump_command.addr = BE32(header_addr); //Any command will initiate jump for mx51, jump address is ignored by mx51 retry = 0; for (;;) { err = dev->transfer(dev, 1, (unsigned char *)&jump_command, sizeof(jump_command), 0, &last_trans); if (!err) break; printf("jump_command err=%i, last_trans=%i\n", err, last_trans); if (retry > 5) { return -4; } retry++; } memset(tmp, 0, sizeof(tmp)); err = dev->transfer(dev, 3, tmp, sizeof(tmp), 4, &last_trans); if (err) printf("j3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); if (dev->mode == MODE_HID) { memset(tmp, 0, sizeof(tmp)); err = dev->transfer(dev, 4, tmp, sizeof(tmp), 4, &last_trans); if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) printf("j4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); // Ignore error. Documentation says "This report is sent by device only in case of an error jumping to the given address..." err = 0; } } ret = (fsize <= transferSize) ? 0 : -16; cleanup: fclose(xfile); free(verify_buffer); free(buf); return ret; } imx_usb_loader/imx_usb.conf0000644000175000017500000000117113203242133016270 0ustar paulliupaulliu#vid:pid, config_file 0x066f:0x3780, mx23_usb_work.conf 0x15a2:0x004f, mx28_usb_work.conf 0x15a2:0x0052, mx50_usb_work.conf 0x15a2:0x0054, mx6_usb_work.conf 0x15a2:0x0061, mx6_usb_work.conf 0x15a2:0x0063, mx6_usb_work.conf 0x15a2:0x0071, mx6_usb_work.conf 0x15a2:0x007d, mx6_usb_work.conf 0x15a2:0x0080, mx6_usb_work.conf 0x1fc9:0x0128, mx6_usb_work.conf 0x15a2:0x0076, mx7_usb_work.conf 0x1fc9:0x0126, mx7ulp_usb_work.conf 0x15a2:0x0041, mx51_usb_work.conf 0x15a2:0x004e, mx53_usb_work.conf 0x15a2:0x006a, vybrid_usb_work.conf 0x066f:0x37ff, linux_gadget.conf 0x1b67:0x4fff, mx6_usb_sdp_spl.conf 0x0525:0xb4a4, mx6_usb_sdp_spl.conf imx_usb_loader/image.h0000644000175000017500000001654313203242133015217 0ustar paulliupaulliu/* * (C) Copyright 2008 Semihalf * * (C) Copyright 2000-2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * SPDX-License-Identifier: GPL-2.0+ ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including * this (unmodified) header file in another file is considered normal * use of U-Boot, and does *not* fall under the heading of "derived * work". ******************************************************************** */ #ifndef __IMAGE_H__ #define __IMAGE_H__ #include typedef uint32_t __be32; /* * Operating System Codes * * The following are exposed to uImage header. * Do not change values for backward compatibility. */ enum { IH_OS_INVALID = 0, /* Invalid OS */ IH_OS_OPENBSD, /* OpenBSD */ IH_OS_NETBSD, /* NetBSD */ IH_OS_FREEBSD, /* FreeBSD */ IH_OS_4_4BSD, /* 4.4BSD */ IH_OS_LINUX, /* Linux */ IH_OS_SVR4, /* SVR4 */ IH_OS_ESIX, /* Esix */ IH_OS_SOLARIS, /* Solaris */ IH_OS_IRIX, /* Irix */ IH_OS_SCO, /* SCO */ IH_OS_DELL, /* Dell */ IH_OS_NCR, /* NCR */ IH_OS_LYNXOS, /* LynxOS */ IH_OS_VXWORKS, /* VxWorks */ IH_OS_PSOS, /* pSOS */ IH_OS_QNX, /* QNX */ IH_OS_U_BOOT, /* Firmware */ IH_OS_RTEMS, /* RTEMS */ IH_OS_ARTOS, /* ARTOS */ IH_OS_UNITY, /* Unity OS */ IH_OS_INTEGRITY, /* INTEGRITY */ IH_OS_OSE, /* OSE */ IH_OS_PLAN9, /* Plan 9 */ IH_OS_OPENRTOS, /* OpenRTOS */ IH_OS_COUNT, }; /* * CPU Architecture Codes (supported by Linux) * * The following are exposed to uImage header. * Do not change values for backward compatibility. */ enum { IH_ARCH_INVALID = 0, /* Invalid CPU */ IH_ARCH_ALPHA, /* Alpha */ IH_ARCH_ARM, /* ARM */ IH_ARCH_I386, /* Intel x86 */ IH_ARCH_IA64, /* IA64 */ IH_ARCH_MIPS, /* MIPS */ IH_ARCH_MIPS64, /* MIPS 64 Bit */ IH_ARCH_PPC, /* PowerPC */ IH_ARCH_S390, /* IBM S390 */ IH_ARCH_SH, /* SuperH */ IH_ARCH_SPARC, /* Sparc */ IH_ARCH_SPARC64, /* Sparc 64 Bit */ IH_ARCH_M68K, /* M68K */ IH_ARCH_NIOS, /* Nios-32 */ IH_ARCH_MICROBLAZE, /* MicroBlaze */ IH_ARCH_NIOS2, /* Nios-II */ IH_ARCH_BLACKFIN, /* Blackfin */ IH_ARCH_AVR32, /* AVR32 */ IH_ARCH_ST200, /* STMicroelectronics ST200 */ IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ IH_ARCH_OPENRISC, /* OpenRISC 1000 */ IH_ARCH_ARM64, /* ARM64 */ IH_ARCH_ARC, /* Synopsys DesignWare ARC */ IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ IH_ARCH_XTENSA, /* Xtensa */ IH_ARCH_COUNT, }; /* * Image Types * * "Standalone Programs" are directly runnable in the environment * provided by U-Boot; it is expected that (if they behave * well) you can continue to work in U-Boot after return from * the Standalone Program. * "OS Kernel Images" are usually images of some Embedded OS which * will take over control completely. Usually these programs * will install their own set of exception handlers, device * drivers, set up the MMU, etc. - this means, that you cannot * expect to re-enter U-Boot except by resetting the CPU. * "RAMDisk Images" are more or less just data blocks, and their * parameters (address, size) are passed to an OS kernel that is * being started. * "Multi-File Images" contain several images, typically an OS * (Linux) kernel image and one or more data images like * RAMDisks. This construct is useful for instance when you want * to boot over the network using BOOTP etc., where the boot * server provides just a single image file, but you want to get * for instance an OS kernel and a RAMDisk image. * * "Multi-File Images" start with a list of image sizes, each * image size (in bytes) specified by an "uint32_t" in network * byte order. This list is terminated by an "(uint32_t)0". * Immediately after the terminating 0 follow the images, one by * one, all aligned on "uint32_t" boundaries (size rounded up to * a multiple of 4 bytes - except for the last file). * * "Firmware Images" are binary images containing firmware (like * U-Boot or FPGA images) which usually will be programmed to * flash memory. * * "Script files" are command sequences that will be executed by * U-Boot's command interpreter; this feature is especially * useful when you configure U-Boot to use a real shell (hush) * as command interpreter (=> Shell Scripts). * * The following are exposed to uImage header. * Do not change values for backward compatibility. */ enum { IH_TYPE_INVALID = 0, /* Invalid Image */ IH_TYPE_STANDALONE, /* Standalone Program */ IH_TYPE_KERNEL, /* OS Kernel Image */ IH_TYPE_RAMDISK, /* RAMDisk Image */ IH_TYPE_MULTI, /* Multi-File Image */ IH_TYPE_FIRMWARE, /* Firmware Image */ IH_TYPE_SCRIPT, /* Script file */ IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ /* OS Kernel Image, can run from any load address */ IH_TYPE_KERNEL_NOLOAD, IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA Preloader */ IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ IH_TYPE_LOADABLE, /* A list of typeless images */ IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ IH_TYPE_RKSD, /* Rockchip SD card */ IH_TYPE_RKSPI, /* Rockchip SPI image */ IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ IH_TYPE_FPGA, /* FPGA Image */ IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ IH_TYPE_FIRMWARE_IVT, /* Firmware Image with HABv4 IVT */ IH_TYPE_COUNT, /* Number of image types */ }; /* * Compression Types * * The following are exposed to uImage header. * Do not change values for backward compatibility. */ enum { IH_COMP_NONE = 0, /* No Compression Used */ IH_COMP_GZIP, /* gzip Compression Used */ IH_COMP_BZIP2, /* bzip2 Compression Used */ IH_COMP_LZMA, /* lzma Compression Used */ IH_COMP_LZO, /* lzo Compression Used */ IH_COMP_LZ4, /* lz4 Compression Used */ IH_COMP_COUNT, }; #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ /* Reused from common.h */ #define ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1)) /* * Legacy format image header, * all data in network byte order (aka natural aka bigendian). */ typedef struct image_header { __be32 ih_magic; /* Image Header Magic Number */ __be32 ih_hcrc; /* Image Header CRC Checksum */ __be32 ih_time; /* Image Creation Timestamp */ __be32 ih_size; /* Image Data Size */ __be32 ih_load; /* Data Load Address */ __be32 ih_ep; /* Entry Point Address */ __be32 ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t; #endif /* __IMAGE_H__ */ imx_usb_loader/mx6_usb_work.conf0000644000175000017500000000237413203242133017255 0ustar paulliupaulliumx6_qsb #hid/bulk,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) hid,1024,0x910000,0x10000000,1G,0x00900000,0x40000 #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - header is after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded #header - uses existing header(error if none), but clears plug and dcd values unless plug also specified #header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution #load nnn - load entire file to address #../u-boot-imx6/u-boot.bin:dcd,plug,jump header #:modify,020e02a8,7,1 #:modify,020e00bc,7,4 #:read,020e02a8 #:read,020e00bc #:read,020c4078 #:modify,020c407c,0,0f000000 #:modify,020c4080,0,c00 #:read,020c4084 #../imx_utils/mx6_ddr_init_xm.bin:dcd #../u-boot-imx6/u-boot.bin:load 0x13effc00 #../u-boot-imx6/u-boot.imx:load 0x13f00000 #../u-boot-dirk/u-boot.imx:load 0x13f00000 #u-boot-6w.bin:load 0x13effc00 #u-boot_1103.bin:load 0x13effc00 #u-boot_1103.bin:jump header #../imx_utils/mx6_ecspi_ram_write_xm.bin:clear_dcd,plug #../imx6_obds/output/mx61/bin/diag-obds-mx61qsb-rev1.bin:jump header imx_usb_loader/mx7_usb_work.conf0000644000175000017500000000236613203242133017257 0ustar paulliupaulliumx7 #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) hid,1024,0x910000,0x80000000,1G,0x00900000,0x20000 #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - header is after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded #header - uses existing header(error if none), but clears plug and dcd values unless plug also specified #header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution #load nnn - load entire file to address #../u-boot-imx6/u-boot.bin:dcd,plug,jump header #:modify,020e02a8,7,1 #:modify,020e00bc,7,4 #:read,020e02a8 #:read,020e00bc #:read,020c4078 #:modify,020c407c,0,0f000000 #:modify,020c4080,0,c00 #:read,020c4084 #../imx_utils/mx6_ddr_init_xm.bin:dcd #../u-boot-imx6/u-boot.bin:load 0x13effc00 #../u-boot-imx6/u-boot.imx:load 0x13f00000 #../u-boot-dirk/u-boot.imx:load 0x13f00000 #u-boot-6w.bin:load 0x13effc00 #u-boot_1103.bin:load 0x13effc00 #u-boot_1103.bin:jump header #../imx_utils/mx6_ecspi_ram_write_xm.bin:clear_dcd,plug #../imx6_obds/output/mx61/bin/diag-obds-mx61qsb-rev1.bin:jump header imx_usb_loader/mx7ulp_usb_work.conf0000644000175000017500000000023013203242133017764 0ustar paulliupaulliumx7ulp #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) hid,1024,0x2f020000,0x60000000,1G,0x900000,0x40000 imx_usb_loader/Makefile.mingw0000644000175000017500000000132113203242133016530 0ustar paulliupaulliuall: imx_usb imx_uart #$(foreach v,$(.VARIABLES), $(info $(v) = $($(v)))) # Building with MinGW natively CC = gcc USBCFLAGS = -I$(LIBUSBPATH)\include USBLDFLAGS = -L$(LIBUSBPATH)\MinGW32\dll -lusb-1.0 imx_usb.o : imx_usb.c imx_sdp.h portable.h $(CC) -c $*.c -o $@ -Wstrict-prototypes -Wno-trigraphs -pipe -ggdb $(USBCFLAGS) $(CFLAGS) %.o : %.c imx_sdp.h portable.h $(CC) -c $*.c -o $@ -Wstrict-prototypes -Wno-trigraphs -pipe -ggdb $(CFLAGS) imx_usb: imx_usb.o imx_sdp.o $(CC) -o $@ $@.o imx_sdp.o $(LDFLAGS) $(USBLDFLAGS) imx_uart: imx_uart.o imx_sdp.o $(CC) -o $@ $@.o imx_sdp.o $(LDFLAGS) clean: del /f /q imx_usb imx_uart imx_usb.o imx_uart.o imx_sdp.o .PHONY: all clean install imx_usb_loader/mx51_usb_work.conf0000644000175000017500000000157713203242133017341 0ustar paulliupaulliumx51 #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) bulk,old_header,64,0x1ffe2000,0x90000000,512M,0x1ffe2000,0x16000 #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - new header is placed after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified # header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution #../u-boot-watchie/u-boot.bin:dcd,plug,jump header ../imx_utils/mx51_ddr_init_xm.bin:dcd,plug,jump header ../u-boot-watchie/mx51_ubl_ecspi.bin:load 0x93f00000 ../imx_utils/mx51_ecspi_ram_write_xm.bin:dcd,plug,jump header imx_usb_loader/mx50_usb_work.conf0000644000175000017500000000130613203242133017326 0ustar paulliupaulliumx50 #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) hid,64,0xf8006400,0xf8006400,128M #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - new header is placed after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified # header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution SPL:dcd u-boot.bin:load 0x77800000 SPL:load 0xF8006400, jump header imx_usb_loader/.gitignore0000644000175000017500000000010113203242133015733 0ustar paulliupaulliu*.o imx_usb imx_uart imx_usb.lds imx_uart.lds *.bin *.imx .*.swp imx_usb_loader/portable.h0000644000175000017500000000222613203242133015736 0ustar paulliupaulliu#ifndef __PORTABLE_H__ #define __PORTABLE_H__ extern int debugmode; #ifndef WIN32 #define dbg_printf(fmt, args...) do{ if(debugmode) fprintf(stderr, fmt, ## args); } while(0) #else #ifdef DEBUG #define dbg_printf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) #else #define dbg_printf(fmt, ...) /* Don't do anything in release builds */ #endif #endif #ifndef _MSC_VER #include #endif #ifdef WIN32 #include #include #include #endif #ifdef __linux__ #include #endif #ifdef __APPLE__ #include #endif #ifdef __FreeBSD__ #include #endif #ifndef WIN32 #define PATH_SEPARATOR '/' #define msleep(ms) usleep((ms) * 1000) #else #define PATH_MAX MAX_PATH #define PATH_SEPARATOR '\\' #define msleep(ms) Sleep(ms) #endif #ifdef _MSC_VER #define R_OK 04 #define open(filename,oflag) _open(filename,oflag) #define write(fd,buffer,count) _write(fd,buffer,count) #define read(fd,buffer,count) _read(fd,buffer,count) #define close(fd) _close(fd) #define access(filename,oflag) _access(filename,oflag) #define getcwd(buffer, maxlen) _getcwd(buffer, maxlen) #endif #endif /* __PORTABLE_H__ */ imx_usb_loader/README.md0000644000175000017500000000560713203242133015242 0ustar paulliupaulliu# imx_loader i.MX/Vybrid recovery utility ## Description This utility allows to download and execute code on Freescale i.MX5/i.MX6/i.MX7 and Vybrid SoCs through the Serial Download Protocol (SDP). Depending on the board, there is usually some kind of recovery button to bring the SoC into serial download boot mode, check documentation of your hardware. The utility support USB and UART as serial link. ## Installation 1. Clone 1. Make sure libusb (1.0) is available 1. Compile using make Two binaries are available, imx_usb and imx_uart for the two supported connections. ### Windows Two variants have been tested successfully to build imx_usb and imx_uart on Windows: 1. MinGW (using the Microsoft C runtime) 1. Visual Studio 2015 #### MinGW MinGW allows to use the GNU toolchain (including GCC) to compile a native Microsoft Windows application. A MinGW specific make file (Makefile.mingw) is available which allows to build imx_usb/imx_uart with the native make port (mingw32-make.exe). After installing MinGW, make sure you have a compiled copy of libusb available and build imx_loader using: ``` mingw32-make -f Makefile.mingw LIBUSBPATH=C:\path\to\libusb ``` This dynamically links against libusb, hence make sure to ship the library libusb-1.0.dll along with imx_usb.exe. #### Visual Studio The subdirectory msvc/ contains the project files for Visual Studio 2015. Make sure you have the Visual C++ component installed. There is one solution containing two projects, one for imx_usb and one for imx_uart. The imx_usb project requires libusb to be present at ../../libusb (relative to the msvc) directory. If you use an alternative location or compile libusb from source too, you will have to alter the include/library path in the project settings. ### macOS libusb and pkg-config can be installed via Homebrew. If imx_usb fails to claim interface, com.apple.driver.usb.IOUSBHostHIDDevice needs to be unloaded so libusb can claim, run: ``` sudo kextunload -b com.apple.driver.usb.IOUSBHostHIDDevice ``` ## Usage Using USB, your device should be detected automatically using the USB VID/PID from imx_usb.conf. Using UART, the user has to specify a configuration file. This file is needed to use the correct protocol variant for the target device (transfer configuration). The configuration file can also contains work item(s). Work items can also be defined using the command line. By specifying a file in the command line, the utility automatically uses this file as a work item and reads parameter from its header: ``` ./imx_usb u-boot.imx ``` However, parameters can also specified manually, e.g. ``` ./imx_usb u-boot.imx -l0x3f400400 -s370796 -v ``` The UART link uses hardware flow control using RTS/CTS, so make sure those are available. The imx_uart utility will configure the target tty with the right baud rate (115200) and flow control settings: ``` ./imx_uart /dev/ttyUSB0 vybrid_usb_work.conf u-boot.imx ``` imx_usb_loader/mx53_usb_work.conf0000644000175000017500000000154113203242133017332 0ustar paulliupaulliumx53 #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) bulk,512,0xf8006000,0x70000000,512M,0xf8006000,0x12000 #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - new header is placed after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified # header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution #../u-boot-watchie/u-boot.bin:dcd,plug,jump header ../imx_utils/mx53_ddr_init_xm.bin:dcd,plug ../u-boot-watchie/mx53_ubl_ecspi.bin:load 0x73f00000 ../imx_utils/mx53_ecspi_ram_write_xm.bin:jump header2 imx_usb_loader/COPYING0000644000175000017500000006364213203242133015021 0ustar paulliupaulliu GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! imx_usb_loader/imx_sdp.h0000644000175000017500000000660713203242133015600 0ustar paulliupaulliu/* * imx_sdp: * Interface of the Serial Download Protocol (SDP) for i.MX/Vybrid * series processors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __IMX_SDP_H__ #define __IMX_SDP_H__ struct ram_area { unsigned start; unsigned size; }; struct mem_work { struct mem_work *next; unsigned type; #define MEM_TYPE_READ 0 #define MEM_TYPE_WRITE 1 #define MEM_TYPE_MODIFY 2 unsigned vals[3]; }; struct sdp_work; struct sdp_work { struct sdp_work *next; struct mem_work *mem; char filename[256]; unsigned char dcd; unsigned char clear_dcd; //means clear dcd_ptr unsigned char clear_boot_data; //means clear boot data ptr unsigned char plug; #define J_ADDR 1 #define J_HEADER 2 #define J_HEADER2 3 unsigned char jump_mode; unsigned load_addr; unsigned jump_addr; unsigned load_size; }; struct sdp_dev { char name[64]; unsigned short max_transfer; #define MODE_HID 0 #define MODE_BULK 1 unsigned char mode; #define HDR_NONE 0 #define HDR_MX51 1 #define HDR_MX53 2 #define HDR_UBOOT 3 unsigned char header_type; unsigned dcd_addr; struct ram_area ram[8]; struct sdp_work *work; /* * dev - SDP devce (this structure) * report - HID Report * p - pointer to buffer * size - size of buffer (used for send and USB receive length) * expected - the expected amount of data (used for UART receive) * last_trans - the actually transfered bytes */ int (*transfer)(struct sdp_dev *dev, int report, unsigned char *p, unsigned int size, unsigned int expected, int* last_trans); void *priv; }; #define HAB_SECMODE_PROD 0x12343412 #define HAB_SECMODE_DEV 0x56787856 /* * Section 8.7.2 of the i.MX6DQ/UL/SoloX RM: * The maximum size of the DCD limited to 1768 bytes. */ #define HAB_MAX_DCD_SIZE 1768 #define SDP_READ_REG 0x0101 #define SDP_WRITE_REG 0x0202 #define SDP_WRITE_FILE 0x0404 #define SDP_ERROR_STATUS 0x0505 #define SDP_WRITE_DCD 0x0a0a #define SDP_JUMP_ADDRESS 0x0b0b #pragma pack (1) struct sdp_command { uint16_t cmd; uint32_t addr; uint8_t format; uint32_t cnt; uint32_t data; uint8_t rsvd; }; #pragma pack () int get_val(const char** pp, int base); const char *move_string(char *dest, const char *src, unsigned cnt); void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr); char const *get_global_conf_path(void); char const *get_base_path(char const *argv0); char const *conf_file_name(char const *file, char const *base_path, char const *conf_path); struct sdp_dev *parse_conf(const char *filename); struct sdp_work *parse_cmd_args(int argc, char * const *argv); void perform_mem_work(struct sdp_dev *dev, struct mem_work *mem); int do_status(struct sdp_dev *dev); int DoIRomDownload(struct sdp_dev *dev, struct sdp_work *curr, int verify); #endif /* __IMX_SDP_H__ */ imx_usb_loader/Makefile0000644000175000017500000000255713203242133015424 0ustar paulliupaulliuall: imx_usb imx_uart DESTDIR ?= prefix ?= /usr bindir ?= $(prefix)/bin sysconfdir ?= $(prefix)/etc BUILDHOST := $(shell uname -s) BUILDHOST := $(patsubst CYGWIN_%,CYGWIN,$(BUILDHOST)) ifneq ($(BUILDHOST),CYGWIN) PKG_CONFIG ?= pkg-config USBCFLAGS = `$(PKG_CONFIG) --cflags libusb-1.0` USBLDFLAGS = `$(PKG_CONFIG) --libs libusb-1.0` else USBCFLAGS = -I/usr/include/libusb-1.0 USBLDFLAGS = -L/usr/lib -lusb-1.0 endif CONFCPPFLAGS = -DSYSCONFDIR='"$(sysconfdir)"' CFLAGS ?= -Wall -Wstrict-prototypes -Wno-trigraphs imx_usb.o : imx_usb.c imx_sdp.h portable.h $(CC) -c $*.c -o $@ -pipe -ggdb $(USBCFLAGS) $(CFLAGS) $(CONFCPPFLAGS) %.o : %.c imx_sdp.h portable.h image.h $(CC) -c $*.c -o $@ -pipe -ggdb $(CFLAGS) $(CONFCPPFLAGS) imx_usb: imx_usb.o imx_sdp.o $(CC) -o $@ $@.o imx_sdp.o $(LDFLAGS) $(USBLDFLAGS) imx_uart: imx_uart.o imx_sdp.o $(CC) -o $@ $@.o imx_sdp.o $(LDFLAGS) install: imx_usb imx_uart mkdir -p '$(DESTDIR)$(sysconfdir)/imx-loader.d/' install -m644 *.conf '$(DESTDIR)$(sysconfdir)/imx-loader.d/' mkdir -p '$(DESTDIR)$(bindir)' install -m755 imx_usb '$(DESTDIR)$(bindir)/imx_usb' install -m755 imx_uart '$(DESTDIR)$(bindir)/imx_uart' uninstall: rm -rf '$(DESTDIR)$(sysconfdir)/imx-loader.d/' rm -rf '$(DESTDIR)$(bindir)/imx_usb' rm -rf '$(DESTDIR)$(bindir)/imx_uart' clean: rm -f imx_usb imx_uart imx_usb.o imx_uart.o imx_sdp.o .PHONY: all clean install imx_usb_loader/mx6_usb_sdp_spl.conf0000644000175000017500000000033413203242133017731 0ustar paulliupaulliumx6_spl_sdp #hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas) #In SPL, we typically load u-boot.img which has a U-boot header... hid,uboot_header,1024,0x10000000,1G,0x00907000,0x31000 imx_usb_loader/msvc/0000755000175000017500000000000013203242133014723 5ustar paulliupaulliuimx_usb_loader/msvc/imx_loader.sln0000644000175000017500000000336113203242133017567 0ustar paulliupaulliu Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imx_uart", "imx_uart.vcxproj", "{E97E957F-CB34-4A96-B2AF-D2E7D902B27E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imx_usb", "imx_usb.vcxproj", "{1D2B783C-E033-49B3-ACD1-8AA3C5A51774}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|Win32.ActiveCfg = Debug|Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|Win32.Build.0 = Debug|Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|x64.ActiveCfg = Debug|Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|Win32.ActiveCfg = Release|Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|Win32.Build.0 = Release|Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|x64.ActiveCfg = Release|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|Win32.ActiveCfg = Debug|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|Win32.Build.0 = Debug|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|x64.ActiveCfg = Debug|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|Win32.ActiveCfg = Release|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|Win32.Build.0 = Release|Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal imx_usb_loader/msvc/imx_uart.vcxproj0000644000175000017500000001232713203242133020175 0ustar paulliupaulliu Debug Win32 Release Win32 {E97E957F-CB34-4A96-B2AF-D2E7D902B27E} Win32Proj imx_loaderuart_loader 8.1 Application true v140 Unicode Application false v140 true Unicode true imx_uart $(VC_IncludePath);$(WindowsSDK_IncludePath);$(MSBuildProjectDirectory) $(SolutionDir)$(ProjectName)\$(Configuration)\ $(ProjectName)\$(Configuration)\ false imx_uart $(SolutionDir)$(ProjectName)\$(Configuration)\ $(ProjectName)\$(Configuration)\ Level3 Disabled WIN32;STATIC_GETOPT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS _UNICODE $(MSBuildProjectDirectory);%(AdditionalIncludeDirectories) Console true Level3 MaxSpeed true true WIN32;STATIC_GETOPT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS _UNICODE $(MSBuildProjectDirectory);%(AdditionalIncludeDirectories) Console true true true imx_usb_loader/msvc/getopt.c0000644000175000017500000006352413203242133016403 0ustar paulliupaulliu/* Getopt for Microsoft C This code is a modification of the Free Software Foundation, Inc. Getopt library for parsing command line argument the purpose was to provide a Microsoft Visual C friendly derivative. This code provides functionality for both Unicode and Multibyte builds. Date: 02/03/2011 - Ludvik Jerabek - Initial Release Version: 1.0 Comment: Supports getopt, getopt_long, and getopt_long_only and POSIXLY_CORRECT environment flag License: LGPL Revisions: 02/03/2011 - Ludvik Jerabek - Initial Release 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features **DISCLAIMER** THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include "getopt.h" #ifdef __cplusplus #define _GETOPT_THROW throw() #else #define _GETOPT_THROW #endif int optind = 1; int opterr = 1; int optopt = '?'; enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }; // // // Ansi structures and functions follow // // static struct _getopt_data_a { int optind; int opterr; int optopt; char *optarg; int __initialized; char *__nextchar; enum ENUM_ORDERING __ordering; int __posixly_correct; int __first_nonopt; int __last_nonopt; } getopt_data_a; char *optarg_a; static void exchange_a(char **argv, struct _getopt_data_a *d) { int bottom = d->__first_nonopt; int middle = d->__last_nonopt; int top = d->optind; char *tem; while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { int len = middle - bottom; register int i; for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } top -= len; } else { int len = top - middle; register int i; for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } bottom += len; } } d->__first_nonopt += (d->optind - d->__last_nonopt); d->__last_nonopt = d->optind; } static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct) { d->__first_nonopt = d->__last_nonopt = d->optind; d->__nextchar = NULL; d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT"); if (optstring[0] == '-') { d->__ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { d->__ordering = REQUIRE_ORDER; ++optstring; } else if (d->__posixly_correct) d->__ordering = REQUIRE_ORDER; else d->__ordering = PERMUTE; return optstring; } int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) { int print_errors = d->opterr; if (argc < 1) return -1; d->optarg = NULL; if (d->optind == 0 || !d->__initialized) { if (d->optind == 0) d->optind = 1; optstring = _getopt_initialize_a (optstring, d, posixly_correct); d->__initialized = 1; } else if (optstring[0] == '-' || optstring[0] == '+') optstring++; if (optstring[0] == ':') print_errors = 0; if (d->__nextchar == NULL || *d->__nextchar == '\0') { if (d->__last_nonopt > d->optind) d->__last_nonopt = d->optind; if (d->__first_nonopt > d->optind) d->__first_nonopt = d->optind; if (d->__ordering == PERMUTE) { if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange_a ((char **) argv, d); else if (d->__last_nonopt != d->optind) d->__first_nonopt = d->optind; while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) d->optind++; d->__last_nonopt = d->optind; } if (d->optind != argc && !strcmp(argv[d->optind], "--")) { d->optind++; if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange_a((char **) argv, d); else if (d->__first_nonopt == d->__last_nonopt) d->__first_nonopt = d->optind; d->__last_nonopt = argc; d->optind = argc; } if (d->optind == argc) { if (d->__first_nonopt != d->__last_nonopt) d->optind = d->__first_nonopt; return -1; } if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) { if (d->__ordering == REQUIRE_ORDER) return -1; d->optarg = argv[d->optind++]; return 1; } d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); } if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))))) { char *nameend; unsigned int namelen; const struct option_a *p; const struct option_a *pfound = NULL; struct option_list { const struct option_a *p; struct option_list *next; } *ambig_list = NULL; int exact = 0; int indfound = -1; int option_index; for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++); namelen = (unsigned int)(nameend - d->__nextchar); for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp(p->name, d->__nextchar, namelen)) { if (namelen == (unsigned int)strlen(p->name)) { pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) { struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); newp->p = p; newp->next = ambig_list; ambig_list = newp; } } if (ambig_list != NULL && !exact) { if (print_errors) { struct option_list first; first.p = pfound; first.next = ambig_list; ambig_list = &first; fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); do { fprintf (stderr, " '--%s'", ambig_list->p->name); ambig_list = ambig_list->next; } while (ambig_list != NULL); fputc ('\n', stderr); } d->__nextchar += strlen(d->__nextchar); d->optind++; d->optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; d->optind++; if (*nameend) { if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { if (argv[d->optind - 1][1] == '-') { fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); } else { fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); } } d->__nextchar += strlen(d->__nextchar); d->optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name); } d->__nextchar += strlen(d->__nextchar); d->optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } d->__nextchar += strlen(d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) { if (print_errors) { if (argv[d->optind][1] == '-') { fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); } else { fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); } } d->__nextchar = (char *)""; d->optind++; d->optopt = 0; return '?'; } } { char c = *d->__nextchar++; char *temp = (char*)strchr(optstring, c); if (*d->__nextchar == '\0') ++d->optind; if (temp == NULL || c == ':' || c == ';') { if (print_errors) { fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c); } d->optopt = c; return '?'; } if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option_a *p; const struct option_a *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; if (longopts == NULL) goto no_longs; if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; d->optind++; } else if (d->optind == argc) { if (print_errors) { fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else d->optarg = argv[d->optind++]; for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++); for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar)) { if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name)) { pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) ambig = 1; } if (ambig && !exact) { if (print_errors) { fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); } d->__nextchar += strlen(d->__nextchar); d->optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); } d->__nextchar += strlen(d->__nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name); } d->__nextchar += strlen(d->__nextchar); return optstring[0] == ':' ? ':' : '?'; } } else d->optarg = NULL; d->__nextchar += strlen(d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } no_longs: d->__nextchar = NULL; return 'W'; } if (temp[1] == ':') { if (temp[2] == ':') { if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; d->optind++; } else d->optarg = NULL; d->__nextchar = NULL; } else { if (*d->__nextchar != '\0') { d->optarg = d->__nextchar; d->optind++; } else if (d->optind == argc) { if (print_errors) { fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); } d->optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else d->optarg = argv[d->optind++]; d->__nextchar = NULL; } } return c; } } int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) { int result; getopt_data_a.optind = optind; getopt_data_a.opterr = opterr; result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct); optind = getopt_data_a.optind; optarg_a = getopt_data_a.optarg; optopt = getopt_data_a.optopt; return result; } int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW { return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0); } int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW { return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0); } int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW { return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0); } int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) { return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0); } int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) { return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0); } // // // Unicode Structures and Functions // // static struct _getopt_data_w { int optind; int opterr; int optopt; wchar_t *optarg; int __initialized; wchar_t *__nextchar; enum ENUM_ORDERING __ordering; int __posixly_correct; int __first_nonopt; int __last_nonopt; } getopt_data_w; wchar_t *optarg_w; static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) { int bottom = d->__first_nonopt; int middle = d->__last_nonopt; int top = d->optind; wchar_t *tem; while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { int len = middle - bottom; register int i; for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } top -= len; } else { int len = top - middle; register int i; for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } bottom += len; } } d->__first_nonopt += (d->optind - d->__last_nonopt); d->__last_nonopt = d->optind; } static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) { d->__first_nonopt = d->__last_nonopt = d->optind; d->__nextchar = NULL; d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT"); if (optstring[0] == L'-') { d->__ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == L'+') { d->__ordering = REQUIRE_ORDER; ++optstring; } else if (d->__posixly_correct) d->__ordering = REQUIRE_ORDER; else d->__ordering = PERMUTE; return optstring; } int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) { int print_errors = d->opterr; if (argc < 1) return -1; d->optarg = NULL; if (d->optind == 0 || !d->__initialized) { if (d->optind == 0) d->optind = 1; optstring = _getopt_initialize_w (optstring, d, posixly_correct); d->__initialized = 1; } else if (optstring[0] == L'-' || optstring[0] == L'+') optstring++; if (optstring[0] == L':') print_errors = 0; if (d->__nextchar == NULL || *d->__nextchar == L'\0') { if (d->__last_nonopt > d->optind) d->__last_nonopt = d->optind; if (d->__first_nonopt > d->optind) d->__first_nonopt = d->optind; if (d->__ordering == PERMUTE) { if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange_w((wchar_t **) argv, d); else if (d->__last_nonopt != d->optind) d->__first_nonopt = d->optind; while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) d->optind++; d->__last_nonopt = d->optind; } if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) { d->optind++; if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) exchange_w((wchar_t **) argv, d); else if (d->__first_nonopt == d->__last_nonopt) d->__first_nonopt = d->optind; d->__last_nonopt = argc; d->optind = argc; } if (d->optind == argc) { if (d->__first_nonopt != d->__last_nonopt) d->optind = d->__first_nonopt; return -1; } if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) { if (d->__ordering == REQUIRE_ORDER) return -1; d->optarg = argv[d->optind++]; return 1; } d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-')); } if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))))) { wchar_t *nameend; unsigned int namelen; const struct option_w *p; const struct option_w *pfound = NULL; struct option_list { const struct option_w *p; struct option_list *next; } *ambig_list = NULL; int exact = 0; int indfound = -1; int option_index; for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++); namelen = (unsigned int)(nameend - d->__nextchar); for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!wcsncmp(p->name, d->__nextchar, namelen)) { if (namelen == (unsigned int)wcslen(p->name)) { pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) { struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); newp->p = p; newp->next = ambig_list; ambig_list = newp; } } if (ambig_list != NULL && !exact) { if (print_errors) { struct option_list first; first.p = pfound; first.next = ambig_list; ambig_list = &first; fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); do { fwprintf (stderr, L" '--%s'", ambig_list->p->name); ambig_list = ambig_list->next; } while (ambig_list != NULL); fputwc (L'\n', stderr); } d->__nextchar += wcslen(d->__nextchar); d->optind++; d->optopt = 0; return L'?'; } if (pfound != NULL) { option_index = indfound; d->optind++; if (*nameend) { if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { if (argv[d->optind - 1][1] == L'-') { fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); } else { fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); } } d->__nextchar += wcslen(d->__nextchar); d->optopt = pfound->val; return L'?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name); } d->__nextchar += wcslen(d->__nextchar); d->optopt = pfound->val; return optstring[0] == L':' ? L':' : L'?'; } } d->__nextchar += wcslen(d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) { if (print_errors) { if (argv[d->optind][1] == L'-') { fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); } else { fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); } } d->__nextchar = (wchar_t *)L""; d->optind++; d->optopt = 0; return L'?'; } } { wchar_t c = *d->__nextchar++; wchar_t *temp = (wchar_t*)wcschr(optstring, c); if (*d->__nextchar == L'\0') ++d->optind; if (temp == NULL || c == L':' || c == L';') { if (print_errors) { fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c); } d->optopt = c; return L'?'; } if (temp[0] == L'W' && temp[1] == L';') { wchar_t *nameend; const struct option_w *p; const struct option_w *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; if (longopts == NULL) goto no_longs; if (*d->__nextchar != L'\0') { d->optarg = d->__nextchar; d->optind++; } else if (d->optind == argc) { if (print_errors) { fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); } d->optopt = c; if (optstring[0] == L':') c = L':'; else c = L'?'; return c; } else d->optarg = argv[d->optind++]; for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++); for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar)) { if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name)) { pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) ambig = 1; } if (ambig && !exact) { if (print_errors) { fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); } d->__nextchar += wcslen(d->__nextchar); d->optind++; return L'?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { if (pfound->has_arg) d->optarg = nameend + 1; else { if (print_errors) { fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); } d->__nextchar += wcslen(d->__nextchar); return L'?'; } } else if (pfound->has_arg == 1) { if (d->optind < argc) d->optarg = argv[d->optind++]; else { if (print_errors) { fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name); } d->__nextchar += wcslen(d->__nextchar); return optstring[0] == L':' ? L':' : L'?'; } } else d->optarg = NULL; d->__nextchar += wcslen(d->__nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } no_longs: d->__nextchar = NULL; return L'W'; } if (temp[1] == L':') { if (temp[2] == L':') { if (*d->__nextchar != L'\0') { d->optarg = d->__nextchar; d->optind++; } else d->optarg = NULL; d->__nextchar = NULL; } else { if (*d->__nextchar != L'\0') { d->optarg = d->__nextchar; d->optind++; } else if (d->optind == argc) { if (print_errors) { fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); } d->optopt = c; if (optstring[0] == L':') c = L':'; else c = L'?'; } else d->optarg = argv[d->optind++]; d->__nextchar = NULL; } } return c; } } int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) { int result; getopt_data_w.optind = optind; getopt_data_w.opterr = opterr; result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct); optind = getopt_data_w.optind; optarg_w = getopt_data_w.optarg; optopt = getopt_data_w.optopt; return result; } int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW { return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0); } int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW { return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0); } int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW { return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0); } int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) { return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0); } int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) { return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0); }imx_usb_loader/msvc/getopt.h0000644000175000017500000001141613203242133016401 0ustar paulliupaulliu/* Getopt for Microsoft C This code is a modification of the Free Software Foundation, Inc. Getopt library for parsing command line argument the purpose was to provide a Microsoft Visual C friendly derivative. This code provides functionality for both Unicode and Multibyte builds. Date: 02/03/2011 - Ludvik Jerabek - Initial Release Version: 1.0 Comment: Supports getopt, getopt_long, and getopt_long_only and POSIXLY_CORRECT environment flag License: LGPL Revisions: 02/03/2011 - Ludvik Jerabek - Initial Release 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features **DISCLAIMER** THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #ifndef __GETOPT_H_ #define __GETOPT_H_ #ifdef _GETOPT_API #undef _GETOPT_API #endif #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" #elif defined(STATIC_GETOPT) #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") #define _GETOPT_API #elif defined(EXPORTS_GETOPT) #pragma message("Exporting getopt library") #define _GETOPT_API __declspec(dllexport) #else #pragma message("Importing getopt library") #define _GETOPT_API __declspec(dllimport) #endif // Change behavior for C\C++ #ifdef __cplusplus #define _BEGIN_EXTERN_C extern "C" { #define _END_EXTERN_C } #define _GETOPT_THROW throw() #else #define _BEGIN_EXTERN_C #define _END_EXTERN_C #define _GETOPT_THROW #endif // Standard GNU options #define null_argument 0 /*Argument Null*/ #define no_argument 0 /*Argument Switch Only*/ #define required_argument 1 /*Argument Required*/ #define optional_argument 2 /*Argument Optional*/ // Shorter Options #define ARG_NULL 0 /*Argument Null*/ #define ARG_NONE 0 /*Argument Switch Only*/ #define ARG_REQ 1 /*Argument Required*/ #define ARG_OPT 2 /*Argument Optional*/ #include #include _BEGIN_EXTERN_C extern _GETOPT_API int optind; extern _GETOPT_API int opterr; extern _GETOPT_API int optopt; // Ansi struct option_a { const char* name; int has_arg; int *flag; char val; }; extern _GETOPT_API char *optarg_a; extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; // Unicode struct option_w { const wchar_t* name; int has_arg; int *flag; wchar_t val; }; extern _GETOPT_API wchar_t *optarg_w; extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; _END_EXTERN_C #undef _BEGIN_EXTERN_C #undef _END_EXTERN_C #undef _GETOPT_THROW #undef _GETOPT_API #ifdef _UNICODE #define getopt getopt_w #define getopt_long getopt_long_w #define getopt_long_only getopt_long_only_w #define option option_w #define optarg optarg_w #else #define getopt getopt_a #define getopt_long getopt_long_a #define getopt_long_only getopt_long_only_a #define option option_a #define optarg optarg_a #endif #endif // __GETOPT_H_ imx_usb_loader/msvc/imx_usb.vcxproj0000644000175000017500000001404213203242133020007 0ustar paulliupaulliu Debug Win32 Release Win32 {1D2B783C-E033-49B3-ACD1-8AA3C5A51774} Win32Proj imx_loaderuart_loader 8.1 Application true v140 Unicode Application false v140 true Unicode true imx_usb $(SolutionDir)$(ProjectName)\$(Configuration)\ $(ProjectName)\$(Configuration)\ false imx_usb $(SolutionDir)$(ProjectName)\$(Configuration)\ $(ProjectName)\$(Configuration)\ Level3 Disabled WIN32;STATIC_GETOPT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS _UNICODE ..\..\libusb\include;$(MSBuildProjectDirectory) MultiThreadedDebug Console true ..\..\libusb\MS32\static\ libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true IMXCONFDIR=$(APPDATA)\imx_loader\;WIN32;STATIC_GETOPT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS _UNICODE ..\..\libusb\include;$(MSBuildProjectDirectory) MultiThreaded Console true true true libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) ..\..\libusb\MS32\static\ imx_usb_loader/vybrid_usb_work.conf0000644000175000017500000000142213203242133020033 0ustar paulliupaulliuvybrid #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) #SysRAM0 #hid,1024,0x3f007000,0x10000000,1G,0x3f007000,0x31000 #gfxRAM hid,1024,0x3f400000,0x10000000,1G,0x3f400000,0x80000 #file:dcd,plug,load nnn,jump [nnn/header/header2] #jump nnn - header is after last downloaded word # entire file is loaded before jump, needs load nnn as well # i.e. file:load nnn,jump nnn #jump header - only length parameter is downloaded #header - uses existing header(error if none), but clears plug and dcd values unless plug also specified #header2 - uses 2nd header found(error if none) #plug - without jump uses header but clears plug flag to stop after plug execution #load nnn - load entire file to address #../u-boot/u-boot.imx:jump header imx_usb_loader/imx_usb.c0000644000175000017500000003635713203242133015603 0ustar paulliupaulliu/* * imx_usb: * * Program to download and execute an image over the USB boot protocol * on i.MX series processors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #else #include #endif #include "portable.h" #include "imx_sdp.h" struct mach_id; struct mach_id { struct mach_id *next; struct mach_id *nextbatch; unsigned short vid; unsigned short pid; char file_name[256]; }; static void print_devs(libusb_device **devs) { int j, k, l; int i = 0; for (;;) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *config; libusb_device *dev = devs[i++]; if (!dev) break; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { fprintf(stderr, "failed to get device descriptor"); return; } libusb_get_config_descriptor(dev, 0, &config); printf("%04x:%04x (bus %d, device %d) bNumInterfaces:%i\n", desc.idVendor, desc.idProduct, libusb_get_bus_number(dev), libusb_get_device_address(dev), config->bNumInterfaces); for (j = 0; j < config->bNumInterfaces; j++) { const struct libusb_interface *inter = &config->interface[j]; printf(" alternates:%i\n", inter->num_altsetting); for (k = 0; k < inter->num_altsetting; k++) { const struct libusb_interface_descriptor *interdesc = &inter->altsetting[k]; printf(" Interface Number: %i, Number of endpoints: %i\n", interdesc->bInterfaceNumber, interdesc->bNumEndpoints); for (l = 0; l < interdesc->bNumEndpoints; l++) { const struct libusb_endpoint_descriptor *epdesc = &interdesc->endpoint[l]; printf(" Descriptor Type: %x, EP Address: %i, wMaxPacketSize: %i\n", epdesc->bDescriptorType, epdesc->bEndpointAddress, epdesc->wMaxPacketSize); } } } libusb_free_config_descriptor(config); } } static struct mach_id *parse_imx_mach(const char **pp) { unsigned short vid; unsigned short pid; struct mach_id *curr = NULL; const char *p = *pp; while (*p==' ') p++; if (p[0] == '#') return NULL; vid = get_val(&p, 16); if (p[0] != ':') { printf("Syntax error(missing ':'): %s [%s]\n", p, *pp); return NULL; } p++; pid = get_val(&p, 16); if (p[0] != ',') { printf("Syntax error(missing ','): %s [%s]\n", p, *pp); return NULL; } p++; while (*p==' ') p++; if (!(vid && pid)) { printf("vid/pid cannot be 0: %s [%s]\n", p, *pp); return NULL; } curr = (struct mach_id *)malloc(sizeof(struct mach_id)); curr->next = NULL; curr->nextbatch = NULL; curr->vid = vid; curr->pid = pid; p = move_string(curr->file_name, p, sizeof(curr->file_name) - 1); *pp = p; return curr; } /* * Parse USB specific machine configuration */ static struct mach_id *parse_imx_conf(char const *filename) { char line[512]; struct mach_id *head = NULL; struct mach_id *tail = NULL; struct mach_id *curr = NULL; const char *p; FILE* xfile = fopen(filename, "rb" ); if (!xfile) { printf("Could not open file: %s\n", filename); return NULL; } while (fgets(line, sizeof(line), xfile) != NULL) { p = line; curr = parse_imx_mach(&p); if (!curr) continue; if (!head) head = curr; if (tail) tail->next = curr; tail = curr; printf("vid=0x%04x pid=0x%04x file_name=%s\n", curr->vid, curr->pid, curr->file_name); while (p[0] == ',') { p++; // Second machine in batch... curr->nextbatch = parse_imx_mach(&p); curr = curr->nextbatch; printf("-> vid=0x%04x pid=0x%04x file_name=%s\n", curr->vid, curr->pid, curr->file_name); } } fclose(xfile); return head; } static struct mach_id * imx_device(unsigned short vid, unsigned short pid, struct mach_id *p) { // printf("%s: vid=%x pid=%x\n", __func__, vid, pid); while (p) { if ((p->vid == vid) && (p->pid == pid)) return p; p = p->next; } return NULL; } static libusb_device *find_imx_dev(libusb_device **devs, struct mach_id **pp_id, struct mach_id *list, int bus, int address) { int i = 0; struct mach_id *p; for (;;) { struct libusb_device_descriptor desc; libusb_device *dev = devs[i++]; if (!dev) break; if ((bus >= 0 && libusb_get_bus_number(dev) != bus) || (address >= 0 && libusb_get_device_address(dev) != address)) continue; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { fprintf(stderr, "failed to get device descriptor"); return NULL; } p = imx_device(desc.idVendor, desc.idProduct, list); if (p) { *pp_id = p; return dev; } } fprintf(stderr, "no matching USB device found\n"); *pp_id = NULL; return NULL; } // HID Class-Specific Requests values. See section 7.2 of the HID specifications #define HID_GET_REPORT 0x01 #define HID_GET_IDLE 0x02 #define HID_GET_PROTOCOL 0x03 #define HID_SET_REPORT 0x09 #define HID_SET_IDLE 0x0A #define HID_SET_PROTOCOL 0x0B #define HID_REPORT_TYPE_INPUT 0x01 #define HID_REPORT_TYPE_OUTPUT 0x02 #define HID_REPORT_TYPE_FEATURE 0x03 #define CTRL_IN LIBUSB_ENDPOINT_IN |LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE #define CTRL_OUT LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE #define EP_IN 0x80 /* * For HID class drivers, 4 reports are used to implement * Serial Download protocol(SDP) * Report 1 (control out endpoint) 16 byte SDP comand * (total of 17 bytes with 1st byte report id of 0x01 * Report 2 (control out endpoint) data associated with report 1 commands * (max size of 1025 with 1st byte of 0x02) * Report 3 (interrupt in endpoint) HAB security state * (max size of 5 bytes with 1st byte of 0x03) * (0x12343412 production) * (0x56787856 engineering) * Report 4 (interrupt in endpoint) date associated with report 1 commands * (max size of 65 bytes with 1st byte of 0x04) * */ int transfer_hid(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, unsigned int expected, int* last_trans) { int err; struct libusb_device_handle *h = (struct libusb_device_handle *)dev->priv; if (cnt > dev->max_transfer) cnt = dev->max_transfer; #ifdef DEBUG printf("report=%i\n", report); if (report < 3) dump_bytes(p, cnt, 0); #endif unsigned char tmp[1028]; tmp[0] = (unsigned char)report; if (report < 3) { memcpy(&tmp[1], p, cnt); if (report == 2) cnt = dev->max_transfer; err = libusb_control_transfer(h, CTRL_OUT, HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT << 8) | report, 0, tmp, cnt + 1, 1000); *last_trans = (err > 0) ? err - 1 : 0; if (err > 0) err = 0; } else { *last_trans = 0; memset(&tmp[1], 0, cnt); err = libusb_interrupt_transfer(h, 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); dbg_printf("libusb_interrupt_transfer, err=%d, trans=%d\n", err, *last_trans); if (err >= 0) { if (tmp[0] == (unsigned char)report) { if (*last_trans > 1) { *last_trans -= 1; memcpy(p, &tmp[1], *last_trans); } } else { printf("Unexpected report %i err=%i, cnt=%i, last_trans=%i, %02x %02x %02x %02x\n", tmp[0], err, cnt, *last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); err = 0; } } } #ifdef DEBUG if (report >= 3) dump_bytes(p, cnt, 0); #endif return err; } /* * For Bulk class drivers, the device is configured as * EP0IN, EP0OUT control transfer * EP1OUT - bulk out * (max packet size of 512 bytes) * EP2IN - bulk in * (max packet size of 512 bytes) */ int transfer_bulk(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, unsigned int expected, int* last_trans) { int err; struct libusb_device_handle *h = (struct libusb_device_handle *)dev->priv; if (cnt > dev->max_transfer) cnt = dev->max_transfer; #ifdef DEBUG printf("report=%i\n", report); if (report < 3) dump_bytes(p, cnt, 0); #endif *last_trans = 0; err = libusb_bulk_transfer(h, (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); #ifdef DEBUG if (report >= 3) dump_bytes(p, cnt, 0); #endif return err; } #define ARRAY_SIZE(w) sizeof(w)/sizeof(w[0]) void print_usage(void) { printf("Usage: imx_usb [OPTIONS...] [JOBS...]\n" " e.g. imx_usb -v u-boot.imx\n" "Load data on target connected to USB using serial download protocol. The target\n" "type is detected using USB ID, a appropriate configuration file.\n" "\n" "Where OPTIONS are\n" " -h --help Show this help\n" " -v --verify Verify downloaded data\n" " -d --debugmode Enable debug logs\n" " -c --configdir=DIR Reading configuration directory from non standard\n" " directory.\n" " -b --bus=NUM Filter bus number.\n" " -D --device=NUM Filter device address.\n" "\n" "And where [JOBS...] are\n" " FILE [-lLOADADDR] [-sSIZE] ...\n" "Multiple jobs can be configured. The first job is treated special, load\n" "address, jump address, and length are read from the IVT header. If no job\n" "is specified, the jobs definied in the target specific configuration file\n" "is being used.\n"); } int parse_opts(int argc, char * const *argv, char const **configdir, int *verify, struct sdp_work **cmd_head, int *bus, int *address) { int c; static struct option long_options[] = { {"help", no_argument, 0, 'h' }, {"debugmode", no_argument, 0, 'd' }, {"verify", no_argument, 0, 'v' }, {"configdir", required_argument, 0, 'c' }, {"bus", required_argument, 0, 'b' }, {"device", required_argument, 0, 'D' }, {0, 0, 0, 0 }, }; while ((c = getopt_long(argc, argv, "+hdvc:b:D:", long_options, NULL)) != -1) { switch (c) { case 'h': case '?': print_usage(); return 1; case 'd': debugmode = 1; /* global extern */ break; case 'v': *verify = 1; break; case 'c': *configdir = optarg; break; case 'b': *bus = atoi(optarg); break; case 'D': *address = atoi(optarg); break; } } if (optind < argc) { // Parse optional job arguments... *cmd_head = parse_cmd_args(argc - optind, &argv[optind]); } else { *cmd_head = NULL; } return 0; } int do_work(struct sdp_dev *p_id, struct sdp_work **work, int verify) { struct sdp_work *curr = *work; int config = 0; int err = 0; libusb_device_handle *h = p_id->priv; libusb_get_configuration(h, &config); dbg_printf("bConfigurationValue = 0x%x\n", config); if (libusb_kernel_driver_active(h, 0)) libusb_detach_kernel_driver(h, 0); err = libusb_claim_interface(h, 0); if (err) { fprintf(stderr, "claim interface failed\n"); return err; } printf("Interface 0 claimed\n"); err = do_status(p_id); if (err) { fprintf(stderr, "status failed\n"); goto err_release_interface; } while (curr) { /* Do current job */ if (curr->mem) perform_mem_work(p_id, curr->mem); if (curr->filename[0]) err = DoIRomDownload(p_id, curr, verify); if (err) { fprintf(stderr, "DoIRomDownload failed, err=%d\n", err); do_status(p_id); break; } /* Check if more work is to do... */ if (!curr->next) { /* * If only one job, but with a plug-in is specified * reexecute the same job, but this time download the * image. This allows to specify a single file with * plugin and image, and imx_usb will download & run * the plugin first and then the image. * NOTE: If the file does not contain a plugin, * DoIRomDownload->process_header will set curr->plug * to 0, so we won't download the same image twice... */ if (curr->plug) { curr->plug = 0; } else { curr = NULL; break; } } else { curr = curr->next; } /* * Check if device is still here, otherwise return * with work (retry) */ err = do_status(p_id); if (err < 0) { err = 0; break; } } *work = curr; err_release_interface: libusb_release_interface(h, 0); return err; } int do_autodetect_dev(char const *base_path, char const *conf_path, struct mach_id *list, int verify, struct sdp_work *cmd_head, int bus, int address) { struct sdp_dev *p_id; struct mach_id *mach; libusb_device **devs; libusb_device *dev; int err = 0; ssize_t cnt; struct sdp_work *curr = NULL; libusb_device_handle *h = NULL; char const *conf; int retry; err = libusb_init(NULL); if (err < 0) return err; cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0) { err = LIBUSB_ERROR_NO_DEVICE; goto out_deinit_usb; } if (debugmode) print_devs(devs); dev = find_imx_dev(devs, &mach, list, bus, address); libusb_free_device_list(devs, 1); if (!dev) { err = LIBUSB_ERROR_NO_DEVICE; goto out_deinit_usb; } while (mach) { // Get machine specific configuration file.. conf = conf_file_name(mach->file_name, base_path, conf_path); if (conf == NULL) { err = LIBUSB_ERROR_OTHER; break; } p_id = parse_conf(conf); if (!p_id) { err = LIBUSB_ERROR_OTHER; break; } if (p_id->mode == MODE_HID) p_id->transfer = &transfer_hid; if (p_id->mode == MODE_BULK) p_id->transfer = &transfer_bulk; curr = p_id->work; // Prefer work from command line, disable batch mode... if (cmd_head) { curr = cmd_head; mach->nextbatch = NULL; } if (curr == NULL) { fprintf(stderr, "no job found\n"); err = LIBUSB_ERROR_OTHER; break; } // Wait for device... printf("Trying to open device vid=0x%04x pid=0x%04x", mach->vid, mach->pid); fflush(stdout); for (retry = 0; retry < 50; retry++) { h = libusb_open_device_with_vid_pid(NULL, mach->vid, mach->pid); if (h) break; msleep(500); if (retry % 2) printf("."); fflush(stdout); } printf("\n"); if (!h) { err = LIBUSB_ERROR_NO_DEVICE; fprintf(stderr, "Could not open device vid=0x%04x pid=0x%04x\n", mach->vid, mach->pid); break; } // USB private pointer is libusb device handle... p_id->priv = h; err = do_work(p_id, &curr, verify); dbg_printf("do_work finished with err=%d, curr=%p\n", err, curr); libusb_close(h); if (err) break; // We might have to retry the same machine in case of plugin... if (!curr) mach = mach->nextbatch; } out_deinit_usb: libusb_exit(NULL); return err; } int main(int argc, char * const argv[]) { int err; int verify = 0; struct sdp_work *cmd_head = NULL; char const *conf; char const *base_path = get_base_path(argv[0]); char const *conf_path = get_global_conf_path(); int bus = -1; int address = -1; err = parse_opts(argc, argv, &conf_path, &verify, &cmd_head, &bus, &address); if (err < 0) return EXIT_FAILURE; else if (err > 0) return EXIT_SUCCESS; // Get list of machines... conf = conf_file_name("imx_usb.conf", base_path, conf_path); if (conf == NULL) return EXIT_FAILURE; struct mach_id *list = parse_imx_conf(conf); if (!list) return EXIT_FAILURE; err = do_autodetect_dev(base_path, conf_path, list, verify, cmd_head, bus, address); if (err < 0) return EXIT_FAILURE; return EXIT_SUCCESS; }