Implement the meat of FLIP version 1 protocol, and document it.
git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1269 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
parent
fcb5db7152
commit
4c645d7945
|
@ -1,3 +1,9 @@
|
||||||
|
2014-01-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
||||||
|
|
||||||
|
* flip1.c: Implement the meat of FLIP version 1 protocol.
|
||||||
|
* avrdude.1: Document the new protocol.
|
||||||
|
* doc/avrdude.texi: (Dito.)
|
||||||
|
|
||||||
2014-01-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
2014-01-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
|
||||||
|
|
||||||
* flip2.c (flip2_page_erase): Remove unimplemented function.
|
* flip2.c (flip2_page_erase): Remove unimplemented function.
|
||||||
|
|
3
NEWS
3
NEWS
|
@ -14,7 +14,8 @@ Current:
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
* New programmers supported:
|
* New programmers supported:
|
||||||
- FLIP v2 (Atmel DFU protocol)
|
- Atmel DFU, using FLIP protocol version 1 (AT90USB and ATmega*U* devices),
|
||||||
|
or version 2 (Xmega devices)
|
||||||
|
|
||||||
* Bugfixes
|
* Bugfixes
|
||||||
- bug #40055: AVRDUDE segfaults when writing eeprom
|
- bug #40055: AVRDUDE segfaults when writing eeprom
|
||||||
|
|
38
avrdude.1
38
avrdude.1
|
@ -18,7 +18,7 @@
|
||||||
.\"
|
.\"
|
||||||
.\" $Id$
|
.\" $Id$
|
||||||
.\"
|
.\"
|
||||||
.Dd DATE September 13, 2013
|
.Dd DATE January 17, 2014
|
||||||
.Os
|
.Os
|
||||||
.Dt AVRDUDE 1
|
.Dt AVRDUDE 1
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -175,7 +175,9 @@ the avrftdi device adds support for many programmers using FTDI's 2232C/D/H
|
||||||
and 4232H parts running in MPSSE mode, which hard-codes (in the chip)
|
and 4232H parts running in MPSSE mode, which hard-codes (in the chip)
|
||||||
SCK to bit 1, MOSI to bit 2, and MISO to bit 3. Reset is usually bit 4.
|
SCK to bit 1, MOSI to bit 2, and MISO to bit 3. Reset is usually bit 4.
|
||||||
.Pp
|
.Pp
|
||||||
The Atmel DFU bootloader is supported in version 2 (Xmega devices).
|
The Atmel DFU bootloader is supported in both, FLIP protocol version 1
|
||||||
|
(AT90USB* and ATmega*U* devices), as well as version 2 (Xmega devices).
|
||||||
|
See below for some hints about FLIP version 1 protocol behaviour.
|
||||||
.Pp
|
.Pp
|
||||||
Input files can be provided, and output files can be written in
|
Input files can be provided, and output files can be written in
|
||||||
different file formats, such as raw binary files containing the data
|
different file formats, such as raw binary files containing the data
|
||||||
|
@ -848,6 +850,38 @@ be accessed using normal ISP programming.
|
||||||
This sequence is automatically initiated by using the JTAG ICE mkII
|
This sequence is automatically initiated by using the JTAG ICE mkII
|
||||||
or AVR Dragon in ISP mode, when they detect that ISP mode cannot be
|
or AVR Dragon in ISP mode, when they detect that ISP mode cannot be
|
||||||
entered.
|
entered.
|
||||||
|
.Ss FLIP version 1 idiosyncrasies
|
||||||
|
Bootloaders using the FLIP protocol version 1 experience some very
|
||||||
|
specific behaviour.
|
||||||
|
.Pp
|
||||||
|
These bootloaders have no option to access memory areas other than
|
||||||
|
Flash and EEPROM.
|
||||||
|
.Pp
|
||||||
|
When the bootloader is started, it enters a
|
||||||
|
.Em security mode
|
||||||
|
where the only acceptable access is to query the device configuration
|
||||||
|
parameters (which are used for the signature on AVR devices).
|
||||||
|
The only way to leave this mode is a
|
||||||
|
.Em chip erase .
|
||||||
|
As a chip erase is normally implied by the
|
||||||
|
.Fl U
|
||||||
|
option when reprogramming the flash, this peculiarity might not be
|
||||||
|
very obvious immediately.
|
||||||
|
.Pp
|
||||||
|
Sometimes, a bootloader with security mode already disabled seems to
|
||||||
|
no longer respond with sensible configuration data, but only 0xFF for
|
||||||
|
all queries.
|
||||||
|
As these queries are used to obtain the equivalent of a signature,
|
||||||
|
.Nm
|
||||||
|
can only continue in that situation by forcing the signature check
|
||||||
|
to be overridden with the
|
||||||
|
.Fl F
|
||||||
|
option.
|
||||||
|
.Pp
|
||||||
|
A
|
||||||
|
.Em chip erase
|
||||||
|
might leave the EEPROM unerased, at least on some
|
||||||
|
versions of the bootloader.
|
||||||
.Ss Programmers accepting extended parameters
|
.Ss Programmers accepting extended parameters
|
||||||
.Bl -tag -offset indent -width indent
|
.Bl -tag -offset indent -width indent
|
||||||
.It Ar JTAG ICE mkII
|
.It Ar JTAG ICE mkII
|
||||||
|
|
|
@ -244,7 +244,9 @@ has been compiled with libusb support.
|
||||||
They both feature simple firmware-only USB implementations, running on
|
They both feature simple firmware-only USB implementations, running on
|
||||||
an ATmega8 (or ATmega88), or ATtiny2313, respectively.
|
an ATmega8 (or ATmega88), or ATtiny2313, respectively.
|
||||||
|
|
||||||
The Atmel DFU bootloader is supported in version 2 (Xmega devices).
|
The Atmel DFU bootloader is supported in both, FLIP protocol version 1
|
||||||
|
(AT90USB* and ATmega*U* devices), as well as version 2 (Xmega devices).
|
||||||
|
See below for some hints about FLIP version 1 protocol behaviour.
|
||||||
|
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
@ -1658,12 +1660,13 @@ functionality does not make sense for these boot loaders.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Atmel STK600::
|
* Atmel STK600::
|
||||||
|
* Atmel DFU bootloader using FLIP version 1::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@c
|
@c
|
||||||
@c Node
|
@c Node
|
||||||
@c
|
@c
|
||||||
@node Atmel STK600, , Programmer Specific Information, Programmer Specific Information
|
@node Atmel STK600, Atmel DFU bootloader using FLIP version 1, Programmer Specific Information, Programmer Specific Information
|
||||||
@section Atmel STK600
|
@section Atmel STK600
|
||||||
|
|
||||||
@c
|
@c
|
||||||
|
@ -1756,6 +1759,34 @@ High-voltage programming requires the target voltage to be set to at
|
||||||
least 4.5 V in order to work. This can be done using
|
least 4.5 V in order to work. This can be done using
|
||||||
@emph{Terminal Mode}, see @ref{Terminal Mode Operation}.
|
@emph{Terminal Mode}, see @ref{Terminal Mode Operation}.
|
||||||
|
|
||||||
|
@c
|
||||||
|
@c Node
|
||||||
|
@c
|
||||||
|
@node Atmel DFU bootloader using FLIP version 1, , Atmel STK600, Programmer Specific Information
|
||||||
|
@section Atmel DFU bootloader using FLIP version 1
|
||||||
|
|
||||||
|
Bootloaders using the FLIP protocol version 1 experience some very
|
||||||
|
specific behaviour.
|
||||||
|
|
||||||
|
These bootloaders have no option to access memory areas other than
|
||||||
|
Flash and EEPROM.
|
||||||
|
|
||||||
|
When the bootloader is started, it enters a @emph{security mode} where
|
||||||
|
the only acceptable access is to query the device configuration
|
||||||
|
parameters (which are used for the signature on AVR devices). The
|
||||||
|
only way to leave this mode is a @emph{chip erase}. As a chip erase
|
||||||
|
is normally implied by the @option{-U} option when reprogramming the
|
||||||
|
flash, this peculiarity might not be very obvious immediately.
|
||||||
|
|
||||||
|
Sometimes, a bootloader with security mode already disabled seems to
|
||||||
|
no longer respond with sensible configuration data, but only 0xFF for
|
||||||
|
all queries. As these queries are used to obtain the equivalent of a
|
||||||
|
signature, AVRDUDE can only continue in that situation by forcing the
|
||||||
|
signature check to be overridden with the @option{-F} option.
|
||||||
|
|
||||||
|
A @emph{chip erase} might leave the EEPROM unerased, at least on some
|
||||||
|
versions of the bootloader.
|
||||||
|
|
||||||
@c
|
@c
|
||||||
@c Node
|
@c Node
|
||||||
@c
|
@c
|
||||||
|
|
641
flip1.c
641
flip1.c
|
@ -52,6 +52,21 @@
|
||||||
* Version 2: XMEGA parts (AVR4023 [doc8457])
|
* Version 2: XMEGA parts (AVR4023 [doc8457])
|
||||||
*
|
*
|
||||||
* This implementation handles protocol version 1.
|
* This implementation handles protocol version 1.
|
||||||
|
*
|
||||||
|
* Protocol version 1 has some, erm, "interesting" features:
|
||||||
|
*
|
||||||
|
* When contacting the fresh bootloader, the only allowed actions are
|
||||||
|
* requesting the configuration/manufacturer information (which is
|
||||||
|
* used to read the signature on AVRs), and to issue a "chip erase".
|
||||||
|
* All operations on flash and EEPROM are restricted before a chip
|
||||||
|
* erase has been seen (security protection).
|
||||||
|
*
|
||||||
|
* However, after the chip erase, the configuration/manufacturer
|
||||||
|
* information can no longer be obtained ... they all respond with
|
||||||
|
* 0xff. Essentially, the device needs a power cycle then, after
|
||||||
|
* which the only actual command to access is a chip erase.
|
||||||
|
*
|
||||||
|
* Quite cumbersome to the user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* EXPORTED CONSTANT STRINGS */
|
/* EXPORTED CONSTANT STRINGS */
|
||||||
|
@ -66,23 +81,66 @@ struct flip1
|
||||||
unsigned char part_sig[3];
|
unsigned char part_sig[3];
|
||||||
unsigned char part_rev;
|
unsigned char part_rev;
|
||||||
unsigned char boot_ver;
|
unsigned char boot_ver;
|
||||||
|
unsigned char security_mode_flag; /* indicates the user has already
|
||||||
|
* been hinted about security
|
||||||
|
* mode */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLIP1(pgm) ((struct flip1 *)(pgm->cookie))
|
#define FLIP1(pgm) ((struct flip1 *)(pgm->cookie))
|
||||||
|
|
||||||
/* FLIP1 data structures and constants. */
|
/* FLIP1 data structures and constants. */
|
||||||
|
|
||||||
|
struct flip1_cmd
|
||||||
|
{
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char args[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flip1_cmd_header /* for memory read/write */
|
||||||
|
{
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char memtype;
|
||||||
|
unsigned char start_addr[2];
|
||||||
|
unsigned char end_addr[2];
|
||||||
|
unsigned char padding[26];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flip1_prog_footer
|
||||||
|
{
|
||||||
|
unsigned char crc[4]; /* not really used */
|
||||||
|
unsigned char ftr_length; /* 0x10 */
|
||||||
|
unsigned char signature[3]; /* "DFU" */
|
||||||
|
unsigned char bcdversion[2]; /* 0x01, 0x10 */
|
||||||
|
unsigned char vendor[2]; /* or 0xff, 0xff */
|
||||||
|
unsigned char product[2]; /* or 0xff, 0xff */
|
||||||
|
unsigned char device[2]; /* or 0xff, 0xff */
|
||||||
|
};
|
||||||
|
|
||||||
#define FLIP1_CMD_PROG_START 0x01
|
#define FLIP1_CMD_PROG_START 0x01
|
||||||
#define FLIP1_CMD_DISPLAY_DATA 0x03
|
#define FLIP1_CMD_DISPLAY_DATA 0x03
|
||||||
#define FLIP1_CMD_WRITE_COMMAND 0x04
|
#define FLIP1_CMD_WRITE_COMMAND 0x04
|
||||||
#define FLIP1_CMD_READ_COMMAND 0x05
|
#define FLIP1_CMD_READ_COMMAND 0x05
|
||||||
#define FLIP1_CMD_CHANGE_BASE_ADDRESS 0x06
|
#define FLIP1_CMD_CHANGE_BASE_ADDRESS 0x06
|
||||||
|
|
||||||
|
/* args[1:0] for FLIP1_CMD_READ_COMMAND */
|
||||||
|
#define FLIP1_READ_BOOTLOADER_VERSION { 0x00, 0x00 }
|
||||||
|
#define FLIP1_READ_DEVICE_BOOT_ID1 { 0x00, 0x01 }
|
||||||
|
#define FLIP1_READ_DEVICE_BOOT_ID2 { 0x00, 0x02 }
|
||||||
|
#define FLIP1_READ_MANUFACTURER_CODE { 0x01, 0x30 }
|
||||||
|
#define FLIP1_READ_FAMILY_CODE { 0x01, 0x31 }
|
||||||
|
#define FLIP1_READ_PRODUCT_NAME { 0x01, 0x60 }
|
||||||
|
#define FLIP1_READ_PRODUCT_REVISION { 0x01, 0x61 }
|
||||||
|
|
||||||
enum flip1_mem_unit {
|
enum flip1_mem_unit {
|
||||||
FLIP1_MEM_UNIT_FLASH = 0x00,
|
FLIP1_MEM_UNIT_FLASH = 0x00,
|
||||||
FLIP1_MEM_UNIT_EEPROM = 0x01
|
FLIP1_MEM_UNIT_EEPROM = 0x01,
|
||||||
|
FLIP1_MEM_UNIT_UNKNOWN = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define STATE_dfuERROR 10 /* bState; requires a DFU_CLRSTATUS */
|
||||||
|
|
||||||
|
#define LONG_DFU_TIMEOUT 10000 /* 10 s for program and erase */
|
||||||
|
|
||||||
/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
|
/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
|
||||||
|
|
||||||
static int flip1_open(PROGRAMMER *pgm, char *port_spec);
|
static int flip1_open(PROGRAMMER *pgm, char *port_spec);
|
||||||
|
@ -97,8 +155,6 @@ static int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned long addr, unsigned char *value);
|
unsigned long addr, unsigned char *value);
|
||||||
static int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
static int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned long addr, unsigned char value);
|
unsigned long addr, unsigned char value);
|
||||||
static int flip1_page_erase(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
|
||||||
unsigned int base_addr);
|
|
||||||
static int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
static int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes);
|
unsigned int page_size, unsigned int addr, unsigned int n_bytes);
|
||||||
static int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
static int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
|
@ -111,18 +167,14 @@ static void flip1_teardown(PROGRAMMER * pgm);
|
||||||
|
|
||||||
static void flip1_show_info(struct flip1 *flip1);
|
static void flip1_show_info(struct flip1 *flip1);
|
||||||
|
|
||||||
static int flip1_read_memory(struct dfu_dev *dfu,
|
static int flip1_read_memory(PROGRAMMER * pgm,
|
||||||
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size);
|
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size);
|
||||||
static int flip1_write_memory(struct dfu_dev *dfu,
|
static int flip1_write_memory(struct dfu_dev *dfu,
|
||||||
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size);
|
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size);
|
||||||
|
|
||||||
static int flip1_read_max1k(struct dfu_dev *dfu,
|
|
||||||
unsigned short offset, void *ptr, unsigned short size);
|
|
||||||
static int flip1_write_max1k(struct dfu_dev *dfu,
|
|
||||||
unsigned short offset, const void *ptr, unsigned short size);
|
|
||||||
|
|
||||||
static const char * flip1_status_str(const struct dfu_status *status);
|
static const char * flip1_status_str(const struct dfu_status *status);
|
||||||
static const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit);
|
static const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit);
|
||||||
|
static int flip1_set_mem_page(struct dfu_dev *dfu, unsigned short page_addr);
|
||||||
static enum flip1_mem_unit flip1_mem_unit(const char *name);
|
static enum flip1_mem_unit flip1_mem_unit(const char *name);
|
||||||
|
|
||||||
/* THE INITPGM FUNCTION DEFINITIONS */
|
/* THE INITPGM FUNCTION DEFINITIONS */
|
||||||
|
@ -140,7 +192,6 @@ void flip1_initpgm(PROGRAMMER *pgm)
|
||||||
pgm->chip_erase = flip1_chip_erase;
|
pgm->chip_erase = flip1_chip_erase;
|
||||||
pgm->open = flip1_open;
|
pgm->open = flip1_open;
|
||||||
pgm->close = flip1_close;
|
pgm->close = flip1_close;
|
||||||
pgm->page_erase = flip1_page_erase;
|
|
||||||
pgm->paged_load = flip1_paged_load;
|
pgm->paged_load = flip1_paged_load;
|
||||||
pgm->paged_write = flip1_paged_write;
|
pgm->paged_write = flip1_paged_write;
|
||||||
pgm->read_byte = flip1_read_byte;
|
pgm->read_byte = flip1_read_byte;
|
||||||
|
@ -250,23 +301,15 @@ int flip1_initialize(PROGRAMMER* pgm, AVRPART *part)
|
||||||
progname, (int) dfu->intf_desc.bInterfaceProtocol);
|
progname, (int) dfu->intf_desc.bInterfaceProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (dfu->dev_desc.bMaxPacketSize0 != 32)
|
||||||
result = flip1_read_memory(FLIP1(pgm)->dfu,
|
fprintf( stderr, "%s: Warning: bMaxPacketSize0 (%d) != 32, things might go wrong\n",
|
||||||
FLIP1_MEM_UNIT_SIGNATURE, 0, FLIP1(pgm)->part_sig, 4);
|
progname, dfu->dev_desc.bMaxPacketSize0);
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
goto flip1_initialize_fail;
|
|
||||||
|
|
||||||
result = flip1_read_memory(FLIP1(pgm)->dfu,
|
|
||||||
FLIP1_MEM_UNIT_BOOTLOADER, 0, &FLIP1(pgm)->boot_ver, 1);
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
goto flip1_initialize_fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
flip1_show_info(FLIP1(pgm));
|
flip1_show_info(FLIP1(pgm));
|
||||||
|
|
||||||
|
dfu_abort(dfu);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
flip1_initialize_fail:
|
flip1_initialize_fail:
|
||||||
|
@ -310,51 +353,57 @@ int flip1_program_enable(PROGRAMMER* pgm, AVRPART *part)
|
||||||
|
|
||||||
int flip1_chip_erase(PROGRAMMER* pgm, AVRPART *part)
|
int flip1_chip_erase(PROGRAMMER* pgm, AVRPART *part)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct dfu_status status;
|
struct dfu_status status;
|
||||||
int cmd_result = 0;
|
int cmd_result = 0;
|
||||||
int aux_result;
|
int aux_result;
|
||||||
|
unsigned int default_timeout = FLIP1(pgm)->dfu->timeout;
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "%s: flip_chip_erase()\n", progname);
|
fprintf(stderr, "%s: flip_chip_erase()\n", progname);
|
||||||
|
|
||||||
struct flip1_cmd cmd = {
|
struct flip1_cmd cmd = {
|
||||||
FLIP1_CMD_GROUP_EXEC, FLIP1_CMD_CHIP_ERASE, { 0xFF, 0, 0, 0 }
|
FLIP1_CMD_WRITE_COMMAND, { 0, 0xff }
|
||||||
};
|
};
|
||||||
|
|
||||||
for (;;) {
|
FLIP1(pgm)->dfu->timeout = LONG_DFU_TIMEOUT;
|
||||||
cmd_result = dfu_dnload(FLIP1(pgm)->dfu, &cmd, sizeof(cmd));
|
cmd_result = dfu_dnload(FLIP1(pgm)->dfu, &cmd, 3);
|
||||||
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||||
|
FLIP1(pgm)->dfu->timeout = default_timeout;
|
||||||
|
|
||||||
if (aux_result != 0)
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
return aux_result;
|
return -1;
|
||||||
|
|
||||||
if (status.bStatus != DFU_STATUS_OK) {
|
if (status.bStatus != DFU_STATUS_OK) {
|
||||||
if (status.bStatus == ((FLIP1_STATUS_ERASE_ONGOING >> 8) & 0xFF) &&
|
fprintf(stderr, "%s: failed to send chip erase command: %s\n",
|
||||||
status.bState == ((FLIP1_STATUS_ERASE_ONGOING >> 0) & 0xFF))
|
progname, flip1_status_str(&status));
|
||||||
{
|
if (status.bState == STATE_dfuERROR)
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
fprintf(stderr, "%s: Error: DFU status %s\n", progname,
|
|
||||||
flip1_status_str(&status));
|
|
||||||
dfu_clrstatus(FLIP1(pgm)->dfu);
|
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||||
} else
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd_result;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned long addr, unsigned char *value)
|
unsigned long addr, unsigned char *value)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
enum flip1_mem_unit mem_unit;
|
enum flip1_mem_unit mem_unit;
|
||||||
|
|
||||||
if (FLIP1(pgm)->dfu == NULL)
|
if (FLIP1(pgm)->dfu == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (strcasecmp(mem->desc, "signature") == 0) {
|
||||||
|
if (flip1_read_sig_bytes(pgm, part, mem) < 0)
|
||||||
|
return -1;
|
||||||
|
if (addr > mem->size) {
|
||||||
|
fprintf(stderr, "%s: flip1_read_byte(signature): address %lu out of range\n",
|
||||||
|
progname, addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*value = mem->buf[addr];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
mem_unit = flip1_mem_unit(mem->desc);
|
mem_unit = flip1_mem_unit(mem->desc);
|
||||||
|
|
||||||
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
if (mem_unit == FLIP1_MEM_UNIT_UNKNOWN) {
|
||||||
|
@ -365,14 +414,16 @@ int flip1_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return flip1_read_memory(FLIP1(pgm)->dfu, mem_unit, addr, value, 1);
|
if (mem_unit == FLIP1_MEM_UNIT_EEPROM)
|
||||||
#endif
|
/* 0x01 is used for blank check when reading, 0x02 is EEPROM */
|
||||||
|
mem_unit = 2;
|
||||||
|
|
||||||
|
return flip1_read_memory(pgm, mem_unit, addr, value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned long addr, unsigned char value)
|
unsigned long addr, unsigned char value)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
enum flip1_mem_unit mem_unit;
|
enum flip1_mem_unit mem_unit;
|
||||||
|
|
||||||
if (FLIP1(pgm)->dfu == NULL)
|
if (FLIP1(pgm)->dfu == NULL)
|
||||||
|
@ -389,21 +440,12 @@ int flip1_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
}
|
}
|
||||||
|
|
||||||
return flip1_write_memory(FLIP1(pgm)->dfu, mem_unit, addr, &value, 1);
|
return flip1_write_memory(FLIP1(pgm)->dfu, mem_unit, addr, &value, 1);
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int flip1_page_erase(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
|
||||||
unsigned int base_addr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
enum flip1_mem_unit mem_unit;
|
enum flip1_mem_unit mem_unit;
|
||||||
int result;
|
|
||||||
|
|
||||||
if (FLIP1(pgm)->dfu == NULL)
|
if (FLIP1(pgm)->dfu == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -418,24 +460,16 @@ int flip1_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_bytes > INT_MAX) {
|
if (mem_unit == FLIP1_MEM_UNIT_EEPROM)
|
||||||
/* This should never happen, unless the int type is only 16 bits. */
|
/* 0x01 is used for blank check when reading, 0x02 is EEPROM */
|
||||||
fprintf(stderr, "%s: Error: Attempting to read more than %d bytes\n",
|
mem_unit = 2;
|
||||||
progname, INT_MAX);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = flip1_read_memory(FLIP1(pgm)->dfu, mem_unit, addr,
|
return flip1_read_memory(pgm, mem_unit, addr, mem->buf + addr, n_bytes);
|
||||||
mem->buf + addr, n_bytes);
|
|
||||||
|
|
||||||
return (result == 0) ? n_bytes : -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
unsigned int page_size, unsigned int addr, unsigned int n_bytes)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
enum flip1_mem_unit mem_unit;
|
enum flip1_mem_unit mem_unit;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -463,12 +497,13 @@ int flip1_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
|
||||||
mem->buf + addr, n_bytes);
|
mem->buf + addr, n_bytes);
|
||||||
|
|
||||||
return (result == 0) ? n_bytes : -1;
|
return (result == 0) ? n_bytes : -1;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
|
int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
|
||||||
{
|
{
|
||||||
#if 0
|
if (verbose > 1)
|
||||||
|
fprintf(stderr, "%s: flip1_read_sig_bytes(): ", progname);
|
||||||
|
|
||||||
if (FLIP1(pgm)->dfu == NULL)
|
if (FLIP1(pgm)->dfu == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -478,9 +513,69 @@ int flip1_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FLIP1(pgm)->part_sig[0] == 0 &&
|
||||||
|
FLIP1(pgm)->part_sig[1] == 0 &&
|
||||||
|
FLIP1(pgm)->part_sig[2] == 0)
|
||||||
|
{
|
||||||
|
/* signature not yet cached */
|
||||||
|
struct dfu_status status;
|
||||||
|
int cmd_result = 0;
|
||||||
|
int aux_result;
|
||||||
|
int i;
|
||||||
|
struct flip1_cmd cmd = {
|
||||||
|
FLIP1_CMD_READ_COMMAND, FLIP1_READ_FAMILY_CODE
|
||||||
|
};
|
||||||
|
|
||||||
|
if (verbose > 1)
|
||||||
|
fprintf(stderr, "from device\n");
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (i == 1)
|
||||||
|
cmd.args[1] = 0x60; /* product name */
|
||||||
|
else if (i == 2)
|
||||||
|
cmd.args[1] = 0x61; /* product revision */
|
||||||
|
|
||||||
|
cmd_result = dfu_dnload(FLIP1(pgm)->dfu, &cmd, 3);
|
||||||
|
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||||
|
|
||||||
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: failed to send cmd for signature byte %d: %s\n",
|
||||||
|
progname, i, flip1_status_str(&status));
|
||||||
|
if (status.bState == STATE_dfuERROR)
|
||||||
|
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_result = dfu_upload(FLIP1(pgm)->dfu, &(FLIP1(pgm)->part_sig[i]), 1);
|
||||||
|
aux_result = dfu_getstatus(FLIP1(pgm)->dfu, &status);
|
||||||
|
|
||||||
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: failed to read signature byte %d: %s\n",
|
||||||
|
progname, i, flip1_status_str(&status));
|
||||||
|
if (status.bState == STATE_dfuERROR)
|
||||||
|
dfu_clrstatus(FLIP1(pgm)->dfu);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbose > 1)
|
||||||
|
fprintf(stderr, "cached\n");
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(mem->buf, FLIP1(pgm)->part_sig, sizeof(FLIP1(pgm)->part_sig));
|
memcpy(mem->buf, FLIP1(pgm)->part_sig, sizeof(FLIP1(pgm)->part_sig));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void flip1_setup(PROGRAMMER * pgm)
|
void flip1_setup(PROGRAMMER * pgm)
|
||||||
|
@ -488,7 +583,8 @@ void flip1_setup(PROGRAMMER * pgm)
|
||||||
pgm->cookie = calloc(1, sizeof(struct flip1));
|
pgm->cookie = calloc(1, sizeof(struct flip1));
|
||||||
|
|
||||||
if (pgm->cookie == NULL) {
|
if (pgm->cookie == NULL) {
|
||||||
perror(progname);
|
fprintf(stderr, "%s: Out of memory allocating private data structure\n",
|
||||||
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,275 +601,255 @@ void flip1_teardown(PROGRAMMER * pgm)
|
||||||
void flip1_show_info(struct flip1 *flip1)
|
void flip1_show_info(struct flip1 *flip1)
|
||||||
{
|
{
|
||||||
dfu_show_info(flip1->dfu);
|
dfu_show_info(flip1->dfu);
|
||||||
|
|
||||||
fprintf(stderr, " Part signature : 0x%02X%02X%02X\n",
|
|
||||||
(int) flip1->part_sig[0],
|
|
||||||
(int) flip1->part_sig[1],
|
|
||||||
(int) flip1->part_sig[2]);
|
|
||||||
|
|
||||||
if (flip1->part_rev < 26)
|
|
||||||
fprintf(stderr, " Part revision : %c\n",
|
|
||||||
(char) (flip1->part_rev + 'A'));
|
|
||||||
else
|
|
||||||
fprintf(stderr, " Part revision : %c%c\n",
|
|
||||||
(char) (flip1->part_rev / 26 - 1 + 'A'),
|
|
||||||
(char) (flip1->part_rev % 26 + 'A'));
|
|
||||||
|
|
||||||
fprintf(stderr, " Bootloader version : 2.%hu.%hu\n",
|
|
||||||
((unsigned short) flip1->boot_ver >> 4) & 0xF,
|
|
||||||
((unsigned short) flip1->boot_ver >> 0) & 0xF);
|
|
||||||
|
|
||||||
fprintf(stderr, " USB max packet size : %hu\n",
|
fprintf(stderr, " USB max packet size : %hu\n",
|
||||||
(unsigned short) flip1->dfu->dev_desc.bMaxPacketSize0);
|
(unsigned short) flip1->dfu->dev_desc.bMaxPacketSize0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_read_memory(struct dfu_dev *dfu,
|
int flip1_read_memory(PROGRAMMER * pgm,
|
||||||
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size)
|
enum flip1_mem_unit mem_unit, uint32_t addr, void *ptr, int size)
|
||||||
{
|
{
|
||||||
#if 0
|
struct dfu_dev *dfu = FLIP1(pgm)->dfu;
|
||||||
unsigned short prev_page_addr;
|
|
||||||
unsigned short page_addr;
|
unsigned short page_addr;
|
||||||
const char * mem_name;
|
struct dfu_status status;
|
||||||
int read_size;
|
int cmd_result = 0;
|
||||||
int result;
|
int aux_result;
|
||||||
|
struct flip1_cmd cmd = {
|
||||||
|
FLIP1_CMD_DISPLAY_DATA, { mem_unit }
|
||||||
|
};
|
||||||
|
unsigned int default_timeout = dfu->timeout;
|
||||||
|
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: flip_read_memory(%s, 0x%04x, %d)\n",
|
"%s: flip_read_memory(%s, 0x%04x, %d)\n",
|
||||||
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
||||||
|
|
||||||
result = flip1_set_mem_unit(dfu, mem_unit);
|
/*
|
||||||
|
* As this function is called once per page, no need to handle 64
|
||||||
if (result != 0) {
|
* KiB border crossing below.
|
||||||
if ((mem_name = flip1_mem_unit_str(mem_unit)) != NULL)
|
*
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X (%s)\n",
|
* Also, on AVRs, no page size is larger than 1 KiB, so no need to
|
||||||
progname, (int) mem_unit, mem_name);
|
* split the request into multiple 1 KiB chunks.
|
||||||
else
|
*/
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X\n",
|
if (mem_unit == FLIP1_MEM_UNIT_FLASH) {
|
||||||
progname, (int) mem_unit);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_addr = addr >> 16;
|
|
||||||
result = flip1_set_mem_page(dfu, page_addr);
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
|
|
||||||
progname, page_addr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (size > 0) {
|
|
||||||
prev_page_addr = page_addr;
|
|
||||||
page_addr = addr >> 16;
|
page_addr = addr >> 16;
|
||||||
|
if (flip1_set_mem_page(dfu, page_addr) < 0)
|
||||||
if (page_addr != prev_page_addr) {
|
|
||||||
result = flip1_set_mem_page(dfu, page_addr);
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
|
|
||||||
progname, page_addr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
read_size = (size > 0x400) ? 0x400 : size;
|
|
||||||
result = flip1_read_max1k(dfu, addr & 0xFFFF, ptr, read_size);
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to read 0x%04X bytes at 0x%04lX\n",
|
|
||||||
progname, read_size, (unsigned long) addr);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += read_size;
|
cmd.args[1] = (addr >> 8) & 0xFF;
|
||||||
addr += read_size;
|
cmd.args[2] = addr & 0xFF;
|
||||||
size -= read_size;
|
cmd.args[3] = ((addr + size - 1) >> 8) & 0xFF;
|
||||||
|
cmd.args[4] = (addr + size - 1) & 0xFF;
|
||||||
|
|
||||||
|
dfu->timeout = LONG_DFU_TIMEOUT;
|
||||||
|
cmd_result = dfu_dnload(dfu, &cmd, 6);
|
||||||
|
dfu->timeout = default_timeout;
|
||||||
|
aux_result = dfu_getstatus(dfu, &status);
|
||||||
|
|
||||||
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: failed to read %u bytes of %s memory @%u: %s\n",
|
||||||
|
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||||
|
flip1_status_str(&status));
|
||||||
|
if (status.bState == STATE_dfuERROR)
|
||||||
|
dfu_clrstatus(dfu);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_result = dfu_upload(dfu, (char*) ptr, size);
|
||||||
|
aux_result = dfu_getstatus(dfu, &status);
|
||||||
|
|
||||||
|
if (cmd_result < 0 && aux_result == 0 &&
|
||||||
|
status.bStatus == DFU_STATUS_ERR_WRITE) {
|
||||||
|
if (FLIP1(pgm)->security_mode_flag == 0)
|
||||||
|
fprintf(stderr,
|
||||||
|
"\n%s:\n"
|
||||||
|
"%s***********************************************************************\n"
|
||||||
|
"%sMaybe the device is in ``security mode´´, and needs a chip erase first?\n"
|
||||||
|
"%s***********************************************************************\n"
|
||||||
|
"\n",
|
||||||
|
progname, progbuf, progbuf, progbuf);
|
||||||
|
FLIP1(pgm)->security_mode_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: failed to read %u bytes of %s memory @%u: %s\n",
|
||||||
|
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||||
|
flip1_status_str(&status));
|
||||||
|
if (status.bState == STATE_dfuERROR)
|
||||||
|
dfu_clrstatus(dfu);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_write_memory(struct dfu_dev *dfu,
|
int flip1_write_memory(struct dfu_dev *dfu,
|
||||||
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size)
|
enum flip1_mem_unit mem_unit, uint32_t addr, const void *ptr, int size)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
unsigned short prev_page_addr;
|
|
||||||
unsigned short page_addr;
|
unsigned short page_addr;
|
||||||
const char * mem_name;
|
|
||||||
int write_size;
|
int write_size;
|
||||||
int result;
|
struct dfu_status status;
|
||||||
|
int cmd_result = 0;
|
||||||
|
int aux_result;
|
||||||
|
struct flip1_cmd_header cmd_header = {
|
||||||
|
FLIP1_CMD_PROG_START, mem_unit
|
||||||
|
};
|
||||||
|
struct flip1_prog_footer cmd_footer = {
|
||||||
|
{ 0, 0, 0, 0 }, /* CRC */
|
||||||
|
0x10, /* footer length */
|
||||||
|
{ 'D', 'F', 'U' }, /* signature */
|
||||||
|
{ 0x01, 0x10 }, /* BCD version */
|
||||||
|
{ 0xff, 0xff }, /* vendor */
|
||||||
|
{ 0xff, 0xff }, /* product */
|
||||||
|
{ 0xff, 0xff } /* device */
|
||||||
|
};
|
||||||
|
unsigned int default_timeout = dfu->timeout;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: flip_write_memory(%s, 0x%04x, %d)\n",
|
"%s: flip_write_memory(%s, 0x%04x, %d)\n",
|
||||||
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
progname, flip1_mem_unit_str(mem_unit), addr, size);
|
||||||
|
|
||||||
result = flip1_set_mem_unit(dfu, mem_unit);
|
if (size < 32) {
|
||||||
|
/* presumably single-byte updates; must be padded to USB endpoint size */
|
||||||
if (result != 0) {
|
if ((addr + size - 1) / 32 != addr / 32) {
|
||||||
if ((mem_name = flip1_mem_unit_str(mem_unit)) != NULL)
|
fprintf(stderr,
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X (%s)\n",
|
"%s: flip_write_memory(): begin (0x%x) and end (0x%x) not within same 32-byte block\n",
|
||||||
progname, (int) mem_unit, mem_name);
|
progname, addr, addr + size - 1);
|
||||||
else
|
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X\n",
|
|
||||||
progname, (int) mem_unit);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_addr = addr >> 16;
|
|
||||||
result = flip1_set_mem_page(dfu, page_addr);
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
|
|
||||||
progname, page_addr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (size > 0) {
|
|
||||||
prev_page_addr = page_addr;
|
|
||||||
page_addr = addr >> 16;
|
|
||||||
|
|
||||||
if (page_addr != prev_page_addr) {
|
|
||||||
result = flip1_set_mem_page(dfu, page_addr);
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
|
|
||||||
progname, page_addr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write_size = (size > 0x800) ? 0x800 : size;
|
|
||||||
result = flip1_write_max1k(dfu, addr & 0xFFFF, ptr, write_size);
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
fprintf(stderr, "%s: Error: Failed to write 0x%04X bytes at 0x%04lX\n",
|
|
||||||
progname, write_size, (unsigned long) addr);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
write_size = 32;
|
||||||
|
} else {
|
||||||
|
write_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
ptr += write_size;
|
if ((buf = malloc(sizeof(struct flip1_cmd_header) +
|
||||||
addr += write_size;
|
write_size +
|
||||||
size -= write_size;
|
sizeof(struct flip1_prog_footer))) == 0) {
|
||||||
|
fprintf(stderr, "%s: Out of memory\n", progname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As this function is called once per page, no need to handle 64
|
||||||
|
* KiB border crossing below.
|
||||||
|
*
|
||||||
|
* Also, on AVRs, no page size is larger than 1 KiB, so no need to
|
||||||
|
* split the request into multiple 1 KiB chunks.
|
||||||
|
*/
|
||||||
|
if (mem_unit == FLIP1_MEM_UNIT_FLASH) {
|
||||||
|
page_addr = addr >> 16;
|
||||||
|
if (flip1_set_mem_page(dfu, page_addr) < 0) {
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_header.start_addr[0] = (addr >> 8) & 0xFF;
|
||||||
|
cmd_header.start_addr[1] = addr & 0xFF;
|
||||||
|
cmd_header.end_addr[0] = ((addr + size - 1) >> 8) & 0xFF;
|
||||||
|
cmd_header.end_addr[1] = (addr + size - 1) & 0xFF;
|
||||||
|
|
||||||
|
memcpy(buf, &cmd_header, sizeof(struct flip1_cmd_header));
|
||||||
|
if (size < 32) {
|
||||||
|
memset(buf + sizeof(struct flip1_cmd_header), 0xff, 32);
|
||||||
|
memcpy(buf + sizeof(struct flip1_cmd_header) + (addr % 32), ptr, size);
|
||||||
|
} else {
|
||||||
|
memcpy(buf + sizeof(struct flip1_cmd_header), ptr, size);
|
||||||
|
}
|
||||||
|
memcpy(buf + sizeof(struct flip1_cmd_header) + write_size,
|
||||||
|
&cmd_footer, sizeof(struct flip1_prog_footer));
|
||||||
|
|
||||||
|
dfu->timeout = LONG_DFU_TIMEOUT;
|
||||||
|
cmd_result = dfu_dnload(dfu, buf,
|
||||||
|
sizeof(struct flip1_cmd_header) +
|
||||||
|
write_size +
|
||||||
|
sizeof(struct flip1_prog_footer));
|
||||||
|
aux_result = dfu_getstatus(dfu, &status);
|
||||||
|
dfu->timeout = default_timeout;
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (aux_result < 0 || cmd_result < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: failed to write %u bytes of %s memory @%u: %s\n",
|
||||||
|
progname, size, flip1_mem_unit_str(mem_unit), addr,
|
||||||
|
flip1_status_str(&status));
|
||||||
|
if (status.bState == STATE_dfuERROR)
|
||||||
|
dfu_clrstatus(dfu);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int flip1_read_max1k(struct dfu_dev *dfu,
|
int flip1_set_mem_page(struct dfu_dev *dfu,
|
||||||
unsigned short offset, void *ptr, unsigned short size)
|
unsigned short page_addr)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct dfu_status status;
|
struct dfu_status status;
|
||||||
int cmd_result = 0;
|
int cmd_result = 0;
|
||||||
int aux_result;
|
int aux_result;
|
||||||
|
|
||||||
struct flip1_cmd cmd = {
|
struct flip1_cmd cmd = {
|
||||||
FLIP1_CMD_GROUP_UPLOAD, FLIP1_CMD_READ_MEMORY, { 0, 0, 0, 0 }
|
FLIP1_CMD_CHANGE_BASE_ADDRESS, { 0, page_addr }
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.args[0] = (offset >> 8) & 0xFF;
|
cmd_result = dfu_dnload(dfu, &cmd, 3);
|
||||||
cmd.args[1] = (offset >> 0) & 0xFF;
|
|
||||||
cmd.args[2] = ((offset+size-1) >> 8) & 0xFF;
|
|
||||||
cmd.args[3] = ((offset+size-1) >> 0) & 0xFF;
|
|
||||||
|
|
||||||
cmd_result = dfu_dnload(dfu, &cmd, sizeof(cmd));
|
|
||||||
|
|
||||||
if (cmd_result != 0)
|
|
||||||
goto flip1_read_max1k_status;
|
|
||||||
|
|
||||||
cmd_result = dfu_upload(dfu, (char*) ptr, size);
|
|
||||||
|
|
||||||
flip1_read_max1k_status:
|
|
||||||
|
|
||||||
aux_result = dfu_getstatus(dfu, &status);
|
aux_result = dfu_getstatus(dfu, &status);
|
||||||
|
|
||||||
if (aux_result != 0)
|
if (cmd_result < 0 || aux_result < 0)
|
||||||
return aux_result;
|
return -1;
|
||||||
|
|
||||||
if (status.bStatus != DFU_STATUS_OK) {
|
if (status.bStatus != DFU_STATUS_OK)
|
||||||
if (status.bStatus == ((FLIP1_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
|
{
|
||||||
status.bState == ((FLIP1_STATUS_OUTOFRANGE >> 0) & 0xFF))
|
fprintf(stderr, "%s: failed to set memory page: %s\n",
|
||||||
{
|
progname, flip1_status_str(&status));
|
||||||
fprintf(stderr, "%s: Error: Address out of range [0x%04hX,0x%04hX]\n",
|
if (status.bState == STATE_dfuERROR)
|
||||||
progname, offset, offset+size-1);
|
dfu_clrstatus(dfu);
|
||||||
} else
|
return -1;
|
||||||
fprintf(stderr, "%s: Error: DFU status %s\n", progname,
|
|
||||||
flip1_status_str(&status));
|
|
||||||
dfu_clrstatus(dfu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd_result;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int flip1_write_max1k(struct dfu_dev *dfu,
|
|
||||||
unsigned short offset, const void *ptr, unsigned short size)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
char buffer[64+64+0x400];
|
|
||||||
unsigned short data_offset;
|
|
||||||
struct dfu_status status;
|
|
||||||
int cmd_result = 0;
|
|
||||||
int aux_result;
|
|
||||||
|
|
||||||
struct flip1_cmd cmd = {
|
|
||||||
FLIP1_CMD_GROUP_DOWNLOAD, FLIP1_CMD_PROG_START, { 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
cmd.args[0] = (offset >> 8) & 0xFF;
|
|
||||||
cmd.args[1] = (offset >> 0) & 0xFF;
|
|
||||||
cmd.args[2] = ((offset+size-1) >> 8) & 0xFF;
|
|
||||||
cmd.args[3] = ((offset+size-1) >> 0) & 0xFF;
|
|
||||||
|
|
||||||
if (size > 0x400) {
|
|
||||||
fprintf(stderr, "%s: Error: Write block too large (%hu > 1024)\n",
|
|
||||||
progname, size);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There are some special padding requirements for writes. The first packet
|
|
||||||
* must consist only of the FLIP1 command data, which must be padded to
|
|
||||||
* fill out the USB packet (the packet size is given by bMaxPacketSize0 in
|
|
||||||
* the device descriptor). In addition, the data must be padded so that the
|
|
||||||
* first byte of data to be written is at located at position (offset mod
|
|
||||||
* bMaxPacketSize0) within the packet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
data_offset = dfu->dev_desc.bMaxPacketSize0;
|
|
||||||
data_offset += offset % dfu->dev_desc.bMaxPacketSize0;
|
|
||||||
|
|
||||||
memcpy(buffer, &cmd, sizeof(cmd));
|
|
||||||
memset(buffer + sizeof(cmd), 0, data_offset - sizeof(cmd));
|
|
||||||
memcpy(buffer + data_offset, ptr, size);
|
|
||||||
|
|
||||||
cmd_result = dfu_dnload(dfu, buffer, data_offset + size);
|
|
||||||
|
|
||||||
aux_result = dfu_getstatus(dfu, &status);
|
|
||||||
|
|
||||||
if (aux_result != 0)
|
|
||||||
return aux_result;
|
|
||||||
|
|
||||||
if (status.bStatus != DFU_STATUS_OK) {
|
|
||||||
if (status.bStatus == ((FLIP1_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
|
|
||||||
status.bState == ((FLIP1_STATUS_OUTOFRANGE >> 0) & 0xFF))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: Error: Address out of range [0x%04hX,0x%04hX]\n",
|
|
||||||
progname, offset, offset+size-1);
|
|
||||||
} else
|
|
||||||
fprintf(stderr, "%s: Error: DFU status %s\n", progname,
|
|
||||||
flip1_status_str(&status));
|
|
||||||
dfu_clrstatus(dfu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd_result;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * flip1_status_str(const struct dfu_status *status)
|
const char * flip1_status_str(const struct dfu_status *status)
|
||||||
{
|
{
|
||||||
// XXX
|
static const char *msg[] = {
|
||||||
|
"No error condition is present",
|
||||||
|
"File is not targeted for use by this device",
|
||||||
|
"File is for this device but fails some vendor-specific verification test",
|
||||||
|
"Device id unable to write memory",
|
||||||
|
"Memory erase function failed",
|
||||||
|
"Memory erase check failed",
|
||||||
|
"Program memory function failed",
|
||||||
|
"Programmed memory failed verification",
|
||||||
|
"Cannot program memory due to received address that is out of range",
|
||||||
|
"Received DFU_DNLOAD with wLength = 0, but device does not think it has all the data yet.",
|
||||||
|
"Device's firmware is corrupted. It cannot return to run-time operations",
|
||||||
|
"iString indicates a vendor-specific error",
|
||||||
|
"Device detected unexpected USB reset signaling",
|
||||||
|
"Device detected unexpected power on reset",
|
||||||
|
"Something went wrong, but the device does not know what it was",
|
||||||
|
"Device stalled an unexpected request",
|
||||||
|
};
|
||||||
|
if (status->bStatus < sizeof msg / sizeof msg[0])
|
||||||
|
return msg[status->bStatus];
|
||||||
|
|
||||||
|
return "Unknown status code";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit)
|
const char * flip1_mem_unit_str(enum flip1_mem_unit mem_unit)
|
||||||
|
@ -790,4 +866,5 @@ enum flip1_mem_unit flip1_mem_unit(const char *name) {
|
||||||
return FLIP1_MEM_UNIT_FLASH;
|
return FLIP1_MEM_UNIT_FLASH;
|
||||||
if (strcasecmp(name, "eeprom") == 0)
|
if (strcasecmp(name, "eeprom") == 0)
|
||||||
return FLIP1_MEM_UNIT_EEPROM;
|
return FLIP1_MEM_UNIT_EEPROM;
|
||||||
|
return FLIP1_MEM_UNIT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue