sw: add missing include files

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2019-03-05 12:02:02 +08:00
parent ffd0285613
commit c78e9ab214
11 changed files with 2707 additions and 0 deletions

81
sw/include/dfu.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef _DFU_H
#define _DFU_H
/*
* Fadecandy DFU Bootloader
*
* Copyright (c) 2013 Micah Elizabeth Scott
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
typedef enum {
appIDLE = 0,
appDETACH,
dfuIDLE,
dfuDNLOAD_SYNC,
dfuDNBUSY,
dfuDNLOAD_IDLE,
dfuMANIFEST_SYNC,
dfuMANIFEST,
dfuMANIFEST_WAIT_RESET,
dfuUPLOAD_IDLE,
dfuERROR
} dfu_state_t;
typedef enum {
OK = 0,
errTARGET,
errFILE,
errWRITE,
errERASE,
errCHECK_ERASED,
errPROG,
errVERIFY,
errADDRESS,
errNOTDONE,
errFIRMWARE,
errVENDOR,
errUSBR,
errPOR,
errUNKNOWN,
errSTALLEDPKT,
} dfu_status_t;
#define DFU_INTERFACE 0
#define DFU_DETACH_TIMEOUT 10000 // 10 second timer
#define DFU_TRANSFER_SIZE 1024 // Flash sector size
// Main thread
void dfu_init();
// USB entry points. Always successful.
uint8_t dfu_getstate();
// USB entry points. True on success, false for stall.
bool dfu_getstatus(uint8_t status[8]);
bool dfu_clrstatus();
bool dfu_abort();
bool dfu_download(unsigned blockNum, unsigned blockLength,
unsigned packetOffset, unsigned packetLength, const uint8_t *data);
#endif /* _DFU_H */

109
sw/include/toboot-api.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef TOBOOT_API_H_
#define TOBOOT_API_H_
#include <stdint.h>
/// Store this configuration struct at offset 0x94 from the start
/// of your binary image.
/// You may set all RESERVED values to 0. as they will be calculated
/// when the program is written to flash.
struct toboot_configuration {
/// Set to 0x907070b2 to indicate a valid configuration header.
uint32_t magic;
/// Reserved value. Used as a generational counter. Toboot will
/// overwrite this value with a monotonically-increasing counter
/// every time a new image is burned. This is used to determine
/// which image is the newest.
uint16_t reserved_gen;
/// The starting page for your program in 1024-byte blocks.
/// Toboot itself sets this to 0. If this is nonzero, then it
/// must be located after the Toboot image. Toboot is currently
/// under 5 kilobytes, so make sure this value is at least 6.
uint8_t start;
/// Configuration bitmask. See below for values.
uint8_t config;
/// Set to 0x18349420 to prevent the user from entering Toboot manually.
/// Use this value with caution, as it can be used to lockout a Tomu.
uint32_t lock_entry;
/// A bitmask of sectors to erase when updating the program. Each "1"
/// causes that sector to be erased, unless it's Toboot itself. Bit values
/// determine flash blocks 0-31.
uint32_t erase_mask_lo;
/// A bitmask of sectors to erase when updating the program. Each "1"
/// causes that sector to e erased. Use these two values to e.g. force
/// private keys to be erased when updating. Bit values determine flash
/// blocks 32-63.
uint32_t erase_mask_hi;
/// A hash of the entire header, minus this entry. Toboot calculates
/// this when it programs the first block. A Toboot configuration
/// header MUST have a valid hash in order to be considered valid.
uint32_t reserved_hash;
} __attribute__((packed));
/// Toboot V1.0 leaves IRQs enabled, mimicking the behavior of
/// AN0042. Toboot V2.0 makes this configurable by adding a
/// bit to the configuration area.
#define TOBOOT_CONFIG_FLAG_ENABLE_IRQ_MASK 0x01
#define TOBOOT_CONFIG_FLAG_ENABLE_IRQ_SHIFT 0
#define TOBOOT_CONFIG_FLAG_ENABLE_IRQ (1 << 0)
#define TOBOOT_CONFIG_FLAG_DISABLE_IRQ (0 << 0)
/// When running a normal program, you won't want Toboot to run.
/// However, when developing new software it is handy to have
/// Toboot run at poweron, instead of jumping straight to your
/// program. Set this flag to enter your program whenever the
/// system has just powered on.
#define TOBOOT_CONFIG_FLAG_AUTORUN_MASK 0x02
#define TOBOOT_CONFIG_FLAG_AUTORUN_SHIFT 1
#define TOBOOT_CONFIG_FLAG_AUTORUN (1 << 1)
#define TOBOOT_CONFIG_FLAG_AUTORUN_DISABLED (0 << 1)
/// When we create a fake header, this flag will be set. Otherwise,
/// leave the flag cleared. This field has no meaning in user
/// applications, and is only used internally.
#define TOBOOT_CONFIG_FAKE_MASK 0x04
#define TOBOOT_CONFIG_FAKE_SHIFT 2
#define TOBOOT_CONFIG_FAKE (1 << 2)
/// Various magic values describing Toboot configuration headers.
#define TOBOOT_V1_MAGIC 0x6fb0
#define TOBOOT_V1_MAGIC_MASK 0x0000ffff
#define TOBOOT_V2_MAGIC 0x907070b2
#define TOBOOT_V2_MAGIC_MASK 0xffffffff
/// This value is used to prevent manual entry into Toboot.
#define TOBOOT_LOCKOUT_MAGIC 0x18349420
/// The seed value for the hash of Toboot's configuration header
#define TOBOOT_HASH_SEED 0x037a5cf1
/// This is the runtime part that lives at the start of RAM.
/// Running programs can use this to force entry into Toboot
/// during the next reboot.
struct toboot_runtime {
/// Set this to 0x74624346 and reboot to enter bootloader,
/// even if LOCKOUT is enabled.
uint32_t magic;
/// Set this to 0 when your program starts.
uint8_t boot_count;
/// The bootloader should set this to 0x23 for Tomu.
uint8_t board_model;
/// Unused.
uint16_t reserved;
};
/// Set runtime.magic to this value and reboot to force
/// entry into Toboot.
#define TOBOOT_FORCE_ENTRY_MAGIC 0x74624346
#endif /* TOBOOT_API_H_ */

View File

