Fix whitespace
Use a consistent standard - Tabs in front for indenting, spaces after for anything else. This way everything stays nice and lined up while also letting users change there prefered indent level. Most of the new files from Haata where already in this format.
This commit is contained in:
parent
a6fdeb47ea
commit
1392571bd7
@ -21,7 +21,7 @@
|
||||
#|
|
||||
set( CHIP
|
||||
"mk20dx128vlf5" # McHCK mk20dx128vlf5
|
||||
# "mk20dx256vlh7" # Kiibohd-dfu mk20dx256vlh7
|
||||
# "mk20dx256vlh7" # Kiibohd-dfu mk20dx256vlh7
|
||||
)
|
||||
|
||||
|
||||
@ -34,8 +34,8 @@ set( CHIP
|
||||
#| Stick with gcc unless you know what you're doing
|
||||
#| Currently only arm is supported with clang
|
||||
set( COMPILER
|
||||
"gcc" # arm-none-eabi-gcc / avr-gcc - Default
|
||||
# "clang" # arm-none-eabi
|
||||
"gcc" # arm-none-eabi-gcc / avr-gcc - Default
|
||||
# "clang" # arm-none-eabi
|
||||
CACHE STRING "Compiler Type" )
|
||||
|
||||
|
||||
|
216
Bootloader/dfu.c
216
Bootloader/dfu.c
@ -26,146 +26,146 @@
|
||||
|
||||
void dfu_write_done( enum dfu_status err, struct dfu_ctx *ctx )
|
||||
{
|
||||
ctx->status = err;
|
||||
if (ctx->status == DFU_STATUS_OK) {
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuDNBUSY:
|
||||
ctx->state = DFU_STATE_dfuDNLOAD_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
}
|
||||
ctx->status = err;
|
||||
if (ctx->status == DFU_STATUS_OK) {
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuDNBUSY:
|
||||
ctx->state = DFU_STATE_dfuDNLOAD_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_dnload_complete( void *buf, ssize_t len, void *cbdata )
|
||||
{
|
||||
struct dfu_ctx *ctx = cbdata;
|
||||
struct dfu_ctx *ctx = cbdata;
|
||||
|
||||
if (len > 0)
|
||||
ctx->state = DFU_STATE_dfuDNBUSY;
|
||||
else
|
||||
ctx->state = DFU_STATE_dfuMANIFEST;
|
||||
ctx->status = ctx->finish_write(buf, ctx->off, len);
|
||||
ctx->off += len;
|
||||
ctx->len = len;
|
||||
if (len > 0)
|
||||
ctx->state = DFU_STATE_dfuDNBUSY;
|
||||
else
|
||||
ctx->state = DFU_STATE_dfuMANIFEST;
|
||||
ctx->status = ctx->finish_write(buf, ctx->off, len);
|
||||
ctx->off += len;
|
||||
ctx->len = len;
|
||||
|
||||
if (ctx->status != DFU_STATUS_async)
|
||||
dfu_write_done(ctx->status, ctx);
|
||||
if (ctx->status != DFU_STATUS_async)
|
||||
dfu_write_done(ctx->status, ctx);
|
||||
|
||||
usb_handle_control_status(ctx->state == DFU_STATE_dfuERROR);
|
||||
usb_handle_control_status(ctx->state == DFU_STATE_dfuERROR);
|
||||
}
|
||||
|
||||
static void dfu_reset_system( void *buf, ssize_t len, void *cbdata )
|
||||
{
|
||||
SOFTWARE_RESET();
|
||||
SOFTWARE_RESET();
|
||||
}
|
||||
|
||||
static int dfu_handle_control( struct usb_ctrl_req_t *req, void *data )
|
||||
{
|
||||
struct dfu_ctx *ctx = data;
|
||||
int fail = 1;
|
||||
struct dfu_ctx *ctx = data;
|
||||
int fail = 1;
|
||||
|
||||
switch ((enum dfu_ctrl_req_code)req->bRequest) {
|
||||
case USB_CTRL_REQ_DFU_DNLOAD: {
|
||||
void *buf;
|
||||
switch ((enum dfu_ctrl_req_code)req->bRequest) {
|
||||
case USB_CTRL_REQ_DFU_DNLOAD: {
|
||||
void *buf;
|
||||
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuIDLE:
|
||||
ctx->off = 0;
|
||||
break;
|
||||
case DFU_STATE_dfuDNLOAD_IDLE:
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuIDLE:
|
||||
ctx->off = 0;
|
||||
break;
|
||||
case DFU_STATE_dfuDNLOAD_IDLE:
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX we are not allowed to STALL here, and we need to eat all transferred data.
|
||||
* better not allow setup_write to break the protocol.
|
||||
*/
|
||||
ctx->status = ctx->setup_write(ctx->off, req->wLength, &buf);
|
||||
if (ctx->status != DFU_STATUS_OK) {
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
goto err_have_status;
|
||||
}
|
||||
/**
|
||||
* XXX we are not allowed to STALL here, and we need to eat all transferred data.
|
||||
* better not allow setup_write to break the protocol.
|
||||
*/
|
||||
ctx->status = ctx->setup_write(ctx->off, req->wLength, &buf);
|
||||
if (ctx->status != DFU_STATUS_OK) {
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
goto err_have_status;
|
||||
}
|
||||
|
||||
if (req->wLength > 0)
|
||||
usb_ep0_rx(buf, req->wLength, dfu_dnload_complete, ctx);
|
||||
else
|
||||
dfu_dnload_complete(NULL, 0, ctx);
|
||||
goto out_no_status;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_GETSTATUS: {
|
||||
struct dfu_status_t st;
|
||||
if (req->wLength > 0)
|
||||
usb_ep0_rx(buf, req->wLength, dfu_dnload_complete, ctx);
|
||||
else
|
||||
dfu_dnload_complete(NULL, 0, ctx);
|
||||
goto out_no_status;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_GETSTATUS: {
|
||||
struct dfu_status_t st;
|
||||
|
||||
st.bState = ctx->state;
|
||||
st.bStatus = ctx->status;
|
||||
st.bwPollTimeout = 1000; /* XXX */
|
||||
/**
|
||||
* If we're in DFU_STATE_dfuMANIFEST, we just finished
|
||||
* the download, and we're just about to send our last
|
||||
* status report. Once the report has been sent, go
|
||||
* and reset the system to put the new firmware into
|
||||
* effect.
|
||||
*/
|
||||
usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
|
||||
if (ctx->state == DFU_STATE_dfuMANIFEST) {
|
||||
usb_handle_control_status_cb(dfu_reset_system);
|
||||
goto out_no_status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_CLRSTATUS:
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
ctx->status = DFU_STATUS_OK;
|
||||
break;
|
||||
case USB_CTRL_REQ_DFU_GETSTATE: {
|
||||
uint8_t st = ctx->state;
|
||||
usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_ABORT:
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuIDLE:
|
||||
case DFU_STATE_dfuDNLOAD_IDLE:
|
||||
/* case DFU_STATE_dfuUPLOAD_IDLE: */
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
/* case USB_CTRL_REQ_DFU_UPLOAD: */
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
st.bState = ctx->state;
|
||||
st.bStatus = ctx->status;
|
||||
st.bwPollTimeout = 1000; /* XXX */
|
||||
/**
|
||||
* If we're in DFU_STATE_dfuMANIFEST, we just finished
|
||||
* the download, and we're just about to send our last
|
||||
* status report. Once the report has been sent, go
|
||||
* and reset the system to put the new firmware into
|
||||
* effect.
|
||||
*/
|
||||
usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
|
||||
if (ctx->state == DFU_STATE_dfuMANIFEST) {
|
||||
usb_handle_control_status_cb(dfu_reset_system);
|
||||
goto out_no_status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_CLRSTATUS:
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
ctx->status = DFU_STATUS_OK;
|
||||
break;
|
||||
case USB_CTRL_REQ_DFU_GETSTATE: {
|
||||
uint8_t st = ctx->state;
|
||||
usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case USB_CTRL_REQ_DFU_ABORT:
|
||||
switch (ctx->state) {
|
||||
case DFU_STATE_dfuIDLE:
|
||||
case DFU_STATE_dfuDNLOAD_IDLE:
|
||||
/* case DFU_STATE_dfuUPLOAD_IDLE: */
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
/* case USB_CTRL_REQ_DFU_UPLOAD: */
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
|
||||
fail = 0;
|
||||
goto out;
|
||||
fail = 0;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
ctx->status = DFU_STATUS_errSTALLEDPKT;
|
||||
ctx->status = DFU_STATUS_errSTALLEDPKT;
|
||||
err_have_status:
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
ctx->state = DFU_STATE_dfuERROR;
|
||||
out:
|
||||
usb_handle_control_status(fail);
|
||||
usb_handle_control_status(fail);
|
||||
out_no_status:
|
||||
return (1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void dfu_init( dfu_setup_write_t setup_write, dfu_finish_write_t finish_write, struct dfu_ctx *ctx )
|
||||
{
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
ctx->setup_write = setup_write;
|
||||
ctx->finish_write = finish_write;
|
||||
usb_attach_function(&dfu_function, &ctx->header);
|
||||
ctx->state = DFU_STATE_dfuIDLE;
|
||||
ctx->setup_write = setup_write;
|
||||
ctx->finish_write = finish_write;
|
||||
usb_attach_function(&dfu_function, &ctx->header);
|
||||
}
|
||||
|
||||
const struct usbd_function dfu_function = {
|
||||
.control = dfu_handle_control,
|
||||
.interface_count = USB_FUNCTION_DFU_IFACE_COUNT,
|
||||
.control = dfu_handle_control,
|
||||
.interface_count = USB_FUNCTION_DFU_IFACE_COUNT,
|
||||
};
|
||||
|
||||
|
196
Bootloader/dfu.h
196
Bootloader/dfu.h
@ -30,104 +30,104 @@
|
||||
|
||||
|
||||
#ifndef USB_DFU_TRANSFER_SIZE
|
||||
#define USB_DFU_TRANSFER_SIZE FLASH_SECTOR_SIZE
|
||||
#define USB_DFU_TRANSFER_SIZE FLASH_SECTOR_SIZE
|
||||
#endif
|
||||
|
||||
#define USB_FUNCTION_DESC_DFU_DECL \
|
||||
struct dfu_function_desc
|
||||
struct dfu_function_desc
|
||||
|
||||
#define USB_FUNCTION_DFU_IFACE_COUNT 1
|
||||
#define USB_FUNCTION_DFU_RX_EP_COUNT 0
|
||||
#define USB_FUNCTION_DFU_TX_EP_COUNT 0
|
||||
#define USB_FUNCTION_DFU_IFACE_COUNT 1
|
||||
#define USB_FUNCTION_DFU_RX_EP_COUNT 0
|
||||
#define USB_FUNCTION_DFU_TX_EP_COUNT 0
|
||||
|
||||
|
||||
|
||||
// ----- Macros -----
|
||||
|
||||
#define USB_FUNCTION_DESC_DFU(state...) \
|
||||
{ \
|
||||
.iface = { \
|
||||
.bLength = sizeof(struct usb_desc_iface_t), \
|
||||
.bDescriptorType = USB_DESC_IFACE, \
|
||||
.bInterfaceNumber = USB_FUNCTION_IFACE(0, state), \
|
||||
.bAlternateSetting = 0, \
|
||||
.bNumEndpoints = 0, \
|
||||
.bInterfaceClass = USB_DEV_CLASS_APP, \
|
||||
.bInterfaceSubClass = USB_DEV_SUBCLASS_APP_DFU, \
|
||||
.bInterfaceProtocol = USB_DEV_PROTO_DFU_DFU, \
|
||||
.iInterface = 0, \
|
||||
}, \
|
||||
.dfu = { \
|
||||
.bLength = sizeof(struct dfu_desc_functional), \
|
||||
.bDescriptorType = { \
|
||||
.id = 0x1, \
|
||||
.type_type = USB_DESC_TYPE_CLASS \
|
||||
}, \
|
||||
.will_detach = 1, \
|
||||
.manifestation_tolerant = 0, \
|
||||
.can_upload = 0, \
|
||||
.can_download = 1, \
|
||||
.wDetachTimeOut = 0, \
|
||||
.wTransferSize = USB_DFU_TRANSFER_SIZE, \
|
||||
.bcdDFUVersion = { .maj = 1, .min = 1 } \
|
||||
} \
|
||||
}
|
||||
{ \
|
||||
.iface = { \
|
||||
.bLength = sizeof(struct usb_desc_iface_t), \
|
||||
.bDescriptorType = USB_DESC_IFACE, \
|
||||
.bInterfaceNumber = USB_FUNCTION_IFACE(0, state), \
|
||||
.bAlternateSetting = 0, \
|
||||
.bNumEndpoints = 0, \
|
||||
.bInterfaceClass = USB_DEV_CLASS_APP, \
|
||||
.bInterfaceSubClass = USB_DEV_SUBCLASS_APP_DFU, \
|
||||
.bInterfaceProtocol = USB_DEV_PROTO_DFU_DFU, \
|
||||
.iInterface = 0, \
|
||||
}, \
|
||||
.dfu = { \
|
||||
.bLength = sizeof(struct dfu_desc_functional), \
|
||||
.bDescriptorType = { \
|
||||
.id = 0x1, \
|
||||
.type_type = USB_DESC_TYPE_CLASS \
|
||||
}, \
|
||||
.will_detach = 1, \
|
||||
.manifestation_tolerant = 0, \
|
||||
.can_upload = 0, \
|
||||
.can_download = 1, \
|
||||
.wDetachTimeOut = 0, \
|
||||
.wTransferSize = USB_DFU_TRANSFER_SIZE, \
|
||||
.bcdDFUVersion = { .maj = 1, .min = 1 } \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----- Enumerations -----
|
||||
|
||||
enum dfu_dev_subclass {
|
||||
USB_DEV_SUBCLASS_APP_DFU = 0x01
|
||||
USB_DEV_SUBCLASS_APP_DFU = 0x01
|
||||
};
|
||||
|
||||
enum dfu_dev_proto {
|
||||
USB_DEV_PROTO_DFU_APP = 0x01,
|
||||
USB_DEV_PROTO_DFU_DFU = 0x02
|
||||
USB_DEV_PROTO_DFU_APP = 0x01,
|
||||
USB_DEV_PROTO_DFU_DFU = 0x02
|
||||
};
|
||||
|
||||
enum dfu_ctrl_req_code {
|
||||
USB_CTRL_REQ_DFU_DETACH = 0,
|
||||
USB_CTRL_REQ_DFU_DNLOAD = 1,
|
||||
USB_CTRL_REQ_DFU_UPLOAD = 2,
|
||||
USB_CTRL_REQ_DFU_GETSTATUS = 3,
|
||||
USB_CTRL_REQ_DFU_CLRSTATUS = 4,
|
||||
USB_CTRL_REQ_DFU_GETSTATE = 5,
|
||||
USB_CTRL_REQ_DFU_ABORT = 6
|
||||
USB_CTRL_REQ_DFU_DETACH = 0,
|
||||
USB_CTRL_REQ_DFU_DNLOAD = 1,
|
||||
USB_CTRL_REQ_DFU_UPLOAD = 2,
|
||||
USB_CTRL_REQ_DFU_GETSTATUS = 3,
|
||||
USB_CTRL_REQ_DFU_CLRSTATUS = 4,
|
||||
USB_CTRL_REQ_DFU_GETSTATE = 5,
|
||||
USB_CTRL_REQ_DFU_ABORT = 6
|
||||
};
|
||||
|
||||
enum dfu_status {
|
||||
DFU_STATUS_async = 0xff,
|
||||
DFU_STATUS_OK = 0x00,
|
||||
DFU_STATUS_errTARGET = 0x01,
|
||||
DFU_STATUS_errFILE = 0x02,
|
||||
DFU_STATUS_errWRITE = 0x03,
|
||||
DFU_STATUS_errERASE = 0x04,
|
||||
DFU_STATUS_errCHECK_ERASED = 0x05,
|
||||
DFU_STATUS_errPROG = 0x06,
|
||||
DFU_STATUS_errVERIFY = 0x07,
|
||||
DFU_STATUS_errADDRESS = 0x08,
|
||||
DFU_STATUS_errNOTDONE = 0x09,
|
||||
DFU_STATUS_errFIRMWARE = 0x0a,
|
||||
DFU_STATUS_errVENDOR = 0x0b,
|
||||
DFU_STATUS_errUSBR = 0x0c,
|
||||
DFU_STATUS_errPOR = 0x0d,
|
||||
DFU_STATUS_errUNKNOWN = 0x0e,
|
||||
DFU_STATUS_errSTALLEDPKT = 0x0f
|
||||
DFU_STATUS_async = 0xff,
|
||||
DFU_STATUS_OK = 0x00,
|
||||
DFU_STATUS_errTARGET = 0x01,
|
||||
DFU_STATUS_errFILE = 0x02,
|
||||
DFU_STATUS_errWRITE = 0x03,
|
||||
DFU_STATUS_errERASE = 0x04,
|
||||
DFU_STATUS_errCHECK_ERASED = 0x05,
|
||||
DFU_STATUS_errPROG = 0x06,
|
||||
DFU_STATUS_errVERIFY = 0x07,
|
||||
DFU_STATUS_errADDRESS = 0x08,
|
||||
DFU_STATUS_errNOTDONE = 0x09,
|
||||
DFU_STATUS_errFIRMWARE = 0x0a,
|
||||
DFU_STATUS_errVENDOR = 0x0b,
|
||||
DFU_STATUS_errUSBR = 0x0c,
|
||||
DFU_STATUS_errPOR = 0x0d,
|
||||
DFU_STATUS_errUNKNOWN = 0x0e,
|
||||
DFU_STATUS_errSTALLEDPKT = 0x0f
|
||||
};
|
||||
|
||||
enum dfu_state {
|
||||
DFU_STATE_appIDLE = 0,
|
||||
DFU_STATE_appDETACH = 1,
|
||||
DFU_STATE_dfuIDLE = 2,
|
||||
DFU_STATE_dfuDNLOAD_SYNC = 3,
|
||||
DFU_STATE_dfuDNBUSY = 4,
|
||||
DFU_STATE_dfuDNLOAD_IDLE = 5,
|
||||
DFU_STATE_dfuMANIFEST_SYNC = 6,
|
||||
DFU_STATE_dfuMANIFEST = 7,
|
||||
DFU_STATE_dfuMANIFEST_WAIT_RESET = 8,
|
||||
DFU_STATE_dfuUPLOAD_IDLE = 9,
|
||||
DFU_STATE_dfuERROR = 10
|
||||
DFU_STATE_appIDLE = 0,
|
||||
DFU_STATE_appDETACH = 1,
|
||||
DFU_STATE_dfuIDLE = 2,
|
||||
DFU_STATE_dfuDNLOAD_SYNC = 3,
|
||||
DFU_STATE_dfuDNBUSY = 4,
|
||||
DFU_STATE_dfuDNLOAD_IDLE = 5,
|
||||
DFU_STATE_dfuMANIFEST_SYNC = 6,
|
||||
DFU_STATE_dfuMANIFEST = 7,
|
||||
DFU_STATE_dfuMANIFEST_WAIT_RESET = 8,
|
||||
DFU_STATE_dfuUPLOAD_IDLE = 9,
|
||||
DFU_STATE_dfuERROR = 10
|
||||
};
|
||||
|
||||
|
||||
@ -135,10 +135,10 @@ enum dfu_state {
|
||||
// ----- Structs -----
|
||||
|
||||
struct dfu_status_t {
|
||||
enum dfu_status bStatus : 8;
|
||||
uint32_t bwPollTimeout : 24;
|
||||
enum dfu_state bState : 8;
|
||||
uint8_t iString;
|
||||
enum dfu_status bStatus : 8;
|
||||
uint32_t bwPollTimeout : 24;
|
||||
enum dfu_state bState : 8;
|
||||
uint8_t iString;
|
||||
} __packed;
|
||||
CTASSERT_SIZE_BYTE(struct dfu_status_t, 6);
|
||||
|
||||
@ -148,38 +148,38 @@ typedef enum dfu_status (*dfu_finish_write_t)(void *, size_t off, size_t len);
|
||||
typedef void (*dfu_detach_t)(void);
|
||||
|
||||
struct dfu_ctx {
|
||||
struct usbd_function_ctx_header header;
|
||||
enum dfu_state state;
|
||||
enum dfu_status status;
|
||||
dfu_setup_write_t setup_write;
|
||||
dfu_finish_write_t finish_write;
|
||||
size_t off;
|
||||
size_t len;
|
||||
struct usbd_function_ctx_header header;
|
||||
enum dfu_state state;
|
||||
enum dfu_status status;
|
||||
dfu_setup_write_t setup_write;
|
||||
dfu_finish_write_t finish_write;
|
||||
size_t off;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
||||
struct dfu_desc_functional {
|
||||
uint8_t bLength;
|
||||
struct usb_desc_type_t bDescriptorType; /* = class DFU/0x1 FUNCTIONAL */
|
||||
union {
|
||||
struct {
|
||||
uint8_t can_download : 1;
|
||||
uint8_t can_upload : 1;
|
||||
uint8_t manifestation_tolerant : 1;
|
||||
uint8_t will_detach : 1;
|
||||
uint8_t _rsvd0 : 4;
|
||||
};
|
||||
uint8_t bmAttributes;
|
||||
};
|
||||
uint16_t wDetachTimeOut;
|
||||
uint16_t wTransferSize;
|
||||
struct usb_bcd_t bcdDFUVersion;
|
||||
uint8_t bLength;
|
||||
struct usb_desc_type_t bDescriptorType; /* = class DFU/0x1 FUNCTIONAL */
|
||||
union {
|
||||
struct {
|
||||
uint8_t can_download : 1;
|
||||
uint8_t can_upload : 1;
|
||||
uint8_t manifestation_tolerant : 1;
|
||||
uint8_t will_detach : 1;
|
||||
uint8_t _rsvd0 : 4;
|
||||
};
|
||||
uint8_t bmAttributes;
|
||||
};
|
||||
uint16_t wDetachTimeOut;
|
||||
uint16_t wTransferSize;
|
||||
struct usb_bcd_t bcdDFUVersion;
|
||||
} __packed;
|
||||
CTASSERT_SIZE_BYTE(struct dfu_desc_functional, 9);
|
||||
|
||||
struct dfu_function_desc {
|
||||
struct usb_desc_iface_t iface;
|
||||
struct dfu_desc_functional dfu;
|
||||
struct usb_desc_iface_t iface;
|
||||
struct dfu_desc_functional dfu;
|
||||
};
|
||||
|
||||
|
||||
|
@ -33,60 +33,60 @@ uint32_t flash_ALLOW_BRICKABLE_ADDRESSES;
|
||||
__attribute__((section(".ramtext.ftfl_submit_cmd"), long_call))
|
||||
int ftfl_submit_cmd(void)
|
||||
{
|
||||
FTFL.fstat.raw = ((struct FTFL_FSTAT_t){
|
||||
.ccif = 1,
|
||||
.rdcolerr = 1,
|
||||
.accerr = 1,
|
||||
.fpviol = 1
|
||||
}).raw;
|
||||
struct FTFL_FSTAT_t stat;
|
||||
while (!(stat = FTFL.fstat).ccif)
|
||||
/* NOTHING */; /* XXX maybe WFI? */
|
||||
return (!!stat.mgstat0);
|
||||
FTFL.fstat.raw = ((struct FTFL_FSTAT_t){
|
||||
.ccif = 1,
|
||||
.rdcolerr = 1,
|
||||
.accerr = 1,
|
||||
.fpviol = 1
|
||||
}).raw;
|
||||
struct FTFL_FSTAT_t stat;
|
||||
while (!(stat = FTFL.fstat).ccif)
|
||||
/* NOTHING */; /* XXX maybe WFI? */
|
||||
return (!!stat.mgstat0);
|
||||
}
|
||||
|
||||
int flash_prepare_flashing(void)
|
||||
{
|
||||
/* switch to FlexRAM */
|
||||
if (!FTFL.fcnfg.ramrdy) {
|
||||
FTFL.fccob.set_flexram.fcmd = FTFL_FCMD_SET_FLEXRAM;
|
||||
FTFL.fccob.set_flexram.flexram_function = FTFL_FLEXRAM_RAM;
|
||||
return (ftfl_submit_cmd());
|
||||
}
|
||||
return (0);
|
||||
/* switch to FlexRAM */
|
||||
if (!FTFL.fcnfg.ramrdy) {
|
||||
FTFL.fccob.set_flexram.fcmd = FTFL_FCMD_SET_FLEXRAM;
|
||||
FTFL.fccob.set_flexram.flexram_function = FTFL_FLEXRAM_RAM;
|
||||
return (ftfl_submit_cmd());
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int flash_erase_sector(uintptr_t addr)
|
||||
{
|
||||
if (addr < (uintptr_t)&_app_rom &&
|
||||
flash_ALLOW_BRICKABLE_ADDRESSES != 0x00023420)
|
||||
return (-1);
|
||||
FTFL.fccob.erase.fcmd = FTFL_FCMD_ERASE_SECTOR;
|
||||
FTFL.fccob.erase.addr = addr;
|
||||
return (ftfl_submit_cmd());
|
||||
if (addr < (uintptr_t)&_app_rom &&
|
||||
flash_ALLOW_BRICKABLE_ADDRESSES != 0x00023420)
|
||||
return (-1);
|
||||
FTFL.fccob.erase.fcmd = FTFL_FCMD_ERASE_SECTOR;
|
||||
FTFL.fccob.erase.addr = addr;
|
||||
return (ftfl_submit_cmd());
|
||||
}
|
||||
|
||||
int flash_program_section(uintptr_t addr, size_t num_words)
|
||||
{
|
||||
FTFL.fccob.program_section.fcmd = FTFL_FCMD_PROGRAM_SECTION;
|
||||
FTFL.fccob.program_section.addr = addr;
|
||||
FTFL.fccob.program_section.num_words = num_words;
|
||||
return (ftfl_submit_cmd());
|
||||
FTFL.fccob.program_section.fcmd = FTFL_FCMD_PROGRAM_SECTION;
|
||||
FTFL.fccob.program_section.addr = addr;
|
||||
FTFL.fccob.program_section.num_words = num_words;
|
||||
return (ftfl_submit_cmd());
|
||||
}
|
||||
|
||||
int flash_program_sector(uintptr_t addr, size_t len)
|
||||
{
|
||||
return (len != FLASH_SECTOR_SIZE ||
|
||||
(addr & (FLASH_SECTOR_SIZE - 1)) != 0 ||
|
||||
flash_erase_sector(addr) ||
|
||||
flash_program_section(addr, FLASH_SECTOR_SIZE/4));
|
||||
return (len != FLASH_SECTOR_SIZE ||
|
||||
(addr & (FLASH_SECTOR_SIZE - 1)) != 0 ||
|
||||
flash_erase_sector(addr) ||
|
||||
flash_program_section(addr, FLASH_SECTOR_SIZE/4));
|
||||
}
|
||||
|
||||
void *flash_get_staging_area(uintptr_t addr, size_t len)
|
||||
{
|
||||
if ((addr & (FLASH_SECTOR_SIZE - 1)) != 0 ||
|
||||
len != FLASH_SECTOR_SIZE)
|
||||
return (NULL);
|
||||
return (FlexRAM);
|
||||
if ((addr & (FLASH_SECTOR_SIZE - 1)) != 0 ||
|
||||
len != FLASH_SECTOR_SIZE)
|
||||
return (NULL);
|
||||
return (FlexRAM);
|
||||
}
|
||||
|
||||
|
@ -27,60 +27,60 @@
|
||||
// ----- Structs -----
|
||||
|
||||
struct FTFL_FSTAT_t {
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t mgstat0 : 1;
|
||||
uint8_t _rsvd0 : 3;
|
||||
uint8_t fpviol : 1;
|
||||
uint8_t accerr : 1;
|
||||
uint8_t rdcolerr : 1;
|
||||
uint8_t ccif : 1;
|
||||
UNION_STRUCT_END;
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t mgstat0 : 1;
|
||||
uint8_t _rsvd0 : 3;
|
||||
uint8_t fpviol : 1;
|
||||
uint8_t accerr : 1;
|
||||
uint8_t rdcolerr : 1;
|
||||
uint8_t ccif : 1;
|
||||
UNION_STRUCT_END;
|
||||
};
|
||||
CTASSERT_SIZE_BIT(struct FTFL_FSTAT_t, 8);
|
||||
|
||||
struct FTFL_FCNFG_t {
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t eeerdy : 1;
|
||||
uint8_t ramrdy : 1;
|
||||
uint8_t pflsh : 1;
|
||||
uint8_t _rsvd0 : 1;
|
||||
uint8_t erssusp : 1;
|
||||
uint8_t ersareq : 1;
|
||||
uint8_t rdcollie : 1;
|
||||
uint8_t ccie : 1;
|
||||
UNION_STRUCT_END;
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t eeerdy : 1;
|
||||
uint8_t ramrdy : 1;
|
||||
uint8_t pflsh : 1;
|
||||
uint8_t _rsvd0 : 1;
|
||||
uint8_t erssusp : 1;
|
||||
uint8_t ersareq : 1;
|
||||
uint8_t rdcollie : 1;
|
||||
uint8_t ccie : 1;
|
||||
UNION_STRUCT_END;
|
||||
};
|
||||
CTASSERT_SIZE_BIT(struct FTFL_FCNFG_t, 8);
|
||||
|
||||
struct FTFL_FSEC_t {
|
||||
UNION_STRUCT_START(8);
|
||||
enum {
|
||||
FTFL_FSEC_SEC_UNSECURE = 2,
|
||||
FTFL_FSEC_SEC_SECURE = 3
|
||||
} sec : 2;
|
||||
enum {
|
||||
FTFL_FSEC_FSLACC_DENY = 1,
|
||||
FTFL_FSEC_FSLACC_GRANT = 3
|
||||
} fslacc : 2;
|
||||
enum {
|
||||
FTFL_FSEC_MEEN_DISABLE = 2,
|
||||
FTFL_FSEC_MEEN_ENABLE = 3
|
||||
} meen : 2;
|
||||
enum {
|
||||
FTFL_FSEC_KEYEN_DISABLE = 1,
|
||||
FTFL_FSEC_KEYEN_ENABLE = 2
|
||||
} keyen : 2;
|
||||
UNION_STRUCT_END;
|
||||
UNION_STRUCT_START(8);
|
||||
enum {
|
||||
FTFL_FSEC_SEC_UNSECURE = 2,
|
||||
FTFL_FSEC_SEC_SECURE = 3
|
||||
} sec : 2;
|
||||
enum {
|
||||
FTFL_FSEC_FSLACC_DENY = 1,
|
||||
FTFL_FSEC_FSLACC_GRANT = 3
|
||||
} fslacc : 2;
|
||||
enum {
|
||||
FTFL_FSEC_MEEN_DISABLE = 2,
|
||||
FTFL_FSEC_MEEN_ENABLE = 3
|
||||
} meen : 2;
|
||||
enum {
|
||||
FTFL_FSEC_KEYEN_DISABLE = 1,
|
||||
FTFL_FSEC_KEYEN_ENABLE = 2
|
||||
} keyen : 2;
|
||||
UNION_STRUCT_END;
|
||||
};
|
||||
CTASSERT_SIZE_BIT(struct FTFL_FSEC_t, 8);
|
||||
|
||||
struct FTFL_FOPT_t {
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t lpboot : 1;
|
||||
uint8_t ezport_dis : 1;
|
||||
uint8_t nmi_dis : 1;
|
||||
uint8_t _rsvd0 : 5;
|
||||
UNION_STRUCT_END;
|
||||
UNION_STRUCT_START(8);
|
||||
uint8_t lpboot : 1;
|
||||
uint8_t ezport_dis : 1;
|
||||
uint8_t nmi_dis : 1;
|
||||
uint8_t _rsvd0 : 5;
|
||||
UNION_STRUCT_END;
|
||||
};
|
||||
CTASSERT_SIZE_BIT(struct FTFL_FOPT_t, 8);
|
||||
|
||||
@ -90,151 +90,151 @@ CTASSERT_SIZE_BIT(struct FTFL_FOPT_t, 8);
|
||||
* some that is little endian.
|
||||
*/
|
||||
union FTFL_FCCOB_t {
|
||||
struct ftfl_generic {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD {
|
||||
FTFL_FCMD_READ_1s_BLOCK = 0x00,
|
||||
FTFL_FCMD_READ_1s_SECTION = 0x01,
|
||||
FTFL_FCMD_PROGRAM_CHECK = 0x02,
|
||||
FTFL_FCMD_READ_RESOURCE = 0x03,
|
||||
FTFL_FCMD_PROGRAM_LONGWORD = 0x06,
|
||||
FTFL_FCMD_ERASE_BLOCK = 0x08,
|
||||
FTFL_FCMD_ERASE_SECTOR = 0x09,
|
||||
FTFL_FCMD_PROGRAM_SECTION = 0x0b,
|
||||
FTFL_FCMD_READ_1s_ALL_BLOCKS = 0x40,
|
||||
FTFL_FCMD_READ_ONCE = 0x41,
|
||||
FTFL_FCMD_PROGRAM_ONCE = 0x43,
|
||||
FTFL_FCMD_ERASE_ALL_BLOCKS = 0x44,
|
||||
FTFL_FCMD_VERIFY_KEY = 0x45,
|
||||
FTFL_FCMD_PROGRAM_PARTITION = 0x80,
|
||||
FTFL_FCMD_SET_FLEXRAM = 0x81
|
||||
} fcmd : 8;
|
||||
uint8_t data_be[8];
|
||||
} generic;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_MARGIN_CHOICE {
|
||||
FTFL_MARGIN_NORMAL = 0x00,
|
||||
FTFL_MARGIN_USER = 0x01,
|
||||
FTFL_MARGIN_FACTORY = 0x02
|
||||
} margin : 8;
|
||||
} read_1s_block;
|
||||
struct ftfl_data_num_words {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0;
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
uint16_t num_words;
|
||||
} read_1s_section;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
uint8_t data_be[4];
|
||||
} program_check;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint32_t data;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_RESOURCE_SELECT {
|
||||
FTFL_RESOURCE_IFR = 0x00,
|
||||
FTFL_RESOURCE_VERSION = 0x01
|
||||
} resource_select : 8;
|
||||
} read_resource;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t data_be[4];
|
||||
} program_longword;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} erase;
|
||||
struct ftfl_data_num_words program_section;
|
||||
struct {
|
||||
uint8_t _rsvd0[2];
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} read_1s_all_blocks;
|
||||
struct ftfl_cmd_once {
|
||||
uint8_t _rsvd0[2];
|
||||
uint8_t idx;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t data_be[4];
|
||||
} read_once;
|
||||
struct ftfl_cmd_once program_once;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} erase_all;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t key_be[8];
|
||||
} verify_key;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd1[2];
|
||||
struct ftfl_generic {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD {
|
||||
FTFL_FCMD_READ_1s_BLOCK = 0x00,
|
||||
FTFL_FCMD_READ_1s_SECTION = 0x01,
|
||||
FTFL_FCMD_PROGRAM_CHECK = 0x02,
|
||||
FTFL_FCMD_READ_RESOURCE = 0x03,
|
||||
FTFL_FCMD_PROGRAM_LONGWORD = 0x06,
|
||||
FTFL_FCMD_ERASE_BLOCK = 0x08,
|
||||
FTFL_FCMD_ERASE_SECTOR = 0x09,
|
||||
FTFL_FCMD_PROGRAM_SECTION = 0x0b,
|
||||
FTFL_FCMD_READ_1s_ALL_BLOCKS = 0x40,
|
||||
FTFL_FCMD_READ_ONCE = 0x41,
|
||||
FTFL_FCMD_PROGRAM_ONCE = 0x43,
|
||||
FTFL_FCMD_ERASE_ALL_BLOCKS = 0x44,
|
||||
FTFL_FCMD_VERIFY_KEY = 0x45,
|
||||
FTFL_FCMD_PROGRAM_PARTITION = 0x80,
|
||||
FTFL_FCMD_SET_FLEXRAM = 0x81
|
||||
} fcmd : 8;
|
||||
uint8_t data_be[8];
|
||||
} generic;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_MARGIN_CHOICE {
|
||||
FTFL_MARGIN_NORMAL = 0x00,
|
||||
FTFL_MARGIN_USER = 0x01,
|
||||
FTFL_MARGIN_FACTORY = 0x02
|
||||
} margin : 8;
|
||||
} read_1s_block;
|
||||
struct ftfl_data_num_words {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0;
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
uint16_t num_words;
|
||||
} read_1s_section;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
uint8_t data_be[4];
|
||||
} program_check;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint32_t data;
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_RESOURCE_SELECT {
|
||||
FTFL_RESOURCE_IFR = 0x00,
|
||||
FTFL_RESOURCE_VERSION = 0x01
|
||||
} resource_select : 8;
|
||||
} read_resource;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t data_be[4];
|
||||
} program_longword;
|
||||
struct {
|
||||
uint32_t addr : 24;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} erase;
|
||||
struct ftfl_data_num_words program_section;
|
||||
struct {
|
||||
uint8_t _rsvd0[2];
|
||||
enum FTFL_MARGIN_CHOICE margin : 8;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} read_1s_all_blocks;
|
||||
struct ftfl_cmd_once {
|
||||
uint8_t _rsvd0[2];
|
||||
uint8_t idx;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t data_be[4];
|
||||
} read_once;
|
||||
struct ftfl_cmd_once program_once;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} erase_all;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t key_be[8];
|
||||
} verify_key;
|
||||
struct {
|
||||
uint8_t _rsvd0[3];
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
uint8_t _rsvd1[2];
|
||||
|
||||
/* the following enum is analogous to enum
|
||||
* SIM_FLEXNVM_PARTITION in sim.h, but this one is padded
|
||||
* with four 1-bits to make an 8-bit value.
|
||||
*/
|
||||
/* the following enum is analogous to enum
|
||||
* SIM_FLEXNVM_PARTITION in sim.h, but this one is padded
|
||||
* with four 1-bits to make an 8-bit value.
|
||||
*/
|
||||
|
||||
enum FTFL_FLEXNVM_PARTITION {
|
||||
FTFL_FLEXNVM_DATA_32_EEPROM_0 = 0xF0,
|
||||
FTFL_FLEXNVM_DATA_24_EEPROM_8 = 0xF1,
|
||||
FTFL_FLEXNVM_DATA_16_EEPROM_16 = 0xF2,
|
||||
FTFL_FLEXNVM_DATA_8_EEPROM_24 = 0xF9,
|
||||
FTFL_FLEXNVM_DATA_0_EEPROM_32 = 0xF3
|
||||
} flexnvm_partition : 8;
|
||||
enum FTFL_EEPROM_SIZE {
|
||||
FTFL_EEPROM_SIZE_0 = 0x3f,
|
||||
FTFL_EEPROM_SIZE_32 = 0x39,
|
||||
FTFL_EEPROM_SIZE_64 = 0x38,
|
||||
FTFL_EEPROM_SIZE_128 = 0x37,
|
||||
FTFL_EEPROM_SIZE_256 = 0x36,
|
||||
FTFL_EEPROM_SIZE_512 = 0x35,
|
||||
FTFL_EEPROM_SIZE_1024 = 0x34,
|
||||
FTFL_EEPROM_SIZE_2048 = 0x33
|
||||
} eeprom_size : 8;
|
||||
} program_partition;
|
||||
struct {
|
||||
uint8_t _rsvd0[2];
|
||||
enum FTFL_FLEXRAM_FUNCTION {
|
||||
FTFL_FLEXRAM_EEPROM = 0x00,
|
||||
FTFL_FLEXRAM_RAM = 0xff
|
||||
} flexram_function : 8;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} set_flexram;
|
||||
enum FTFL_FLEXNVM_PARTITION {
|
||||
FTFL_FLEXNVM_DATA_32_EEPROM_0 = 0xF0,
|
||||
FTFL_FLEXNVM_DATA_24_EEPROM_8 = 0xF1,
|
||||
FTFL_FLEXNVM_DATA_16_EEPROM_16 = 0xF2,
|
||||
FTFL_FLEXNVM_DATA_8_EEPROM_24 = 0xF9,
|
||||
FTFL_FLEXNVM_DATA_0_EEPROM_32 = 0xF3
|
||||
} flexnvm_partition : 8;
|
||||
enum FTFL_EEPROM_SIZE {
|
||||
FTFL_EEPROM_SIZE_0 = 0x3f,
|
||||
FTFL_EEPROM_SIZE_32 = 0x39,
|
||||
FTFL_EEPROM_SIZE_64 = 0x38,
|
||||
FTFL_EEPROM_SIZE_128 = 0x37,
|
||||
FTFL_EEPROM_SIZE_256 = 0x36,
|
||||
FTFL_EEPROM_SIZE_512 = 0x35,
|
||||
FTFL_EEPROM_SIZE_1024 = 0x34,
|
||||
FTFL_EEPROM_SIZE_2048 = 0x33
|
||||
} eeprom_size : 8;
|
||||
} program_partition;
|
||||
struct {
|
||||
uint8_t _rsvd0[2];
|
||||
enum FTFL_FLEXRAM_FUNCTION {
|
||||
FTFL_FLEXRAM_EEPROM = 0x00,
|
||||
FTFL_FLEXRAM_RAM = 0xff
|
||||
} flexram_function : 8;
|
||||
enum FTFL_FCMD fcmd : 8;
|
||||
} set_flexram;
|
||||
};
|
||||
CTASSERT_SIZE_BYTE(union FTFL_FCCOB_t, 12);
|
||||
|
||||
struct FTFL_t {
|
||||
struct FTFL_FSTAT_t fstat;
|
||||
struct FTFL_FCNFG_t fcnfg;
|
||||
struct FTFL_FSEC_t fsec;
|
||||
struct FTFL_FOPT_t fopt;
|
||||
union FTFL_FCCOB_t fccob;
|
||||
uint8_t fprot_be[4];
|
||||
uint8_t feprot;
|
||||
uint8_t fdprot;
|
||||
struct FTFL_FSTAT_t fstat;
|
||||
struct FTFL_FCNFG_t fcnfg;
|
||||
struct FTFL_FSEC_t fsec;
|
||||
struct FTFL_FOPT_t fopt;
|
||||
union FTFL_FCCOB_t fccob;
|
||||
uint8_t fprot_be[4];
|
||||
uint8_t feprot;
|
||||
uint8_t fdprot;
|
||||
};
|
||||
CTASSERT_SIZE_BYTE(struct FTFL_t, 0x18);
|
||||
|
||||
/* Flash Configuration Field, see Sub-Family Reference Manual, section 28.3.1 */
|
||||
struct FTFL_CONFIG_t {
|
||||
uint8_t key[8];
|
||||
uint8_t fprot[4];
|
||||
struct FTFL_FSEC_t fsec;
|
||||
struct FTFL_FOPT_t fopt;
|
||||
uint8_t feprot;
|
||||
uint8_t fdprot;
|
||||
uint8_t key[8];
|
||||
uint8_t fprot[4];
|
||||
struct FTFL_FSEC_t fsec;
|
||||
struct FTFL_FOPT_t fopt;
|
||||
uint8_t feprot;
|
||||
uint8_t fdprot;
|
||||
};
|
||||
CTASSERT_SIZE_BYTE(struct FTFL_CONFIG_t, 16);
|
||||
|
||||
|
@ -55,272 +55,272 @@ static struct USB_BD_t bdt[USB_MAX_EP * 2 *2] __attribute__((section(".usbdescri
|
||||
static struct USB_BD_t *
|
||||
usb_get_bd(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
return (&bdt[(s->ep_num << 2) | (s->ep_dir << 1) | s->pingpong]);
|
||||
return (&bdt[(s->ep_num << 2) | (s->ep_dir << 1) | s->pingpong]);
|
||||
}
|
||||
|
||||
static struct USB_BD_t *
|
||||
usb_get_bd_stat(struct USB_STAT_t *stat)
|
||||
{
|
||||
return (((void *)(uintptr_t)bdt + (stat->raw << 1)));
|
||||
return (((void *)(uintptr_t)bdt + (stat->raw << 1)));
|
||||
}
|
||||
|
||||
void *usb_get_xfer_data(struct usb_xfer_info *i)
|
||||
{
|
||||
return (usb_get_bd_stat(i)->addr);
|
||||
return (usb_get_bd_stat(i)->addr);
|
||||
}
|
||||
|
||||
enum usb_tok_pid usb_get_xfer_pid(struct usb_xfer_info *i)
|
||||
{
|
||||
return (usb_get_bd_stat(i)->tok_pid);
|
||||
return (usb_get_bd_stat(i)->tok_pid);
|
||||
}
|
||||
|
||||
int usb_get_xfer_ep(struct usb_xfer_info *i)
|
||||
{
|
||||
return (i->ep);
|
||||
return (i->ep);
|
||||
}
|
||||
|
||||
enum usb_ep_dir usb_get_xfer_dir(struct usb_xfer_info *i)
|
||||
{
|
||||
return (i->dir);
|
||||
return (i->dir);
|
||||
}
|
||||
|
||||
void usb_enable_xfers(void)
|
||||
{
|
||||
USB0.ctl.raw = ((struct USB_CTL_t){
|
||||
.txd_suspend = 0,
|
||||
.usben = 1
|
||||
}).raw;
|
||||
USB0.ctl.raw = ((struct USB_CTL_t){
|
||||
.txd_suspend = 0,
|
||||
.usben = 1
|
||||
}).raw;
|
||||
}
|
||||
|
||||
void usb_set_addr(int addr)
|
||||
{
|
||||
USB0.addr.raw = addr;
|
||||
USB0.addr.raw = addr;
|
||||
}
|
||||
|
||||
|
||||
void usb_pipe_stall(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
bd->raw = ((struct USB_BD_BITS_t){
|
||||
.stall = 1,
|
||||
.own = 1
|
||||
}).raw;
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
bd->raw = ((struct USB_BD_BITS_t){
|
||||
.stall = 1,
|
||||
.own = 1
|
||||
}).raw;
|
||||
}
|
||||
|
||||
void usb_pipe_unstall(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
struct USB_BD_BITS_t state = { .raw = bd->raw };
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
struct USB_BD_BITS_t state = { .raw = bd->raw };
|
||||
|
||||
if (state.own && state.stall)
|
||||
bd->raw = 0;
|
||||
if (state.own && state.stall)
|
||||
bd->raw = 0;
|
||||
}
|
||||
|
||||
void usb_pipe_enable(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
USB0.endpt[s->ep_num].raw |= ((struct USB_ENDPT_t){
|
||||
.eptxen = s->ep_dir == USB_EP_TX,
|
||||
.eprxen = s->ep_dir == USB_EP_RX,
|
||||
.ephshk = 1, /* XXX ISO */
|
||||
.epctldis = s->ep_num != 0
|
||||
}).raw;
|
||||
USB0.endpt[s->ep_num].raw |= ((struct USB_ENDPT_t){
|
||||
.eptxen = s->ep_dir == USB_EP_TX,
|
||||
.eprxen = s->ep_dir == USB_EP_RX,
|
||||
.ephshk = 1, /* XXX ISO */
|
||||
.epctldis = s->ep_num != 0
|
||||
}).raw;
|
||||
}
|
||||
|
||||
void usb_pipe_disable(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
USB0.endpt[s->ep_num].raw &= ~((struct USB_ENDPT_t){
|
||||
.eptxen = s->ep_dir == USB_EP_TX,
|
||||
.eprxen = s->ep_dir == USB_EP_RX,
|
||||
.epctldis = 1
|
||||
}).raw;
|
||||
USB0.endpt[s->ep_num].raw &= ~((struct USB_ENDPT_t){
|
||||
.eptxen = s->ep_dir == USB_EP_TX,
|
||||
.eprxen = s->ep_dir == USB_EP_RX,
|
||||
.epctldis = 1
|
||||
}).raw;
|
||||
}
|
||||
|
||||
size_t usb_ep_get_transfer_size(struct usbd_ep_pipe_state_t *s)
|
||||
{
|
||||
struct USB_BD_t *bd = usb_get_bd(s);
|
||||
return (bd->bc);
|
||||
struct USB_BD_t *bd = usb_get_bd(s);
|
||||
return (bd->bc);
|
||||
}
|
||||
|
||||
void usb_queue_next(struct usbd_ep_pipe_state_t *s, void *addr, size_t len)
|
||||
{
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(s);
|
||||
|
||||
bd->addr = addr;
|
||||
/* damn you bitfield problems */
|
||||
bd->raw = ((struct USB_BD_BITS_t){
|
||||
.dts = 1,
|
||||
.own = 1,
|
||||
.data01 = s->data01,
|
||||
.bc = len,
|
||||
}).raw;
|
||||
bd->addr = addr;
|
||||
/* damn you bitfield problems */
|
||||
bd->raw = ((struct USB_BD_BITS_t){
|
||||
.dts = 1,
|
||||
.own = 1,
|
||||
.data01 = s->data01,
|
||||
.bc = len,
|
||||
}).raw;
|
||||
}
|
||||
|
||||
static void usb_reset(void)
|
||||
{
|
||||
/* reset pingpong state */
|
||||
/* For some obscure reason, we need to use or here. */
|
||||
USB0.ctl.raw |= ((struct USB_CTL_t){
|
||||
.txd_suspend = 1,
|
||||
.oddrst = 1,
|
||||
}).raw;
|
||||
/* reset pingpong state */
|
||||
/* For some obscure reason, we need to use or here. */
|
||||
USB0.ctl.raw |= ((struct USB_CTL_t){
|
||||
.txd_suspend = 1,
|
||||
.oddrst = 1,
|
||||
}).raw;
|
||||
|
||||
/* clear all interrupt bits - not sure if needed */
|
||||
USB0.istat.raw = 0xff;
|
||||
USB0.errstat.raw = 0xff;
|
||||
USB0.otgistat.raw = 0xff;
|
||||
/* clear all interrupt bits - not sure if needed */
|
||||
USB0.istat.raw = 0xff;
|
||||
USB0.errstat.raw = 0xff;
|
||||
USB0.otgistat.raw = 0xff;
|
||||
|
||||
/* zap also BDT pingpong & queued transactions */
|
||||
memset(bdt, 0, sizeof(bdt));
|
||||
USB0.addr.raw = 0;
|
||||
/* zap also BDT pingpong & queued transactions */
|
||||
memset(bdt, 0, sizeof(bdt));
|
||||
USB0.addr.raw = 0;
|
||||
|
||||
usb_restart();
|
||||
usb_restart();
|
||||
|
||||
USB0.ctl.raw = ((struct USB_CTL_t){
|
||||
.txd_suspend = 0,
|
||||
.usben = 1
|
||||
}).raw;
|
||||
USB0.ctl.raw = ((struct USB_CTL_t){
|
||||
.txd_suspend = 0,
|
||||
.usben = 1
|
||||
}).raw;
|
||||
|
||||
/* we're only interested in reset and transfers */
|
||||
USB0.inten.raw = ((struct USB_ISTAT_t){
|
||||
.tokdne = 1,
|
||||
.usbrst = 1,
|
||||
.stall = 1,
|
||||
.sleep = 1,
|
||||
}).raw;
|
||||
/* we're only interested in reset and transfers */
|
||||
USB0.inten.raw = ((struct USB_ISTAT_t){
|
||||
.tokdne = 1,
|
||||
.usbrst = 1,
|
||||
.stall = 1,
|
||||
.sleep = 1,
|
||||
}).raw;
|
||||
|
||||
USB0.usbtrc0.usbresmen = 0;
|
||||
USB0.usbctrl.susp = 0;
|
||||
USB0.usbtrc0.usbresmen = 0;
|
||||
USB0.usbctrl.susp = 0;
|
||||
}
|
||||
|
||||
void usb_enable(void)
|
||||
{
|
||||
SIM.sopt2.usbsrc = 1; /* usb from mcg */
|
||||
SIM.scgc4.usbotg = 1; /* enable usb clock */
|
||||
SIM.sopt2.usbsrc = 1; /* usb from mcg */
|
||||
SIM.scgc4.usbotg = 1; /* enable usb clock */
|
||||
|
||||
/* reset module - not sure if needed */
|
||||
USB0.usbtrc0.raw = ((struct USB_USBTRC0_t){
|
||||
.usbreset = 1,
|
||||
.usbresmen = 1
|
||||
}).raw;
|
||||
while (USB0.usbtrc0.usbreset)
|
||||
/* NOTHING */;
|
||||
/* reset module - not sure if needed */
|
||||
USB0.usbtrc0.raw = ((struct USB_USBTRC0_t){
|
||||
.usbreset = 1,
|
||||
.usbresmen = 1
|
||||
}).raw;
|
||||
while (USB0.usbtrc0.usbreset)
|
||||
/* NOTHING */;
|
||||
|
||||
USB0.bdtpage1 = (uintptr_t)bdt >> 8;
|
||||
USB0.bdtpage2 = (uintptr_t)bdt >> 16;
|
||||
USB0.bdtpage3 = (uintptr_t)bdt >> 24;
|
||||
USB0.bdtpage1 = (uintptr_t)bdt >> 8;
|
||||
USB0.bdtpage2 = (uintptr_t)bdt >> 16;
|
||||
USB0.bdtpage3 = (uintptr_t)bdt >> 24;
|
||||
|
||||
USB0.control.raw = ((struct USB_CONTROL_t){
|
||||
.dppullupnonotg = 1 /* enable pullup */
|
||||
}).raw;
|
||||
USB0.control.raw = ((struct USB_CONTROL_t){
|
||||
.dppullupnonotg = 1 /* enable pullup */
|
||||
}).raw;
|
||||
|
||||
USB0.usbctrl.raw = 0; /* resume peripheral & disable pulldowns */
|
||||
usb_reset(); /* this will start usb processing */
|
||||
USB0.usbctrl.raw = 0; /* resume peripheral & disable pulldowns */
|
||||
usb_reset(); /* this will start usb processing */
|
||||
|
||||
/* really only one thing we want */
|
||||
USB0.inten.raw = ((struct USB_ISTAT_t){
|
||||
.usbrst = 1,
|
||||
}).raw;
|
||||
/* really only one thing we want */
|
||||
USB0.inten.raw = ((struct USB_ISTAT_t){
|
||||
.usbrst = 1,
|
||||
}).raw;
|
||||
|
||||
/**
|
||||
* Suspend transceiver now - we'll wake up at reset again.
|
||||
*/
|
||||
/**
|
||||
* Suspend transceiver now - we'll wake up at reset again.
|
||||
*/
|
||||
// TODO - Possible removal
|
||||
USB0.usbctrl.susp = 1;
|
||||
USB0.usbtrc0.usbresmen = 1;
|
||||
USB0.usbctrl.susp = 1;
|
||||
USB0.usbtrc0.usbresmen = 1;
|
||||
}
|
||||
|
||||
void USB0_Handler(void)
|
||||
{
|
||||
struct USB_ISTAT_t stat = {.raw = USB0.istat.raw };
|
||||
struct USB_ISTAT_t stat = {.raw = USB0.istat.raw };
|
||||
|
||||
if (stat.usbrst) {
|
||||
usb_reset();
|
||||
return;
|
||||
}
|
||||
if (stat.stall) {
|
||||
/* XXX need more work for non-0 ep */
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(&usb.ep_state[0].rx);
|
||||
if (bd->stall)
|
||||
usb_setup_control();
|
||||
}
|
||||
if (stat.tokdne) {
|
||||
struct usb_xfer_info stat = USB0.stat;
|
||||
usb_handle_transaction(&stat);
|
||||
}
|
||||
if (stat.sleep) {
|
||||
USB0.inten.sleep = 0;
|
||||
USB0.inten.resume = 1;
|
||||
USB0.usbctrl.susp = 1;
|
||||
USB0.usbtrc0.usbresmen = 1;
|
||||
if (stat.usbrst) {
|
||||
usb_reset();
|
||||
return;
|
||||
}
|
||||
if (stat.stall) {
|
||||
/* XXX need more work for non-0 ep */
|
||||
volatile struct USB_BD_t *bd = usb_get_bd(&usb.ep_state[0].rx);
|
||||
if (bd->stall)
|
||||
usb_setup_control();
|
||||
}
|
||||
if (stat.tokdne) {
|
||||
struct usb_xfer_info stat = USB0.stat;
|
||||
usb_handle_transaction(&stat);
|
||||
}
|
||||
if (stat.sleep) {
|
||||
USB0.inten.sleep = 0;
|
||||
USB0.inten.resume = 1;
|
||||
USB0.usbctrl.susp = 1;
|
||||
USB0.usbtrc0.usbresmen = 1;
|
||||
|
||||
/**
|
||||
* Clear interrupts now so that we can detect a fresh
|
||||
* resume later on.
|
||||
*/
|
||||
USB0.istat.raw = stat.raw;
|
||||
/**
|
||||
* Clear interrupts now so that we can detect a fresh
|
||||
* resume later on.
|
||||
*/
|
||||
USB0.istat.raw = stat.raw;
|
||||
|
||||
const struct usbd_config *c = usb_get_config_data(-1);
|
||||
if (c && c->suspend)
|
||||
c->suspend();
|
||||
}
|
||||
/**
|
||||
* XXX it is unclear whether we will receive a synchronous
|
||||
* resume interrupt if we were in sleep. This code assumes we
|
||||
* do.
|
||||
*/
|
||||
if (stat.resume || USB0.usbtrc0.usb_resume_int) {
|
||||
USB0.inten.resume = 0;
|
||||
USB0.inten.sleep = 1;
|
||||
USB0.usbtrc0.usbresmen = 0;
|
||||
USB0.usbctrl.susp = 0;
|
||||
const struct usbd_config *c = usb_get_config_data(-1);
|
||||
if (c && c->suspend)
|
||||
c->suspend();
|
||||
}
|
||||
/**
|
||||
* XXX it is unclear whether we will receive a synchronous
|
||||
* resume interrupt if we were in sleep. This code assumes we
|
||||
* do.
|
||||
*/
|
||||
if (stat.resume || USB0.usbtrc0.usb_resume_int) {
|
||||
USB0.inten.resume = 0;
|
||||
USB0.inten.sleep = 1;
|
||||
USB0.usbtrc0.usbresmen = 0;
|
||||
USB0.usbctrl.susp = 0;
|
||||
|
||||
const struct usbd_config *c = usb_get_config_data(-1);
|
||||
if (c && c->resume)
|
||||
c->resume();
|
||||
const struct usbd_config *c = usb_get_config_data(-1);
|
||||
if (c && c->resume)
|
||||
c->resume();
|
||||
|
||||
stat.resume = 1; /* always clear bit */
|
||||
}
|
||||
USB0.istat.raw = stat.raw;
|
||||
stat.resume = 1; /* always clear bit */
|
||||
}
|
||||
USB0.istat.raw = stat.raw;
|
||||
}
|
||||
|
||||
void usb_poll(void)
|
||||
{
|
||||
USB0_Handler();
|
||||
USB0_Handler();
|
||||
}
|
||||
|
||||
int usb_tx_serialno(size_t reqlen)
|
||||
{
|
||||
struct usb_desc_string_t *d;
|
||||
const size_t nregs = 3;
|
||||
/**
|
||||
* actually 4, but UIDH is 0xffffffff. Also our output buffer
|
||||
* is only 64 bytes, and 128 bit + desc header exceeds this by
|
||||
* 2 bytes.
|
||||
*/
|
||||
const size_t len = nregs * 4 * 2 * 2 + sizeof(*d);
|
||||
struct usb_desc_string_t *d;
|
||||
const size_t nregs = 3;
|
||||
/**
|
||||
* actually 4, but UIDH is 0xffffffff. Also our output buffer
|
||||
* is only 64 bytes, and 128 bit + desc header exceeds this by
|
||||
* 2 bytes.
|
||||
*/
|
||||
const size_t len = nregs * 4 * 2 * 2 + sizeof(*d);
|
||||
|
||||