mirror of
git://projects.qi-hardware.com/f32xbase.git
synced 2024-11-30 17:51:52 +02:00
fw/boot/ - The boot loader, fresh from IDBG. Needs major cleanup.
This commit is contained in:
parent
bdfe058079
commit
e23181e40b
26
fw/boot/Makefile
Normal file
26
fw/boot/Makefile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#
|
||||||
|
# boot/Makefile - Makefile for DFU-capable boot loader
|
||||||
|
#
|
||||||
|
# Written 2008, 2010 by Werner Almesberger
|
||||||
|
# Copyright 2008, 2010 Werner Almesberger
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
|
||||||
|
MAIN=boot
|
||||||
|
OBJS=$(MAIN) uart usb dfu version
|
||||||
|
|
||||||
|
include ../common/Makefile.system
|
||||||
|
include ../common/Makefile.common
|
||||||
|
|
||||||
|
CFLAGS += -I../include # -DLOW_SPEED
|
||||||
|
LDFLAGS += --code-size $(PAYLOAD_START)
|
||||||
|
|
||||||
|
uart.rel: ../common/uart.c
|
||||||
|
$(CC) $(CFLAGS) $(DEFINE_UART_SPEED) -o $@ -c $<
|
||||||
|
|
||||||
|
usb.rel: ../common/usb.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ -c $<
|
1
fw/boot/README
Normal file
1
fw/boot/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
Prerequisites: sdcc
|
243
fw/boot/boot.c
Normal file
243
fw/boot/boot.c
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* boot/boot.c - Boot loader setup and main loop
|
||||||
|
*
|
||||||
|
* Written 2008, 2010 by Werner Almesberger
|
||||||
|
* Copyright 2008, 2010 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code follows the register read/write sequences from the examples in
|
||||||
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_Main.c and
|
||||||
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_ISR.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "version.h"
|
||||||
|
#include "regs.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "uart.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "dfu.h"
|
||||||
|
|
||||||
|
|
||||||
|
void run_payload(void)
|
||||||
|
{
|
||||||
|
/* No interrupts while jumping between worlds */
|
||||||
|
EA = 0;
|
||||||
|
|
||||||
|
/* Restart USB */
|
||||||
|
USB0XCN = 0;
|
||||||
|
|
||||||
|
/* Re-enable pull-ups */
|
||||||
|
GPIOCN &= ~WEAKPUD;
|
||||||
|
|
||||||
|
#ifdef GTA
|
||||||
|
/* Don't waste power in pull-down */
|
||||||
|
I2C_SDA_PULL = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
debug("launching payload\n");
|
||||||
|
|
||||||
|
__asm
|
||||||
|
ljmp PAYLOAD_START
|
||||||
|
__endasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Interrupts -------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The boot loader doesn't use interrupts, so we forward all interrupts to the
|
||||||
|
* payload.
|
||||||
|
*
|
||||||
|
* What we'd really like to do here is to say something like
|
||||||
|
*
|
||||||
|
* void whatever_isr(void) __interrupt(n) __at(PAYLOAD+n*8+1);
|
||||||
|
*
|
||||||
|
* However, sdcc doesn't support such things yet. So we declare the ISR such
|
||||||
|
* that the vector entry gets created, and then we tell the assembler where to
|
||||||
|
* find it.
|
||||||
|
*
|
||||||
|
* Since __asm/__endasm isn't allowed outside a function body, we generate a
|
||||||
|
* dummy function for each assignment. The function is "naked", so that no
|
||||||
|
* actual code is generated for it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ISR(n) \
|
||||||
|
void isr_nr_##n(void) __interrupt(n); \
|
||||||
|
void isr_dummy_##n(void) __naked \
|
||||||
|
{ \
|
||||||
|
__asm \
|
||||||
|
_isr_nr_##n = PAYLOAD_START+n*8+3 \
|
||||||
|
__endasm; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ISR(0)
|
||||||
|
ISR(1)
|
||||||
|
ISR(2)
|
||||||
|
ISR(3)
|
||||||
|
ISR(4)
|
||||||
|
ISR(8)
|
||||||
|
ISR(15)
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- The actual boot loader -------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static void delay(void)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < 500; x)
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void boot_loader(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If we have VBUS, proceed as follows:
|
||||||
|
* - bring up USB
|
||||||
|
* - try to contact the PMU (in a loop)
|
||||||
|
* - possible transitions:
|
||||||
|
* - DFU gets selected -> enter DFU mode
|
||||||
|
* - PMU responds -> jump to payload
|
||||||
|
*
|
||||||
|
* In DFU mode, the following transitions are possible:
|
||||||
|
* - VBUS drops -> reset
|
||||||
|
* - USB bus reset -> reset
|
||||||
|
*
|
||||||
|
* @@@ this may be too complex - probably don't really need to talk to
|
||||||
|
* the PMU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: if we do anything that delays CPU bringup after nRESET goes
|
||||||
|
* high, we must still stay in the 100ms budget for raising KEEPACT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OSCICN |= IFCN0 | IFCN1;
|
||||||
|
|
||||||
|
#ifdef LOW_SPEED
|
||||||
|
|
||||||
|
CLKSEL = 0x10; /* USBCLK = int/2, SYS_INT_OSC = int */
|
||||||
|
|
||||||
|
#else /* LOW_SPEED */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clock multiplier enable sequence, section 10.4
|
||||||
|
*
|
||||||
|
* - reset the multiplier
|
||||||
|
* - select the multiplier input source
|
||||||
|
* - enable the multiplier
|
||||||
|
* - delay for 5us
|
||||||
|
* - initialize the multiplier
|
||||||
|
* - poll for multiplier to be ready
|
||||||
|
*/
|
||||||
|
|
||||||
|
CLKMUL = 0;
|
||||||
|
CLKMUL |= MULEN;
|
||||||
|
delay();
|
||||||
|
CLKMUL |= MULINIT | MULEN;
|
||||||
|
while (!(CLKMUL & MULRDY));
|
||||||
|
CLKSEL = 0; /* USBCLK = 4*int, SYSCLK = int */
|
||||||
|
CLKSEL = 0x02; /* F326_USB_Main.c does this (sets 24MHz). Why ? */
|
||||||
|
|
||||||
|
uart_init(24);
|
||||||
|
|
||||||
|
#endif /* !LOW_SPEED */
|
||||||
|
|
||||||
|
printk("%s #%u\n", build_date, build_number);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very weakly pull SDA down and disable all pull-ups.
|
||||||
|
*
|
||||||
|
* We use SDA as a system power presence detector. When I2C is idle,
|
||||||
|
* SDA is kept high. This is accomplished with pull-ups in the system.
|
||||||
|
* We can therefore detect if IO_3V3 is any good by checking whether
|
||||||
|
* SDA is high.
|
||||||
|
*
|
||||||
|
* This should work even without our own pull-down. However, when the
|
||||||
|
* IDBG board is operating standalone (or, generally, if SDA isn't
|
||||||
|
* connected), SDA would float. We therefore have to pull it down a
|
||||||
|
* little.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ben variant:
|
||||||
|
*
|
||||||
|
* We use exactly the same logic as on GTA01/02, but with different
|
||||||
|
* signals. P0_1 (I2C_SDA_PULL) and P0_2 (I2C_SDA) both connect to
|
||||||
|
* +V3.3, with a 1 kOhm resistor on P0_1. If the Ben is not powered, we
|
||||||
|
* can therefore pull +V3.3 to GND, and detect this condition. As on
|
||||||
|
* the GTA01/02, once the system is powered up, IDBG exits this loop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
GPIOCN |= WEAKPUD;
|
||||||
|
#ifdef GTA
|
||||||
|
I2C_SDA_PULL = 0;
|
||||||
|
#endif
|
||||||
|
delay();
|
||||||
|
|
||||||
|
dfu_init();
|
||||||
|
usb_init();
|
||||||
|
|
||||||
|
#ifdef GTA
|
||||||
|
|
||||||
|
while (!I2C_SDA || dfu.state != dfuIDLE)
|
||||||
|
usb_poll();
|
||||||
|
|
||||||
|
#else /* GTA */
|
||||||
|
|
||||||
|
#define MS_TO_LOOPS(ms) ((uint32_t) (ms)*190)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t loop = 0;
|
||||||
|
|
||||||
|
while (loop != MS_TO_LOOPS(2000)) {
|
||||||
|
usb_poll();
|
||||||
|
if (dfu.state == dfuIDLE)
|
||||||
|
loop++;
|
||||||
|
else
|
||||||
|
loop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !GTA */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* VDD monitor enable sequence, section 7.2
|
||||||
|
*
|
||||||
|
* - enable voltage monitor
|
||||||
|
* - wait for monitor to stabilize
|
||||||
|
* - enable VDD monitor reset
|
||||||
|
*/
|
||||||
|
|
||||||
|
VDM0CN = VDMEN;
|
||||||
|
while (!(VDM0CN & VDDSTAT));
|
||||||
|
RSTSRC = PORSF;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @@@ if we don't have VBUS, proceed as follows:
|
||||||
|
* - stay at 3MHz (current < 2mA, so we're fine with GPIO power)
|
||||||
|
* - jump directly to the payload
|
||||||
|
*/
|
||||||
|
|
||||||
|
OSCICN |= IFCN0;
|
||||||
|
uart_init(3);
|
||||||
|
if (REG0CN & VBSTAT)
|
||||||
|
boot_loader();
|
||||||
|
run_payload();
|
||||||
|
}
|
21
fw/boot/config.h
Normal file
21
fw/boot/config.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* boot/config.h - Boot loader configuration
|
||||||
|
*
|
||||||
|
* Written 2008 by Werner Almesberger
|
||||||
|
* Copyright 2008 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
//#define CONFIG_DEBUG
|
||||||
|
//#define CONFIG_ERROR
|
||||||
|
//#define CONFIG_PRINTK
|
||||||
|
|
||||||
|
#endif /* !CONFIG_H */
|
331
fw/boot/dfu.c
Normal file
331
fw/boot/dfu.c
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
* boot/dfu.c - DFU protocol engine
|
||||||
|
*
|
||||||
|
* Written 2008-2010 by Werner Almesberger
|
||||||
|
* Copyright 2008-2010 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A few, erm, shortcuts:
|
||||||
|
*
|
||||||
|
* - we don't bother with the app* states since DFU is all this firmware does
|
||||||
|
* - after DFU_DNLOAD, we just block until things are written, so we never
|
||||||
|
* enter dfuDNLOAD_SYNC or dfuDNBUSY
|
||||||
|
* - no dfuMANIFEST_SYNC, dfuMANIFEST, or dfuMANIFEST_WAIT_RESET
|
||||||
|
* - to keep our buffers small, we only accept EP0-sized blocks
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "regs.h"
|
||||||
|
#include "uart.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "dfu.h"
|
||||||
|
#include "idbg/usb-ids.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define PAYLOAD_END (PAYLOAD_START+PAYLOAD_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t device_descriptor[] = {
|
||||||
|
18, /* bLength */
|
||||||
|
USB_DT_DEVICE, /* bDescriptorType */
|
||||||
|
LE(0x100), /* bcdUSB */
|
||||||
|
USB_CLASS_PER_INTERFACE,/* bDeviceClass */
|
||||||
|
0x00, /* bDeviceSubClass (per interface) */
|
||||||
|
0x00, /* bDeviceProtocol (per interface) */
|
||||||
|
EP0_SIZE, /* bMaxPacketSize */
|
||||||
|
LE(USB_VENDOR), /* idVendor */
|
||||||
|
LE(USB_PRODUCT_IDBG_DFU),/* idProduct */
|
||||||
|
LE(0x0001), /* bcdDevice */
|
||||||
|
0, /* iManufacturer */
|
||||||
|
0, /* iProduct */
|
||||||
|
0, /* iSerialNumber */
|
||||||
|
1 /* bNumConfigurations */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t config_descriptor[] = {
|
||||||
|
9, /* bLength */
|
||||||
|
USB_DT_CONFIG, /* bDescriptorType */
|
||||||
|
LE(9+9), /* wTotalLength */
|
||||||
|
1, /* bNumInterfaces */
|
||||||
|
1, /* bConfigurationValue (> 0 !) */
|
||||||
|
0, /* iConfiguration */
|
||||||
|
// USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED,
|
||||||
|
USB_ATTR_BUS_POWERED, /* bmAttributes */
|
||||||
|
15, /* bMaxPower */
|
||||||
|
|
||||||
|
/* Interface #0 */
|
||||||
|
|
||||||
|
9, /* bLength */
|
||||||
|
USB_DT_INTERFACE, /* bDescriptorType */
|
||||||
|
0, /* bInterfaceNumber */
|
||||||
|
0, /* bAlternateSetting */
|
||||||
|
0, /* bNumEndpoints */
|
||||||
|
0xfe, /* bInterfaceClass (application specific) */
|
||||||
|
0x01, /* bInterfaceSubClass (device fw upgrade) */
|
||||||
|
0x02, /* bInterfaceProtocol (DFU mode protocol) */
|
||||||
|
0, /* iInterface */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const uint8_t functional_descriptor[] = {
|
||||||
|
9, /* bLength */
|
||||||
|
DFU_DT_FUNCTIONAL, /* bDescriptorType */
|
||||||
|
0xf, /* bmAttributes (claim omnipotence :-) */
|
||||||
|
LE(0xffff), /* wDetachTimeOut (we're very patient) */
|
||||||
|
LE(EP0_SIZE), /* wTransferSize */
|
||||||
|
LE(0x101), /* bcdDFUVersion */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct dfu dfu = {
|
||||||
|
OK,
|
||||||
|
LE(1000), 0,
|
||||||
|
dfuIDLE,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static uint16_t next_block = 0;
|
||||||
|
static uint16_t payload;
|
||||||
|
static __bit did_download;
|
||||||
|
|
||||||
|
|
||||||
|
static __xdata uint8_t buf[EP0_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
static void flash_erase_page(uint16_t addr)
|
||||||
|
{
|
||||||
|
FLKEY = 0xa5;
|
||||||
|
FLKEY = 0xf1;
|
||||||
|
PSCTL |= PSEE;
|
||||||
|
PSCTL |= PSWE;
|
||||||
|
*(__xdata uint8_t *) addr = 0;
|
||||||
|
PSCTL &= ~PSWE;
|
||||||
|
PSCTL &= ~PSEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void flash_write_byte(uint16_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
FLKEY = 0xa5;
|
||||||
|
FLKEY = 0xf1;
|
||||||
|
PSCTL |= PSWE;
|
||||||
|
PSCTL &= ~PSEE;
|
||||||
|
*(__xdata uint8_t *) addr = value;
|
||||||
|
PSCTL &= ~PSWE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void block_write(void *user)
|
||||||
|
{
|
||||||
|
uint16_t *size = user;
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
for (p = buf; p != buf+*size; p++) {
|
||||||
|
if (!(payload & 511))
|
||||||
|
flash_erase_page(payload);
|
||||||
|
flash_write_byte(payload, *p);
|
||||||
|
payload++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __bit block_receive(uint16_t length)
|
||||||
|
{
|
||||||
|
static uint16_t size;
|
||||||
|
|
||||||
|
if (payload < PAYLOAD_START || payload+length > PAYLOAD_END) {
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errADDRESS;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (length > EP0_SIZE) {
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errUNKNOWN;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size = length;
|
||||||
|
usb_recv(&ep0, buf, size, block_write, &size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __bit block_transmit(uint16_t length)
|
||||||
|
{
|
||||||
|
uint16_t left;
|
||||||
|
|
||||||
|
if (payload < PAYLOAD_START || payload > PAYLOAD_END) {
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errADDRESS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (length > EP0_SIZE) {
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errUNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
left = PAYLOAD_END-payload;
|
||||||
|
if (left < length) {
|
||||||
|
length = left;
|
||||||
|
dfu.state = dfuIDLE;
|
||||||
|
}
|
||||||
|
usb_send(&ep0, (__code uint8_t *) payload, length, NULL, NULL);
|
||||||
|
payload += length;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __bit my_setup(struct setup_request *setup) __reentrant
|
||||||
|
{
|
||||||
|
__bit ok;
|
||||||
|
|
||||||
|
switch (setup->bmRequestType | setup->bRequest << 8) {
|
||||||
|
case DFU_TO_DEV(DFU_DETACH):
|
||||||
|
debug("DFU_DETACH\n");
|
||||||
|
/*
|
||||||
|
* The DFU spec says thay this is sent in protocol 1 only.
|
||||||
|
* However, dfu-util also sends it to get out of DFU mode,
|
||||||
|
* so we just don't make a fuss and ignore it.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
case DFU_TO_DEV(DFU_DNLOAD):
|
||||||
|
debug("DFU_DNLOAD\n");
|
||||||
|
if (dfu.state == dfuIDLE) {
|
||||||
|
next_block = setup->wValue;
|
||||||
|
payload = PAYLOAD_START;
|
||||||
|
}
|
||||||
|
else if (dfu.state != dfuDNLOAD_IDLE) {
|
||||||
|
error("bad state\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (dfu.state != dfuIDLE && setup->wValue == next_block-1) {
|
||||||
|
debug("retransmisson\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (setup->wValue != next_block) {
|
||||||
|
debug("bad block (%d vs. %d)\n",
|
||||||
|
setup->wValue, next_block);
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errUNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!setup->wLength) {
|
||||||
|
debug("DONE\n");
|
||||||
|
dfu.state = dfuIDLE;
|
||||||
|
did_download = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ok = block_receive(setup->wLength);
|
||||||
|
next_block++;
|
||||||
|
dfu.state = dfuDNLOAD_IDLE;
|
||||||
|
return ok;
|
||||||
|
case DFU_FROM_DEV(DFU_UPLOAD):
|
||||||
|
debug("DFU_UPLOAD\n");
|
||||||
|
if (dfu.state == dfuIDLE) {
|
||||||
|
next_block = setup->wValue;
|
||||||
|
payload = PAYLOAD_START;
|
||||||
|
}
|
||||||
|
else if (dfu.state != dfuUPLOAD_IDLE)
|
||||||
|
return 0;
|
||||||
|
if (dfu.state != dfuIDLE && setup->wValue == next_block-1) {
|
||||||
|
debug("retransmisson\n");
|
||||||
|
/* @@@ try harder */
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errUNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (setup->wValue != next_block) {
|
||||||
|
debug("bad block (%d vs. %d)\n",
|
||||||
|
setup->wValue, next_block);
|
||||||
|
dfu.state = dfuERROR;
|
||||||
|
dfu.status = errUNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ok = block_transmit(setup->wLength);
|
||||||
|
next_block++;
|
||||||
|
dfu.state = dfuUPLOAD_IDLE;
|
||||||
|
return ok;
|
||||||
|
case DFU_FROM_DEV(DFU_GETSTATUS):
|
||||||
|
debug("DFU_GETSTATUS\n");
|
||||||
|
usb_send(&ep0, (uint8_t *) &dfu, sizeof(dfu), NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
case DFU_TO_DEV(DFU_CLRSTATUS):
|
||||||
|
debug("DFU_CLRSTATUS\n");
|
||||||
|
dfu.state = dfuIDLE;
|
||||||
|
dfu.status = OK;
|
||||||
|
return 1;
|
||||||
|
case DFU_FROM_DEV(DFU_GETSTATE):
|
||||||
|
debug("DFU_GETSTATE\n");
|
||||||
|
usb_send(&ep0, &dfu.state, 1, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
case DFU_TO_DEV(DFU_ABORT):
|
||||||
|
debug("DFU_ABORT\n");
|
||||||
|
dfu.state = dfuIDLE;
|
||||||
|
dfu.status = OK;
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
#ifdef CONFIG_PRINTK
|
||||||
|
printk("DFU rt %x, rq%x ?\n",
|
||||||
|
setup->bmRequestType, setup->bRequest);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* @@@ SDCC 2.7.0 ends up OR'in setup->bmRequestType with
|
||||||
|
* setup->bRequest unshifted if we don't use at least one of
|
||||||
|
* them here.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
static volatile uint8_t foo;
|
||||||
|
foo = setup->bRequest;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __bit my_descr(uint8_t type, uint8_t index, const uint8_t **reply,
|
||||||
|
uint8_t *size) __reentrant
|
||||||
|
{
|
||||||
|
index; /* suppress warning */
|
||||||
|
if (type != DFU_DT_FUNCTIONAL)
|
||||||
|
return 0;
|
||||||
|
*reply = functional_descriptor;
|
||||||
|
*size = sizeof(functional_descriptor);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void my_reset(void) __reentrant
|
||||||
|
{
|
||||||
|
/* @@@ not nice -- think about where this should go */
|
||||||
|
extern void run_payload(void);
|
||||||
|
|
||||||
|
if (did_download)
|
||||||
|
run_payload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dfu_init(void)
|
||||||
|
{
|
||||||
|
user_setup = my_setup;
|
||||||
|
user_get_descriptor = my_descr;
|
||||||
|
user_reset = my_reset;
|
||||||
|
}
|
86
fw/boot/dfu.h
Normal file
86
fw/boot/dfu.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* boot/dfu.h - DFU protocol constants and data structures
|
||||||
|
*
|
||||||
|
* Written 2008 by Werner Almesberger
|
||||||
|
* Copyright 2008 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DFU_H
|
||||||
|
#define DFU_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum dfu_request {
|
||||||
|
DFU_DETACH,
|
||||||
|
DFU_DNLOAD,
|
||||||
|
DFU_UPLOAD,
|
||||||
|
DFU_GETSTATUS,
|
||||||
|
DFU_CLRSTATUS,
|
||||||
|
DFU_GETSTATE,
|
||||||
|
DFU_ABORT,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum dfu_status {
|
||||||
|
OK,
|
||||||
|
errTARGET,
|
||||||
|
errFILE,
|
||||||
|
errWRITE,
|
||||||
|
errERASE,
|
||||||
|
errCHECK_ERASED,
|
||||||
|
errPROG,
|
||||||
|
errVERIFY,
|
||||||
|
errADDRESS,
|
||||||
|
errNOTDONE,
|
||||||
|
errFIRMWARE,
|
||||||
|
errVENDOR,
|
||||||
|
errUSBR,
|
||||||
|
errPOR,
|
||||||
|
errUNKNOWN,
|
||||||
|
errSTALLEDPKT,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum dfu_state {
|
||||||
|
appIDLE,
|
||||||
|
appDETACH,
|
||||||
|
dfuIDLE,
|
||||||
|
dfuDNLOAD_SYNC,
|
||||||
|
dfuDNBUSY,
|
||||||
|
dfuDNLOAD_IDLE,
|
||||||
|
dfuMANIFEST_SYNC,
|
||||||
|
dfuMANIFEST,
|
||||||
|
dfuMANIFEST_WAIT_RESET,
|
||||||
|
dfuUPLOAD_IDLE,
|
||||||
|
dfuERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define DFU_DT_FUNCTIONAL 0x21 /* DFU FUNCTIONAL descriptor type */
|
||||||
|
|
||||||
|
|
||||||
|
#define DFU_TO_DEV(req) (0x21 | (req) << 8)
|
||||||
|
#define DFU_FROM_DEV(req) (0xa1 | (req) << 8)
|
||||||
|
|
||||||
|
|
||||||
|
struct dfu {
|
||||||
|
uint8_t status; /* bStatus */
|
||||||
|
uint8_t toL, toM, toH; /* bwPollTimeout */
|
||||||
|
uint8_t state; /* bState */
|
||||||
|
uint8_t iString;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern struct dfu dfu;
|
||||||
|
|
||||||
|
|
||||||
|
void dfu_init(void);
|
||||||
|
|
||||||
|
#endif /* !DFU_H */
|
26
fw/boot/version.h
Normal file
26
fw/boot/version.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* boot/version.h - Automatically generated version string
|
||||||
|
*
|
||||||
|
* Written 2008 by Werner Almesberger
|
||||||
|
* Copyright 2008 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VERSION_H
|
||||||
|
#define VERSION_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Oddly, sdcc seems to insist on the "extern" to mean "declaration".
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern const char *build_date;
|
||||||
|
extern const uint16_t build_number;
|
||||||
|
|
||||||
|
#endif /* !VERSION_H */
|
Loading…
Reference in New Issue
Block a user