@ -0,0 +1,49 @@
#ifndef TOBOOT_INTERNAL_H_
#define TOBOOT_INTERNAL_H_
#include <stdint.h>
/// This describes the structure that allows the OS to communicate
/// with the bootloader. It keeps track of how many times we've
/// tried booting, as well as a magic value that tells us to enter
/// the bootloader instead of booting the app.
/// It also keeps track of the board model.
__attribute__((section(".boot_token"))) extern struct toboot_runtime boot_token;
enum bootloader_reason
{
NOT_ENTERING_BOOTLOADER = 0,
BOOT_TOKEN_PRESENT = 1,
BOOT_FAILED_TOO_MANY_TIMES = 2,
NO_PROGRAM_PRESENT = 3,
BUTTON_HELD_DOWN = 4,
COLD_BOOT_CONFIGURATION_FLAG = 5,
};
extern enum bootloader_reason bootloader_reason;
/// Legacy Toboot V1 configuration values
#ifndef TOBOOT_V1_CFG_FLAGS
#define TOBOOT_V1_CFG_FLAGS 0
#endif
#define TOBOOT_V1_CFG_MAGIC_MASK 0xffff
#define TOBOOT_V1_CFG_MAGIC 0x70b0
#ifndef TOBOOT_V1_APP_FLAGS
#define TOBOOT_V1_APP_FLAGS 0
#endif
#define TOBOOT_V1_APP_MAGIC_MASK 0xffff
#define TOBOOT_V1_APP_MAGIC 0x6fb0
#define TOBOOT_V1_APP_PAGE_MASK 0x00ff0000
#define TOBOOT_V1_APP_PAGE_SHIFT 16
uint32_t tb_first_free_address(void);
uint32_t tb_first_free_sector(void);
const struct toboot_configuration *tb_get_config(void);
uint32_t tb_config_hash(const struct toboot_configuration *cfg);
void tb_sign_config(struct toboot_configuration *cfg);
uint32_t tb_generation(const struct toboot_configuration *cfg);
int tb_valid_signature_at_page(uint32_t page);
#endif /* TOBOOT_INTERNAL_H_ */

95
sw/include/usb-desc.h Normal file
View File

@ -0,0 +1,95 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _usb_desc_h_
#define _usb_desc_h_
#include <stdint.h>
#include <stddef.h>
#include <dfu.h>
#include <webusb-defs.h>
struct usb_setup_request {
union {
struct {
uint8_t bmRequestType;
uint8_t bRequest;
};
uint16_t wRequestAndType;
};
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wString[];
};
#define NUM_USB_BUFFERS 8
#define VENDOR_ID 0x1209 // pid.codes
#define PRODUCT_ID 0x70b1 // Assigned to Tomu project
#define DEVICE_VER 0x0101 // Bootloader version
#define MANUFACTURER_NAME u"Kosagi"
#define MANUFACTURER_NAME_LEN sizeof(MANUFACTURER_NAME)
#define PRODUCT_NAME u"Tomu Bootloader (0) " GIT_VERSION
#define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME)
#define EP0_SIZE 64
#define NUM_INTERFACE 1
#define CONFIG_DESC_SIZE (9+9+9)
// Microsoft Compatible ID Feature Descriptor
#define MSFT_VENDOR_CODE '~' // Arbitrary, but should be printable ASCII
#define MSFT_WCID_LEN 40
extern const uint8_t usb_microsoft_wcid[MSFT_WCID_LEN];
typedef struct {
uint16_t wValue;
uint16_t length;
const uint8_t *addr;
} usb_descriptor_list_t;
extern const usb_descriptor_list_t usb_descriptor_list[];
// WebUSB Landing page URL descriptor
#define WEBUSB_VENDOR_CODE 2
#ifndef LANDING_PAGE_URL
#define LANDING_PAGE_URL "dfu.tomu.im"
#endif
#define LANDING_PAGE_DESCRIPTOR_SIZE (WEBUSB_DT_URL_DESCRIPTOR_SIZE \
+ sizeof(LANDING_PAGE_URL) - 1)
extern const struct webusb_url_descriptor landing_url_descriptor;
#endif

55
sw/include/webusb-defs.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, Devan Lai
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice
* appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef WEBUSB_DEFS_H_INCLUDED
#define WEBUSB_DEFS_H_INCLUDED
#include <stdint.h>
#define WEBUSB_REQ_GET_URL 0x02
#define WEBUSB_DT_URL 3
#define WEBUSB_URL_SCHEME_HTTP 0
#define WEBUSB_URL_SCHEME_HTTPS 1
struct webusb_platform_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDevCapabilityType;
uint8_t bReserved;
uint8_t platformCapabilityUUID[16];
uint16_t bcdVersion;
uint8_t bVendorCode;
uint8_t iLandingPage;
} __attribute__((packed));
#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor)
#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65}
struct webusb_url_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bScheme;
char URL[];
} __attribute__((packed));
#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3
#endif

912
sw/include/xxhash.c Normal file
View File

