1 /*
2  * DfuSe specific functions
3  *
4  * This implements the ST Microsystems DFU extensions (DfuSe)
5  * as per the DfuSe 1.1a specification (ST documents AN3156, AN2606)
6  * The DfuSe file format is described in ST document UM0391.
7  *
8  * Copyright 2010-2018 Tormod Volden <debian.tormod@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33 
34 #include "portable.h"
35 #include "dfu.h"
36 #include "usb_dfu.h"
37 #include "dfu_file.h"
38 #include "dfuse.h"
39 #include "dfuse_mem.h"
40 #include "quirks.h"
41 
42 #define DFU_TIMEOUT 5000
43 
44 extern int verbose;
45 static unsigned int last_erased_page = 1; /* non-aligned value, won't match */
46 static unsigned int dfuse_address = 0;
47 static unsigned int dfuse_address_present = 0;
48 static unsigned int dfuse_length = 0;
49 static int dfuse_force = 0;
50 static int dfuse_leave = 0;
51 static int dfuse_unprotect = 0;
52 static int dfuse_mass_erase = 0;
53 static int dfuse_will_reset = 0;
54 
quad2uint(unsigned char * p)55 static unsigned int quad2uint(unsigned char *p)
56 {
57 	return (*p + (*(p + 1) << 8) + (*(p + 2) << 16) + (*(p + 3) << 24));
58 }
59 
dfuse_parse_options(const char * options)60 static void dfuse_parse_options(const char *options)
61 {
62 	char *end;
63 	const char *endword;
64 	unsigned int number;
65 
66 	/* address, possibly empty, must be first */
67 	if (*options != ':') {
68 		endword = strchr(options, ':');
69 		if (!endword)
70 			endword = options + strlen(options); /* GNU strchrnul */
71 
72 		number = strtoul(options, &end, 0);
73 		if (end == endword) {
74 			dfuse_address = number;
75 			dfuse_address_present = 1;
76 		} else {
77 			errx(EX_USAGE, "Invalid dfuse address: %s", options);
78 		}
79 		options = endword;
80 	}
81 
82 	while (*options) {
83 		if (*options == ':') {
84 			options++;
85 			continue;
86 		}
87 		endword = strchr(options, ':');
88 		if (!endword)
89 			endword = options + strlen(options);
90 
91 		if (!strncmp(options, "force", endword - options)) {
92 			dfuse_force++;
93 			options += 5;
94 			continue;
95 		}
96 		if (!strncmp(options, "leave", endword - options)) {
97 			dfuse_leave = 1;
98 			options += 5;
99 			continue;
100 		}
101 		if (!strncmp(options, "unprotect", endword - options)) {
102 			dfuse_unprotect = 1;
103 			options += 9;
104 			continue;
105 		}
106 		if (!strncmp(options, "mass-erase", endword - options)) {
107 			dfuse_mass_erase = 1;
108 			options += 10;
109 			continue;
110 		}
111 		if (!strncmp(options, "will-reset", endword - options)) {
112 			dfuse_will_reset = 1;
113 			options += 10;
114 			continue;
115 		}
116 
117 		/* any valid number is interpreted as upload length */
118 		number = strtoul(options, &end, 0);
119 		if (end == endword) {
120 			dfuse_length = number;
121 		} else {
122 			errx(EX_USAGE, "Invalid dfuse modifier: %s", options);
123 		}
124 		options = endword;
125 	}
126 }
127 
128 /* DFU_UPLOAD request for DfuSe 1.1a */
dfuse_upload(struct dfu_if * dif,const unsigned short length,unsigned char * data,unsigned short transaction)129 static int dfuse_upload(struct dfu_if *dif, const unsigned short length,
130 		 unsigned char *data, unsigned short transaction)
131 {
132 	int status;
133 
134 	status = libusb_control_transfer(dif->dev_handle,
135 		 /* bmRequestType */	 LIBUSB_ENDPOINT_IN |
136 					 LIBUSB_REQUEST_TYPE_CLASS |
137 					 LIBUSB_RECIPIENT_INTERFACE,
138 		 /* bRequest      */	 DFU_UPLOAD,
139 		 /* wValue        */	 transaction,
140 		 /* wIndex        */	 dif->interface,
141 		 /* Data          */	 data,
142 		 /* wLength       */	 length,
143 					 DFU_TIMEOUT);
144 	if (status < 0) {
145 		warnx("dfuse_upload: libusb_control_transfer returned %d (%s)",
146 		      status, libusb_error_name(status));
147 	}
148 	return status;
149 }
150 
151 /* DFU_DNLOAD request for DfuSe 1.1a */
dfuse_download(struct dfu_if * dif,const unsigned short length,unsigned char * data,unsigned short transaction)152 static int dfuse_download(struct dfu_if *dif, const unsigned short length,
153 		   unsigned char *data, unsigned short transaction)
154 {
155 	int status;
156 
157 	status = libusb_control_transfer(dif->dev_handle,
158 		 /* bmRequestType */	 LIBUSB_ENDPOINT_OUT |
159 					 LIBUSB_REQUEST_TYPE_CLASS |
160 					 LIBUSB_RECIPIENT_INTERFACE,
161 		 /* bRequest      */	 DFU_DNLOAD,
162 		 /* wValue        */	 transaction,
163 		 /* wIndex        */	 dif->interface,
164 		 /* Data          */	 data,
165 		 /* wLength       */	 length,
166 					 DFU_TIMEOUT);
167 	if (status < 0) {
168 		/* Silently fail on leave request on some unpredictable devices */
169 		if ((dif->quirks & QUIRK_DFUSE_LEAVE) && !length && !data && transaction == 2)
170 			return status;
171 		warnx("dfuse_download: libusb_control_transfer returned %d (%s)",
172 		      status, libusb_error_name(status));
173 	}
174 	return status;
175 }
176 
177 /* DfuSe only commands */
178 /* Leaves the device in dfuDNLOAD-IDLE state */
dfuse_special_command(struct dfu_if * dif,unsigned int address,enum dfuse_command command)179 static int dfuse_special_command(struct dfu_if *dif, unsigned int address,
180 			  enum dfuse_command command)
181 {
182 	const char* dfuse_command_name[] = { "SET_ADDRESS" , "ERASE_PAGE",
183 					     "MASS_ERASE", "READ_UNPROTECT"};
184 	unsigned char buf[5];
185 	int length;
186 	int ret;
187 	struct dfu_status dst;
188 	int firstpoll = 1;
189 	int zerotimeouts = 0;
190 	int polltimeout = 0;
191 	int stalls = 0;
192 
193 	if (command == ERASE_PAGE) {
194 		struct memsegment *segment;
195 		int page_size;
196 
197 		segment = find_segment(dif->mem_layout, address);
198 		if (!segment || !(segment->memtype & DFUSE_ERASABLE)) {
199 			errx(EX_USAGE, "Page at 0x%08x can not be erased",
200 				address);
201 		}
202 		page_size = segment->pagesize;
203 		if (verbose)
204 			fprintf(stderr, "Erasing page size %i at address 0x%08x, page "
205 			       "starting at 0x%08x\n", page_size, address,
206 			       address & ~(page_size - 1));
207 		buf[0] = 0x41;	/* Erase command */
208 		length = 5;
209 		last_erased_page = address & ~(page_size - 1);
210 	} else if (command == SET_ADDRESS) {
211 		if (verbose > 1)
212 			fprintf(stderr, "  Setting address pointer to 0x%08x\n",
213 			       address);
214 		buf[0] = 0x21;	/* Set Address Pointer command */
215 		length = 5;
216 	} else if (command == MASS_ERASE) {
217 		buf[0] = 0x41;	/* Mass erase command when length = 1 */
218 		length = 1;
219 	} else if (command == READ_UNPROTECT) {
220 		buf[0] = 0x92;
221 		length = 1;
222 	} else {
223 		errx(EX_SOFTWARE, "Non-supported special command %d", command);
224 	}
225 	buf[1] = address & 0xff;
226 	buf[2] = (address >> 8) & 0xff;
227 	buf[3] = (address >> 16) & 0xff;
228 	buf[4] = (address >> 24) & 0xff;
229 
230 	ret = dfuse_download(dif, length, buf, 0);
231 	if (ret < 0) {
232 		errx(EX_IOERR, "Error during special command \"%s\" download",
233 			dfuse_command_name[command]);
234 	}
235 	do {
236 		ret = dfu_get_status(dif, &dst);
237 		/* Workaround for some STM32L4 bootloaders that report a too
238 		 * short poll timeout and may stall the pipe when we poll */
239 		if (ret == LIBUSB_ERROR_PIPE && polltimeout != 0 && stalls < 3) {
240 			dst.bState = DFU_STATE_dfuDNBUSY;
241 			stalls++;
242 			if (verbose)
243 				fprintf(stderr, "* Device stalled USB pipe, reusing last poll timeout\n");
244 		} else if (ret < 0) {
245 			errx(EX_IOERR, "Error during special command \"%s\" get_status",
246 			     dfuse_command_name[command]);
247 		} else {
248 			polltimeout = dst.bwPollTimeout;
249 		}
250 		if (firstpoll) {
251 			firstpoll = 0;
252 			if (dst.bState != DFU_STATE_dfuDNBUSY) {
253 				fprintf(stderr, "DFU state(%u) = %s, status(%u) = %s\n", dst.bState,
254 				       dfu_state_to_string(dst.bState), dst.bStatus,
255 				       dfu_status_to_string(dst.bStatus));
256 				errx(EX_PROTOCOL, "Wrong state after command \"%s\" download",
257 				     dfuse_command_name[command]);
258 			}
259 			/* STM32F405 lies about mass erase timeout */
260 			if (command == MASS_ERASE && dst.bwPollTimeout == 100) {
261 				polltimeout = 35000; /* Datasheet says up to 32 seconds */
262 				printf("Setting timeout to 35 seconds\n");
263 			}
264 		}
265 		/* wait while command is executed */
266 		if (verbose > 1)
267 			fprintf(stderr, "   Poll timeout %i ms\n", polltimeout);
268 		milli_sleep(polltimeout);
269 		if (command == READ_UNPROTECT)
270 			return ret;
271 		/* Workaround for e.g. Black Magic Probe getting stuck */
272 		if (dst.bwPollTimeout == 0) {
273 			if (++zerotimeouts == 100)
274 				errx(EX_IOERR, "Device stuck after special command request");
275 		} else {
276 			zerotimeouts = 0;
277 		}
278 	} while (dst.bState == DFU_STATE_dfuDNBUSY);
279 
280 	if (dst.bStatus != DFU_STATUS_OK) {
281 		errx(EX_IOERR, "%s not correctly executed",
282 			dfuse_command_name[command]);
283 	}
284 	return ret;
285 }
286 
287 /* returns number of bytes sent */
dfuse_dnload_chunk(struct dfu_if * dif,unsigned char * data,int size,int transaction)288 static int dfuse_dnload_chunk(struct dfu_if *dif, unsigned char *data, int size,
289 		       int transaction)
290 {
291 	int bytes_sent;
292 	struct dfu_status dst;
293 	int ret;
294 
295 	ret = dfuse_download(dif, size, size ? data : NULL, transaction);
296 	if (ret < 0) {
297 		errx(EX_IOERR, "Error during download");
298 		return ret;
299 	}
300 	bytes_sent = ret;
301 
302 	do {
303 		ret = dfu_get_status(dif, &dst);
304 		if (ret < 0) {
305 			errx(EX_IOERR, "Error during download get_status");
306 			return ret;
307 		}
308 		milli_sleep(dst.bwPollTimeout);
309 	} while (dst.bState != DFU_STATE_dfuDNLOAD_IDLE &&
310 		 dst.bState != DFU_STATE_dfuERROR &&
311 		 dst.bState != DFU_STATE_dfuMANIFEST &&
312 		 !(dfuse_will_reset && (dst.bState == DFU_STATE_dfuDNBUSY)));
313 
314 	if (dst.bState == DFU_STATE_dfuMANIFEST)
315 			printf("Transitioning to dfuMANIFEST state\n");
316 
317 	if (dst.bStatus != DFU_STATUS_OK) {
318 		printf(" failed!\n");
319 		fprintf(stderr, "DFU state(%u) = %s, status(%u) = %s\n", dst.bState,
320 		       dfu_state_to_string(dst.bState), dst.bStatus,
321 		       dfu_status_to_string(dst.bStatus));
322 		return -1;
323 	}
324 	return bytes_sent;
325 }
326 
dfuse_do_leave(struct dfu_if * dif)327 static void dfuse_do_leave(struct dfu_if *dif)
328 {
329 	if (dfuse_address_present)
330 		dfuse_special_command(dif, dfuse_address, SET_ADDRESS);
331 	printf("Submitting leave request...\n");
332 	if (dif->quirks & QUIRK_DFUSE_LEAVE) {
333 		struct dfu_status dst;
334 		/* The device might leave after this request, with or without a response */
335 		dfuse_download(dif, 0, NULL, 2);
336 		/* Or it might leave after this request, with or without a response */
337 		dfu_get_status(dif, &dst);
338 	} else {
339 		dfuse_dnload_chunk(dif, NULL, 0, 2);
340 	}
341 }
342 
dfuse_do_upload(struct dfu_if * dif,int xfer_size,int fd,const char * dfuse_options)343 int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd,
344 		    const char *dfuse_options)
345 {
346 	int total_bytes = 0;
347 	int upload_limit = 0;
348 	unsigned char *buf;
349 	int transaction;
350 	int ret;
351 
352 	buf = dfu_malloc(xfer_size);
353 
354 	if (dfuse_options)
355 		dfuse_parse_options(dfuse_options);
356 	if (dfuse_length)
357 		upload_limit = dfuse_length;
358 	if (dfuse_address_present) {
359 		struct memsegment *mem_layout, *segment;
360 
361 		mem_layout = parse_memory_layout((char *)dif->alt_name);
362 		if (!mem_layout)
363 			errx(EX_IOERR, "Failed to parse memory layout");
364 		if (dif->quirks & QUIRK_DFUSE_LAYOUT)
365 			fixup_dfuse_layout(dif, &mem_layout);
366 
367 		segment = find_segment(mem_layout, dfuse_address);
368 		if (!dfuse_force &&
369 		    (!segment || !(segment->memtype & DFUSE_READABLE)))
370 			errx(EX_USAGE, "Page at 0x%08x is not readable",
371 				dfuse_address);
372 
373 		if (!upload_limit) {
374 			if (segment) {
375 				upload_limit = segment->end - dfuse_address + 1;
376 				printf("Limiting upload to end of memory segment, "
377 				       "%i bytes\n", upload_limit);
378 			} else {
379 				/* unknown segment - i.e. "force" has been used */
380 				upload_limit = 0x4000;
381 				printf("Limiting upload to %i bytes\n", upload_limit);
382 			}
383 		}
384 		dfuse_special_command(dif, dfuse_address, SET_ADDRESS);
385 		dfu_abort_to_idle(dif);
386 	} else {
387 		/* Boot loader decides the start address, unknown to us */
388 		/* Use a short length to lower risk of running out of bounds */
389 		if (!upload_limit) {
390 			warnx("Unbound upload not supported on DfuSe devices");
391 			upload_limit = 0x4000;
392 		}
393 		printf("Limiting default upload to %i bytes\n", upload_limit);
394 	}
395 
396 	dfu_progress_bar("Upload", 0, 1);
397 
398 	transaction = 2;
399 	while (1) {
400 		int rc;
401 
402 		/* last chunk can be smaller than original xfer_size */
403 		if (upload_limit - total_bytes < xfer_size)
404 			xfer_size = upload_limit - total_bytes;
405 		rc = dfuse_upload(dif, xfer_size, buf, transaction++);
406 		if (rc < 0) {
407 			ret = rc;
408 			goto out_free;
409 		}
410 
411 		dfu_file_write_crc(fd, 0, buf, rc);
412 		total_bytes += rc;
413 
414 		if (total_bytes < 0)
415 			errx(EX_SOFTWARE, "Received too many bytes");
416 
417 		if (rc < xfer_size || total_bytes >= upload_limit) {
418 			/* last block, return successfully */
419 			ret = 0;
420 			break;
421 		}
422 		dfu_progress_bar("Upload", total_bytes, upload_limit);
423 	}
424 
425 	dfu_progress_bar("Upload", total_bytes, total_bytes);
426 
427 	dfu_abort_to_idle(dif);
428 	if (dfuse_leave)
429 		dfuse_do_leave(dif);
430 
431  out_free:
432 	free(buf);
433 
434 	return ret;
435 }
436 
437 /* Writes an element of any size to the device, taking care of page erases */
438 /* returns 0 on success, otherwise -EINVAL */
dfuse_dnload_element(struct dfu_if * dif,unsigned int dwElementAddress,unsigned int dwElementSize,unsigned char * data,int xfer_size)439 static int dfuse_dnload_element(struct dfu_if *dif, unsigned int dwElementAddress,
440 			 unsigned int dwElementSize, unsigned char *data,
441 			 int xfer_size)
442 {
443 	int p;
444 	int ret;
445 	struct memsegment *segment;
446 
447 	/* Check at least that we can write to the last address */
448 	segment =
449 	    find_segment(dif->mem_layout, dwElementAddress + dwElementSize - 1);
450 	if (!dfuse_force &&
451             (!segment || !(segment->memtype & DFUSE_WRITEABLE))) {
452 		errx(EX_USAGE, "Last page at 0x%08x is not writeable",
453 			dwElementAddress + dwElementSize - 1);
454 	}
455 
456 	if (!verbose)
457 		dfu_progress_bar("Erase   ", 0, 1);
458 
459 	/* First pass: Erase involved pages if needed */
460 	for (p = 0; p < (int)dwElementSize; p += xfer_size) {
461 		int page_size;
462 		unsigned int erase_address;
463 		unsigned int address = dwElementAddress + p;
464 		int chunk_size = xfer_size;
465 
466 		segment = find_segment(dif->mem_layout, address);
467 		if (!dfuse_force &&
468 		    (!segment || !(segment->memtype & DFUSE_WRITEABLE))) {
469 			errx(EX_USAGE, "Page at 0x%08x is not writeable",
470 				address);
471 		}
472 		/* If the location is not in the memory map we skip erasing */
473 		/* since we wouldn't know the correct page size for flash erase */
474 		if (!segment)
475 			continue;
476 
477 		page_size = segment->pagesize;
478 
479 		/* check if this is the last chunk */
480 		if (p + chunk_size > (int)dwElementSize)
481 			chunk_size = dwElementSize - p;
482 
483 		/* Erase only for flash memory downloads */
484 		if ((segment->memtype & DFUSE_ERASABLE) && !dfuse_mass_erase) {
485 			/* erase all involved pages */
486 			for (erase_address = address;
487 			     erase_address < address + chunk_size;
488 			     erase_address += page_size)
489 				if ((erase_address & ~(page_size - 1)) !=
490 				    last_erased_page)
491 					dfuse_special_command(dif,
492 							      erase_address,
493 							      ERASE_PAGE);
494 
495 			if (((address + chunk_size - 1) & ~(page_size - 1)) !=
496 			    last_erased_page) {
497 				if (verbose > 1)
498 					fprintf(stderr, " Chunk extends into next page,"
499 					       " erase it as well\n");
500 				dfuse_special_command(dif,
501 						      address + chunk_size - 1,
502 						      ERASE_PAGE);
503 			}
504 			if (!verbose)
505 				dfu_progress_bar("Erase   ", p, dwElementSize);
506 		}
507 	}
508 	if (!verbose)
509 		dfu_progress_bar("Erase   ", dwElementSize, dwElementSize);
510 	if (!verbose)
511 		dfu_progress_bar("Download", 0, 1);
512 
513 	/* Second pass: Write data to (erased) pages */
514 	for (p = 0; p < (int)dwElementSize; p += xfer_size) {
515 		unsigned int address = dwElementAddress + p;
516 		int chunk_size = xfer_size;
517 
518 		/* check if this is the last chunk */
519 		if (p + chunk_size > (int)dwElementSize)
520 			chunk_size = dwElementSize - p;
521 
522 		if (verbose) {
523 			fprintf(stderr, " Download from image offset "
524 			       "%08x to memory %08x-%08x, size %i\n",
525 			       p, address, address + chunk_size - 1,
526 			       chunk_size);
527 		} else {
528 			dfu_progress_bar("Download", p, dwElementSize);
529 		}
530 
531 		dfuse_special_command(dif, address, SET_ADDRESS);
532 
533 		/* transaction = 2 for no address offset */
534 		ret = dfuse_dnload_chunk(dif, data + p, chunk_size, 2);
535 		if (ret != chunk_size) {
536 			errx(EX_IOERR, "Failed to write whole chunk: "
537 				"%i of %i bytes", ret, chunk_size);
538 			return -EINVAL;
539 		}
540 	}
541 	if (!verbose)
542 		dfu_progress_bar("Download", dwElementSize, dwElementSize);
543 	return 0;
544 }
545 
546 static void
dfuse_memcpy(unsigned char * dst,unsigned char ** src,int * rem,int size)547 dfuse_memcpy(unsigned char *dst, unsigned char **src, int *rem, int size)
548 {
549 	if (size > *rem) {
550 		errx(EX_NOINPUT, "Corrupt DfuSe file: "
551 		    "Cannot read %d bytes from %d bytes", size, *rem);
552 	}
553 	if (dst != NULL)
554 		memcpy(dst, *src, size);
555 	(*src) += size;
556 	(*rem) -= size;
557 }
558 
559 /* Download raw binary file to DfuSe device */
dfuse_do_bin_dnload(struct dfu_if * dif,int xfer_size,struct dfu_file * file,unsigned int start_address)560 static int dfuse_do_bin_dnload(struct dfu_if *dif, int xfer_size,
561 			struct dfu_file *file, unsigned int start_address)
562 {
563 	unsigned int dwElementAddress;
564 	unsigned int dwElementSize;
565 	unsigned char *data;
566 	int ret;
567 
568 	dwElementAddress = start_address;
569 	dwElementSize = file->size.total -
570 	    file->size.suffix - file->size.prefix;
571 
572 	printf("Downloading element to address = 0x%08x, size = %i\n",
573 	       dwElementAddress, dwElementSize);
574 
575 	data = file->firmware + file->size.prefix;
576 
577 	ret = dfuse_dnload_element(dif, dwElementAddress, dwElementSize, data,
578 				   xfer_size);
579 	if (ret == 0)
580 		printf("File downloaded successfully\n");
581 
582 	return ret;
583 }
584 
585 /* Parse a DfuSe file and download contents to device */
dfuse_do_dfuse_dnload(struct dfu_if * dif,int xfer_size,struct dfu_file * file)586 static int dfuse_do_dfuse_dnload(struct dfu_if *dif, int xfer_size,
587 			  struct dfu_file *file)
588 {
589 	uint8_t dfuprefix[11];
590 	uint8_t targetprefix[274];
591 	uint8_t elementheader[8];
592 	int image;
593 	int element;
594 	int bTargets;
595 	int bAlternateSetting;
596 	struct dfu_if *adif;
597 	int dwNbElements;
598 	unsigned int dwElementAddress;
599 	unsigned int dwElementSize;
600 	uint8_t *data;
601 	int ret;
602 	int rem;
603 	int bFirstAddressSaved = 0;
604 
605 	rem = file->size.total - file->size.prefix - file->size.suffix;
606 	data = file->firmware + file->size.prefix;
607 
608         /* Must be larger than a minimal DfuSe header and suffix */
609 	if (rem < (int)(sizeof(dfuprefix) +
610 	    sizeof(targetprefix) + sizeof(elementheader))) {
611 		errx(EX_DATAERR, "File too small for a DfuSe file");
612         }
613 
614 	dfuse_memcpy(dfuprefix, &data, &rem, sizeof(dfuprefix));
615 
616 	if (strncmp((char *)dfuprefix, "DfuSe", 5)) {
617 		errx(EX_DATAERR, "No valid DfuSe signature");
618 		return -EINVAL;
619 	}
620 	if (dfuprefix[5] != 0x01) {
621 		errx(EX_DATAERR, "DFU format revision %i not supported",
622 			dfuprefix[5]);
623 		return -EINVAL;
624 	}
625 	bTargets = dfuprefix[10];
626 	printf("File contains %i DFU images\n", bTargets);
627 
628 	for (image = 1; image <= bTargets; image++) {
629 		printf("Parsing DFU image %i\n", image);
630 		dfuse_memcpy(targetprefix, &data, &rem, sizeof(targetprefix));
631 		if (strncmp((char *)targetprefix, "Target", 6)) {
632 			errx(EX_DATAERR, "No valid target signature");
633 			return -EINVAL;
634 		}
635 		bAlternateSetting = targetprefix[6];
636 		if (targetprefix[7])
637 			printf("Target name: %s\n", &targetprefix[11]);
638 		else
639 			printf("No target name\n");
640 		dwNbElements = quad2uint((unsigned char *)targetprefix + 270);
641 		printf("Image for alternate setting %i, ", bAlternateSetting);
642 		printf("(%i elements, ", dwNbElements);
643 		printf("total size = %i)\n",
644 		       quad2uint((unsigned char *)targetprefix + 266));
645 
646 		adif = dif;
647 		while (adif) {
648 			if (bAlternateSetting == adif->altsetting) {
649 				adif->dev_handle = dif->dev_handle;
650 				printf("Setting Alternate Interface #%d ...\n",
651 				       adif->altsetting);
652 				ret = libusb_set_interface_alt_setting(
653 					  adif->dev_handle,
654 					  adif->interface, adif->altsetting);
655 				if (ret < 0) {
656 					errx(EX_IOERR,
657 					  "Cannot set alternate interface: %s",
658 					  libusb_error_name(ret));
659 				}
660 				break;
661 			}
662 			adif = adif->next;
663 		}
664 		if (!adif)
665 			warnx("No alternate setting %d (skipping elements)",
666 			     bAlternateSetting);
667 
668 		for (element = 1; element <= dwNbElements; element++) {
669 			printf("Parsing element %i, ", element);
670 			dfuse_memcpy(elementheader, &data, &rem, sizeof(elementheader));
671 			dwElementAddress =
672 			    quad2uint((unsigned char *)elementheader);
673 			dwElementSize =
674 			    quad2uint((unsigned char *)elementheader + 4);
675 			printf("address = 0x%08x, ", dwElementAddress);
676 			printf("size = %i\n", dwElementSize);
677 
678 			if (!bFirstAddressSaved) {
679 				bFirstAddressSaved = 1;
680 				dfuse_address = dwElementAddress;
681 			}
682 			/* sanity check */
683 			if ((int)dwElementSize > rem)
684 				errx(EX_DATAERR, "File too small for element size");
685 
686 			if (adif)
687 				ret = dfuse_dnload_element(adif, dwElementAddress,
688 							   dwElementSize, data, xfer_size);
689 			else
690 				ret = 0;
691 
692 			/* advance read pointer */
693 			dfuse_memcpy(NULL, &data, &rem, dwElementSize);
694 
695 			if (ret != 0)
696 				return ret;
697 		}
698 	}
699 
700 	if (rem != 0)
701 		warnx("%d bytes leftover", rem);
702 
703 	printf("Done parsing DfuSe file\n");
704 
705 	return 0;
706 }
707 
dfuse_do_dnload(struct dfu_if * dif,int xfer_size,struct dfu_file * file,const char * dfuse_options)708 int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file,
709 		    const char *dfuse_options)
710 {
711 	int ret;
712 	struct dfu_if *adif;
713 
714 	if (dfuse_options)
715 		dfuse_parse_options(dfuse_options);
716 
717 	adif = dif;
718 	while (adif) {
719 		adif->mem_layout = parse_memory_layout((char *)adif->alt_name);
720 		if (!adif->mem_layout)
721 			errx(EX_IOERR,
722 			     "Failed to parse memory layout for alternate interface %i",
723 			     adif->altsetting);
724 		if (adif->quirks & QUIRK_DFUSE_LAYOUT)
725 			fixup_dfuse_layout(adif, &(adif->mem_layout));
726 		adif = adif->next;
727 	}
728 
729 	if (dfuse_unprotect) {
730 		if (!dfuse_force) {
731 			errx(EX_USAGE, "The read unprotect command "
732 				"will erase the flash memory"
733 				"and can only be used with force\n");
734 		}
735 		ret = dfuse_special_command(dif, 0, READ_UNPROTECT);
736 		printf("Device disconnects, erases flash and resets now\n");
737 		return ret;
738 	}
739 	if (dfuse_mass_erase) {
740 		if (!dfuse_force) {
741 			errx(EX_USAGE, "The mass erase command "
742 				"can only be used with force");
743 		}
744 		printf("Performing mass erase, this can take a moment\n");
745 		ret = dfuse_special_command(dif, 0, MASS_ERASE);
746 	}
747 	if (!file->name) {
748 		printf("DfuSe command mode\n");
749 		ret = 0;
750 	} else if (dfuse_address_present) {
751 		if (file->bcdDFU == 0x11a) {
752 			errx(EX_USAGE, "This is a DfuSe file, not "
753 				"meant for raw download");
754 		}
755 		ret = dfuse_do_bin_dnload(dif, xfer_size, file, dfuse_address);
756 	} else {
757 		if (file->bcdDFU != 0x11a) {
758 			warnx("Only DfuSe file version 1.1a is supported");
759 			errx(EX_USAGE, "(for raw binary download, use the "
760 			     "--dfuse-address option)");
761 		}
762 		ret = dfuse_do_dfuse_dnload(dif, xfer_size, file);
763 	}
764 
765 	adif = dif;
766 	while (adif) {
767 		free_segment_list(adif->mem_layout);
768 		adif = adif->next;
769 	}
770 
771 	if (!dfuse_will_reset) {
772 		dfu_abort_to_idle(dif);
773 	}
774 
775 	if (dfuse_leave)
776 		dfuse_do_leave(dif);
777 
778 	return ret;
779 }
780 
781 /* Check if we have one interface, possibly multiple alternate interfaces */
dfuse_multiple_alt(struct dfu_if * dfu_root)782 int dfuse_multiple_alt(struct dfu_if *dfu_root)
783 {
784 	libusb_device *dev = dfu_root->dev;
785 	uint8_t configuration = dfu_root->configuration;
786 	uint8_t interface = dfu_root->interface;
787 	struct dfu_if *dif = dfu_root->next;
788 
789 	while (dif) {
790 		if (dev != dif->dev ||
791 		    configuration != dif->configuration ||
792 		    interface != dif->interface)
793 			return 0;
794 		dif = dif->next;
795 	}
796 	return 1;
797 }
798