lpcboot.c (6133B)
1 /* lpcboot.c 2 * 3 * Copyright 2011 Brian Swetland <swetland@frotz.net> 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 #include <string.h> 22 #include <fcntl.h> 23 #include <stdint.h> 24 25 #include "usb.h" 26 27 int usage(void) { 28 fprintf(stderr, 29 "lpcboot usage\n-------------\n" 30 " lpcboot query display information about target\n" 31 " lpcboot boot <app> download app to ram and execute\n" 32 " lpcboot flash <app> write app image to flash\n" 33 " lpcboot erase erase app image\n" 34 " lpcboot reboot reboot the bootloader\n" 35 " lpcboot app reboot into the app in flash\n"); 36 return -1; 37 } 38 39 struct device_info { 40 char part[16]; 41 char board[16]; 42 uint32_t version; 43 uint32_t ram_base; 44 uint32_t ram_size; 45 uint32_t rom_base; 46 uint32_t rom_size; 47 uint32_t ununsed0; 48 uint32_t ununsed1; 49 uint32_t ununsed2; 50 }; 51 52 #define DFU_DETACH 0 53 #define DFU_DNLOAD 1 54 #define DFU_UPLOAD 2 55 #define DFU_GETSTATUS 3 56 #define DFU_CLRSTATUS 4 57 #define DFU_GETSTATE 5 58 #define DFU_ABORT 6 59 60 #define STATE_APP_IDLE 0x00 61 #define STATE_APP_DETACH 0x01 62 #define STATE_DFU_IDLE 0x02 63 #define STATE_DFU_DOWNLOAD_SYNC 0x03 64 #define STATE_DFU_DOWNLOAD_BUSY 0x04 65 #define STATE_DFU_DOWNLOAD_IDLE 0x05 66 #define STATE_DFU_MANIFEST_SYNC 0x06 67 #define STATE_DFU_MANIFEST 0x07 68 #define STATE_DFU_MANIFEST_WAIT_RESET 0x08 69 #define STATE_DFU_UPLOAD_IDLE 0x09 70 #define STATE_DFU_ERROR 0x0a 71 72 // 0xA1 getstatus: status[1] pollms[3] state[1] stridx[1] 73 int dfu_status(usb_handle *usb, unsigned *state) { 74 uint8_t io[6]; 75 if (usb_ctrl(usb, io, 0xA1, DFU_GETSTATUS, 0, 0, 6) != 6) { 76 fprintf(stderr, "dfu status: io error\n"); 77 return -1; 78 } 79 if (io[0]) { 80 fprintf(stderr, "dfu status: 0x%02x\n", io[0]); 81 return io[0]; 82 } 83 *state = io[4]; 84 return 0; 85 } 86 87 static uint8_t lpcheader[16] = { 88 0xda, 0xff, 0x40, 0x00, 0xff, 0xff, 0xff, 0xff, 89 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 90 }; 91 92 int dfu_download(void *_data, unsigned sz) { 93 int once = 1; 94 uint8_t *data = _data; 95 usb_handle *usb; 96 unsigned state; 97 unsigned xfer; 98 uint16_t count = 0; 99 for (;;) { 100 usb = usb_open(0x1fc9, 0x000c, 0); 101 if (usb == 0) { 102 if (once) { 103 fprintf(stderr,"waiting for DFU device...\n"); 104 once = 0; 105 } 106 } else { 107 break; 108 } 109 } 110 if (dfu_status(usb, &state)) return -1; 111 if (state != STATE_DFU_IDLE) { 112 fprintf(stderr, "dfu state not idle (0x%02x)?\n", state); 113 return -1; 114 } 115 116 // prepend isp header 117 data -= 16; 118 sz += 16; 119 memcpy(data, lpcheader, 16); 120 121 // send binary 122 while (sz > 0) { 123 fprintf(stderr,"."); 124 xfer = (sz > 2048) ? 2048 : sz; 125 if (usb_ctrl(usb, data, 0x21, DFU_DNLOAD, count, 0, xfer) != xfer) { 126 fprintf(stderr,"\ndfu dnload: io error\n"); 127 return -1; 128 } 129 count++; 130 data += xfer; 131 sz -= xfer; 132 if (dfu_status(usb, &state)) return -1; 133 if (state != STATE_DFU_DOWNLOAD_IDLE) { 134 fprintf(stderr,"\ndfu dnload state 0x%02x?!\n", state); 135 return -1; 136 } 137 } 138 if (usb_ctrl(usb, NULL, 0x21, DFU_DNLOAD, 0, 0, 0) != 0) { 139 fprintf(stderr,"\ndfu dnload2: io error\n"); 140 return -1; 141 } 142 fprintf(stderr,"\ndone\n"); 143 if (dfu_status(usb, &state)) return -1; 144 if (state == STATE_DFU_MANIFEST_WAIT_RESET) return 0; 145 fprintf(stderr,"dfu dnload2: state 0x%02x?!\n", state); 146 return -1; 147 } 148 149 int main(int argc, char **argv) { 150 usb_handle *usb; 151 char buf[1024*1024+256]; 152 int fd, once = 1, sz = 0, dl = 0, dfu = 0; 153 uint32_t cmd[3]; 154 uint32_t rep[2]; 155 struct device_info di; 156 157 if (argc < 2) 158 return usage(); 159 160 cmd[0] = 0xDB00A5A5; 161 if (!strcmp(argv[1],"flash")) { 162 dl = 1; 163 cmd[1] = 'W'; 164 } else if (!strcmp(argv[1],"flash:boot")) { 165 dl = 1; 166 cmd[1] = 'w'; 167 } else if (!strcmp(argv[1],"boot")) { 168 dl = 1; 169 cmd[1] = 'X'; 170 } else if (!strcmp(argv[1],"erase")) { 171 cmd[1] = 'E'; 172 } else if (!strcmp(argv[1],"query")) { 173 cmd[1] = 'Q'; 174 } else if (!strcmp(argv[1],"reboot")) { 175 cmd[1] = 'R'; 176 } else if (!strcmp(argv[1],"app")) { 177 cmd[1] = 'A'; 178 } else if (!strcmp(argv[1],"dfu")) { 179 dl = 1; 180 dfu = 1; 181 } else { 182 return usage(); 183 } 184 185 if (dl) { 186 if (argc < 3) 187 return usage(); 188 fd = open(argv[2], O_RDONLY); 189 sz = read(fd, buf + 256, sizeof(buf) - 256); 190 close(fd); 191 if ((fd < 0) || (sz < 1)) { 192 fprintf(stderr,"error: cannot read '%s'\n", argv[2]); 193 return -1; 194 } 195 } 196 cmd[2] = sz; 197 198 if (dfu) { 199 return dfu_download(buf + 256, sz); 200 } 201 for (;;) { 202 usb = usb_open(0x18d1, 0xdb00, 0); 203 if (usb == 0) { 204 if (once) { 205 fprintf(stderr,"waiting for device...\n"); 206 once = 0; 207 } 208 } else { 209 break; 210 } 211 } 212 213 if (usb_write(usb, cmd, 12) != 12) { 214 fprintf(stderr,"io error\n"); 215 return -1; 216 } 217 for (;;) { 218 if (usb_read(usb, rep, 8) != 8) { 219 fprintf(stderr,"io error\n"); 220 return -1; 221 } 222 if (rep[0] != 0xDB00A5A5) { 223 fprintf(stderr,"protocol error\n"); 224 return -1; 225 } 226 if (rep[1] != 0) { 227 fprintf(stderr,"%s failure\n", argv[1]); 228 return -1; 229 } 230 if (!strcmp(argv[1],"query")) { 231 if (usb_read(usb, &di, sizeof(di)) != sizeof(di)) { 232 fprintf(stderr,"io error\n"); 233 return -1; 234 } 235 fprintf(stderr,"Part: %s\n", di.part); 236 fprintf(stderr,"Board: %s\n", di.board); 237 fprintf(stderr,"RAM: @%08x (%dKB)\n", 238 di.ram_base, di.ram_size / 1024); 239 fprintf(stderr,"Flash: @%08x (%dKB)\n", 240 di.rom_base, di.rom_size / 1024); 241 return 0; 242 } 243 if (!dl) 244 break; 245 fprintf(stderr,"sending %d bytes...\n", sz); 246 if (usb_write(usb, buf + 256, sz) != sz) { 247 fprintf(stderr,"download failure %d\n", sz); 248 return -1; 249 } 250 dl = 0; 251 } 252 fprintf(stderr,"OKAY\n"); 253 return 0; 254 }