@ -0,0 +1,912 @@
/*
* xxHash - Fast Hash algorithm
* Copyright (C) 2012-2016, Yann Collet
*
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at :
* - xxHash homepage: http://www.xxhash.com
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* *************************************
* Tuning parameters
***************************************/
/*!XXH_FORCE_MEMORY_ACCESS :
* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
* The below switch allow to select different access method for improved performance.
* Method 0 (default) : use `memcpy()`. Safe and portable.
* Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
* Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
* It can generate buggy code on targets which do not support unaligned memory accesses.
* But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
* See http://stackoverflow.com/a/32095106/646947 for details.
* Prefer these methods in priority order (0 > 1 > 2)
*/
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
# define XXH_FORCE_MEMORY_ACCESS 2
# elif defined(__INTEL_COMPILER) || \
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7S__) ))
# define XXH_FORCE_MEMORY_ACCESS 1
# endif
#endif
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
* If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.
* When this macro is enabled, xxHash actively checks input for null pointer.
* It it is, result for null input pointers is the same as a null-length input.
*/
#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */
# define XXH_ACCEPT_NULL_INPUT_POINTER 0
#endif
/*!XXH_FORCE_NATIVE_FORMAT :
* By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
* Results are therefore identical for little-endian and big-endian CPU.
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
* Should endian-independence be of no importance for your application, you may set the #define below to 1,
* to improve speed for Big-endian CPU.
* This option has no impact on Little_Endian CPU.
*/
#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
# define XXH_FORCE_NATIVE_FORMAT 0
#endif
/*!XXH_FORCE_ALIGN_CHECK :
* This is a minor performance trick, only useful with lots of very small keys.
* It means : check for aligned/unaligned input.
* The check costs one initial branch per hash;
* set it to 0 when the input is guaranteed to be aligned,
* or when alignment doesn't matter for performance.
*/
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
# define XXH_FORCE_ALIGN_CHECK 0
# else
# define XXH_FORCE_ALIGN_CHECK 1
# endif
#endif
/* *************************************
* Includes & Memory related functions
***************************************/
/*! Modify the local functions below should you wish to use some other memory routines
* for malloc(), free() */
#include <stdlib.h>
static void* XXH_malloc(size_t s) { return malloc(s); }
static void XXH_free (void* p) { free(p); }
/*! and for memcpy() */
#include <string.h>
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
#define XXH_STATIC_LINKING_ONLY
#include "xxhash.h"
/* *************************************
* Compiler Specific Options
***************************************/
#ifdef _MSC_VER /* Visual Studio */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# define FORCE_INLINE static __forceinline
#else
# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
# ifdef __GNUC__
# define FORCE_INLINE static inline __attribute__((always_inline))
# else
# define FORCE_INLINE static inline
# endif
# else
# define FORCE_INLINE static
# endif /* __STDC_VERSION__ */
#endif
/* *************************************
* Basic Types
***************************************/
#ifndef MEM_MODULE
# if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint8_t BYTE;
typedef uint16_t U16;
typedef uint32_t U32;
# else
typedef unsigned char BYTE;
typedef unsigned short U16;
typedef unsigned int U32;
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; } __attribute__((packed)) unalign;
static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U32 XXH_read32(const void* memPtr)
{
U32 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
/* ****************************************
* Compiler-specific Functions and Macros
******************************************/
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
#if defined(_MSC_VER)
# define XXH_rotl32(x,r) _rotl(x,r)
# define XXH_rotl64(x,r) _rotl64(x,r)
#else
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
#endif
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap32 _byteswap_ulong
#elif XXH_GCC_VERSION >= 403
# define XXH_swap32 __builtin_bswap32
#else
static U32 XXH_swap32 (U32 x)
{
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
#endif
/* *************************************
* Architecture Macros
***************************************/
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
#ifndef XXH_CPU_LITTLE_ENDIAN
static const int g_one = 1;
# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
#endif
/* ***************************
* Memory reads
*****************************/
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
else
return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
}
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
{
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
}
static U32 XXH_readBE32(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
}
/* *************************************
* Macros
***************************************/
#define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
/* *******************************************************************
* 32-bit hash functions
*********************************************************************/
static const U32 PRIME32_1 = 2654435761U;
static const U32 PRIME32_2 = 2246822519U;
static const U32 PRIME32_3 = 3266489917U;
static const U32 PRIME32_4 = 668265263U;
static const U32 PRIME32_5 = 374761393U;
static U32 XXH32_round(U32 seed, U32 input)
{
seed += input * PRIME32_2;
seed = XXH_rotl32(seed, 13);
seed *= PRIME32_1;
return seed;
}
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* bEnd = p + len;
U32 h32;
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)16;
}
#endif
if (len>=16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = seed + PRIME32_1 + PRIME32_2;
U32 v2 = seed + PRIME32_2;
U32 v3 = seed + 0;
U32 v4 = seed - PRIME32_1;
do {
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
} while (p<=limit);
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
} else {
h32 = seed + PRIME32_5;
}
h32 += (U32) len;
while (p+4<=bEnd) {
h32 += XXH_get32bits(p) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH32_state_t state;
XXH32_reset(&state, seed);
XXH32_update(&state, input, len);
return XXH32_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash streaming ======*/
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
{
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
{
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state));
state.v1 = seed + PRIME32_1 + PRIME32_2;
state.v2 = seed + PRIME32_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME32_1;
/* do not write into reserved, planned to be removed in a future version */
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
return XXH_OK;
}
FORCE_INLINE
XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
if (input==NULL)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
return XXH_OK;
#else
return XXH_ERROR;
#endif
state->total_len_32 += (unsigned)len;
state->large_len |= (len>=16) | (state->total_len_32>=16);
if (state->memsize + len < 16) { /* fill in tmp buffer */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
state->memsize += (unsigned)len;
return XXH_OK;
}
if (state->memsize) { /* some data left from previous update */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
{ const unsigned* p32 = state->mem32;
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));
}
p += 16-state->memsize;
state->memsize = 0;
}
if (p <= bEnd-16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = state->v1;
U32 v2 = state->v2;
U32 v3 = state->v3;
U32 v4 = state->v4;
do {
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem32;
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
U32 h32;
if (state->large_len) {
h32 = XXH_rotl32(state->v1, 1)
+ XXH_rotl32(state->v2, 7)
+ XXH_rotl32(state->v3, 12)
+ XXH_rotl32(state->v4, 18);
} else {
h32 = state->v3 /* == seed */ + PRIME32_5;
}
h32 += state->total_len_32;
while (p+4<=bEnd) {
h32 += XXH_readLE32(p, endian) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_digest_endian(state_in, XXH_littleEndian);
else
return XXH32_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
/*! Default XXH result types are basic unsigned 32 and 64 bits.
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file or buffer, remaining comparable across different systems.
*/
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
{
return XXH_readBE32(src);
}
#ifndef XXH_NO_LONG_LONG
/* *******************************************************************
* 64-bit hash functions
*********************************************************************/
/*====== Memory access ======*/
#ifndef MEM_MODULE
# define MEM_MODULE
# if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint64_t U64;
# else
/* if compiler doesn't support unsigned long long, replace by another 64-bit type */
typedef unsigned long long U64;
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U64 XXH_read64(const void* memPtr)
{
U64 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap64 _byteswap_uint64
#elif XXH_GCC_VERSION >= 403
# define XXH_swap64 __builtin_bswap64
#else
static U64 XXH_swap64 (U64 x)
{
return ((x << 56) & 0xff00000000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) |
((x << 24) & 0x0000ff0000000000ULL) |
((x << 8) & 0x000000ff00000000ULL) |
((x >> 8) & 0x00000000ff000000ULL) |
((x >> 24) & 0x0000000000ff0000ULL) |
((x >> 40) & 0x000000000000ff00ULL) |
((x >> 56) & 0x00000000000000ffULL);
}
#endif
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
else
return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
}
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
{
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
}
static U64 XXH_readBE64(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
}
/*====== xxh64 ======*/
static const U64 PRIME64_1 = 11400714785074694791ULL;
static const U64 PRIME64_2 = 14029467366897019727ULL;
static const U64 PRIME64_3 = 1609587929392839161ULL;
static const U64 PRIME64_4 = 9650029242287828579ULL;
static const U64 PRIME64_5 = 2870177450012600261ULL;
static U64 XXH64_round(U64 acc, U64 input)
{
acc += input * PRIME64_2;
acc = XXH_rotl64(acc, 31);
acc *= PRIME64_1;
return acc;
}
static U64 XXH64_mergeRound(U64 acc, U64 val)
{
val = XXH64_round(0, val);
acc ^= val;
acc = acc * PRIME64_1 + PRIME64_4;
return acc;
}
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* bEnd = p + len;
U64 h64;
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)32;
}
#endif
if (len>=32) {
const BYTE* const limit = bEnd - 32;
U64 v1 = seed + PRIME64_1 + PRIME64_2;
U64 v2 = seed + PRIME64_2;
U64 v3 = seed + 0;
U64 v4 = seed - PRIME64_1;
do {
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
} while (p<=limit);
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = seed + PRIME64_5;
}
h64 += (U64) len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH64_state_t state;
XXH64_reset(&state, seed);
XXH64_update(&state, input, len);
return XXH64_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash Streaming ======*/
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
{
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
{
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state));
state.v1 = seed + PRIME64_1 + PRIME64_2;
state.v2 = seed + PRIME64_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME64_1;
/* do not write into reserved, planned to be removed in a future version */
memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));
return XXH_OK;
}
FORCE_INLINE
XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
if (input==NULL)
#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)
return XXH_OK;
#else
return XXH_ERROR;
#endif
state->total_len += len;
if (state->memsize + len < 32) { /* fill in tmp buffer */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
state->memsize += (U32)len;
return XXH_OK;
}
if (state->memsize) { /* tmp buffer is full */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
p += 32-state->memsize;
state->memsize = 0;
}
if (p+32 <= bEnd) {
const BYTE* const limit = bEnd - 32;
U64 v1 = state->v1;
U64 v2 = state->v2;
U64 v3 = state->v3;
U64 v4 = state->v4;
do {
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem64;
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
U64 h64;
if (state->total_len >= 32) {
U64 const v1 = state->v1;
U64 const v2 = state->v2;
U64 const v3 = state->v3;
U64 const v4 = state->v4;
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = state->v3 + PRIME64_5;
}
h64 += (U64) state->total_len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_digest_endian(state_in, XXH_littleEndian);
else
return XXH64_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
{
return XXH_readBE64(src);
}
#endif /* XXH_NO_LONG_LONG */

294
sw/include/xxhash.h Normal file
View File

@ -0,0 +1,294 @@
/*
xxHash - Extremely Fast Hash algorithm
Header File
Copyright (C) 2012-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* Notice extracted from xxHash homepage :
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
It also successfully passes all tests from the SMHasher suite.
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
Name Speed Q.Score Author
xxHash 5.4 GB/s 10
CrapWow 3.2 GB/s 2 Andrew
MumurHash 3a 2.7 GB/s 10 Austin Appleby
SpookyHash 2.0 GB/s 10 Bob Jenkins
SBox 1.4 GB/s 9 Bret Mulvey
Lookup3 1.2 GB/s 9 Bob Jenkins
SuperFastHash 1.2 GB/s 1 Paul Hsieh
CityHash64 1.05 GB/s 10 Pike & Alakuijala
FNV 0.55 GB/s 5 Fowler, Noll, Vo
CRC32 0.43 GB/s 9
MD5-32 0.33 GB/s 10 Ronald L. Rivest
SHA1-32 0.28 GB/s 10
Q.Score is a measure of quality of the hash function.
It depends on successfully passing SMHasher test set.
10 is a perfect score.
A 64-bit version, named XXH64, is available since r35.
It offers much better speed, but for 64-bit applications only.
Name Speed on 64 bits Speed on 32 bits
XXH64 13.8 GB/s 1.9 GB/s
XXH32 6.8 GB/s 6.0 GB/s
*/
#ifndef XXHASH_H_5627135585666179
#define XXHASH_H_5627135585666179 1
#if defined (__cplusplus)
extern "C" {
#endif
/* ****************************
* Definitions
******************************/
#include <stddef.h> /* size_t */
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
/* ****************************
* API modifier
******************************/
/** XXH_PRIVATE_API
* This is useful to include xxhash functions in `static` mode
* in order to inline them, and remove their symbol from the public list.
* Methodology :
* #define XXH_PRIVATE_API
* #include "xxhash.h"
* `xxhash.c` is automatically included.
* It's not useful to compile and link it as a separate module.
*/
#ifdef XXH_PRIVATE_API
# ifndef XXH_STATIC_LINKING_ONLY
# define XXH_STATIC_LINKING_ONLY
# endif
# if defined(__GNUC__)
# define XXH_PUBLIC_API static __inline __attribute__((unused))
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define XXH_PUBLIC_API static inline
# elif defined(_MSC_VER)
# define XXH_PUBLIC_API static __inline
# else
/* this version may generate warnings for unused static functions */
# define XXH_PUBLIC_API static
# endif
#else
# define XXH_PUBLIC_API /* do nothing */
#endif /* XXH_PRIVATE_API */
/*!XXH_NAMESPACE, aka Namespace Emulation :
If you want to include _and expose_ xxHash functions from within your own library,
but also want to avoid symbol collisions with other libraries which may also include xxHash,
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
Note that no change is required within the calling program as long as it includes `xxhash.h` :
regular symbol name will be automatically translated by this header.
*/
#ifdef XXH_NAMESPACE
# define XXH_CAT(A,B) A##B
# define XXH_NAME2(A,B) XXH_CAT(A,B)
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
#endif
/* *************************************
* Version
***************************************/
#define XXH_VERSION_MAJOR 0
#define XXH_VERSION_MINOR 6
#define XXH_VERSION_RELEASE 4
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
/*-**********************************************************************
* 32-bit hash
************************************************************************/
typedef unsigned int XXH32_hash_t;
/*! XXH32() :
Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input".
The memory between input & input+length must be valid (allocated and read-accessible).
"seed" can be used to alter the result predictably.
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
/*====== Streaming ======*/
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
/*
These functions generate the xxHash of an input provided in multiple segments.
Note that, for small input, they are slower than single-call functions, due to state management.
For small input, prefer `XXH32()` and `XXH64()` .
XXH state must first be allocated, using XXH*_createState() .
Start a new hash by initializing state with a seed, using XXH*_reset().
Then, feed the hash state by calling XXH*_update() as many times as necessary.
Obviously, input must be allocated and read accessible.
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
Finally, a hash value can be produced anytime, by using XXH*_digest().
This function returns the nn-bits hash as an int or long long.
It's still possible to continue inserting input into the hash state after a digest,
and generate some new hashes later on, by calling again XXH*_digest().
When done, free XXH state space if it was allocated dynamically.
*/
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
*/
#ifndef XXH_NO_LONG_LONG
/*-**********************************************************************
* 64-bit hash
************************************************************************/
typedef unsigned long long XXH64_hash_t;
/*! XXH64() :
Calculate the 64-bit hash of sequence of length "len" stored at memory address "input".
"seed" can be used to alter the result predictably.
This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).
*/
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
/*====== Streaming ======*/
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
#endif /* XXH_NO_LONG_LONG */
#ifdef XXH_STATIC_LINKING_ONLY
/* ================================================================================================
This section contains declarations which are not guaranteed to remain stable.
They may change in future versions, becoming incompatible with a different version of the library.
These declarations should only be used with static linking.
Never use them in association with dynamic linking !
=================================================================================================== */
/* These definitions are only meant to make possible
static allocation of XXH state, on stack or in a struct for example.
Never use members directly. */
struct XXH32_state_s {
unsigned total_len_32;
unsigned large_len;
unsigned v1;
unsigned v2;
unsigned v3;
unsigned v4;
unsigned mem32[4]; /* buffer defined as U32 for alignment */
unsigned memsize;
unsigned reserved; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH32_state_t */
#ifndef XXH_NO_LONG_LONG /* remove 64-bit support */
struct XXH64_state_s {
unsigned long long total_len;
unsigned long long v1;
unsigned long long v2;
unsigned long long v3;
unsigned long long v4;
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
unsigned memsize;
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH64_state_t */
#endif
#ifdef XXH_PRIVATE_API
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
#endif
#endif /* XXH_STATIC_LINKING_ONLY */
#if defined (__cplusplus)
}
#endif
#endif /* XXHASH_H_5627135585666179 */

500
sw/src/dfu.c Normal file
View File

@ -0,0 +1,500 @@
/*
* Fadecandy DFU Bootloader
*
* Copyright (c) 2013 Micah Elizabeth Scott
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <string.h>
#include <toboot-api.h>
#include <toboot-internal.h>
#include <dfu.h>
// Internal flash-programming state machine
static unsigned fl_current_addr = 0;
static enum {
flsIDLE = 0,
flsERASING,
flsPROGRAMMING
} fl_state;
static struct toboot_state {
// Version number of the program being loaded:
// 0 (legacy)
// 1 (toboot v1)
// 2 (toboot v2)
uint8_t version;
// When clearing, first ensure these sectors are cleared prior to updating
uint32_t clear_lo;
uint32_t clear_hi;
// The current block we're clearing
uint32_t clear_current;
// This is the address we'll start programming/erasing from after clearing
uint32_t next_addr;
enum {
/// Toboot has just started
tbsIDLE,
/// Secure erase memory is being cleared
tbsCLEARING,
/// New image is being loaded
tbsLOADING,
} state;
} tb_state;
static dfu_state_t dfu_state = dfuIDLE;
static dfu_status_t dfu_status = OK;
static unsigned dfu_poll_timeout = 1;
static uint32_t dfu_buffer[DFU_TRANSFER_SIZE/4];
static uint32_t dfu_buffer_offset;
static uint32_t fl_num_words;
// Memory offset we're uploading to.
static uint32_t dfu_target_address;
static void set_state(dfu_state_t new_state, dfu_status_t new_status) {
dfu_state = new_state;
dfu_status = new_status;
}
bool fl_is_idle(void) {
return fl_state == flsIDLE;
}
/*
void *memcpy(void *dst, const void *src, size_t cnt) {
uint8_t *dst8 = dst;
const uint8_t *src8 = src;
while (cnt > 0) {
cnt--;
*(dst8++) = *(src8++);
}
return dst;
}
*/
static bool ftfl_busy()
{
// Is the flash memory controller busy?
// return (MSC->STATUS & MSC_STATUS_BUSY);
return 0;
}
static void ftfl_busy_wait()
{
// Wait for the flash memory controller to finish any pending operation.
while (ftfl_busy())
;//watchdog_refresh();
}
static void ftfl_begin_erase_sector(uint32_t address)
{
// Erase the page at the specified address.
//MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
ftfl_busy_wait();
//MSC->ADDRB = address;
//MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
//MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
}
static void ftfl_begin_program_section(uint32_t address)
{
// Write the buffer word to the currently selected address.
// Note that after this is done, the address is incremented by 4.
dfu_buffer_offset = 0;
dfu_target_address = address;
fl_num_words--;
ftfl_busy_wait();
//MSC->ADDRB = address;
ftfl_busy_wait();
//MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
//MSC->WDATA = dfu_buffer[dfu_buffer_offset++];
//MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
}
static uint32_t address_for_block(unsigned blockNum)
{
static uint32_t starting_offset;
if (blockNum == 0) {
// Determine Toboot version.
if ((dfu_buffer[0x94 / 4] & TOBOOT_V2_MAGIC_MASK) == TOBOOT_V2_MAGIC) {
tb_state.version = 2;
starting_offset = ((struct toboot_configuration *)&dfu_buffer[0x94 / 4])->start;
}
// V1 used a different offset.
else if ((dfu_buffer[0x98 / 4] & TOBOOT_V1_MAGIC_MASK) == TOBOOT_V1_MAGIC) {
// Applications that know about Toboot will indicate their block
// offset by placing a magic byte at offset 0x98.
// Ordinarily this would be the address offset for IRQ 22,
// but since there are only 20 IRQs on the EFM32HG, there are three
// 32-bit values that are unused starting at offset 0x94.
// We already use offset 0x94 for "disable boot", so use offset 0x98
// in the incoming stream to indicate flags for Toboot.
tb_state.version = 1;
starting_offset = (dfu_buffer[0x98 / 4] & TOBOOT_V1_APP_PAGE_MASK) >> TOBOOT_V1_APP_PAGE_SHIFT;
}
// Legacy programs default to offset 0x4000.
else {
tb_state.version = 0;
starting_offset = 16;
}
// Set the state to "CLEARING", since we're just starting the programming process.
tb_state.state = tbsCLEARING;
starting_offset *= 0x400;
}
return starting_offset + (blockNum << 10);
}
// If requested, erase sectors before loading new code.
static void pre_clear_next_block(void) {
// If there is another sector to clear, do that.
while (++tb_state.clear_current < 64) {
if (tb_state.clear_current < 32) {
if ((tb_state.clear_lo & (1 << tb_state.clear_current))) {
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
return;
}
}
else if (tb_state.clear_current < 64) {
if ((tb_state.clear_hi & (1 << (tb_state.clear_current & 31)))) {
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
return;
}
}
}
// No more sectors to clear, continue with programming
tb_state.state = tbsLOADING;
ftfl_begin_erase_sector(tb_state.next_addr);
}
void dfu_init(void)
{
tb_state.state = tbsIDLE;
/*
// Ensure the clocks for the memory are enabled
CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
while (!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY))
;
// Unlock the MSC
MSC->LOCK = MSC_UNLOCK_CODE;
// Enable writing to flash
MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
MSC->IEN |= MSC_IEN_WRITE | MSC_IEN_ERASE;
NVIC_EnableIRQ(MSC_IRQn);
*/
}
uint8_t dfu_getstate(void)
{
return dfu_state;
}
bool dfu_download(unsigned blockNum, unsigned blockLength,
unsigned packetOffset, unsigned packetLength, const uint8_t *data)
{
uint32_t i;
if (packetOffset + packetLength > DFU_TRANSFER_SIZE ||
packetOffset + packetLength > blockLength) {
// Overflow!
set_state(dfuERROR, errADDRESS);
return false;
}
// Store more data...
memcpy(((uint8_t *)dfu_buffer) + packetOffset, data, packetLength);
if (packetOffset + packetLength != blockLength) {
// Still waiting for more data.
return true;
}
if (dfu_state != dfuIDLE && dfu_state != dfuDNLOAD_IDLE) {
// Wrong state! Oops.
set_state(dfuERROR, errSTALLEDPKT);
return false;
}
if (ftfl_busy() || fl_state != flsIDLE) {
// Flash controller shouldn't be busy now!
set_state(dfuERROR, errUNKNOWN);
return false;
}
if (!blockLength) {
// End of download
set_state(dfuMANIFEST_SYNC, OK);
return true;
}
// Start programming a block by erasing the corresponding flash sector
fl_state = flsERASING;
fl_current_addr = address_for_block(blockNum);
fl_num_words = blockLength / 4;
// If it's the first block, figure out what we need to do in terms of erasing
// data and programming the new file.
if (blockNum == 0) {
const struct toboot_configuration *old_config = tb_get_config();
// Don't allow overwriting Toboot itself.
if (fl_current_addr < tb_first_free_address()) {
set_state(dfuERROR, errADDRESS);
return false;
}
// Calculate generation number and hash
if (tb_state.version == 2) {
struct toboot_configuration *new_config = (struct toboot_configuration *)&dfu_buffer[0x94 / 4];
// Update generation number
new_config->reserved_gen = old_config->reserved_gen + 1;
// Ensure we know this header is not fake
new_config->config &= ~TOBOOT_CONFIG_FAKE;
// Generate a valid signature
tb_sign_config(new_config);
}
// If the old configuration requires that certain blocks be erased, do that.
tb_state.clear_hi = old_config->erase_mask_hi;
tb_state.clear_lo = old_config->erase_mask_lo;
tb_state.clear_current = 0;
// Ensure we don't erase Toboot itself
for (i = 0; i < tb_first_free_sector(); i++) {
if (i < 32)
tb_state.clear_lo &= ~(1 << i);
else
tb_state.clear_hi &= ~(1 << i);
}
// If the newly-loaded program does not conform to Toboot V2.0, then look
// for any existing programs on the flash and delete those sectors.
// Because of boot priority, we need to ensure that no V2.0 applications
// exist on flash.
if (tb_state.version < 2) {
for (i = tb_first_free_sector(); i < 64; i++) {
if (tb_valid_signature_at_page(i) < 0)
continue;
if (i < 32)
tb_state.clear_lo |= (1 << i);
else
tb_state.clear_hi |= (1 << (i - 32));
}
}
// If we still have sectors to clear, do that. Otherwise,
// go straight into loading the program.
if (tb_state.clear_lo || tb_state.clear_hi) {
tb_state.state = tbsCLEARING;
tb_state.next_addr = fl_current_addr;
pre_clear_next_block();
}
else {
tb_state.state = tbsLOADING;
ftfl_begin_erase_sector(fl_current_addr);
}
}
else
ftfl_begin_erase_sector(fl_current_addr);
set_state(dfuDNLOAD_SYNC, OK);
return true;
}
static bool fl_handle_status(uint8_t fstat)
{
/*
* Handle common errors from an FSTAT register value.
* The indicated "specificError" is used for reporting a command-specific
* error from MGSTAT0.
*
* Returns true if handled, false if not.
*/
#if 0
if (fstat & MSC_STATUS_BUSY) {
// Still working...
return true;
}
if (fstat & (MSC_STATUS_ERASEABORTED | MSC_STATUS_WORDTIMEOUT)) {
// Bus collision. We did something wrong internally.
set_state(dfuERROR, errUNKNOWN);
fl_state = flsIDLE;
return true;
}
if (fstat & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) {
// Address or protection error
set_state(dfuERROR, errADDRESS);
fl_state = flsIDLE;
return true;
}
if (fl_state == flsPROGRAMMING) {
// Still programming...
return true;
}
#endif
return false;
}
static void fl_state_poll(void)
{
// Try to advance the state of our own flash programming state machine.
uint32_t fstat = 0;//MSC->STATUS;
switch (fl_state) {
case flsIDLE:
break;
case flsERASING:
if (!fl_handle_status(fstat)) {
// ?If we're still pre-clearing, continue with that.
if (tb_state.state == tbsCLEARING) {
pre_clear_next_block();
}
// Done! Move on to programming the sector.
else {
fl_state = flsPROGRAMMING;
ftfl_begin_program_section(fl_current_addr);
}
}
break;
case flsPROGRAMMING:
if (!fl_handle_status(fstat)) {
// Done!
fl_state = flsIDLE;
}
break;
}
}
bool dfu_getstatus(uint8_t status[8])
{
switch (dfu_state) {
case dfuDNLOAD_SYNC:
case dfuDNBUSY:
// Programming operation in progress. Advance our private flash state machine.
fl_state_poll();
if (dfu_state == dfuERROR) {
// An error occurred inside fl_state_poll();
} else if (fl_state == flsIDLE) {
dfu_state = dfuDNLOAD_IDLE;
} else {
dfu_state = dfuDNBUSY;
}
break;
case dfuMANIFEST_SYNC:
// Ready to reboot. The main thread will take care of this. Also let the DFU tool
// know to leave us alone until this happens.
dfu_state = dfuMANIFEST;
dfu_poll_timeout = 10;
break;
case dfuMANIFEST:
// Perform the reboot
dfu_state = dfuMANIFEST_WAIT_RESET;
dfu_poll_timeout = 1000;
break;
default:
break;
}
status[0] = dfu_status;
status[1] = dfu_poll_timeout;
status[2] = dfu_poll_timeout >> 8;
status[3] = dfu_poll_timeout >> 16;
status[4] = dfu_state;
status[5] = 0; // iString
return true;
}
bool dfu_clrstatus(void)
{
switch (dfu_state) {
case dfuERROR:
// Clear an error
set_state(dfuIDLE, OK);
return true;
default:
// Unexpected request
set_state(dfuERROR, errSTALLEDPKT);
return false;
}
}
bool dfu_abort(void)
{
set_state(dfuIDLE, OK);
return true;
}
/*
void MSC_Handler(void) {
uint32_t msc_irq_reason = MSC->IF;
if (msc_irq_reason & MSC_IF_WRITE) {
// Write the buffer word to the currently selected address.
// Note that after this is done, the address is incremented by 4.
if (fl_num_words > 0) {
fl_num_words--;
dfu_target_address += 4;
MSC->ADDRB = dfu_target_address;
ftfl_busy_wait();
MSC->WDATA = dfu_buffer[dfu_buffer_offset++];
MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
}
else {
// Move to the IDLE state only if we're out of data to write.
fl_state = flsIDLE;
}
}
// Clear iterrupts so we don't fire again.
MSC->IFC = MSC_IFC_ERASE | MSC_IFC_WRITE;
}
*/

138
sw/src/toboot.c Normal file
View File

@ -0,0 +1,138 @@
#include "toboot-api.h"
#include "toboot-internal.h"
#define XXH_NO_LONG_LONG
#define XXH_FORCE_ALIGN_CHECK 0
#define XXH_FORCE_NATIVE_FORMAT 0
#define XXH_PRIVATE_API
#include "xxhash.h"
static const struct toboot_configuration *current_config = NULL;
uint32_t tb_first_free_address(void) {
return 131072;
/*
extern uint32_t _eflash;
extern uint32_t _sdtext;
extern uint32_t _edtext;
#define PADDR(x) ((uint32_t)&x)
#define PAGE_SIZE 1024
#define PAGE_ROUND_UP(x) ( (((uint32_t)(x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1)) )
return PAGE_ROUND_UP(PADDR(_eflash) + (PADDR(_edtext) - PADDR(_sdtext)));
#undef PADDR
#undef PAGE_SIZE
#undef PAGE_ROUND_UP
*/
}
uint32_t tb_config_hash(const struct toboot_configuration *cfg) {
return XXH32(cfg, sizeof(*cfg) - 4, TOBOOT_HASH_SEED);
}
void tb_sign_config(struct toboot_configuration *cfg) {
cfg->reserved_hash = tb_config_hash(cfg);
}
int tb_valid_signature_at_page(uint32_t page) {
const struct toboot_configuration *cfg = (const struct toboot_configuration *)((page * 1024) + 0x94);
if (cfg->magic != TOBOOT_V2_MAGIC)
return -1;
uint32_t calc_hash = tb_config_hash(cfg);
if (calc_hash != cfg->reserved_hash)
return -2;
return 0;
}
uint32_t tb_first_free_sector(void) {
return tb_first_free_address() / 1024;
}
const struct toboot_configuration *tb_get_config(void) {
uint32_t __app_start__ = 131072;
// When examining every application in flash, find the newest program
// with the highest generation counter.
uint32_t newest_generation = 0;
// Fake toboot config, for v1 and v0 programs.
static struct toboot_configuration fake_config;
if (current_config)
return current_config;
// Look for a V2 header
uint32_t page;
for (page = 1; page < 65536/1024; page++) {
if (!tb_valid_signature_at_page(page)) {
const struct toboot_configuration *test_cfg = (const struct toboot_configuration *)((page * 1024) + 0x94);
if (test_cfg->reserved_gen > newest_generation) {
newest_generation = test_cfg->reserved_gen;
current_config = test_cfg;
}
}
}
if (current_config)
return current_config;
// No V2 header found, so create one.
// Fake V2 magic
fake_config.magic = TOBOOT_V2_MAGIC;
if (((*((uint32_t *)(((uint32_t)&__app_start__) + 0x98))) & TOBOOT_V1_MAGIC_MASK) == TOBOOT_V1_MAGIC)
// Applications that know about Toboot will indicate their block
// offset by placing a magic byte at offset 0x98.
// Ordinarily this would be the address offset for IRQ 22,
// but since there are only 20 IRQs on the EFM32HG, there are three
// 32-bit values that are unused starting at offset 0x94.
// We already use offset 0x94 for "disable boot", so use offset 0x98
// in the incoming stream to indicate flags for Toboot.
fake_config.start = ((*((uint32_t *)(((uint32_t)&__app_start__) + 0x98))) & TOBOOT_V1_APP_PAGE_MASK) >> TOBOOT_V1_APP_PAGE_SHIFT;
else
// Default to offset 0x4000
fake_config.start = 16;
// Leave interrupts enabled (and indicate the header is fake)
fake_config.config = TOBOOT_CONFIG_FLAG_ENABLE_IRQ | TOBOOT_CONFIG_FAKE;
// Lock out bootloader entry, if the magic value is present
if (((*((uint32_t *)(((uint32_t)&__app_start__) + 0x94))) & TOBOOT_V1_CFG_MAGIC_MASK) == TOBOOT_V1_CFG_MAGIC)
fake_config.lock_entry = TOBOOT_LOCKOUT_MAGIC;
else
fake_config.lock_entry = 0;
// Don't erase anything in particular
fake_config.erase_mask_lo = 0;
fake_config.erase_mask_hi = 0;
// Calculate a valid hash
tb_sign_config(&fake_config);
return &fake_config;
}
uint32_t tb_generation(const struct toboot_configuration *cfg) {
if (!cfg)
return 0;
return cfg->reserved_gen;
}
__attribute__ ((used, section(".toboot_configuration"))) struct toboot_configuration toboot_configuration = {
.magic = TOBOOT_V2_MAGIC,
// The current "generation" flag sits at the same location as the
// old Toboot "Config" flag. By setting "reserved_gen" to this value,
// we can make the V1 bootloader treat V2 images as valid.
.reserved_gen = TOBOOT_V1_APP_MAGIC,
.start = 0,
.config = 0,
.lock_entry = 0,
.erase_mask_lo = 0,
.erase_mask_hi = 0,
.reserved_hash = 0,
};

229
sw/src/usb-desc.c Normal file
View File

@ -0,0 +1,229 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <usb-desc.h>
// USB Descriptors are binary data which the USB host reads to
// automatically detect a USB device's capabilities. The format
// and meaning of every field is documented in numerous USB
// standards. When working with USB descriptors, despite the
// complexity of the standards and poor writing quality in many
// of those documents, remember descriptors are nothing more
// than constant binary data that tells the USB host what the
// device can do. Computers will load drivers based on this data.
// Those drivers then communicate on the endpoints specified by
// the descriptors.
// To configure a new combination of interfaces or make minor
// changes to existing configuration (eg, change the name or ID
// numbers), usually you would edit "usb_desc.h". This file
// is meant to be configured by the header, so generally it is
// only edited to add completely new USB interfaces or features.
// **************************************************************
// USB Device
// **************************************************************
#define LSB(n) ((n) & 255)
#define MSB(n) (((n) >> 8) & 255)
#define USB_DT_BOS_SIZE 5
#define USB_DT_BOS 0xf
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DC_PLATFORM 5
struct usb_bos_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumDeviceCaps;
} __attribute__((packed));
// USB Device Descriptor. The USB host reads this first, to learn
// what type of device is connected.
static const uint8_t device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x10, 0x02, // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
EP0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
LSB(DEVICE_VER), MSB(DEVICE_VER), // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};
// These descriptors must NOT be "const", because the USB DMA
// has trouble accessing flash memory with enough bandwidth
// while the processor is executing from flash.
// **************************************************************
// USB Configuration
// **************************************************************
// USB Configuration Descriptor. This huge descriptor tells all
// of the devices capbilities.
static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG_DESC_SIZE), // wTotalLength
MSB(CONFIG_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
2, // iConfiguration
0x80, // bmAttributes
50, // bMaxPower
// interface descriptor, DFU Mode (DFU spec Table 4.4)
9, // bLength
4, // bDescriptorType
DFU_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
0, // bNumEndpoints
0xFE, // bInterfaceClass
0x01, // bInterfaceSubClass
0x02, // bInterfaceProtocol
2, // iInterface
// DFU Functional Descriptor (DFU spec TAble 4.2)
9, // bLength
0x21, // bDescriptorType
0x0D, // bmAttributes
LSB(DFU_DETACH_TIMEOUT), // wDetachTimeOut
MSB(DFU_DETACH_TIMEOUT),
LSB(DFU_TRANSFER_SIZE), // wTransferSize
MSB(DFU_TRANSFER_SIZE),
0x01,0x01, // bcdDFUVersion
};
// **************************************************************
// String Descriptors
// **************************************************************
// The descriptors above can provide human readable strings,
// referenced by index numbers. These descriptors are the
// actual string data
static const struct usb_string_descriptor_struct string0 = {
4,
3,
{0x0409}
};
// Microsoft OS String Descriptor. See: https://github.com/pbatard/libwdi/wiki/WCID-Devices
static const struct usb_string_descriptor_struct usb_string_microsoft = {
18, 3,
{'M','S','F','T','1','0','0', MSFT_VENDOR_CODE}
};
// Microsoft WCID
const uint8_t usb_microsoft_wcid[MSFT_WCID_LEN] = {
MSFT_WCID_LEN, 0, 0, 0, // Length
0x00, 0x01, // Version
0x04, 0x00, // Compatibility ID descriptor index
0x01, // Number of sections
0, 0, 0, 0, 0, 0, 0, // Reserved (7 bytes)
0, // Interface number
0x01, // Reserved
'W','I','N','U','S','B',0,0, // Compatible ID
0,0,0,0,0,0,0,0, // Sub-compatible ID (unused)
0,0,0,0,0,0, // Reserved
};
const struct webusb_url_descriptor landing_url_descriptor = {
.bLength = LANDING_PAGE_DESCRIPTOR_SIZE,
.bDescriptorType = WEBUSB_DT_URL,
.bScheme = WEBUSB_URL_SCHEME_HTTPS,
.URL = LANDING_PAGE_URL
};
struct full_bos {
struct usb_bos_descriptor bos;
struct webusb_platform_descriptor webusb;
};
static const struct full_bos full_bos = {
.bos = {
.bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS,
.wTotalLength = USB_DT_BOS_SIZE + WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bNumDeviceCaps = 1,
},
.webusb = {
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_DC_PLATFORM,
.bReserved = 0,
.platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE,
.iLandingPage = 1,
},
};
__attribute__((aligned(4)))
static const struct usb_string_descriptor_struct usb_string_manufacturer_name = {
2 + MANUFACTURER_NAME_LEN,
3,
MANUFACTURER_NAME
};
__attribute__((aligned(4)))
struct usb_string_descriptor_struct usb_string_product_name = {
2 + PRODUCT_NAME_LEN,
3,
PRODUCT_NAME
};
// **************************************************************
// Descriptors List
// **************************************************************
// This table provides access to all the descriptor data above.
const usb_descriptor_list_t usb_descriptor_list[] = {
{0x0100, sizeof(device_descriptor), device_descriptor},
{0x0200, sizeof(config_descriptor), config_descriptor},
{0x0300, 0, (const uint8_t *)&string0},
{0x0301, 0, (const uint8_t *)&usb_string_manufacturer_name},
{0x0302, 0, (const uint8_t *)&usb_string_product_name},
{0x03EE, 0, (const uint8_t *)&usb_string_microsoft},
{0x0F00, sizeof(full_bos), (const uint8_t *)&full_bos},
{0, 0, NULL}
};

245
sw/src/usb-dev.c Normal file
View File

@ -0,0 +1,245 @@
#include <stdint.h>
#include <unistd.h>
#include <usb.h>
#include <dfu.h>
#include <printf.h>
#include <usb-desc.h>
static uint8_t reply_buffer[8];
static uint8_t usb_configuration = 0;
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
static uint8_t rx_buffer[USB_MAX_PACKET_SIZE];
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
{
const uint8_t *data = NULL;
uint32_t datalen = 0;
const usb_descriptor_list_t *list;
// printf("%s:%d SETUP packet (%04x) value: %02x index: %02x\n", __FILE__, __LINE__, setup->wRequestAndType, setup->wIndex, setup->wValue);
switch (setup->wRequestAndType)
{
case 0x0500: // SET_ADDRESS
// TODO: Handle set_daddr
// efm32hg_set_daddr(setup->wValue);
break;
case 0x0900: // SET_CONFIGURATION
usb_configuration = setup->wValue;
break;
case 0x0880: // GET_CONFIGURATION
reply_buffer[0] = usb_configuration;
datalen = 1;
data = reply_buffer;
break;
case 0x0080: // GET_STATUS (device)
reply_buffer[0] = 0;
reply_buffer[1] = 0;
datalen = 2;
data = reply_buffer;
break;
case 0x0082: // GET_STATUS (endpoint)
if (setup->wIndex > 0)
{
printf("get_status (setup->wIndex: %d)\n", setup->wIndex);
usb_err(dev, 0);
return;
}
reply_buffer[0] = 0;
reply_buffer[1] = 0;
// XXX handle endpoint stall here
// if (USB->DIEP0CTL & USB_DIEP_CTL_STALL)
// reply_buffer[0] = 1;
data = reply_buffer;
datalen = 2;
break;
case 0x0102: // CLEAR_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0)
{
// TODO: do we need to handle IN vs OUT here?
printf("%s:%d clear feature (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
// XXX: Should we clear the stall bit?
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
// TODO: do we need to clear the data toggle here?
break;
case 0x0302: // SET_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0)
{
// TODO: do we need to handle IN vs OUT here?
printf("%s:%d clear feature (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
// XXX: Should we set the stall bit?
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
// TODO: do we need to clear the data toggle here?
break;
case 0x0680: // GET_DESCRIPTOR
case 0x0681:
for (list = usb_descriptor_list; 1; list++)
{
if (list->addr == NULL)
break;
if (setup->wValue == list->wValue)
{
data = list->addr;
if ((setup->wValue >> 8) == 3)
{
// for string descriptors, use the descriptor's
// length field, allowing runtime configured
// length.
datalen = *(list->addr);
}
else
{
datalen = list->length;
}
goto send;
}
}
printf("%s:%d couldn't find descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
case (MSFT_VENDOR_CODE << 8) | 0xC0: // Get Microsoft descriptor
case (MSFT_VENDOR_CODE << 8) | 0xC1:
if (setup->wIndex == 0x0004)
{
// Return WCID descriptor
data = usb_microsoft_wcid;
datalen = MSFT_WCID_LEN;
break;
}
printf("%s:%d couldn't find microsoft descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
case (WEBUSB_VENDOR_CODE << 8) | 0xC0: // Get WebUSB descriptor
if (setup->wIndex == 0x0002)
{
if (setup->wValue == 0x0001)
{
// Return landing page URL descriptor
data = (uint8_t*)&landing_url_descriptor;
datalen = LANDING_PAGE_DESCRIPTOR_SIZE;
break;
}
}
printf("%s:%d couldn't find webusb descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
case 0x0121: // DFU_DNLOAD
if (setup->wIndex > 0)
{
printf("%s:%d dfu download descriptor index invalid (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
// Data comes in the OUT phase. But if it's a zero-length request, handle it now.
if (setup->wLength == 0)
{
if (!dfu_download(setup->wValue, 0, 0, 0, NULL))
{
usb_err(dev, 0);
return;
}
usb_ack(dev, 0);
return;
}
unsigned int len = setup->wLength;
if (len > sizeof(rx_buffer))
len = sizeof(rx_buffer);
usb_recv(dev, rx_buffer, len);
return;
case 0x03a1: // DFU_GETSTATUS
if (setup->wIndex > 0)
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
if (dfu_getstatus(reply_buffer))
{
data = reply_buffer;
datalen = 6;
break;
}
else
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
break;
case 0x0421: // DFU_CLRSTATUS
if (setup->wIndex > 0)
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
if (dfu_clrstatus())
{
break;
}
else
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
case 0x05a1: // DFU_GETSTATE
if (setup->wIndex > 0)
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
reply_buffer[0] = dfu_getstate();
data = reply_buffer;
datalen = 1;
break;
case 0x0621: // DFU_ABORT
if (setup->wIndex > 0)
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
if (dfu_abort())
{
break;
}
else
{
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
default:
printf("%s:%d unrecognized request type (%04x) value: %02x index: %02x\n", __FILE__, __LINE__, setup->wRequestAndType, setup->wIndex, setup->wValue);
usb_err(dev, 0);
return;
}
send:
if (data && datalen) {
printf("%s:%d sending %d bytes from %08x\n", __FILE__, __LINE__, datalen, data);
usb_send(dev, 0, data, datalen);
}
else
usb_ack(dev, 0);
return;
}