summaryrefslogtreecommitdiff
path: root/libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch
diff options
context:
space:
mode:
Diffstat (limited to 'libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch')
-rw-r--r--libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch4893
1 files changed, 0 insertions, 4893 deletions
diff --git a/libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch b/libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch
deleted file mode 100644
index aa4cb07dc..000000000
--- a/libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch
+++ /dev/null
@@ -1,4893 +0,0 @@
-From dd4bc9ff49b9a7075e579fdd62fd930d27a9a7df Mon Sep 17 00:00:00 2001
-From: Jason Self <j@jxself.org>
-Date: Thu, 4 Jul 2019 15:55:48 -0700
-Subject: [PATCH 2/8] Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
-
-http://shop.sysmocom.de/products/atusb/
----
- INSTALL | 20 +-
- Makefile | 6 +-
- WHENCE | 12 ++
- atusb/Makefile | 236 +++++++++++++++++++++
- atusb/README | 94 +++++++++
- atusb/an/README | 25 +++
- atusb/an/dec.py | 127 ++++++++++++
- atusb/an/get.py | 31 +++
- atusb/an/plot | 12 ++
- atusb/atusb.c | 63 ++++++
- atusb/board.c | 120 +++++++++++
- atusb/board.h | 95 +++++++++
- atusb/board_app.c | 173 ++++++++++++++++
- atusb/board_atusb.c | 162 +++++++++++++++
- atusb/board_atusb.h | 48 +++++
- atusb/board_hulusb.c | 179 ++++++++++++++++
- atusb/board_hulusb.h | 66 ++++++
- atusb/board_rzusb.c | 169 +++++++++++++++
- atusb/board_rzusb.h | 48 +++++
- atusb/boot.c | 77 +++++++
- atusb/descr.c | 104 ++++++++++
- atusb/ep0.c | 338 ++++++++++++++++++++++++++++++
- atusb/flash.c | 97 +++++++++
- atusb/include/at86rf230.h | 402 ++++++++++++++++++++++++++++++++++++
- atusb/include/atusb/atusb.h | 97 +++++++++
- atusb/include/atusb/ep0.h | 64 ++++++
- atusb/mac.c | 250 ++++++++++++++++++++++
- atusb/mac.h | 26 +++
- atusb/sernum.c | 47 +++++
- atusb/sernum.h | 37 ++++
- atusb/spi.c | 51 +++++
- atusb/spi.h | 30 +++
- atusb/uart.c | 64 ++++++
- atusb/uart.h | 25 +++
- atusb/usb/atu2.c | 247 ++++++++++++++++++++++
- atusb/usb/dfu.c | 260 +++++++++++++++++++++++
- atusb/usb/dfu.h | 119 +++++++++++
- atusb/usb/dfu_common.c | 101 +++++++++
- atusb/usb/usb.c | 181 ++++++++++++++++
- atusb/usb/usb.h | 189 +++++++++++++++++
- atusb/version.h | 23 +++
- 42 files changed, 4512 insertions(+), 3 deletions(-)
- create mode 100644 atusb/Makefile
- create mode 100644 atusb/README
- create mode 100644 atusb/an/README
- create mode 100755 atusb/an/dec.py
- create mode 100755 atusb/an/get.py
- create mode 100755 atusb/an/plot
- create mode 100644 atusb/atusb.c
- create mode 100644 atusb/board.c
- create mode 100644 atusb/board.h
- create mode 100644 atusb/board_app.c
- create mode 100644 atusb/board_atusb.c
- create mode 100644 atusb/board_atusb.h
- create mode 100644 atusb/board_hulusb.c
- create mode 100644 atusb/board_hulusb.h
- create mode 100644 atusb/board_rzusb.c
- create mode 100644 atusb/board_rzusb.h
- create mode 100644 atusb/boot.c
- create mode 100644 atusb/descr.c
- create mode 100644 atusb/ep0.c
- create mode 100644 atusb/flash.c
- create mode 100644 atusb/include/at86rf230.h
- create mode 100644 atusb/include/atusb/atusb.h
- create mode 100644 atusb/include/atusb/ep0.h
- create mode 100644 atusb/mac.c
- create mode 100644 atusb/mac.h
- create mode 100644 atusb/sernum.c
- create mode 100644 atusb/sernum.h
- create mode 100644 atusb/spi.c
- create mode 100644 atusb/spi.h
- create mode 100644 atusb/uart.c
- create mode 100644 atusb/uart.h
- create mode 100644 atusb/usb/atu2.c
- create mode 100644 atusb/usb/dfu.c
- create mode 100644 atusb/usb/dfu.h
- create mode 100644 atusb/usb/dfu_common.c
- create mode 100644 atusb/usb/usb.c
- create mode 100644 atusb/usb/usb.h
- create mode 100644 atusb/version.h
-
-diff --git a/INSTALL b/INSTALL
-index 74c5cfd..7fb1116 100644
---- a/INSTALL
-+++ b/INSTALL
-@@ -16,6 +16,8 @@ In order to build everything you will need the following on the host
- system:
-
- * A C/C++ compiler, like GCC
-+ * AVR-GCC
-+ * Standard C library for AVR-GCC
- * Cmake
- * GNU Bison/YACC
- * GNU Flex
-@@ -32,13 +34,27 @@ system:
-
- On GNU/Linux distros that use apt you can install these with:
-
-- apt install binutils-arm-linux-gnueabi binutils-arm-none-eabi bison \
-- cmake flex g++ gcc gcc-arm-linux-gnueabi gcc-arm-none-eabi gperf make wget
-+ apt install avr-gcc avr-libc binutils-arm-linux-gnueabi \
-+ binutils-arm-none-eabi bison cmake flex g++ gcc \
-+ gcc-arm-linux-gnueabi gcc-arm-none-eabi gperf make wget
-
- CARL9170 Firmware Configuration
-+-------------------------------
- When building the carl9170 firmware you will be prompted with
- configuration questions.
-
-+atusb: Firmware for the ATUSB IEEE 802.15.4 USB Adapter
-+-------------------------------------------------------
-+
-+To flash the firmware you need dfu-util on the host. Issue
-+
-+ make dfu
-+
-+right after plugging the device into the USB port while the red led is
-+still on.
-+
-+Refer to the included README file for more information.
-+
- Licensing
- ---------
-
-diff --git a/Makefile b/Makefile
-index 21d16fb..8474b30 100644
---- a/Makefile
-+++ b/Makefile
-@@ -17,7 +17,7 @@ shell=/bin/sh
- prefix=/lib/firmware
- install_program=install
-
--.PHONY: all test clean install a56 as31 aica ath9k_htc_toolchain ath9k_htc av7110 b43-tools carl9170fw-toolchain carl9170fw cis-tools cis dsp56k ihex2fw isci keyspan_pda openfwwf usbdux
-+.PHONY: all test clean install a56 as31 aica ath9k_htc_toolchain ath9k_htc atusb av7110 b43-tools carl9170fw-toolchain carl9170fw cis-tools cis dsp56k ihex2fw isci keyspan_pda openfwwf usbdux
-
- all: aica ath9k_htc av7110 carl9170fw cis dsp56k isci keyspan_pda openfwwf usbdux
-
-@@ -36,6 +36,9 @@ ath9k_htc_toolchain:
- ath9k_htc: ath9k_htc_toolchain
- cd ath9k_htc && $(MAKE) -C target_firmware
-
-+atusb:
-+ cd atusb && $(MAKE)
-+
- av7110:
- cd av7110 && $(MAKE)
-
-@@ -81,6 +84,7 @@ clean:
- if [ -a as31/Makefile ]; then cd as31 && $(MAKE) clean; fi;
- cd ath9k_htc && $(MAKE) toolchain-clean
- cd ath9k_htc && $(MAKE) -C target_firmware clean
-+ cd atusb && $(MAKE) clean
- cd av7110 && $(MAKE) clean
- cd carl9170fw/toolchain && $(MAKE) clean
- if [ -a carl9170fw/Makefile ]; then cd carl9170fw && $(MAKE) clean; fi;
-diff --git a/WHENCE b/WHENCE
-index 2932155..756de43 100644
---- a/WHENCE
-+++ b/WHENCE
-@@ -112,6 +112,18 @@ From https://github.com/qca/open-ath9k-htc-firmware
-
- --------------------------------------------------------------------------
-
-+atusb: Firmware for the ATUSB IEEE 802.15.4 USB Adapter
-+http://shop.sysmocom.de/products/atusb/
-+
-+From http://projects.qi-hardware.com/index.php/p/ben-wpan/source/tree/master/atusb/fw
-+
-+License: GPL-2.0-or-later
-+
-+Version: Based on commit 805db6ebf5d80692158acadf88e239da9d3e67af
-+dated September 13 2017
-+
-+--------------------------------------------------------------------------
-+
- Driver: b43 - OpenFWWF -- Free firmware for some Broadcom 43xx series WLAN chips
-
- License: GPLv2
-diff --git a/atusb/Makefile b/atusb/Makefile
-new file mode 100644
-index 0000000..c79cb26
---- /dev/null
-+++ b/atusb/Makefile
-@@ -0,0 +1,236 @@
-+#
-+# Makefile - Makefile of the ATUSB firmware
-+#
-+# Written 2010-2011, 2013 by Werner Almesberger
-+# Copyright 2010-2011, 2013 by 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.
-+#
-+
-+SHELL = /bin/bash
-+
-+NAME = atusb
-+DEBUG = false
-+
-+CFLAGS = -g -mmcu=$(CHIP) -DBOOT_ADDR=$(BOOT_ADDR) \
-+ -Wall -Wextra -Wshadow -Werror -Wno-unused-parameter \
-+ -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes
-+
-+ifeq ($(DEBUG),true)
-+CFLAGS += -DDEBUG
-+endif
-+
-+ifeq ($(NAME),rzusb)
-+CHIP=at90usb1287
-+CFLAGS += -DRZUSB -DAT86RF230
-+else ifeq ($(NAME),hulusb)
-+CHIP=at90usb1287
-+CFLAGS += -DHULUSB -DAT86RF212
-+else
-+CHIP=atmega32u2
-+CFLAGS += -DATUSB -DAT86RF231
-+endif
-+HOST=jlime
-+BOOT_ADDR=0x7000
-+
-+AVR_PREFIX = $(BIN_PATH) avr-
-+CC = $(AVR_PREFIX)gcc
-+OBJCOPY = $(AVR_PREFIX)objcopy
-+#OBJDUMP = $(AVR_PREFIX)objdump
-+SIZE = $(AVR_PREFIX)size
-+
-+# BCD notion is 0xJJMM with JJ being major and MM being minor. Thus 0x0020 is
-+# version 0.2 */
-+USB_BCD_VERSION = 0030
-+USB_VENDOR_ID = 20b7
-+USB_PRODUCT_ID = 1540
-+USB_ID = $(USB_VENDOR_ID):$(USB_PRODUCT_ID)
-+
-+OBJS = atusb.o board.o board_app.o sernum.o spi.o descr.o ep0.o \
-+ dfu_common.o usb.o app-atu2.o mac.o
-+BOOT_OBJS = boot.o board.o sernum.o spi.o flash.o dfu.o \
-+ dfu_common.o usb.o boot-atu2.o
-+
-+ifeq ($(DEBUG),true)
-+OBJS += uart.o
-+endif
-+
-+ifeq ($(NAME),rzusb)
-+OBJS += board_rzusb.o
-+BOOT_OBJS += board_rzusb.o
-+else ifeq ($(NAME),hulusb)
-+OBJS += board_hulusb.o
-+BOOT_OBJS += board_hulusb.o
-+else
-+OBJS += board_atusb.o
-+BOOT_OBJS += board_atusb.o
-+endif
-+
-+
-+vpath %.c usb/
-+
-+CFLAGS += -Iinclude -Iusb -I.
-+
-+# ----- Verbosity control -----------------------------------------------------
-+
-+CC_normal := $(CC)
-+BUILD_normal :=
-+DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
-+
-+CC_quiet = @echo " CC " $@ && $(CC_normal)
-+BUILD_quiet = @echo " BUILD " $@ && $(BUILD_normal)
-+DEPEND_quiet = @$(DEPEND_normal)
-+
-+ifeq ($(V),1)
-+ CC = $(CC_normal)
-+ BUILD = $(BUILD_normal)
-+ DEPEND = $(DEPEND_normal)
-+else
-+ CC = $(CC_quiet)
-+ BUILD = $(BUILD_quiet)
-+ DEPEND = $(DEPEND_quiet)
-+endif
-+
-+# ----- Rules -----------------------------------------------------------------
-+
-+.PHONY: all clean upload prog dfu update version.c bindist
-+.PHONY: prog-app prog-read on off reset
-+
-+all: $(NAME).bin boot.hex
-+
-+$(NAME).elf: $(OBJS)
-+ $(MAKE) version.o
-+ $(CC) $(CFLAGS) -o $@ $(OBJS) version.o
-+ $(SIZE) $@
-+
-+boot.elf: $(BOOT_OBJS)
-+ $(CC) $(CFLAGS) -o $@ $(BOOT_OBJS) \
-+ -Wl,--section-start=.text=$(BOOT_ADDR)
-+ $(SIZE) $@
-+
-+%.bin: %.elf
-+ $(BUILD) $(OBJCOPY) -j .text -j .data -O binary $< $@
-+ @echo "build #`cat .version`, `ls -l $@`"
-+
-+%.dfu: %.bin
-+ cp $(NAME).bin $(NAME).dfu
-+ dfu-suffix -a $(NAME).dfu -d 0x$(USB_BCD_VERSION) \
-+ -p 0x$(USB_PRODUCT_ID) -v 0x$(USB_VENDOR_ID)
-+
-+%.hex: %.elf
-+ $(BUILD) $(OBJCOPY) -j .text -j .data -O ihex $< $@
-+ @echo "Size: `$(SIZE) -A boot.hex | sed '/Total */s///p;d'` B"
-+
-+# ----- Cleanup ---------------------------------------------------------------
-+
-+clean:
-+ rm -f $(NAME).bin $(NAME).elf $(NAME).dfu
-+ rm -f $(OBJS) $(OBJS:.o=.d)
-+ rm -f boot.hex boot.elf
-+ rm -f $(BOOT_OBJS) $(BOOT_OBJS:.o=.d)
-+ rm -f version.c version.d version.o
-+
-+# ----- Build version ---------------------------------------------------------
-+
-+version.c:
-+ @if [ -f .version ]; then \
-+ v=`cat .version`; \
-+ expr $$v + 1 >.version; \
-+ else \
-+ echo 0 >.version; \
-+ fi
-+ @[ -s .version ] || echo 0 >.version
-+ @echo '/* MACHINE-GENERATED. DO NOT EDIT ! */' >version.c
-+ @echo '#include "version.h"' >>version.c
-+ @echo "const char *build_date = \"`date`\";" >>version.c
-+ @echo "const uint16_t build_number = `cat .version`;" \
-+ >>version.c
-+
-+# ----- Dependencies ----------------------------------------------------------
-+
-+MKDEP = \
-+ $(DEPEND) $< | \
-+ sed \
-+ -e 's|^$(basename $(notdir $<)).o:|$@:|' \
-+ -e '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
-+ -e '$${g;p;}' \
-+ -e d >$(basename $@).d; \
-+ [ "$${PIPESTATUS[*]}" = "0 0" ] || \
-+ { rm -f $(basename $@).d; exit 1; }
-+
-+%.o: %.c
-+ $(CC) $(CFLAGS) -Os -c $<
-+ $(MKDEP)
-+
-+-include $(OBJS:.o=.d)
-+
-+# ----- Object file variants --------------------------------------------------
-+
-+app-%.o: usb/%.c
-+ $(CC) $(CFLAGS) -Os -o $@ -c $<
-+ $(MKDEP)
-+
-+boot-%.o: usb/%.c
-+ $(CC) $(CFLAGS) -DBOOT_LOADER -Os -o $@ -c $<
-+ $(MKDEP)
-+
-+# ----- Distribution ----------------------------------------------------------
-+
-+BINDIST_BASE=http://downloads.qi-hardware.com/people/werner/wpan/bindist
-+ATUSB_BIN_NAME=atusb-`git rev-parse HEAD | cut -c 1-7`.bin
-+
-+bindist:
-+ qippl atusb.bin wpan/bindist/$(ATUSB_BIN_NAME)
-+ @echo $(BINDIST_BASE)/$(ATUSB_BIN_NAME)
-+ @echo md5sum: `md5sum atusb.bin | sed 's/ .*//'`
-+ @echo atrf-id: \
-+ `sed '/.*number = \(.*\);/s//#\1/p;d' version.c` \
-+ `sed '/.*date = "\(.*\)";/s//\1/p;d' version.c`
-+
-+# ----- Programming and device control ----------------------------------------
-+
-+upload: $(NAME).bin boot.hex
-+ scp $(NAME).bin boot.hex $(HOST):
-+
-+# lfuse: external clock, slow start-up
-+# hfuse: 4 kB boot loader, reset into boot loader
-+# lock: allow everything but SPM to the boot loader
-+# Note: when trying to program 0xef, we get back 0x2f, failing
-+# verification. So we just program 0x2f.
-+
-+prog-app:
-+ ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb -e \
-+ -U flash:w:atusb.bin:r \
-+ -U lfuse:w:0x60:m
-+
-+prog:
-+ ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb -e \
-+ -U flash:w:boot.hex:i \
-+ -U lfuse:w:0x60:m \
-+ -U hfuse:w:0xd8:m \
-+ -U lock:w:0x2f:m
-+
-+prog-read:
-+ ssh $(HOST) avrdude -F -p $(CHIP) -c nanonote_atusb \
-+ -U flash:r:mcu.bin:r
-+
-+dfu: $(NAME).dfu
-+ dfu-util -d $(USB_ID) -D $(NAME).dfu
-+
-+update: $(NAME).bin
-+ -atrf-reset -a
-+ usbwait -r -i 0.01 -t 5 $(USB_ID)
-+ $(MAKE) dfu
-+
-+on:
-+ ssh $(HOST) poke 0x10010318 4
-+
-+off:
-+ ssh $(HOST) poke 0x10010314 4
-+
-+reset:
-+ ssh $(HOST) poke 0x10010318 2048
-+ ssh $(HOST) poke 0x10010314 2048
-diff --git a/atusb/README b/atusb/README
-new file mode 100644
-index 0000000..99ceb22
---- /dev/null
-+++ b/atusb/README
-@@ -0,0 +1,94 @@
-+Requires a very recent toolchain, because ATmega32U2 is relatively new.
-+
-+- Building:
-+
-+ make
-+
-+- Uploading the firmware to a Ben (for flashing with the atusb-pgm cable):
-+
-+ make HOST=<hostname> upload
-+
-+ Example:
-+
-+ make HOST=ben upload
-+
-+ HOST defaults to "jlime".
-+
-+- Flashing the boot loader:
-+
-+ Prerequisite: avrdude on the Ben.
-+
-+ Disconnect the atusb board from USB. Insert the atusb-pgm connector into
-+ the Ben. Place the atusb-pgm adapter on the exposed contact pads of the
-+ atusb board and push it down. Then run
-+
-+ make prog
-+
-+ This takes about 30 seconds. If the programming fails with an error
-+ message like "Yikes! Invalid device signature.", verify that the
-+ atusb-pgm board is properly connected and placed, then try again.
-+
-+- Uploading the application:
-+
-+ Prerequisite: dfu-util installed on the PC.
-+
-+ Insert atusb into the PC, then run
-+
-+ make dfu
-+
-+ Note: since the boot loader resets the USB bus after timing out,
-+ this operation can fail with a message like "No DFU capable USB device
-+ found". Just retry, and it will eventually get through.
-+
-+
-+HULUSB notes:
-+-------------
-+To prepare and flash the firmware on a HULUSB device some additional steps are
-+needed;
-+
-+avr-objcopy -O ihex -R .signature -R .fuse -R .eeprom hulusb.elf hulusb.hex
-+dfu-programmer at90usb1287 flash hulusb.hex
-+dfu-programmer at90usb1287 reset
-+
-+--------------------------
-+
-+Making the toolchain:
-+
-+# patches according to
-+# http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789527
-+
-+# some gcc prerequisites
-+
-+apt-get remove avr-libc gcc-avr binutils-avr
-+apt-get install libmpfr-dev libmpc-dev
-+
-+# binutils
-+
-+wget http://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.bz2
-+tar xfj binutils-2.21.tar.bz2
-+cd binutils-2.21
-+./configure --target=avr --disable-nls
-+make
-+make install
-+
-+# gcc
-+
-+wget http://ftpmirror.gnu.org/gcc/gcc-4.5.2/gcc-4.5.2.tar.bz2
-+wget -O gcc_452_avr.patch http://gcc.gnu.org/bugzilla/attachment.cgi?id=23050
-+tar xfj gcc-4.5.2.tar.bz2
-+cd gcc-4.5.2
-+patch -p1 -s <../gcc_452_avr.patch
-+mkdir obj-avr
-+cd obj-avr
-+../configure --target=avr --enable-languages=c \
-+ --disable-nls --disable-libssp --with-dwarf2
-+make
-+make install
-+
-+wget http://download.savannah.gnu.org/releases/avr-libc/avr-libc-1.7.1.tar.bz2
-+tar xfj avr-libc-1.7.1.tar.bz2
-+cd avr-libc-1.7.1
-+./bootstrap # the automake at the end takes a while
-+./configure --build=`./config.guess` --host=avr
-+make
-+make install
-diff --git a/atusb/an/README b/atusb/an/README
-new file mode 100644
-index 0000000..8e0d2fc
---- /dev/null
-+++ b/atusb/an/README
-@@ -0,0 +1,25 @@
-+workflow:
-+
-+- connect zprobe (note: it currently inverts because it didn't have any
-+ other chips around. this may change later.)
-+
-+- capture the USB signals at an interesting moment with a sample rate of
-+ 50 MSa/s
-+
-+- zoom into the frame(s) of interest
-+
-+- download the data with
-+ ./get.py
-+
-+- decode with
-+ ./dec.py
-+
-+ For manual decoding, set the coders to D+ and D- (we need D- for SE0
-+ and SE1 detection), then click on a rising clock edge left of the
-+ packet and move the cursor to the right.
-+
-+- if there are problems with the clock, the analog signal and digital
-+ signals derived from it can be examined after running dec.py with
-+ ./plot
-+
-+ (Note that the digital zprobe hides any analog anomalies.)
-diff --git a/atusb/an/dec.py b/atusb/an/dec.py
-new file mode 100755
-index 0000000..8534857
---- /dev/null
-+++ b/atusb/an/dec.py
-@@ -0,0 +1,127 @@
-+#!/usr/bin/python
-+
-+from tmc.wave import *
-+from tmc.dxplore import dxplore
-+from tmc.decode import d_usb_stream
-+
-+
-+#
-+# Clock recovery: we assume that each change in the wave is triggered by a
-+# clock edge. We know the clock's nominal period and resynchronize on each
-+# edge. Additionally, we can obtain a list of times when a timing violation
-+# has occurred.
-+#
-+# Note that the timing violations logic doesn't make much sense in its present
-+# form, since it mainly measures noise (particularly if we're digitizing slow
-+# edges) and not clock drift.
-+#
-+# A more useful metric would be accumulated error from some point of reference
-+# or at least the timing of same edges, to eliminate (generally harmless) time
-+# offsets introduced by digitizing.
-+#
-+# So it would probably make more sense for "recover" not to check for timing
-+# violations at all, and leave this to more specialized functions.
-+#
-+def recover(self, period, min = None, max = None, t0 = None):
-+ if t0 is None:
-+ t0 = self.data[0]
-+ v = not self.initial
-+ res = []
-+ violations = []
-+ for t in self.data:
-+ v = not v
-+ if t <= t0:
-+ continue
-+ n = 0
-+ while t0 < t-period/2:
-+ res.append(t0)
-+ t0 += period
-+ n += 1
-+ if min is not None:
-+ if t0-t > n*min:
-+ violations.append(t)
-+ if max is not None:
-+ if t-t0 > n*max:
-+ violations.append(t)
-+ t0 = t
-+ return res, violations
-+
-+
-+#
-+# Load the analog waves saved by get.py
-+#
-+wv = waves()
-+wv.load("_wv")
-+
-+#
-+# Digitize the waves and save the result.
-+#
-+dp = wv[0].digitize(1.5, 1.8)
-+dm = wv[1].digitize(1.5, 1.8)
-+wv = waves(dp, dm, dp-dm)
-+wv.save("_dig")
-+
-+#
-+# Also record the differential signal.
-+#
-+wd = wv[1]-wv[0]
-+dd = wd.digitize(-0.5, 0.5)
-+wd.save("_diff")
-+
-+#
-+# Run clock recovery on D+/D-. We only need one, but check both to be sure.
-+#
-+#p = 1/1.5e6
-+p = 1/12e6
-+dp_t, viol = recover(dp, p, p*0.9, p*1.1)
-+print viol
-+dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0])
-+print viol
-+
-+#
-+# Shift the clock by half a period, add a few periods to get steady state and
-+# SE0s (if any), and then sample the data lines.
-+#
-+clk = map(lambda t: t+p/2, dp_t)
-+clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p))
-+dp_bv = dp.get(clk)
-+dm_bv = dm.get(clk)
-+
-+#
-+# Save a wave with the recovered clock to make it easier to find the bits in
-+# analog graphs.
-+#
-+dd.data = dp_t;
-+dd.save("_clk")
-+
-+#
-+# For decoding, we need a fake bit clock. We generate it by doubling each data
-+# bit and generating a L->H transition during this bit.
-+#
-+dpd = []
-+dmd = []
-+dck = []
-+
-+# err, silly, seems that we've mixed up D+ and D- all over the place :-)
-+print d_usb_stream(dm_bv[:], dp_bv[:])
-+
-+for v in dp_bv:
-+ dpd.append(v)
-+ dpd.append(v)
-+ dck.append(0)
-+ dck.append(1)
-+
-+for v in dm_bv:
-+ dmd.append(v)
-+ dmd.append(v)
-+
-+#
-+# Display the reconstructed digital signal. Note that the absolute time is only
-+# correct at the beginning and that relative time is only accurate over
-+# intervals in which no significant clock resynchronization has occurred.
-+#
-+# In fact, dxplore should probably have an option to either turn off time
-+# entirely or to display a user-provided time axis. The latter may be a bit
-+# tricky to implement.
-+#
-+dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK"))
-diff --git a/atusb/an/get.py b/atusb/an/get.py
-new file mode 100755
-index 0000000..685e00f
---- /dev/null
-+++ b/atusb/an/get.py
-@@ -0,0 +1,31 @@
-+#!/usr/bin/python
-+
-+from tmc.scope import rigol_ds1000c
-+
-+#-800, +1600
-+s = rigol_ds1000c()
-+#s.debug = False
-+
-+pos = s.hor.pos
-+scale = s.hor.scale
-+t0 = pos-scale*s.div_hor/2
-+t1 = pos+scale*s.div_hor/2
-+print t0, t1
-+
-+#zoom = 10
-+#step = scale/s.samples_per_div/zoom
-+#print step
-+step = 4e-9
-+step = 2e-9
-+
-+w = s.wave((s.ch[0], s.ch[1]), start = t0, end = t1, step = step)
-+w[0] = 3.3-w[0]
-+w[1] = 3.3-w[1]
-+
-+s.hor.pos = pos
-+s.hor.scale = scale
-+
-+w[0].label = "D+";
-+w[1].label = "D-";
-+
-+w.save("_wv")
-diff --git a/atusb/an/plot b/atusb/an/plot
-new file mode 100755
-index 0000000..1dea789
---- /dev/null
-+++ b/atusb/an/plot
-@@ -0,0 +1,12 @@
-+#!/bin/sh
-+#
-+# Plot output of "dec"
-+#
-+gnuplot -persist <<EOF
-+set style data lines
-+plot "_wv" using 1:(\$2-4), \
-+ "_dig" using 1:(\$2*3.3-4) lw 2, \
-+ "_wv" using 1:3, \
-+ "_dig" using 1:(\$3*3.3) lw 2, \
-+ "_clk" using 1:(\$2+1) lt 7
-+EOF
-diff --git a/atusb/atusb.c b/atusb/atusb.c
-new file mode 100644
-index 0000000..28faf40
---- /dev/null
-+++ b/atusb/atusb.c
-@@ -0,0 +1,63 @@
-+/*
-+ * fw/atusb.c - ATUSB initialization and main loop
-+ *
-+ * Written 2008-2011 by Werner Almesberger
-+ * Copyright 2008-2011 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.
-+ */
-+
-+
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/sleep.h>
-+#include <avr/interrupt.h>
-+
-+#include "usb.h"
-+
-+#include "board.h"
-+#include "sernum.h"
-+#include "spi.h"
-+#include "atusb/ep0.h"
-+
-+#ifdef DEBUG
-+#include "uart.h"
-+#endif
-+
-+
-+int main(void)
-+{
-+ board_init();
-+ board_app_init();
-+ reset_rf();
-+
-+ user_get_descriptor = sernum_get_descr;
-+
-+ /* now we should be at 8 MHz */
-+
-+#ifdef DEBUG
-+ uart_init();
-+ static FILE atben_stdout = FDEV_SETUP_STREAM(uart_write_char, NULL,
-+ _FDEV_SETUP_WRITE);
-+ stdout = &atben_stdout;
-+#endif
-+
-+ usb_init();
-+ ep0_init();
-+#ifdef ATUSB
-+ timer_init();
-+
-+ /* move interrupt vectors to 0 */
-+ MCUCR = 1 << IVCE;
-+ MCUCR = 0;
-+#endif
-+
-+ sei();
-+
-+ while (1)
-+ sleep_mode();
-+}
-diff --git a/atusb/board.c b/atusb/board.c
-new file mode 100644
-index 0000000..c3b8d26
---- /dev/null
-+++ b/atusb/board.c
-@@ -0,0 +1,120 @@
-+/*
-+ * fw/board.c - Board-specific functions (for boot loader and application)
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include <avr/boot.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "at86rf230.h"
-+#include "board.h"
-+#include "spi.h"
-+
-+
-+uint8_t board_sernum[42] = { 42, USB_DT_STRING };
-+
-+/* ----- Register access --------------------------------------------------- */
-+
-+void change_state(uint8_t new)
-+{
-+ while ((reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK) ==
-+ TRX_STATUS_TRANSITION);
-+ reg_write(REG_TRX_STATE, new);
-+}
-+
-+
-+uint8_t reg_read(uint8_t reg)
-+{
-+ uint8_t value;
-+
-+ spi_begin();
-+ spi_send(AT86RF230_REG_READ | reg);
-+ value = spi_recv();
-+ spi_end();
-+
-+ return value;
-+}
-+
-+
-+uint8_t subreg_read(uint8_t address, uint8_t mask, uint8_t position)
-+{
-+ /* Read current register value and mask out subregister. */
-+ uint8_t register_value = reg_read(address);
-+ register_value &= mask;
-+ register_value >>= position; /* Align subregister value. */
-+
-+ return register_value;
-+}
-+
-+
-+void reg_write(uint8_t reg, uint8_t value)
-+{
-+ spi_begin();
-+ spi_send(AT86RF230_REG_WRITE | reg);
-+ spi_send(value);
-+ spi_end();
-+}
-+
-+
-+void subreg_write(uint8_t address, uint8_t mask, uint8_t position, uint8_t value)
-+{
-+ /* Read current register value and mask area outside the subregister. */
-+ uint8_t register_value = reg_read(address);
-+ register_value &= ~mask;
-+
-+ /* Start preparing the new subregister value. shift in place and mask. */
-+ value <<= position;
-+ value &= mask;
-+
-+ value |= register_value; /* Set the new subregister value. */
-+
-+ /* Write the modified register value. */
-+ reg_write(address, value);
-+}
-+
-+
-+void panic(void)
-+{
-+ cli();
-+ while (1) {
-+ SET(LED);
-+ _delay_ms(100);
-+ CLR(LED);
-+ _delay_ms(100);
-+ }
-+}
-+
-+
-+static char hex(uint8_t nibble)
-+{
-+ return nibble < 10 ? '0'+nibble : 'a'+nibble-10;
-+}
-+
-+
-+void get_sernum(void)
-+{
-+ uint8_t sig;
-+ uint8_t i;
-+
-+ for (i = 0; i != 10; i++) {
-+ sig = boot_signature_byte_get(i+0xe);
-+ board_sernum[(i << 2)+2] = hex(sig >> 4);
-+ board_sernum[(i << 2)+4] = hex(sig & 0xf);
-+ }
-+}
-diff --git a/atusb/board.h b/atusb/board.h
-new file mode 100644
-index 0000000..dbcd410
---- /dev/null
-+++ b/atusb/board.h
-@@ -0,0 +1,95 @@
-+/*
-+ * fw/board.h - Board-specific functions and definitions
-+ *
-+ * Written 2008-2011, 2013, 2013 by Werner Almesberger
-+ * Copyright 2008-2011, 2013, 2013 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 BOARD_H
-+#define BOARD_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <atusb/atusb.h>
-+
-+#ifdef ATUSB
-+#include "board_atusb.h"
-+#endif
-+#ifdef RZUSB
-+#include "board_rzusb.h"
-+#endif
-+#ifdef HULUSB
-+#include "board_hulusb.h"
-+#endif
-+
-+#define SET_2(p, b) PORT##p |= 1 << (b)
-+#define CLR_2(p, b) PORT##p &= ~(1 << (b))
-+#define IN_2(p, b) DDR##p &= ~(1 << (b))
-+#define OUT_2(p, b) DDR##p |= 1 << (b)
-+#define PIN_2(p, b) ((PIN##p >> (b)) & 1)
-+
-+#define SET_1(p, b) SET_2(p, b)
-+#define CLR_1(p, b) CLR_2(p, b)
-+#define IN_1(p, b) IN_2(p, b)
-+#define OUT_1(p, b) OUT_2(p, b)
-+#define PIN_1(p, b) PIN_2(p, b)
-+
-+#define SET(n) SET_1(n##_PORT, n##_BIT)
-+#define CLR(n) CLR_1(n##_PORT, n##_BIT)
-+#define IN(n) IN_1(n##_PORT, n##_BIT)
-+#define OUT(n) OUT_1(n##_PORT, n##_BIT)
-+#define PIN(n) PIN_1(n##_PORT, n##_BIT)
-+
-+
-+#define USB_VENDOR ATUSB_VENDOR_ID
-+#define USB_PRODUCT ATUSB_PRODUCT_ID
-+
-+#define DFU_USB_VENDOR USB_VENDOR
-+#define DFU_USB_PRODUCT USB_PRODUCT
-+
-+
-+#define BOARD_MAX_mA 40
-+
-+#ifdef BOOT_LOADER
-+#define NUM_EPS 1
-+#else
-+#define NUM_EPS 2
-+#endif
-+
-+#define HAS_BOARD_SERNUM
-+
-+extern uint8_t board_sernum[42];
-+extern uint8_t irq_serial;
-+
-+
-+void reset_rf(void);
-+void reset_cpu(void);
-+uint8_t read_irq(void);
-+void slp_tr(void);
-+
-+void led(bool on);
-+void panic(void);
-+
-+uint64_t timer_read(void);
-+void timer_init(void);
-+
-+bool gpio(uint8_t port, uint8_t data, uint8_t dir, uint8_t mask, uint8_t *res);
-+void gpio_cleanup(void);
-+
-+void get_sernum(void);
-+
-+void board_app_init(void);
-+
-+uint8_t reg_read(uint8_t reg);
-+uint8_t subreg_read(uint8_t address, uint8_t mask, uint8_t position);
-+void reg_write(uint8_t reg, uint8_t value);
-+void subreg_write(uint8_t address, uint8_t mask, uint8_t position, uint8_t value);
-+void change_state(uint8_t new);
-+
-+#endif /* !BOARD_H */
-diff --git a/atusb/board_app.c b/atusb/board_app.c
-new file mode 100644
-index 0000000..1fa9bf4
---- /dev/null
-+++ b/atusb/board_app.c
-@@ -0,0 +1,173 @@
-+/*
-+ * fw/board_app.c - Board-specific functions (for the application)
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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.
-+ */
-+
-+
-+#include <stddef.h>
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "at86rf230.h"
-+#include "spi.h"
-+#include "mac.h"
-+#include "board.h"
-+
-+
-+static volatile uint32_t timer_h = 0; /* 2^(16+32) / 8 MHz = ~1.1 years */
-+
-+
-+void reset_cpu(void)
-+{
-+ WDTCSR = 1 << WDE;
-+}
-+
-+
-+uint8_t read_irq(void)
-+{
-+ return PIN(IRQ_RF);
-+}
-+
-+
-+void slp_tr(void)
-+{
-+ SET(SLP_TR);
-+ CLR(SLP_TR);
-+}
-+
-+
-+ISR(TIMER1_OVF_vect)
-+{
-+ timer_h++;
-+}
-+
-+
-+uint64_t timer_read(void)
-+{
-+ uint32_t high;
-+ uint8_t low, mid;
-+
-+ do {
-+ if (TIFR1 & (1 << TOV1)) {
-+ TIFR1 = 1 << TOV1;
-+ timer_h++;
-+ }
-+ high = timer_h;
-+ low = TCNT1L;
-+ mid = TCNT1H;
-+ }
-+ while (TIFR1 & (1 << TOV1));
-+
-+ /*
-+ * We need all these casts because the intermediate results are handled
-+ * as if they were signed and thus get sign-expanded. Sounds wrong-ish.
-+ */
-+ return (uint64_t) high << 16 | (uint64_t) mid << 8 | (uint64_t) low;
-+}
-+
-+
-+void timer_init(void)
-+{
-+ /* configure timer 1 as a free-running CLK counter */
-+
-+ TCCR1A = 0;
-+ TCCR1B = 1 << CS10;
-+
-+ /* enable timer overflow interrupt */
-+
-+ TIMSK1 = 1 << TOIE1;
-+}
-+
-+
-+bool gpio(uint8_t port, uint8_t data, uint8_t dir, uint8_t mask, uint8_t *res)
-+{
-+ EIMSK = 0; /* recover INT_RF to ATUSB_GPIO_CLEANUP or an MCU reset */
-+
-+ switch (port) {
-+ case 1:
-+ DDRB = (DDRB & ~mask) | dir;
-+ PORTB = (PORTB & ~mask) | data;
-+ break;
-+ case 2:
-+ DDRC = (DDRC & ~mask) | dir;
-+ PORTC = (PORTC & ~mask) | data;
-+ break;
-+ case 3:
-+ DDRD = (DDRD & ~mask) | dir;
-+ PORTD = (PORTD & ~mask) | data;
-+ break;
-+ default:
-+ return 0;
-+ }
-+
-+ /* disable the UART so that we can meddle with these pins as well. */
-+ spi_off();
-+ _delay_ms(1);
-+
-+ switch (port) {
-+ case 1:
-+ res[0] = PINB;
-+ res[1] = PORTB;
-+ res[2] = DDRB;
-+ break;
-+ case 2:
-+ res[0] = PINC;
-+ res[1] = PORTC;
-+ res[2] = DDRC;
-+ break;
-+ case 3:
-+ res[0] = PIND;
-+ res[1] = PORTD;
-+ res[2] = DDRD;
-+ break;
-+ }
-+
-+ return 1;
-+}
-+
-+
-+void gpio_cleanup(void)
-+{
-+ EIMSK = 1 << 0;
-+}
-+
-+
-+static void done(void *user)
-+{
-+ led(0);
-+}
-+
-+
-+uint8_t irq_serial;
-+
-+#if defined(ATUSB) || defined(HULUSB)
-+ISR(INT0_vect)
-+#endif
-+#ifdef RZUSB
-+ISR(TIMER1_CAPT_vect)
-+#endif
-+{
-+ if (mac_irq) {
-+ if (mac_irq())
-+ return;
-+ }
-+ if (eps[1].state == EP_IDLE) {
-+ led(1);
-+ irq_serial = (irq_serial+1) | 0x80;
-+ usb_send(&eps[1], &irq_serial, 1, done, NULL);
-+ }
-+}
-diff --git a/atusb/board_atusb.c b/atusb/board_atusb.c
-new file mode 100644
-index 0000000..a02fb7f
---- /dev/null
-+++ b/atusb/board_atusb.c
-@@ -0,0 +1,162 @@
-+/*
-+ * fw/board_atusb.c - ATUSB Board-specific functions (for boot loader and application)
-+ *
-+ * Written 2016 by Stefan Schmidt
-+ * Copyright 2016 Stefan Schmidt
-+ *
-+ * 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include <avr/boot.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "at86rf230.h"
-+#include "board.h"
-+#include "spi.h"
-+#include "usb/usb.h"
-+
-+static bool spi_initialized = 0;
-+
-+void reset_rf(void)
-+{
-+ /* set up all the outputs; default port value is 0 */
-+
-+ DDRB = 0;
-+ DDRC = 0;
-+ DDRD = 0;
-+ PORTB = 0;
-+ PORTC = 0;
-+ PORTD = 0;
-+
-+ OUT(LED);
-+ OUT(nRST_RF); /* this also resets the transceiver */
-+ OUT(SLP_TR);
-+
-+ spi_init();
-+
-+ /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
-+
-+ CLR(nRST_RF);
-+ _delay_us(2);
-+ SET(nRST_RF);
-+
-+ /* 12.4.14: SPI access latency after reset: 625 ns (min) */
-+
-+ _delay_us(2);
-+
-+ /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
-+
-+ set_clkm();
-+}
-+
-+void led(bool on)
-+{
-+ if (on)
-+ SET(LED);
-+ else
-+ CLR(LED);
-+}
-+
-+void set_clkm(void)
-+{
-+ /* switch CLKM to 8 MHz */
-+
-+ /*
-+ * @@@ Note: Atmel advise against changing the external clock in
-+ * mid-flight. We should therefore switch to the RC clock first, then
-+ * crank up the external clock, and finally switch back to the external
-+ * clock. The clock switching procedure is described in the ATmega32U2
-+ * data sheet in secton 8.2.2.
-+ */
-+ spi_begin();
-+ spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
-+ spi_send(CLKM_CTRL_8MHz);
-+ spi_end();
-+}
-+
-+void board_init(void)
-+{
-+ /* Disable the watchdog timer */
-+
-+ MCUSR = 0; /* Remove override */
-+ WDTCSR |= 1 << WDCE; /* Enable change */
-+ WDTCSR = 1 << WDCE; /* Disable watchdog while still enabling
-+ change */
-+
-+ CLKPR = 1 << CLKPCE;
-+ /* We start with a 1 MHz/8 clock. Disable the prescaler. */
-+ CLKPR = 0;
-+
-+ get_sernum();
-+}
-+
-+void spi_begin(void)
-+{
-+ if (!spi_initialized)
-+ spi_init();
-+ CLR(nSS);
-+}
-+
-+void spi_off(void)
-+{
-+ spi_initialized = 0;
-+ UCSR1B = 0;
-+}
-+
-+void spi_init(void)
-+{
-+ SET(nSS);
-+ OUT(SCLK);
-+ OUT(MOSI);
-+ OUT(nSS);
-+ IN(MISO);
-+
-+ UBRR1 = 0; /* set bit rate to zero to begin */
-+ UCSR1C = 1 << UMSEL11 | 1 << UMSEL10;
-+ /* set MSPI, MSB first, SPI data mode 0 */
-+ UCSR1B = 1 << RXEN1 | 1 << TXEN1;
-+ /* enable receiver and transmitter */
-+ UBRR1 = 0; /* reconfirm the bit rate */
-+
-+ spi_initialized = 1;
-+}
-+
-+void usb_init(void)
-+{
-+ USBCON |= 1 << FRZCLK; /* freeze the clock */
-+
-+ /* enable the PLL and wait for it to lock */
-+ PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
-+ PLLCSR |= 1 << PLLE;
-+ while (!(PLLCSR & (1 << PLOCK)));
-+
-+ USBCON &= ~(1 << USBE); /* reset the controller */
-+ USBCON |= 1 << USBE;
-+
-+ USBCON &= ~(1 << FRZCLK); /* thaw the clock */
-+
-+ UDCON &= ~(1 << DETACH); /* attach the pull-up */
-+ UDIEN = 1 << EORSTE; /* enable device interrupts */
-+// UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
-+
-+ ep_init();
-+}
-+
-+void board_app_init(void)
-+{
-+ /* enable INT0, trigger on rising edge */
-+ EICRA = 1 << ISC01 | 1 << ISC00;
-+ EIMSK = 1 << 0;
-+}
-diff --git a/atusb/board_atusb.h b/atusb/board_atusb.h
-new file mode 100644
-index 0000000..e5974c7
---- /dev/null
-+++ b/atusb/board_atusb.h
-@@ -0,0 +1,48 @@
-+/*
-+ * fw/board_atusb.h - ATUSB Board-specific functions and definitions
-+ *
-+ * Written 2016 by Stefan Schmidt
-+ * Copyright 2016 Stefan Schmidt
-+ *
-+ * 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 BOARD_ATUSB_H
-+#define BOARD_ATUSB_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#define LED_PORT B
-+#define LED_BIT 6
-+#define nRST_RF_PORT C
-+#define nRST_RF_BIT 7
-+#define SLP_TR_PORT B
-+#define SLP_TR_BIT 4
-+
-+#define SCLK_PORT D
-+#define SCLK_BIT 5
-+#define MOSI_PORT D
-+#define MOSI_BIT 3
-+
-+#define MISO_PORT D
-+#define MISO_BIT 2
-+#define nSS_PORT D
-+#define nSS_BIT 1
-+#define IRQ_RF_PORT D
-+#define IRQ_RF_BIT 0
-+
-+#define SPI_WAIT_DONE() while (!(UCSR1A & 1 << RXC1))
-+#define SPI_DATA UDR1
-+
-+void set_clkm(void);
-+void board_init(void);
-+
-+void spi_begin(void);
-+void spi_off(void);
-+void spi_init(void);
-+
-+#endif /* !BOARD_H */
-diff --git a/atusb/board_hulusb.c b/atusb/board_hulusb.c
-new file mode 100644
-index 0000000..084714e
---- /dev/null
-+++ b/atusb/board_hulusb.c
-@@ -0,0 +1,179 @@
-+/*
-+ * fw/board_hulusb.c - Busware HUL Board-specific functions (for boot loader and application)
-+ *
-+ * Written 2017 by Filzmaier Josef
-+ * Based on fw/board_rzusb written and Copyright 2016 Stefan Schmidt
-+ *
-+ * 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include <avr/boot.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "at86rf230.h"
-+#include "board.h"
-+#include "spi.h"
-+#include "usb/usb.h"
-+
-+static bool spi_initialized = 0;
-+
-+void reset_rf(void)
-+{
-+ /* set up all the outputs; default port value is 0 */
-+
-+ DDRB = 0;
-+ DDRC = 0;
-+ DDRD = 0;
-+ PORTB = 0;
-+ PORTC = 0;
-+ PORTD = 0;
-+
-+ OUT(LED_RED);
-+ OUT(LED_GREEN);
-+ SET(LED_RED); /* Leds are active low on HULUSB board */
-+ CLR(LED_GREEN); /* Green Led indicates the dongle is running */
-+ OUT(nRST_RF); /* this also resets the transceiver */
-+ OUT(SLP_TR);
-+
-+ spi_init();
-+
-+ /* AT86RF212 data sheet, Appendix B, p166 Power-On Reset procedure */
-+ /*-----------------------------------------------------------------*/
-+ CLR(SLP_TR);
-+ SET(nRST_RF);
-+ SET(nSS);
-+ _delay_us(400);
-+
-+ CLR(nRST_RF);
-+ _delay_us(2);
-+ SET(nRST_RF);
-+
-+ /* 5.1.4.5: Wait t10: 625 ns (min) */
-+
-+ _delay_us(2);
-+
-+ reg_write(REG_TRX_CTRL_0, 0x19);
-+
-+ change_state(TRX_CMD_FORCE_TRX_OFF);
-+ /*-----------------------------------------------------------------*/
-+
-+ /* we must restore TRX_CTRL_0 after each reset (7.7.4) */
-+
-+ set_clkm();
-+}
-+
-+void led_red(bool on) {
-+ if (on)
-+ CLR(LED_RED);
-+ else
-+ SET(LED_RED);
-+}
-+
-+void led_green(bool on) {
-+ if (on)
-+ CLR(LED_GREEN);
-+ else
-+ SET(LED_GREEN);
-+}
-+
-+void led(bool on)
-+{
-+ led_red(on);
-+}
-+
-+void set_clkm(void)
-+{
-+ /* CLKM is not connected on BUSWARE HUL and therefore it is running in
-+ * async mode. */
-+ reg_write(REG_TRX_CTRL_0, 0x00);
-+
-+ /* TX_AUTO_CRC_ON, default disabled */
-+ subreg_write(SR_TX_AUTO_CRC_ON, 1);
-+}
-+
-+void board_init(void)
-+{
-+ /* Disable the watchdog timer */
-+
-+ MCUSR = 0; /* Remove override */
-+ WDTCSR |= 1 << WDCE; /* Enable change */
-+ WDTCSR = 1 << WDCE; /* Disable watchdog while still enabling
-+ change */
-+
-+ CLKPR = 1 << CLKPCE;
-+ /* We start with a 16 MHz/8 clock. Put the prescaler to 2. */
-+ CLKPR = 1 << CLKPS0;
-+
-+ get_sernum();
-+}
-+
-+void spi_begin(void)
-+{
-+ if (!spi_initialized)
-+ spi_init();
-+ CLR(nSS);
-+}
-+
-+void spi_off(void)
-+{
-+ spi_initialized = 0;
-+ SPCR &= ~(1 << SPE);
-+}
-+
-+void spi_init(void)
-+{
-+ SET(nSS);
-+ OUT(SCLK);
-+ OUT(MOSI);
-+ OUT(nSS);
-+ IN(MISO);
-+
-+ SPCR = (1 << SPE) | (1 << MSTR);
-+ SPSR = (1 << SPI2X);
-+
-+ spi_initialized = 1;
-+}
-+
-+void usb_init(void)
-+{
-+ USBCON |= 1 << FRZCLK; /* freeze the clock */
-+
-+ /* enable the PLL and wait for it to lock */
-+ /* TODO sheet page 50 For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x. */
-+ /* FOR 8 XTAL Mhz only!!! */
-+ PLLCSR = ((1 << PLLP1) | (1 << PLLP0));
-+ PLLCSR |= 1 << PLLE;
-+ while (!(PLLCSR & (1 << PLOCK)));
-+
-+ UHWCON |= (1 << UVREGE);
-+
-+ USBCON &= ~((1 << USBE) | (1 << OTGPADE)); /* reset the controller */
-+ USBCON |= ((1 << USBE) | (1 << OTGPADE));
-+
-+ USBCON &= ~(1 << FRZCLK); /* thaw the clock */
-+
-+ UDCON &= ~(1 << DETACH); /* attach the pull-up */
-+ UDIEN = 1 << EORSTE; /* enable device interrupts */
-+ // UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
-+
-+ ep_init();
-+}
-+
-+void board_app_init(void)
-+{
-+ /* enable INT0, trigger on rising edge */
-+ EICRA = 1 << ISC01 | 1 << ISC00;
-+ EIMSK = 1 << INT0;
-+}
-diff --git a/atusb/board_hulusb.h b/atusb/board_hulusb.h
-new file mode 100644
-index 0000000..a1dadf0
---- /dev/null
-+++ b/atusb/board_hulusb.h
-@@ -0,0 +1,66 @@
-+/*
-+ * fw/board_hulusb.h - Busware HUL Board-specific functions (for boot loader and application)
-+ *
-+ * Written 2017 by Filzmaier Josef
-+ * Based on fw/board_rzusb written and Copyright 2016 Stefan Schmidt
-+ *
-+ * 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 BOARD_HULUSB_H
-+#define BOARD_HULUSB_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#define LED_RED_PORT A
-+#define LED_GREEN_PORT A
-+#define LED_RED_BIT 3
-+#define LED_GREEN_BIT 4
-+#define LED_PORT LED_RED_PORT
-+#define LED_BIT LED_RED_BIT
-+
-+#define nRST_RF_PORT B
-+#define nRST_RF_BIT 5
-+#define SLP_TR_PORT B
-+#define SLP_TR_BIT 4
-+
-+#define SCLK_PORT B
-+#define SCLK_BIT 1
-+#define MOSI_PORT B
-+#define MOSI_BIT 2
-+
-+#define MISO_PORT B
-+#define MISO_BIT 3
-+#define nSS_PORT B
-+#define nSS_BIT 0
-+#define IRQ_RF_PORT D
-+#define IRQ_RF_BIT 4
-+
-+#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
-+#define SR_CHANNEL 0x08, 0x1f, 0
-+
-+#define RG_CC_CTRL_1 (0x14)
-+
-+#define SPI_WAIT_DONE() while ((SPSR & (1 << SPIF)) == 0)
-+#define SPI_DATA SPDR
-+
-+void set_clkm(void);
-+void board_init(void);
-+
-+void led_red(bool on);
-+void led_green(bool on);
-+
-+void spi_begin(void);
-+void spi_off(void);
-+void spi_init(void);
-+
-+#ifdef DEBUG
-+void printStatus(void);
-+#define PRINT_STATUS() printStatus()
-+#endif
-+
-+#endif /* !BOARD_HULUSB_H */
-diff --git a/atusb/board_rzusb.c b/atusb/board_rzusb.c
-new file mode 100644
-index 0000000..e83d6fa
---- /dev/null
-+++ b/atusb/board_rzusb.c
-@@ -0,0 +1,169 @@
-+/*
-+ * fw/board_rzusb.c - RZUSB Board-specific functions (for boot loader and application)
-+ *
-+ * Written 2016 by Stefan Schmidt
-+ * Copyright 2016 Stefan Schmidt
-+ *
-+ * 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include <avr/boot.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "at86rf230.h"
-+#include "board.h"
-+#include "spi.h"
-+#include "usb/usb.h"
-+
-+static bool spi_initialized = 0;
-+
-+void reset_rf(void)
-+{
-+ /* set up all the outputs; default port value is 0 */
-+
-+ DDRB = 0;
-+ DDRC = 0;
-+ DDRD = 0;
-+ PORTB = 0;
-+ PORTC = 0;
-+ PORTD = 0;
-+
-+ OUT(LED);
-+ OUT(nRST_RF); /* this also resets the transceiver */
-+ OUT(SLP_TR);
-+
-+ spi_init();
-+
-+ /* AT86RF231 data sheet, 12.4.13, reset pulse width: 625 ns (min) */
-+
-+ CLR(nRST_RF);
-+ _delay_us(2);
-+ SET(nRST_RF);
-+
-+ /* 12.4.14: SPI access latency after reset: 625 ns (min) */
-+
-+ _delay_us(2);
-+
-+ /* we must restore TRX_CTRL_0 after each reset (9.6.4) */
-+
-+ set_clkm();
-+}
-+
-+void led(bool on)
-+{
-+ if (on)
-+ SET(LED);
-+ else
-+ CLR(LED);
-+}
-+
-+void set_clkm(void)
-+{
-+ /* switch CLKM to 8 MHz */
-+
-+ /*
-+ * @@@ Note: Atmel advise against changing the external clock in
-+ * mid-flight. We should therefore switch to the RC clock first, then
-+ * crank up the external clock, and finally switch back to the external
-+ * clock. The clock switching procedure is described in the ATmega32U2
-+ * data sheet in secton 8.2.2.
-+ */
-+ spi_begin();
-+ spi_send(AT86RF230_REG_WRITE | REG_TRX_CTRL_0);
-+ spi_send(0x10);
-+ spi_end();
-+
-+ /* TX_AUTO_CRC_ON, default disabled */
-+ spi_begin();
-+ spi_send(AT86RF230_REG_WRITE | 0x05);
-+ spi_send(0x80);
-+ spi_end();
-+}
-+
-+void board_init(void)
-+{
-+ /* Disable the watchdog timer */
-+
-+ MCUSR = 0; /* Remove override */
-+ WDTCSR |= 1 << WDCE; /* Enable change */
-+ WDTCSR = 1 << WDCE; /* Disable watchdog while still enabling
-+ change */
-+
-+ CLKPR = 1 << CLKPCE;
-+ /* We start with a 16 MHz/8 clock. Put the prescaler to 2. */
-+ CLKPR = 1 << CLKPS0;
-+
-+ get_sernum();
-+}
-+
-+void spi_begin(void)
-+{
-+ if (!spi_initialized)
-+ spi_init();
-+ CLR(nSS);
-+}
-+
-+void spi_off(void)
-+{
-+ spi_initialized = 0;
-+ SPCR &= ~(1 << SPE);
-+}
-+
-+void spi_init(void)
-+{
-+ SET(nSS);
-+ OUT(SCLK);
-+ OUT(MOSI);
-+ OUT(nSS);
-+ IN(MISO);
-+
-+ SPCR = (1 << SPE) | (1 << MSTR);
-+ SPSR = (1 << SPI2X);
-+
-+ spi_initialized = 1;
-+}
-+
-+void usb_init(void)
-+{
-+ USBCON |= 1 << FRZCLK; /* freeze the clock */
-+
-+ /* enable the PLL and wait for it to lock */
-+ /* TODO sheet page 50 For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x. */
-+ /* FOR 8 XTAL Mhz only!!! */
-+ PLLCSR = ((1 << PLLP1) | (1 << PLLP0));
-+ PLLCSR |= 1 << PLLE;
-+ while (!(PLLCSR & (1 << PLOCK)));
-+
-+ UHWCON |= (1 << UVREGE);
-+
-+ USBCON &= ~((1 << USBE) | (1 << OTGPADE)); /* reset the controller */
-+ USBCON |= ((1 << USBE) | (1 << OTGPADE));
-+
-+ USBCON &= ~(1 << FRZCLK); /* thaw the clock */
-+
-+ UDCON &= ~(1 << DETACH); /* attach the pull-up */
-+ UDIEN = 1 << EORSTE; /* enable device interrupts */
-+// UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
-+
-+ ep_init();
-+}
-+
-+void board_app_init(void)
-+{
-+ /* enable timer input capture 1, trigger on rising edge */
-+ TCCR1B = (1 << ICES1);
-+ TIFR1 = (1 << ICF1);
-+ TIMSK1 = (1 << ICIE1);
-+}
-diff --git a/atusb/board_rzusb.h b/atusb/board_rzusb.h
-new file mode 100644
-index 0000000..c2e518f
---- /dev/null
-+++ b/atusb/board_rzusb.h
-@@ -0,0 +1,48 @@
-+/*
-+ * fw/board_rzusb.h - RZUSB Board-specific functions and definitions
-+ *
-+ * Written 2016 by Stefan Schmidt
-+ * Copyright 2016 Stefan Schmidt
-+ *
-+ * 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 BOARD_RZUSB_H
-+#define BOARD_RZUSB_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#define LED_PORT D
-+#define LED_BIT 7
-+#define nRST_RF_PORT B
-+#define nRST_RF_BIT 5
-+#define SLP_TR_PORT B
-+#define SLP_TR_BIT 4
-+
-+#define SCLK_PORT B
-+#define SCLK_BIT 1
-+#define MOSI_PORT B
-+#define MOSI_BIT 2
-+
-+#define MISO_PORT B
-+#define MISO_BIT 3
-+#define nSS_PORT B
-+#define nSS_BIT 0
-+#define IRQ_RF_PORT D
-+#define IRQ_RF_BIT 4
-+
-+#define SPI_WAIT_DONE() while ((SPSR & (1 << SPIF)) == 0)
-+#define SPI_DATA SPDR
-+
-+void set_clkm(void);
-+void board_init(void);
-+
-+void spi_begin(void);
-+void spi_off(void);
-+void spi_init(void);
-+
-+#endif /* !BOARD_H */
-diff --git a/atusb/boot.c b/atusb/boot.c
-new file mode 100644
-index 0000000..6826ac6
---- /dev/null
-+++ b/atusb/boot.c
-@@ -0,0 +1,77 @@
-+/*
-+ * fw/boot.c - DFU boot loader for ATUSB
-+ *
-+ * Written 2008-2011 by Werner Almesberger
-+ * Copyright 2008-2011 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.
-+ */
-+
-+
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include <avr/pgmspace.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include "usb.h"
-+#include "dfu.h"
-+
-+#include "board.h"
-+#include "spi.h"
-+#include "atusb/ep0.h"
-+
-+
-+#define MS_TO_LOOPS(ms) ((uint32_t) (ms)*335)
-+
-+
-+static void (*run_payload)(void) = 0;
-+
-+
-+int main(void)
-+{
-+ /*
-+ * pgm_read_byte gets cached and there doesn't seem to be any other
-+ * way to dissuade gcc from doing this.
-+ */
-+ volatile int zero = 0;
-+ uint32_t loop = 0;
-+
-+ board_init();
-+ reset_rf();
-+
-+ /* now we should be at 8 MHz */
-+
-+ usb_init();
-+ dfu_init();
-+
-+ /* move interrupt vectors to the boot loader */
-+ MCUCR = 1 << IVCE;
-+ MCUCR = 1 << IVSEL;
-+
-+ sei();
-+
-+ led(1);
-+
-+ while (loop != MS_TO_LOOPS(2500)) {
-+ if (dfu.state == dfuIDLE && pgm_read_byte(zero) != 0xff)
-+ loop++;
-+ else
-+ loop = 0;
-+ }
-+
-+ led(0);
-+
-+ cli();
-+
-+ usb_reset();
-+ run_payload();
-+
-+ while (1); /* not reached */
-+}
-diff --git a/atusb/descr.c b/atusb/descr.c
-new file mode 100644
-index 0000000..f96b0ee
---- /dev/null
-+++ b/atusb/descr.c
-@@ -0,0 +1,104 @@
-+/*
-+ * fw/descr.c - USB descriptors
-+ *
-+ * Written 2008-2011, 2014 by Werner Almesberger
-+ * Copyright 2008-2011, 2014 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.
-+ */
-+
-+
-+#include "usb.h"
-+#include "dfu.h"
-+#include "board.h"
-+
-+
-+#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
-+
-+/*
-+ * Device descriptor
-+ */
-+
-+const uint8_t device_descriptor[18] = {
-+ 18, /* bLength */
-+ USB_DT_DEVICE, /* bDescriptorType */
-+ LE(0x200), /* bcdUSB */
-+ USB_CLASS_VENDOR_SPEC, /* bDeviceClass */
-+ 0x00, /* bDeviceSubClass */
-+ 0x00, /* bDeviceProtocol */
-+ EP0_SIZE, /* bMaxPacketSize */
-+ LE(USB_VENDOR), /* idVendor */
-+ LE(USB_PRODUCT), /* idProduct */
-+ LE(0x0001), /* bcdDevice */
-+ 0, /* iManufacturer */
-+ 0, /* iProduct */
-+#ifdef HAS_BOARD_SERNUM
-+ 1, /* iSerialNumber */
-+#else
-+ 0, /* iSerialNumber */
-+#endif
-+ 1 /* bNumConfigurations */
-+};
-+
-+
-+/*
-+ * Our configuration
-+ *
-+ * We're always bus-powered.
-+ */
-+
-+const uint8_t config_descriptor[] = {
-+ 9, /* bLength */
-+ USB_DT_CONFIG, /* bDescriptorType */
-+#if 0
-+ LE(9+9+7+7), /* wTotalLength */
-+#else
-+ LE(9+9+7+9), /* wTotalLength */
-+#endif
-+ 2, /* bNumInterfaces */
-+ 1, /* bConfigurationValue (> 0 !) */
-+ 0, /* iConfiguration */
-+ USB_ATTR_BUS_POWERED, /* bmAttributes */
-+ ((BOARD_MAX_mA)+1)/2, /* bMaxPower */
-+
-+ /* Interface #0 */
-+
-+ 9, /* bLength */
-+ USB_DT_INTERFACE, /* bDescriptorType */
-+ 0, /* bInterfaceNumber */
-+ 0, /* bAlternateSetting */
-+ 1, /* bNumEndpoints */
-+ USB_CLASS_VENDOR_SPEC, /* bInterfaceClass */
-+ 0, /* bInterfaceSubClass */
-+ 0, /* bInterfaceProtocol */
-+ 0, /* iInterface */
-+
-+#if 0
-+ /* EP OUT */
-+
-+ 7, /* bLength */
-+ USB_DT_ENDPOINT, /* bDescriptorType */
-+ 0x01, /* bEndPointAddress */
-+ 0x02, /* bmAttributes (bulk) */
-+ LE(EP1_SIZE), /* wMaxPacketSize */
-+ 0, /* bInterval */
-+#endif
-+
-+#if 1
-+ /* EP IN */
-+
-+ 7, /* bLength */
-+ USB_DT_ENDPOINT, /* bDescriptorType */
-+ 0x81, /* bEndPointAddress */
-+ 0x02, /* bmAttributes (bulk) */
-+ LE(EP1_SIZE), /* wMaxPacketSize */
-+ 0, /* bInterval */
-+#endif
-+
-+ /* Interface #1 */
-+
-+ DFU_ITF_DESCR(1, 0, dfu_proto_runtime, 0)
-+};
-diff --git a/atusb/ep0.c b/atusb/ep0.c
-new file mode 100644
-index 0000000..fa43f3b
---- /dev/null
-+++ b/atusb/ep0.c
-@@ -0,0 +1,338 @@
-+/*
-+ * fw/ep0.c - EP0 extension protocol
-+ *
-+ * Written 2008-2011, 2013 by Werner Almesberger
-+ * Copyright 2008-2011, 2013 Werner Almesberger
-+ * Copyright 2015-2016 Stefan Schmidt
-+ *
-+ * 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+#include <string.h>
-+
-+#include <avr/io.h>
-+#include <avr/eeprom.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#ifndef NULL
-+#define NULL 0
-+#endif
-+
-+#include "usb.h"
-+#include "dfu.h"
-+
-+#include "at86rf230.h"
-+#include "atusb/ep0.h"
-+#include "version.h"
-+#include "board.h"
-+#include "sernum.h"
-+#include "spi.h"
-+#include "mac.h"
-+
-+#ifdef ATUSB
-+#define HW_TYPE ATUSB_HW_TYPE_110131
-+#endif
-+
-+#ifdef RZUSB
-+#define HW_TYPE ATUSB_HW_TYPE_RZUSB
-+#endif
-+
-+#ifdef HULUSB
-+#define HW_TYPE ATUSB_HW_TYPE_HULUSB
-+#endif
-+
-+#ifdef DEBUG
-+#include "uart.h"
-+#include <stdio.h>
-+#define debug(FORMAT,args...) printf(FORMAT,##args)
-+#define error(FORMAT,args...) printf(FORMAT,##args)
-+#else
-+#define debug(...)
-+#define error(...)
-+#endif
-+
-+
-+static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
-+static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
-+static uint8_t size;
-+
-+
-+static void do_eeprom_write(void *user)
-+{
-+ int i;
-+
-+ for (i = 0; i < size; i++)
-+ eeprom_update_byte((uint8_t*)i, buf[i]);
-+}
-+
-+static void do_buf_write(void *user)
-+{
-+ uint8_t i;
-+
-+ spi_begin();
-+ for (i = 0; i != size; i++)
-+ spi_send(buf[i]);
-+ spi_end();
-+}
-+
-+
-+#define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */
-+
-+
-+static bool my_setup(const struct setup_request *setup)
-+{
-+ uint16_t req = setup->bmRequestType | setup->bRequest << 8;
-+ unsigned tmp;
-+ uint8_t i;
-+ uint64_t tmp64;
-+
-+ switch (req) {
-+ case ATUSB_FROM_DEV(ATUSB_ID):
-+ debug("ATUSB_ID\n");
-+ if (setup->wLength > 3)
-+ return 0;
-+ usb_send(&eps[0], id, setup->wLength, NULL, NULL);
-+ return 1;
-+ case ATUSB_FROM_DEV(ATUSB_BUILD):
-+ debug("ATUSB_BUILD\n");
-+ tmp = build_number;
-+ for (i = BUILD_OFFSET-2; tmp; i--) {
-+ buf[i] = (tmp % 10)+'0';
-+ tmp /= 10;
-+ }
-+ buf[i] = '#';
-+ buf[BUILD_OFFSET-1] = ' ';
-+ for (size = 0; build_date[size]; size++)
-+ buf[BUILD_OFFSET+size] = build_date[size];
-+ size += BUILD_OFFSET-i;
-+ if (size > setup->wLength)
-+ return 0;
-+ usb_send(&eps[0], buf+i, size, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_RESET):
-+ debug("ATUSB_RESET\n");
-+ reset_cpu();
-+ while (1);
-+
-+ case ATUSB_TO_DEV(ATUSB_RF_RESET):
-+ debug("ATUSB_RF_RESET\n");
-+ reset_rf();
-+ mac_reset();
-+ //ep_send_zlp(EP_CTRL);
-+ return 1;
-+
-+ case ATUSB_FROM_DEV(ATUSB_POLL_INT):
-+ debug("ATUSB_POLL_INT\n");
-+ if (setup->wLength < 1)
-+ return 0;
-+ *buf = read_irq();
-+ usb_send(&eps[0], buf, 1, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_FROM_DEV(ATUSB_TIMER):
-+ debug("ATUSB_TIMER\n");
-+ size = setup->wLength;
-+ if (size > sizeof(tmp64))
-+ size = sizeof(tmp64);
-+ tmp64 = timer_read();
-+ memcpy(buf, &tmp64, sizeof(tmp64));
-+ usb_send(&eps[0], buf, size, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_FROM_DEV(ATUSB_GPIO):
-+ debug("ATUSB_GPIO\n");
-+ if (setup->wLength < 3)
-+ return 0;
-+ if (!gpio(setup->wIndex, setup->wValue, setup->wValue >> 8,
-+ setup->wIndex >> 8, buf))
-+ return 0;
-+ usb_send(&eps[0], buf, 3, NULL, NULL);
-+ return 1;
-+ case ATUSB_TO_DEV(ATUSB_GPIO_CLEANUP):
-+ gpio_cleanup();
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_SLP_TR):
-+ debug("ATUSB_SLP_TR\n");
-+ slp_tr();
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_REG_WRITE):
-+ debug("ATUSB_REG_WRITE\n");
-+ spi_begin();
-+ spi_send(AT86RF230_REG_WRITE | setup->wIndex);
-+ spi_send(setup->wValue);
-+ spi_end();
-+ //ep_send_zlp(EP_CTRL);
-+ return 1;
-+ case ATUSB_FROM_DEV(ATUSB_REG_READ):
-+ debug("ATUSB_REG_READ\n");
-+ spi_begin();
-+ spi_send(AT86RF230_REG_READ | setup->wIndex);
-+ *buf = spi_recv();
-+ spi_end();
-+ usb_send(&eps[0], buf, 1, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
-+ debug("ATUSB_BUF_WRITE\n");
-+ if (setup->wLength < 1)
-+ return 0;
-+ if (setup->wLength > MAX_PSDU)
-+ return 0;
-+ buf[0] = AT86RF230_BUF_WRITE;
-+ buf[1] = setup->wLength;
-+ size = setup->wLength+2;
-+ usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
-+ return 1;
-+ case ATUSB_FROM_DEV(ATUSB_BUF_READ):
-+ debug("ATUSB_BUF_READ\n");
-+ if (setup->wLength < 2) /* PHR+LQI */
-+ return 0;
-+ if (setup->wLength > MAX_PSDU+2) /* PHR+PSDU+LQI */
-+ return 0;
-+ spi_begin();
-+ spi_send(AT86RF230_BUF_READ);
-+ size = spi_recv();
-+ if (size >= setup->wLength)
-+ size = setup->wLength-1;
-+ for (i = 0; i != size+1; i++)
-+ buf[i] = spi_recv();
-+ spi_end();
-+ usb_send(&eps[0], buf, size+1, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
-+ debug("ATUSB_SRAM_WRITE\n");
-+ if (setup->wIndex > SRAM_SIZE)
-+ return 0;
-+ if (setup->wIndex+setup->wLength > SRAM_SIZE)
-+ return 0;
-+ buf[0] = AT86RF230_SRAM_WRITE;
-+ buf[1] = setup->wIndex;
-+ size = setup->wLength+2;
-+ usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
-+ return 1;
-+ case ATUSB_FROM_DEV(ATUSB_SRAM_READ):
-+ debug("ATUSB_SRAM_READ\n");
-+ if (setup->wIndex > SRAM_SIZE)
-+ return 0;
-+ if (setup->wIndex+setup->wLength > SRAM_SIZE)
-+ return 0;
-+ spi_begin();
-+ spi_send(AT86RF230_SRAM_READ);
-+ spi_send(setup->wIndex);
-+ for (i = 0; i != setup->wLength; i++)
-+ buf[i] = spi_recv();
-+ spi_end();
-+ usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_SPI_WRITE):
-+ size = setup->wLength+2;
-+ if (size > sizeof(buf))
-+ return 0;
-+ buf[0] = setup->wValue;
-+ buf[1] = setup->wIndex;
-+ if (setup->wLength)
-+ usb_recv(&eps[0], buf+2, setup->wLength,
-+ do_buf_write, NULL);
-+ else
-+ do_buf_write(NULL);
-+ return 1;
-+ case ATUSB_FROM_DEV(ATUSB_SPI_WRITE2_SYNC):
-+ spi_begin();
-+ spi_send(setup->wValue);
-+ spi_send(setup->wIndex);
-+ spi_end();
-+ buf[0] = irq_serial;
-+ if (setup->wLength)
-+ usb_send(&eps[0], buf, 1, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_FROM_DEV(ATUSB_SPI_READ1):
-+ case ATUSB_FROM_DEV(ATUSB_SPI_READ2):
-+ spi_begin();
-+ spi_send(setup->wValue);
-+ if (req == ATUSB_FROM_DEV(ATUSB_SPI_READ2))
-+ spi_send(setup->wIndex);
-+ for (i = 0; i != setup->wLength; i++)
-+ buf[i] = spi_recv();
-+ spi_end();
-+ usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
-+ return 1;
-+
-+ case ATUSB_TO_DEV(ATUSB_RX_MODE):
-+ return mac_rx(setup->wValue);
-+ case ATUSB_TO_DEV(ATUSB_TX):
-+ return mac_tx(setup->wValue, setup->wIndex, setup->wLength);
-+ case ATUSB_TO_DEV(ATUSB_EUI64_WRITE):
-+ debug("ATUSB_EUI64_WRITE\n");
-+ usb_recv(&eps[0], buf, setup->wLength, do_eeprom_write, NULL);
-+ _delay_ms(100);
-+ reset_cpu();
-+ return 1;
-+
-+ case ATUSB_FROM_DEV(ATUSB_EUI64_READ):
-+ debug("ATUSB_EUI64_READ\n");
-+ eeprom_read_block(buf, (const void*)0, 8);
-+ usb_send(&eps[0], buf, 8, NULL, NULL);
-+ return 1;
-+
-+ default:
-+ error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
-+ setup->bmRequestType, setup->bRequest);
-+ return 0;
-+ }
-+}
-+
-+
-+static bool my_dfu_setup(const struct setup_request *setup)
-+{
-+ switch (setup->bmRequestType | setup->bRequest << 8) {
-+ case DFU_TO_DEV(DFU_DETACH):
-+ /* @@@ should use wTimeout */
-+ dfu.state = appDETACH;
-+ return 1;
-+ default:
-+ return dfu_setup_common(setup);
-+ }
-+}
-+
-+
-+static void my_set_interface(int nth)
-+{
-+ if (nth) {
-+ user_setup = my_dfu_setup;
-+ user_get_descriptor = dfu_my_descr;
-+ dfu.state = appIDLE;
-+ } else {
-+ user_setup = my_setup;
-+ user_get_descriptor = sernum_get_descr;
-+ }
-+}
-+
-+
-+static void my_reset(void)
-+{
-+ if (dfu.state == appDETACH)
-+ reset_cpu();
-+}
-+
-+
-+void ep0_init(void)
-+{
-+ user_setup = my_setup;
-+ user_set_interface = my_set_interface;
-+ my_set_interface(0);
-+ user_reset = my_reset;
-+}
-diff --git a/atusb/flash.c b/atusb/flash.c
-new file mode 100644
-index 0000000..1f8e59d
---- /dev/null
-+++ b/atusb/flash.c
-@@ -0,0 +1,97 @@
-+/*
-+ * fw/flash.c - Board-specific flash functions
-+ *
-+ * Written 2011, 2013-2015 by Werner Almesberger
-+ * Copyright 2011, 2013-2015 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/boot.h>
-+#include <avr/pgmspace.h>
-+
-+#include "dfu.h"
-+#include "board.h"
-+
-+
-+static uint32_t payload;
-+
-+
-+static void flash_start(void)
-+{
-+ payload = 0;
-+}
-+
-+
-+static bool flash_can_write(uint16_t size)
-+{
-+ return payload+size <= BOOT_ADDR;
-+}
-+
-+
-+static void flash_write(const uint8_t *buf, uint16_t size)
-+{
-+ static uint8_t last;
-+ const uint8_t *p;
-+
-+ for (p = buf; p != buf+size; p++) {
-+ if (!(payload & (SPM_PAGESIZE-1))) {
-+ boot_page_erase(payload);
-+ boot_spm_busy_wait();
-+ }
-+
-+ if (payload & 1)
-+ boot_page_fill(payload, last | (*p << 8));
-+ else
-+ last = *p;
-+ payload++;
-+
-+ if (!(payload & (SPM_PAGESIZE-1))) {
-+ boot_page_write(payload-SPM_PAGESIZE);
-+ boot_spm_busy_wait();
-+ }
-+ }
-+}
-+
-+
-+static void flash_end_write(void)
-+{
-+ if (payload & (SPM_PAGESIZE-1)) {
-+ boot_page_write(payload & ~(SPM_PAGESIZE-1));
-+ boot_spm_busy_wait();
-+ }
-+ boot_rww_enable();
-+}
-+
-+
-+static uint16_t flash_read(uint8_t *buf, uint16_t size)
-+{
-+ uint16_t got = 0;
-+
-+ while (size && payload != (uint32_t) FLASHEND+1) {
-+ *buf++ = pgm_read_byte(payload);
-+ payload++;
-+ size--;
-+ got++;
-+ }
-+ return got;
-+}
-+
-+
-+static const struct dfu_flash_ops flash_ops = {
-+ .start = flash_start,
-+ .can_write = flash_can_write,
-+ .write = flash_write,
-+ .end_write = flash_end_write,
-+ .read = flash_read,
-+};
-+
-+
-+const struct dfu_flash_ops *dfu_flash_ops = &flash_ops;
-diff --git a/atusb/include/at86rf230.h b/atusb/include/at86rf230.h
-new file mode 100644
-index 0000000..4c3ae22
---- /dev/null
-+++ b/atusb/include/at86rf230.h
-@@ -0,0 +1,402 @@
-+/*
-+ * include/at86rf230.h - AT86RF230/AT86RF231 protocol and register definitions
-+ *
-+ * Written 2008-2011 by Werner Almesberger
-+ * Copyright 2008-2011 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 AT86RF230_H
-+#define AT86RF230_H
-+
-+enum {
-+ AT86RF230_REG_WRITE = 0xc0, /* 11... */
-+ AT86RF230_REG_READ = 0x80, /* 10... */
-+ AT86RF230_BUF_WRITE = 0x60, /* 011... */
-+ AT86RF230_BUF_READ = 0x20, /* 001... */
-+ AT86RF230_SRAM_WRITE = 0x40, /* 010... */
-+ AT86RF230_SRAM_READ = 0x00 /* 000... */
-+};
-+
-+#define MAX_PSDU 127 /* octets, see AT86RF230 manual section 8.1 */
-+#define SRAM_SIZE 128
-+
-+
-+/* --- Registers ----------------------------------------------------------- */
-+
-+enum {
-+ REG_TRX_STATUS = 0x01,
-+ REG_TRX_STATE = 0x02,
-+ REG_TRX_CTRL_0 = 0x03,
-+
-+ REG_TRX_CTRL_1 = 0x04, /* 231 only */
-+
-+ REG_PHY_TX_PWR = 0x05,
-+ REG_PHY_RSSI = 0x06,
-+ REG_PHY_ED_LEVEL = 0x07,
-+ REG_PHY_CC_CCA = 0x08,
-+ REG_CCA_THRES = 0x09,
-+
-+ REG_RX_CTRL = 0x0a, /* 231 only */
-+ REG_SFD_VALUE = 0x0b, /* 231 only */
-+ REG_TRX_CTRL_2 = 0x0c, /* 231 only */
-+ REG_ANT_DIV = 0x0d, /* 231 only */
-+
-+ REG_IRQ_MASK = 0x0e,
-+ REG_IRQ_STATUS = 0x0f,
-+ REG_VREG_CTRL = 0x10,
-+ REG_BATMON = 0x11,
-+ REG_XOSC_CTRL = 0x12,
-+
-+ REG_RX_SYN = 0x15, /* 231 only */
-+ REG_XAH_CTRL_1 = 0x17, /* 231 only */
-+ REG_FTN_CTRL = 0x18, /* 231 only */
-+
-+ REG_PLL_CF = 0x1a,
-+ REL_PLL_DCU = 0x1b,
-+ REG_PART_NUM = 0x1c,
-+ REG_VERSION_NUM = 0x1d,
-+ REG_MAN_ID_0 = 0x1e,
-+ REG_MAN_ID_1 = 0x1f,
-+ REG_SHORT_ADDR_0 = 0x20,
-+ REG_SHORT_ADDR_1 = 0x21,
-+ REG_PAN_ID_0 = 0x22,
-+ REG_PAN_ID_1 = 0x23,
-+ REG_IEEE_ADDR_0 = 0x24,
-+ REG_IEEE_ADDR_1 = 0x25,
-+ REG_IEEE_ADDR_2 = 0x26,
-+ REG_IEEE_ADDR_3 = 0x27,
-+ REG_IEEE_ADDR_4 = 0x28,
-+ REG_IEEE_ADDR_5 = 0x29,
-+ REG_IEEE_ADDR_6 = 0x2a,
-+ REG_IEEE_ADDR_7 = 0x2b,
-+
-+ REG_XAH_CTRL_0 = 0x2c, /* XAH_CTRL in 230 */
-+ REG_CSMA_SEED_0 = 0x2d,
-+ REG_CSMA_SEED_1 = 0x2e,
-+ REG_CSMA_BE = 0x2f, /* 231 only */
-+
-+ REG_CONT_TX_0 = 0x36,
-+ REG_CONT_TX_1 = 0x3d, /* 230 only */
-+};
-+
-+/* --- TRX_STATUS --- ------------------------------------------------------ */
-+
-+#define CCA_DONE (1 << 7)
-+#define CCA_STATUS (1 << 6)
-+
-+#define TRX_STATUS_SHIFT 0
-+#define TRX_STATUS_MASK 0x1f
-+
-+enum {
-+ TRX_STATUS_P_ON = 0x00, /* reset default */
-+ TRX_STATUS_BUSY_RX = 0x01,
-+ TRX_STATUS_BUSY_TX = 0x02,
-+ TRX_STATUS_RX_ON = 0x06,
-+ TRX_STATUS_TRX_OFF = 0x08,
-+ TRX_STATUS_PLL_ON = 0x09,
-+ TRX_STATUS_SLEEP = 0x0f,
-+ TRX_STATUS_BUSY_RX_AACK = 0x11,
-+ TRX_STATUS_BUSY_TX_ARET = 0x12,
-+ TRX_STATUS_RX_AACK_ON = 0x16,
-+ TRX_STATUS_TX_ARET_ON = 0x19,
-+ TRX_STATUS_RX_ON_NOCLK = 0x1c,
-+ TRX_STATUS_RX_AACK_ON_NOCLK = 0x1d,
-+ TRX_STATUS_BUSY_RX_AACK_NOCLK = 0x1e,
-+ TRX_STATUS_TRANSITION = 0x1f /* ..._IN_PROGRESS */
-+};
-+
-+/* --- TRX_STATE ----------------------------------------------------------- */
-+
-+#define TRAC_STATUS_SHIFT 5
-+#define TRAC_STATUS_MASK 7
-+
-+enum {
-+ TRAC_STATUS_SUCCESS = 0, /* reset default */
-+ TRAC_STATUS_SUCCESS_DATA_PENDING = 1,
-+ TRAC_STATUS_SUCCESS_WAIT_FOR_ACK = 2, /* 231 only */
-+ TRAC_STATUS_CHANNEL_ACCESS_FAILURE = 3,
-+ TRAC_STATUS_NO_ACK = 5,
-+ TRAC_STATUS_INVALID = 7
-+};
-+
-+#define TRX_CMD_SHIFT 0
-+#define TRX_CMD_MASK 0x1f
-+
-+enum {
-+ TRX_CMD_NOP = 0x00, /* reset default */
-+ TRX_CMD_TX_START = 0x02,
-+ TRX_CMD_FORCE_TRX_OFF = 0x03,
-+ TRX_CMD_FORCE_PLL_ON = 0x04, /* 231 only */
-+ TRX_CMD_RX_ON = 0x06,
-+ TRX_CMD_TRX_OFF = 0x08,
-+ TRX_CMD_PLL_ON = 0x09,
-+ TRX_CMD_RX_AACK_ON = 0x16,
-+ TRX_CMD_TX_ARET_ON = 0x19,
-+};
-+
-+/* --- TRX_CTRL_0 ---------------------------------------------------------- */
-+
-+#define PAD_IO_SHIFT 6
-+#define PAD_IO_MASK 3
-+
-+enum {
-+ PAD_IO_2mA, /* reset default */
-+ PAD_IO_4mA,
-+ PAD_IO_6mA,
-+ PAD_IO_8mA
-+};
-+
-+#define PAD_IO_CLKM_SHIFT 4
-+#define PAD_IO_CLKM_MASK 3
-+
-+enum {
-+ PAD_IO_CLKM_2mA,
-+ PAD_IO_CLKM_4mA, /* reset default */
-+ PAD_IO_CLKM_5mA,
-+ PAD_IO_CLKM_8mA,
-+};
-+
-+#define CLKM_SHA_SEL (1 << 3)
-+
-+#define CLKM_CTRL_SHIFT 0
-+#define CLKM_CTRL_MASK 7
-+
-+enum {
-+ CLKM_CTRL_OFF = 0,
-+ CLKM_CTRL_1MHz = 1, /* reset default */
-+ CLKM_CTRL_2MHz = 2,
-+ CLKM_CTRL_4MHz = 3,
-+ CLKM_CTRL_8MHz = 4,
-+ CLKM_CTRL_16MHz = 5
-+};
-+
-+/* --- TRX_CTRL_1 (231 only) ----------------------------------------------- */
-+
-+#define PA_EXT_EN (1 << 7)
-+#define IRQ_2_EXT_EN (1 << 6)
-+#define TX_AUTO_CRC_ON (1 << 5) /* 231 location */
-+#define RX_BL_CTRL (1 << 4)
-+
-+#define SPI_CMD_MODE_SHIFT 2
-+#define SPI_CMD_MODE_MASK 3
-+
-+enum {
-+ SPI_CMD_MODE_EMPTY = 0, /* reset default */
-+ SPI_CMD_MODE_TRX_STATUS = 1,
-+ SPI_CMD_MODE_PHY_RSSI = 2,
-+ SPI_CMD_MODE_IRQ_STATUS = 3,
-+};
-+
-+#define IRQ_MASK_MODE (1 << 1)
-+#define IRQ_POLARITY (1 << 0)
-+
-+/* --- PHY_TX_PWR ---------------------------------------------------------- */
-+
-+#define TX_AUTO_CRC_ON_230 (1 << 7) /* 230 location */
-+
-+#define PA_BUF_LT_SHIFT 6
-+#define PA_BUF_LT_MASK 3
-+
-+#define PA_LT_SHIFT 4
-+#define PA_LT_MASK 3
-+
-+#define TX_PWR_SHIFT 0
-+#define TX_PWR_MASK 0x0f
-+
-+/* --- PHY_RSSI ------------------------------------------------------------ */
-+
-+#define RX_CRC_VALID (1 << 7)
-+
-+#define RND_VALUE_SHIFT 5 /* 231 only */
-+#define RND_VALUE_MASK 3
-+
-+#define RSSI_SHIFT 0
-+#define RSSI_MASK 0x1f
-+
-+/* --- PHY_CC_CCA ---------------------------------------------------------- */
-+
-+#define CCA_REQUEST (1 << 7)
-+
-+#define CCA_MODE_SHIFT 5
-+#define CCA_MODE_MASK 3
-+
-+enum {
-+ CCA_MODE_CARRIER_OR_ENERGY = 0, /* 231 only */
-+ CCA_MODE_ENERGY = 1, /* reset default */
-+ CCA_MODE_CARRIER = 2,
-+ CCA_MODE_CARRIER_AND_ENERGY = 3
-+};
-+
-+#define CHANNEL_SHIFT 0
-+#define CHANNEL_MASK 0x1f
-+
-+/* --- CCA_THRES ----------------------------------------------------------- */
-+
-+#define CCA_ED_THRES_SHIFT 0
-+#define CCA_ED_THRES_MASK 0x0f
-+
-+/* --- RX_CTRL (231 only) -------------------------------------------------- */
-+
-+#define PDT_THRES_SHIFT 0
-+#define PDT_THRES_MASK 0x0f
-+
-+enum {
-+ PDT_THRES_DEFAULT = 0x07, /* reset default */
-+ PDT_THRES_DIVERSITY = 0x03,
-+};
-+
-+/* --- TRX_CTRL_2 (231 only) ----------------------------------------------- */
-+
-+#define RX_SAFE_MODE (1 << 7)
-+
-+#define OQPSK_DATA_RATE_SHIFT 0
-+#define OQPSK_DATA_RATE_MASK 3
-+
-+enum {
-+ OQPSK_DATA_RATE_250 = 0, /* reset default */
-+ OQPSK_DATA_RATE_500 = 1,
-+ OQPSK_DATA_RATE_1000 = 2,
-+ OQPSK_DATA_RATE_2000 = 3
-+};
-+
-+/* --- ANT_DIV (231 only) -------------------------------------------------- */
-+
-+#define ANT_SEL (1 << 7)
-+#define ANT_DIV_EN (1 << 3)
-+#define ANT_EXT_SW_EN (1 << 2)
-+
-+#define ANT_CTRL_SHIFT 0
-+#define ANT_CTRL_MASK 3
-+
-+enum {
-+ ANT_CTRL_ANT_0 = 1,
-+ ANT_CTRL_ANT_1 = 2,
-+ ANT_CTRL_NODIV = 3, /* reset default */
-+};
-+
-+/* --- IRQ_MASK/IRQ_STATUS ------------------------------------------------- */
-+
-+enum {
-+ IRQ_PLL_LOCK = 1 << 0,
-+ IRQ_PLL_UNLOCK = 1 << 1,
-+ IRQ_RX_START = 1 << 2,
-+ IRQ_TRX_END = 1 << 3,
-+ IRQ_CCA_ED_DONE = 1 << 4, /* 231 only */
-+ IRQ_AMI = 1 << 5, /* 231 only */
-+ IRQ_TRX_UR = 1 << 6,
-+ IRQ_BAT_LOW = 1 << 7
-+};
-+
-+/* --- VREG_CTRL ----------------------------------------------------------- */
-+
-+#define AVREG_EXT (1 << 7)
-+#define AVDD_OK (1 << 6)
-+#define DVREG_EXT (1 << 3)
-+#define DVDD_OK (1 << 2)
-+
-+/* --- BATMON -------------------------------------------------------------- */
-+
-+#define BATMON_OK (1 << 5)
-+#define BATMON_HR (1 << 4)
-+
-+#define BATMON_VTH_SHIFT 0
-+#define BATMON_VTH_MASK 0x0f
-+
-+/* --- XOSC_CTRL ----------------------------------------------------------- */
-+
-+#define XTAL_MODE_SHIFT 4
-+#define XTAL_MODE_MASK 0x0f
-+
-+enum {
-+ XTAL_MODE_OFF = 0x0, /* 230 only */
-+ XTAL_MODE_EXT = 0x4,
-+ XTAL_MODE_INT = 0xf /* reset default */
-+};
-+
-+#define XTAL_TRIM_SHIFT 4
-+#define XTAL_TRIM_MASK 0x0f
-+
-+/* --- RX_SYN (231 only) --------------------------------------------------- */
-+
-+#define RX_PDT_DIS (1 << 7)
-+
-+#define RX_PDT_LEVEL_SHIFT 0
-+#define RX_PDT_LEVEL_MASK 0xf
-+
-+/* --- XAH_CTRL_1 (231 only) ----------------------------------------------- */
-+
-+#define AACK_FLTR_RES_FT (1 << 5)
-+#define AACK_UPLD_RES_FT (1 << 4)
-+#define AACK_ACK_TIME (1 << 2)
-+#define AACK_PROM_MODE (1 << 1)
-+
-+/* --- FTN_CTRL (231 only) ------------------------------------------------- */
-+
-+#define FTN_START (1 << 7)
-+
-+/* --- PLL_CF -------------------------------------------------------------- */
-+
-+#define PLL_CF_START (1 << 7)
-+
-+/* --- PLL_DCU ------------------------------------------------------------- */
-+
-+#define PLL_DCU_START (1 << 7)
-+
-+/* --- XAH_CTRL_0 (XAH_CTRL in 230) ---------------------------------------- */
-+
-+#define MAX_FRAME_RETRIES_SHIFT 4
-+#define MAX_FRAME_RETRIES_MASK 0x0f
-+
-+#define MAX_CSMA_RETRIES_SHIFT 1
-+#define MAX_CSMA_RETRIES_MASK 0x07
-+
-+#define SLOTTED_OPERATION (1 << 0) /* 231 only */
-+
-+/* --- CSMA_SEED_1 --------------------------------------------------------- */
-+
-+#define MIN_BE_SHIFT_230 6 /* 230 location */
-+#define MIN_BE_MASK_230 3
-+
-+#define AACK_FVN_MODE_SHIFT 6 /* 231 only */
-+#define AACK_FVN_MODE_MASK 3
-+
-+enum {
-+ AACK_FVN_MODE_0 = 0,
-+ AACK_FVN_MODE_01 = 1, /* reset default */
-+ AACK_FVN_MODE_012 = 2,
-+ AACK_FVN_MODE_ANY = 3
-+};
-+
-+#define AACK_SET_PD (1 << 5)
-+#define AACK_DIS_ACK (1 << 4) /* 231 only */
-+#define I_AM_COORD (1 << 3)
-+
-+#define CSMA_SEED_1_SHIFT 0
-+#define CSMA_SEED_1_MASK 7
-+
-+/* --- CSMA_BE ------------------------------------------------------------- */
-+
-+#define MAX_BE_SHIFT 4
-+#define MAX_BE_MASK 0x0f
-+
-+#define MIN_BE_SHIFT 0 /* 231 location */
-+#define MIN_BE_MASK 0x0f
-+
-+/* --- REG_CONT_TX_0 ------------------------------------------------------- */
-+
-+#define CONT_TX_MAGIC 0x0f
-+
-+/* --- REG_CONT_TX_1 (230 only) -------------------------------------------- */
-+
-+#define CONT_TX_MOD 0x00 /* modulated */
-+#define CONT_TX_M2M 0x10 /* f_CH-2 MHz */
-+#define CONT_TX_M500K 0x80 /* f_CH-0.5 MHz */
-+#define CONT_TX_P500K 0xc0 /* f_CH+0.5 MHz */
-+
-+#endif /* !AT86RF230_H */
-diff --git a/atusb/include/atusb/atusb.h b/atusb/include/atusb/atusb.h
-new file mode 100644
-index 0000000..555d14b
---- /dev/null
-+++ b/atusb/include/atusb/atusb.h
-@@ -0,0 +1,97 @@
-+/*
-+ * atusb.h - Definitions shared between kernel and ATUSB firmware
-+ *
-+ * Written 2013 by Werner Almesberger <werner@almesberger.net>
-+ *
-+ * 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, version 2, or
-+ * (at your option) any later version.
-+ *
-+ * This file should be identical for kernel and firmware.
-+ * Kernel: drivers/net/ieee802154/atusb.h
-+ * Firmware: ben-wpan/atusb/fw/include/atusb/atusb.h
-+ */
-+
-+#ifndef _ATUSB_H
-+#define _ATUSB_H
-+
-+#define ATUSB_VENDOR_ID 0x20b7 /* Qi Hardware*/
-+#define ATUSB_PRODUCT_ID 0x1540 /* 802.15.4, device 0 */
-+ /* -- - - */
-+
-+#define ATUSB_BUILD_SIZE 256 /* maximum build version/date message length */
-+
-+/* Commands to our device. Make sure this is synced with the firmware */
-+enum atusb_requests {
-+ ATUSB_ID = 0x00, /* system status/control grp */
-+ ATUSB_BUILD,
-+ ATUSB_RESET,
-+ ATUSB_RF_RESET = 0x10, /* debug/test group */
-+ ATUSB_POLL_INT,
-+ ATUSB_TEST, /* atusb-sil only */
-+ ATUSB_TIMER,
-+ ATUSB_GPIO,
-+ ATUSB_SLP_TR,
-+ ATUSB_GPIO_CLEANUP,
-+ ATUSB_REG_WRITE = 0x20, /* transceiver group */
-+ ATUSB_REG_READ,
-+ ATUSB_BUF_WRITE,
-+ ATUSB_BUF_READ,
-+ ATUSB_SRAM_WRITE,
-+ ATUSB_SRAM_READ,
-+ ATUSB_SPI_WRITE = 0x30, /* SPI group */
-+ ATUSB_SPI_READ1,
-+ ATUSB_SPI_READ2,
-+ ATUSB_SPI_WRITE2_SYNC,
-+ ATUSB_RX_MODE = 0x40, /* HardMAC group */
-+ ATUSB_TX,
-+ ATUSB_EUI64_WRITE = 0x50, /* Parameter in EEPROM grp */
-+ ATUSB_EUI64_READ,
-+};
-+
-+enum {
-+ ATUSB_HW_TYPE_100813, /* 2010-08-13 */
-+ ATUSB_HW_TYPE_101216, /* 2010-12-16 */
-+ ATUSB_HW_TYPE_110131, /* 2011-01-31, ATmega32U2-based */
-+ ATUSB_HW_TYPE_RZUSB, /* Atmel Raven USB dongle with at86rf230 */
-+ ATUSB_HW_TYPE_HULUSB, /* Busware HUL USB dongle with at86rf212 */
-+};
-+
-+/*
-+ * Direction bRequest wValue wIndex wLength
-+ *
-+ * ->host ATUSB_ID - - 3
-+ * ->host ATUSB_BUILD - - #bytes
-+ * host-> ATUSB_RESET - - 0
-+ *
-+ * host-> ATUSB_RF_RESET - - 0
-+ * ->host ATUSB_POLL_INT - - 1
-+ * host-> ATUSB_TEST - - 0
-+ * ->host ATUSB_TIMER - - #bytes (6)
-+ * ->host ATUSB_GPIO dir+data mask+p# 3
-+ * host-> ATUSB_SLP_TR - - 0
-+ * host-> ATUSB_GPIO_CLEANUP - - 0
-+ *
-+ * host-> ATUSB_REG_WRITE value addr 0
-+ * ->host ATUSB_REG_READ - addr 1
-+ * host-> ATUSB_BUF_WRITE - - #bytes
-+ * ->host ATUSB_BUF_READ - - #bytes
-+ * host-> ATUSB_SRAM_WRITE - addr #bytes
-+ * ->host ATUSB_SRAM_READ - addr #bytes
-+ *
-+ * host-> ATUSB_SPI_WRITE byte0 byte1 #bytes
-+ * ->host ATUSB_SPI_READ1 byte0 - #bytes
-+ * ->host ATUSB_SPI_READ2 byte0 byte1 #bytes
-+ * ->host ATUSB_SPI_WRITE2_SYNC byte0 byte1 0/1
-+ *
-+ * host-> ATUSB_RX_MODE on - 0
-+ * host-> ATUSB_TX flags ack_seq #bytes
-+ * host-> ATUSB_EUI64_WRITE - - #bytes (8)
-+ * ->host ATUSB_EUI64_READ - - #bytes (8)
-+ */
-+
-+#define ATUSB_REQ_FROM_DEV (USB_TYPE_VENDOR | USB_DIR_IN)
-+#define ATUSB_REQ_TO_DEV (USB_TYPE_VENDOR | USB_DIR_OUT)
-+
-+#endif /* !_ATUSB_H */
-diff --git a/atusb/include/atusb/ep0.h b/atusb/include/atusb/ep0.h
-new file mode 100644
-index 0000000..7777345
---- /dev/null
-+++ b/atusb/include/atusb/ep0.h
-@@ -0,0 +1,64 @@
-+/*
-+ * include/atusb/ep0.h - EP0 extension protocol
-+ *
-+ * Written 2008-2011, 2013 by Werner Almesberger
-+ * Copyright 2008-2011, 2013 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 EP0_H
-+#define EP0_H
-+
-+#include <atusb/atusb.h>
-+
-+
-+/*
-+ * EP0 protocol:
-+ *
-+ * 0.0 initial release
-+ * 0.1 addition of ATUSB_TEST
-+ * 0.2 First public release
-+ * 0.3 ATUSB_EUI64_READ/WRITE for permanent EUI64 handling
-+ * Support to run the firmware on Atmel Raven USB dongles
-+ * Remove FCS frame check from firmware and leave it to the driver
-+ * Use extended operation mode for TX for automatic ACK handling
-+ */
-+
-+#define EP0ATUSB_MAJOR 0 /* EP0 protocol, major revision */
-+#define EP0ATUSB_MINOR 3 /* EP0 protocol, minor revision */
-+
-+
-+/*
-+ * bmRequestType:
-+ *
-+ * D7 D6..5 D4...0
-+ * | | |
-+ * direction (0 = host->dev)
-+ * type (2 = vendor)
-+ * recipient (0 = device)
-+ */
-+
-+#ifndef USB_TYPE_VENDOR
-+#define USB_TYPE_VENDOR 0x40
-+#endif
-+
-+#ifndef USB_DIR_IN
-+#define USB_DIR_IN 0x80
-+#endif
-+
-+#ifndef USB_DIR_OUT
-+#define USB_DIR_OUT 0x00
-+#endif
-+
-+#define ATUSB_FROM_DEV(req) (ATUSB_REQ_FROM_DEV | (req) << 8)
-+#define ATUSB_TO_DEV(req) (ATUSB_REQ_TO_DEV | (req) << 8)
-+
-+
-+void ep0_init(void);
-+
-+#endif /* !EP0_H */
-diff --git a/atusb/mac.c b/atusb/mac.c
-new file mode 100644
-index 0000000..835002c
---- /dev/null
-+++ b/atusb/mac.c
-@@ -0,0 +1,250 @@
-+/*
-+ * fw/mac.c - HardMAC functions
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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.
-+ */
-+
-+#include <stddef.h>
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.h"
-+
-+#include "at86rf230.h"
-+#include "spi.h"
-+#include "board.h"
-+#include "mac.h"
-+
-+#define RX_BUFS 3
-+
-+
-+bool (*mac_irq)(void) = NULL;
-+
-+
-+static uint8_t rx_buf[RX_BUFS][MAX_PSDU+2]; /* PHDR+payload+LQ */
-+static uint8_t tx_buf[MAX_PSDU];
-+static uint8_t tx_size = 0;
-+static bool txing = 0;
-+static bool queued_tx_ack = 0;
-+static uint8_t next_seq, this_seq, queued_seq;
-+
-+
-+/* ----- Receive buffer management ----------------------------------------- */
-+
-+
-+static uint8_t rx_in = 0, rx_out = 0;
-+
-+
-+static inline void next_buf(uint8_t *index)
-+{
-+ *index = (*index+1) % RX_BUFS;
-+}
-+
-+
-+/* ----- Interrupt handling ------------------------------------------------ */
-+
-+
-+static void rx_done(void *user);
-+static void tx_ack_done(void *user);
-+
-+
-+static void usb_next(void)
-+{
-+ const uint8_t *buf;
-+
-+ if (rx_in != rx_out) {
-+ buf = rx_buf[rx_out];
-+ led(1);
-+ usb_send(&eps[1], buf, buf[0]+2, rx_done, NULL);
-+ }
-+
-+ if (queued_tx_ack) {
-+ usb_send(&eps[1], &queued_seq, 1, tx_ack_done, NULL);
-+ queued_tx_ack = 0;
-+ }
-+}
-+
-+
-+static void tx_ack_done(void *user)
-+{
-+ usb_next();
-+}
-+
-+static void rx_done(void *user)
-+{
-+ led(0);
-+ next_buf(&rx_out);
-+ usb_next();
-+#ifdef AT86RF230
-+ /* slap at86rf230 - reduce fragmentation issue */
-+ change_state(TRX_STATUS_RX_AACK_ON);
-+#endif
-+}
-+
-+
-+static void receive_frame(void)
-+{
-+ uint8_t size;
-+ uint8_t *buf;
-+
-+ spi_begin();
-+ spi_io(AT86RF230_BUF_READ);
-+
-+ size = spi_recv();
-+ if (!size || (size & 0x80)) {
-+ spi_end();
-+ return;
-+ }
-+
-+ buf = rx_buf[rx_in];
-+ spi_recv_block(buf+1, size+1);
-+ spi_end();
-+
-+ buf[0] = size;
-+ next_buf(&rx_in);
-+
-+ if (eps[1].state == EP_IDLE)
-+ usb_next();
-+}
-+
-+
-+static bool handle_irq(void)
-+{
-+ uint8_t irq;
-+
-+ irq = reg_read(REG_IRQ_STATUS);
-+ if (!(irq & IRQ_TRX_END))
-+ return 1;
-+
-+ if (txing) {
-+ if (eps[1].state == EP_IDLE) {
-+ usb_send(&eps[1], &this_seq, 1, tx_ack_done, NULL);
-+ } else {
-+ queued_tx_ack = 1;
-+ queued_seq = this_seq;
-+ }
-+ txing = 0;
-+ return 1;
-+ }
-+
-+ /* likely */
-+ if (eps[1].state == EP_IDLE || rx_in != rx_out)
-+ receive_frame();
-+
-+ return 1;
-+}
-+
-+
-+/* ----- TX/RX ------------------------------------------------------------- */
-+
-+
-+bool mac_rx(int on)
-+{
-+ if (on) {
-+ mac_irq = handle_irq;
-+ reg_read(REG_IRQ_STATUS);
-+ change_state(TRX_CMD_RX_AACK_ON);
-+ } else {
-+ mac_irq = NULL;
-+ change_state(TRX_CMD_FORCE_TRX_OFF);
-+ txing = 0;
-+ }
-+ return 1;
-+}
-+
-+
-+static void do_tx(void *user)
-+{
-+ uint16_t timeout = 0xffff;
-+ uint8_t status;
-+ uint8_t i;
-+
-+ /*
-+ * If we time out here, the host driver will time out waiting for the
-+ * TRX_END acknowledgement.
-+ */
-+ do {
-+ if (!--timeout)
-+ return;
-+ status = reg_read(REG_TRX_STATUS) & TRX_STATUS_MASK;
-+ }
-+ while (status != TRX_STATUS_RX_ON && status != TRX_STATUS_RX_AACK_ON);
-+
-+#ifdef AT86RF231
-+ /*
-+ * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
-+ * reception may have begun while we were still working on the previous
-+ * one.
-+ */
-+ reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
-+#endif
-+#ifdef AT86RF230
-+ /*
-+ * at86rf230 doesn't support force change, nevetherless this works
-+ * somehow
-+ */
-+ reg_write(REG_TRX_STATE, TRX_CMD_PLL_ON);
-+#endif
-+#ifdef AT86RF212
-+ /*
-+ * We use TRX_CMD_FORCE_PLL_ON instead of TRX_CMD_PLL_ON because a new
-+ * reception may have begun while we were still working on the previous
-+ * one.
-+ */
-+ reg_write(REG_TRX_STATE, TRX_CMD_FORCE_PLL_ON);
-+#endif
-+
-+ handle_irq();
-+
-+ spi_begin();
-+ spi_send(AT86RF230_BUF_WRITE);
-+ spi_send(tx_size+2); /* CRC */
-+ for (i = 0; i != tx_size; i++)
-+ spi_send(tx_buf[i]);
-+ spi_end();
-+
-+ change_state(TRX_STATUS_TX_ARET_ON);
-+
-+ slp_tr();
-+
-+ txing = 1;
-+ this_seq = next_seq;
-+
-+ /*
-+ * Wait until we reach BUSY_TX_ARET, so that we command the transition to
-+ * RX_AACK_ON which will be executed upon TX completion.
-+ */
-+ change_state(TRX_CMD_PLL_ON);
-+ change_state(TRX_CMD_RX_AACK_ON);
-+}
-+
-+
-+bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len)
-+{
-+ if (len > MAX_PSDU)
-+ return 0;
-+ tx_size = len;
-+ next_seq = seq;
-+ usb_recv(&eps[0], tx_buf, len, do_tx, NULL);
-+ return 1;
-+}
-+
-+
-+void mac_reset(void)
-+{
-+ mac_irq = NULL;
-+ txing = 0;
-+ queued_tx_ack = 0;
-+ rx_in = rx_out = 0;
-+ next_seq = this_seq = queued_seq = 0;
-+
-+ /* enable CRC and PHY_RSSI (with RX_CRC_VALID) in SPI status return */
-+ reg_write(REG_TRX_CTRL_1,
-+ TX_AUTO_CRC_ON | SPI_CMD_MODE_PHY_RSSI << SPI_CMD_MODE_SHIFT);
-+}
-diff --git a/atusb/mac.h b/atusb/mac.h
-new file mode 100644
-index 0000000..f3c92fb
---- /dev/null
-+++ b/atusb/mac.h
-@@ -0,0 +1,26 @@
-+/*
-+ * fw/mac.h - HardMAC functions
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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 MAC_H
-+#define MAC_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+
-+extern bool (*mac_irq)(void);
-+
-+bool mac_rx(int on);
-+bool mac_tx(uint16_t flags, uint8_t seq, uint16_t len);
-+void mac_reset(void);
-+
-+#endif /* !MAC_H */
-diff --git a/atusb/sernum.c b/atusb/sernum.c
-new file mode 100644
-index 0000000..41e434c
---- /dev/null
-+++ b/atusb/sernum.c
-@@ -0,0 +1,47 @@
-+/*
-+ * fw/sernum.c - ATUSB serial number
-+ *
-+ * Written 2008-2011, 2013 by Werner Almesberger
-+ * Copyright 2008-2011, 2013 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.h"
-+
-+#include "board.h"
-+#include "sernum.h"
-+
-+
-+static const uint8_t string_descriptor_0[] = {
-+ 4, /* blength */
-+ USB_DT_STRING, /* bDescriptorType */
-+ LE(USB_LANGID_ENGLISH_US) /* wLANGID[0] */
-+};
-+
-+
-+bool sernum_get_descr(uint8_t type, uint8_t index, const uint8_t **reply,
-+ uint8_t *size)
-+{
-+ if (type != USB_DT_STRING)
-+ return 0;
-+ switch (index) {
-+ case 0:
-+ *reply = string_descriptor_0;
-+ *size = sizeof(string_descriptor_0);
-+ return 1;
-+ case 1:
-+ *reply = board_sernum;
-+ *size = sizeof(board_sernum);
-+ return 1;
-+ default:
-+ return 0;
-+ }
-+}
-diff --git a/atusb/sernum.h b/atusb/sernum.h
-new file mode 100644
-index 0000000..31a8e27
---- /dev/null
-+++ b/atusb/sernum.h
-@@ -0,0 +1,37 @@
-+/*
-+ * fw/sernum.h - ATUSB serial number
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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 SERNUM_H
-+#define SERNUM_H
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include "board.h"
-+
-+
-+#ifdef HAS_BOARD_SERNUM
-+
-+bool sernum_get_descr(uint8_t type, uint8_t index, const uint8_t **reply,
-+ uint8_t *size);
-+
-+#else /* HAS_BOARD_SERNUM */
-+
-+static inline bool sernum_get_descr(uint8_t type, uint8_t index,
-+ const uint8_t **reply, uint8_t *size)
-+{
-+ return 0;
-+}
-+
-+#endif /* !HAS_BOARD_SERNUM */
-+
-+#endif /* !SERNUM_H */
-diff --git a/atusb/spi.c b/atusb/spi.c
-new file mode 100644
-index 0000000..3fa5715
---- /dev/null
-+++ b/atusb/spi.c
-@@ -0,0 +1,51 @@
-+/*
-+ * fw/spi.c - ATmega8 family SPI I/O
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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.
-+ */
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include <avr/io.h>
-+
-+#include "board.h"
-+#include "spi.h"
-+
-+
-+uint8_t spi_io(uint8_t v)
-+{
-+// while (!(UCSR1A & 1 << UDRE1));
-+ SPI_DATA = v;
-+ SPI_WAIT_DONE();
-+ return SPI_DATA;
-+}
-+
-+
-+void spi_end(void)
-+{
-+// while (!(UCSR1A & 1 << TXC1));
-+ SET(nSS);
-+}
-+
-+
-+void spi_recv_block(uint8_t *buf, uint8_t n)
-+{
-+ if (!n)
-+ return;
-+ SPI_DATA = 0;
-+ while (--n) {
-+ SPI_WAIT_DONE();
-+ *buf++ = SPI_DATA;
-+ SPI_DATA = 0;
-+ }
-+ SPI_WAIT_DONE();
-+ *buf++ = SPI_DATA;
-+}
-diff --git a/atusb/spi.h b/atusb/spi.h
-new file mode 100644
-index 0000000..6e04f4e
---- /dev/null
-+++ b/atusb/spi.h
-@@ -0,0 +1,30 @@
-+/*
-+ * fw/spi.h - ATmega8 family SPI I/O
-+ *
-+ * Written 2011, 2013 by Werner Almesberger
-+ * Copyright 2011, 2013 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 SPI_H
-+#define SPI_H
-+
-+#include <stdint.h>
-+
-+
-+void spi_begin(void);
-+uint8_t spi_io(uint8_t v);
-+void spi_end(void);
-+void spi_off(void);
-+void spi_init(void);
-+
-+#define spi_send(v) (void) spi_io(v)
-+#define spi_recv(v) spi_io(0)
-+
-+void spi_recv_block(uint8_t *buf, uint8_t n);
-+
-+#endif /* !SPI_H */
-diff --git a/atusb/uart.c b/atusb/uart.c
-new file mode 100644
-index 0000000..44bec27
---- /dev/null
-+++ b/atusb/uart.c
-@@ -0,0 +1,64 @@
-+/*
-+ * fw/uart.h - Functions needed for debugging over uart
-+ *
-+ * Code adapted from http://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc
-+ * and http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
-+ *
-+ * Published under the Creative Commons Share-Alike licence
-+ * https://creativecommons.org/licenses/by-sa/2.0/de/
-+ *
-+ * S. Salewski 2007
-+ *
-+ * Adapted by
-+ * Josef Filzmaier 2017
-+ */
-+
-+#include <avr/io.h>
-+#include "uart.h"
-+
-+#define USART_BAUD 38400UL
-+#define F_CPU 8000000UL
-+
-+#define Wait_USART_Ready() while (!(UCSR1A & (1<<UDRE1)))
-+#define UART_UBRR (F_CPU/(16L*USART_BAUD)-1)
-+
-+// initialize USART, 8N1 mode
-+void
-+uart_init(void)
-+{
-+/* TODO: Find a working configuration for uart for the atmega32u2 */
-+#if CHIP == at90usb1287
-+ CLKPR = (1 << CLKPCE);
-+ CLKPR = 0; // clock prescaler == 0, so we have 16 MHz mpu frequency
-+ UBRR1 = UART_UBRR;
-+ UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
-+ UCSR1B = (1 << TXEN1);
-+ do
-+ {
-+ UDR1;
-+ }
-+ while (UCSR1A & (1 << RXC1));
-+#endif
-+
-+}
-+
-+int uart_write_char(char c, FILE* stream)
-+{
-+ if (c == '\n'){
-+ uart_new_line();
-+ }
-+ else {
-+ Wait_USART_Ready();
-+ UDR1 = c;
-+ }
-+ return 0;
-+}
-+
-+void
-+uart_new_line(void)
-+{
-+ Wait_USART_Ready();
-+ UDR1 = '\r';
-+ Wait_USART_Ready();
-+ UDR1 = '\n';
-+}
-diff --git a/atusb/uart.h b/atusb/uart.h
-new file mode 100644
-index 0000000..4810f9c
---- /dev/null
-+++ b/atusb/uart.h
-@@ -0,0 +1,25 @@
-+/*
-+ * fw/uart.h - Functions needed for debugging over uart
-+ *
-+ * Code adapted from http://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc
-+ * and http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
-+ *
-+ * Published under the Creative Commons Share-Alike licence
-+ * https://creativecommons.org/licenses/by-sa/2.0/de/
-+ *
-+ * S. Salewski 2007
-+ *
-+ * Adapted by
-+ * Josef Filzmaier 2017
-+ */
-+
-+#ifndef UART_H_
-+#define UART_H_
-+
-+#include <stdio.h>
-+
-+void uart_init(void);
-+int uart_write_char(char c, FILE* stream);
-+void uart_new_line(void);
-+
-+#endif /* UART_H_ */
-diff --git a/atusb/usb/atu2.c b/atusb/usb/atu2.c
-new file mode 100644
-index 0000000..98158bf
---- /dev/null
-+++ b/atusb/usb/atu2.c
-@@ -0,0 +1,247 @@
-+/*
-+ * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
-+ *
-+ * Written 2008-2011, 2013-2014 by Werner Almesberger
-+ * Copyright 2008-2011, 2013-2014 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.
-+ */
-+
-+/*
-+ * Known issues:
-+ * - no suspend/resume
-+ * - we don't call back after failed transmissions,
-+ * - we don't reset the EP buffer after failed receptions
-+ * - enumeration often encounters an error -71 (from which it recovers)
-+ */
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#define F_CPU 8000000UL
-+#include <util/delay.h>
-+
-+#include <avr/io.h>
-+#include <avr/interrupt.h>
-+#include "usb.h"
-+#include "board.h"
-+
-+
-+#ifndef NULL
-+#define NULL 0
-+#endif
-+
-+#if 1
-+#define BUG_ON(cond) do { if (cond) panic(); } while (0)
-+#else
-+#define BUG_ON(cond)
-+#endif
-+
-+
-+struct ep_descr eps[NUM_EPS];
-+
-+
-+static uint16_t usb_read_word(void)
-+{
-+ uint8_t low;
-+
-+ low = UEDATX;
-+ return low | UEDATX << 8;
-+}
-+
-+
-+static void enable_addr(void *user)
-+{
-+ while (!(UEINTX & (1 << TXINI)));
-+ UDADDR |= 1 << ADDEN;
-+}
-+
-+
-+void set_addr(uint8_t addr)
-+{
-+ UDADDR = addr;
-+ usb_send(&eps[0], NULL, 0, enable_addr, NULL);
-+}
-+
-+
-+void usb_ep_change(struct ep_descr *ep)
-+{
-+ if (ep->state == EP_TX) {
-+ UENUM = ep-eps;
-+ UEIENX |= 1 << TXINE;
-+ }
-+}
-+
-+
-+static bool ep_setup(void)
-+{
-+ struct setup_request setup;
-+
-+ BUG_ON(UEBCLX < 8);
-+
-+ setup.bmRequestType = UEDATX;
-+ setup.bRequest = UEDATX;
-+ setup.wValue = usb_read_word();
-+ setup.wIndex = usb_read_word();
-+ setup.wLength = usb_read_word();
-+
-+ if (!handle_setup(&setup))
-+ return 0;
-+ if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
-+ usb_send(&eps[0], NULL, 0, NULL, NULL);
-+ return 1;
-+}
-+
-+
-+static bool ep_rx(struct ep_descr *ep)
-+{
-+ uint8_t size;
-+
-+ size = UEBCLX;
-+ if (size > ep->end-ep->buf)
-+ return 0;
-+ while (size--)
-+ *ep->buf++ = UEDATX;
-+ if (ep->buf == ep->end) {
-+ ep->state = EP_IDLE;
-+ if (ep->callback)
-+ ep->callback(ep->user);
-+// if (ep == &eps[0])
-+ usb_send(ep, NULL, 0, NULL, NULL);
-+ }
-+ return 1;
-+}
-+
-+
-+static void ep_tx(struct ep_descr *ep)
-+{
-+ uint8_t size = ep->end-ep->buf;
-+ uint8_t left;
-+
-+ if (size > ep->size)
-+ size = ep->size;
-+ for (left = size; left; left--)
-+ UEDATX = *ep->buf++;
-+ if (size == ep->size)
-+ return;
-+ ep->state = EP_IDLE;
-+}
-+
-+
-+static void handle_ep(int n)
-+{
-+ struct ep_descr *ep = eps+n;
-+ uint8_t mask;
-+
-+ UENUM = n;
-+ if (UEINTX & (1 << RXSTPI)) {
-+ /* @@@ EP_RX. EP_TX: cancel */
-+ ep->state = EP_IDLE;
-+ if (!ep_setup())
-+ goto stall;
-+ UEINTX = ~(1 << RXSTPI);
-+ }
-+ if (UEINTX & (1 << RXOUTI)) {
-+ /* @@ EP_TX: cancel */
-+ if (ep->state != EP_RX)
-+ goto stall;
-+ if (!ep_rx(ep))
-+ goto stall;
-+ /* @@@ gcc 4.5.2 wants this cast */
-+ UEINTX = (uint8_t) ~(1 << RXOUTI | 1 << FIFOCON);
-+ }
-+ if (UEINTX & (1 << STALLEDI)) {
-+ ep->state = EP_IDLE;
-+ UEINTX = ~(1 << STALLEDI);
-+ }
-+ if (UEINTX & (1 << TXINI)) {
-+ /* @@ EP_RX: cancel (?) */
-+ if (ep->state == EP_TX) {
-+ ep_tx(ep);
-+ mask = 1 << TXINI;
-+ if (n)
-+ mask |= 1 << FIFOCON;
-+ UEINTX = ~mask;
-+ if (ep->state == EP_IDLE && ep->callback)
-+ ep->callback(ep->user);
-+ } else {
-+ UEIENX &= ~(1 << TXINE);
-+ }
-+ }
-+ return;
-+
-+stall:
-+ UEINTX = ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
-+ ep->state = EP_IDLE;
-+ UECONX |= 1 << STALLRQ;
-+}
-+
-+
-+void ep_init(void)
-+{
-+ UENUM = 0;
-+ UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
-+ UECFG0X = 0; /* control, direction is ignored */
-+ UECFG1X = 3 << EPSIZE0; /* 64 bytes */
-+ UECFG1X |= 1 << ALLOC;
-+
-+ while (!(UESTA0X & (1 << CFGOK)));
-+
-+ UEIENX =
-+ (1 << RXSTPE) | (1 << RXOUTE) | (1 << STALLEDE) | (1 << TXINE);
-+
-+ eps[0].state = EP_IDLE;
-+ eps[0].size = 64;
-+
-+#ifndef BOOT_LOADER
-+
-+ UENUM = 1;
-+ UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
-+ UECFG0X = (1 << EPTYPE1) | (1 << EPDIR); /* bulk IN */
-+ UECFG1X = 3 << EPSIZE0; /* 64 bytes */
-+ UECFG1X |= 1 << ALLOC;
-+
-+ while (!(UESTA0X & (1 << CFGOK)));
-+
-+ UEIENX = (1 << STALLEDE) | (1 << TXINE);
-+
-+ eps[1].state = EP_IDLE;
-+ eps[1].size = 64;
-+
-+#endif
-+}
-+
-+
-+ISR(USB_GEN_vect)
-+{
-+ uint8_t flags;
-+
-+ flags = UDINT;
-+ if (flags & (1 << EORSTI)) {
-+ if (user_reset)
-+ user_reset();
-+ ep_init();
-+ UDINT = ~(1 << EORSTI);
-+ }
-+}
-+
-+
-+ISR(USB_COM_vect)
-+{
-+ uint8_t flags, i;
-+
-+ flags = UEINT;
-+ for (i = 0; i != NUM_EPS; i++)
-+ if (flags & (1 << i))
-+ handle_ep(i);
-+}
-+
-+
-+void usb_reset(void)
-+{
-+ UDCON |= 1 << DETACH; /* detach the pull-up */
-+ _delay_ms(1);
-+}
-diff --git a/atusb/usb/dfu.c b/atusb/usb/dfu.c
-new file mode 100644
-index 0000000..c84a28d
---- /dev/null
-+++ b/atusb/usb/dfu.c
-@@ -0,0 +1,260 @@
-+/*
-+ * boot/dfu.c - DFU protocol engine
-+ *
-+ * Written 2008-2011, 2013-2015 by Werner Almesberger
-+ * Copyright 2008-2011, 2013-2015 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 <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.h"
-+#include "dfu.h"
-+
-+#include "board.h"
-+
-+
-+#ifndef NULL
-+#define NULL 0
-+#endif
-+
-+#define debug(...)
-+#define error(...)
-+
-+
-+#ifndef DFU_ALT_SETTINGS
-+#define DFU_ALT_SETTINGS 1
-+#endif
-+
-+#ifndef DFU_ALT_NAME_0_IDX
-+#define DFU_ALT_NAME_0_IDX 0
-+#endif
-+
-+#ifndef DFU_ALT_NAME_1_IDX
-+#define DFU_ALT_NAME_1_IDX 0
-+#endif
-+
-+#ifndef DFU_ALT_NAME_2_IDX
-+#define DFU_ALT_NAME_2_IDX 0
-+#endif
-+
-+
-+const uint8_t device_descriptor[] = {
-+ 18, /* bLength */
-+ USB_DT_DEVICE, /* bDescriptorType */
-+ LE(0x100), /* bcdUSB */
-+ USB_CLASS_APP_SPEC, /* bDeviceClass */
-+ 0x00, /* bDeviceSubClass (per interface) */
-+ 0x00, /* bDeviceProtocol (per interface) */
-+ EP0_SIZE, /* bMaxPacketSize */
-+ LE(DFU_USB_VENDOR), /* idVendor */
-+ LE(DFU_USB_PRODUCT), /* idProduct */
-+ LE(0x0001), /* bcdDevice */
-+ 0, /* iManufacturer */
-+ 0, /* iProduct */
-+#ifdef HAS_BOARD_SERNUM
-+ 1, /* iSerialNumber */
-+#else
-+ 0, /* iSerialNumber */
-+#endif
-+ 1 /* bNumConfigurations */
-+};
-+
-+
-+const uint8_t config_descriptor[] = {
-+ 9, /* bLength */
-+ USB_DT_CONFIG, /* bDescriptorType */
-+ LE(9+9*DFU_ALT_SETTINGS), /* wTotalLength */
-+ 1, /* bNumInterfaces */
-+ 1, /* bConfigurationValue (> 0 !) */
-+ 0, /* iConfiguration */
-+// USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED,
-+ USB_ATTR_BUS_POWERED, /* bmAttributes */
-+ ((BOARD_MAX_mA)+1)/2, /* bMaxPower */
-+
-+ /* Interface #0 */
-+
-+ DFU_ITF_DESCR(0, 0, dfu_proto_dfu, DFU_ALT_NAME_0_IDX)
-+#if DFU_ALT_SETTINGS > 1
-+ DFU_ITF_DESCR(0, 1, dfu_proto_dfu, DFU_ALT_NAME_1_IDX)
-+#endif
-+#if DFU_ALT_SETTINGS > 2
-+ DFU_ITF_DESCR(0, 2, dfu_proto_dfu, DFU_ALT_NAME_2_IDX)
-+#endif
-+};
-+
-+
-+static uint16_t next_block = 0;
-+static bool did_download;
-+
-+
-+static uint8_t buf[EP0_SIZE];
-+
-+
-+static void block_write(void *user)
-+{
-+ uint16_t *size = user;
-+
-+ dfu_flash_ops->write(buf, *size);
-+}
-+
-+
-+static bool block_receive(uint16_t length)
-+{
-+ static uint16_t size;
-+
-+ if (!dfu_flash_ops->can_write(length)) {
-+ dfu.state = dfuERROR;
-+ dfu.status = errADDRESS;
-+ return 0;
-+ }
-+ if (length > EP0_SIZE) {
-+ dfu.state = dfuERROR;
-+ dfu.status = errUNKNOWN;
-+ return 0;
-+ }
-+ size = length;
-+ usb_recv(&eps[0], buf, size, block_write, &size);
-+ return 1;
-+}
-+
-+
-+static bool block_transmit(uint16_t length)
-+{
-+ uint16_t got;
-+
-+ if (length > EP0_SIZE) {
-+ dfu.state = dfuERROR;
-+ dfu.status = errUNKNOWN;
-+ return 1;
-+ }
-+ got = dfu_flash_ops->read(buf, length);
-+ if (got < length) {
-+ length = got;
-+ dfu.state = dfuIDLE;
-+ }
-+ usb_send(&eps[0], buf, length, NULL, NULL);
-+ return 1;
-+}
-+
-+
-+static bool my_setup(const struct setup_request *setup)
-+{
-+ bool 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;
-+ dfu_flash_ops->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_flash_ops->end_write();
-+ 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;
-+ dfu_flash_ops->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_TO_DEV(DFU_ABORT):
-+ debug("DFU_ABORT\n");
-+ dfu.state = dfuIDLE;
-+ dfu.status = OK;
-+ return 1;
-+ default:
-+ return dfu_setup_common(setup);
-+ }
-+}
-+
-+
-+static void my_reset(void)
-+{
-+#if 0
-+ /* @@@ not nice -- think about where this should go */
-+ extern void run_payload(void);
-+
-+ if (did_download)
-+ run_payload();
-+#endif
-+}
-+
-+
-+void dfu_init(void)
-+{
-+ user_setup = my_setup;
-+ user_get_descriptor = dfu_my_descr;
-+ user_reset = my_reset;
-+}
-diff --git a/atusb/usb/dfu.h b/atusb/usb/dfu.h
-new file mode 100644
-index 0000000..bc35bbc
---- /dev/null
-+++ b/atusb/usb/dfu.h
-@@ -0,0 +1,119 @@
-+/*
-+ * boot/dfu.h - DFU protocol constants and data structures
-+ *
-+ * Written 2008, 2011, 2013-2015 by Werner Almesberger
-+ * Copyright 2008, 2011, 2013-2015 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 <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.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
-+};
-+
-+enum dfu_itf_proto {
-+ dfu_proto_runtime = 1, /* Runtime protocol */
-+ dfu_proto_dfu = 2, /* DFU mode protocol */
-+};
-+
-+
-+#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;
-+};
-+
-+
-+#define DFU_ITF_DESCR(itf, alt, proto, idx) \
-+ 9, /* bLength */ \
-+ USB_DT_INTERFACE, /* bDescriptorType */ \
-+ (itf), /* bInterfaceNumber */ \
-+ (alt), /* bAlternateSetting */ \
-+ 0, /* bNumEndpoints */ \
-+ 0xfe, /* bInterfaceClass (application specific) */ \
-+ 0x01, /* bInterfaceSubClass (device fw upgrade) */ \
-+ (proto), /* bInterfaceProtocol (dfu_proto_*) */ \
-+ (idx), /* iInterface */
-+
-+
-+struct dfu_flash_ops {
-+ void (*start)(void);
-+ bool (*can_write)(uint16_t size);
-+ void (*write)(const uint8_t *buf, uint16_t size);
-+ void (*end_write)(void);
-+ uint16_t (*read)(uint8_t *buf, uint16_t size);
-+};
-+
-+extern struct dfu dfu;
-+extern const struct dfu_flash_ops *dfu_flash_ops;
-+
-+
-+bool dfu_setup_common(const struct setup_request *setup);
-+bool dfu_my_descr(uint8_t type, uint8_t index, const uint8_t **reply,
-+ uint8_t *size);
-+
-+void dfu_init(void);
-+
-+#endif /* !DFU_H */
-diff --git a/atusb/usb/dfu_common.c b/atusb/usb/dfu_common.c
-new file mode 100644
-index 0000000..9b6feef
---- /dev/null
-+++ b/atusb/usb/dfu_common.c
-@@ -0,0 +1,101 @@
-+/*
-+ * boot/dfu_common.c - DFU protocol engine parts common to App/DFU
-+ *
-+ * Written 2008-2011, 2013-2014 by Werner Almesberger
-+ * Copyright 2008-2011, 2013-2014 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 <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.h"
-+#include "dfu.h"
-+
-+#include "board.h"
-+#include "../sernum.h"
-+
-+
-+#ifndef NULL
-+#define NULL 0
-+#endif
-+
-+#define debug(...)
-+#define error(...)
-+
-+
-+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 */
-+};
-+
-+
-+/*
-+ * The worst-case activity would be flashing a one page and erasing another
-+ * one, would should take less than 10 ms. A 100 ms timeout ought to be plenty.
-+ */
-+
-+struct dfu dfu = {
-+ OK, /* bStatus */
-+ LE(100), 0, /* bwPollTimeout, 100 ms */
-+ dfuIDLE, /* bState */
-+ 0, /* iString */
-+};
-+
-+
-+bool dfu_setup_common(const struct setup_request *setup)
-+{
-+ switch (setup->bmRequestType | setup->bRequest << 8) {
-+ case DFU_FROM_DEV(DFU_GETSTATUS):
-+ debug("DFU_GETSTATUS\n");
-+ usb_send(&eps[0], (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(&eps[0], &dfu.state, 1, NULL, NULL);
-+ return 1;
-+ default:
-+ error("DFU rt %x, rq%x ?\n",
-+ setup->bmRequestType, setup->bRequest);
-+ return 0;
-+ }
-+}
-+
-+
-+bool dfu_my_descr(uint8_t type, uint8_t index, const uint8_t **reply,
-+ uint8_t *size)
-+{
-+ if (type != DFU_DT_FUNCTIONAL)
-+ return sernum_get_descr(type, index, reply, size);
-+ *reply = functional_descriptor;
-+ *size = sizeof(functional_descriptor);
-+ return 1;
-+}
-diff --git a/atusb/usb/usb.c b/atusb/usb/usb.c
-new file mode 100644
-index 0000000..543d8c2
---- /dev/null
-+++ b/atusb/usb/usb.c
-@@ -0,0 +1,181 @@
-+/*
-+ * fw/usb/usb.c - USB hardware setup and standard device requests
-+ *
-+ * Written 2008-2011, 2013, 2015 by Werner Almesberger
-+ * Copyright 2008-2011, 2013, 2015 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.
-+ */
-+
-+/*
-+ * Known issues:
-+ * - no suspend/resume
-+ * - should support EP clearing and stalling
-+ */
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include "usb.h"
-+#include "board.h"
-+
-+
-+#ifndef NULL
-+#define NULL 0
-+#endif
-+
-+#if 1
-+extern void panic(void);
-+#define BUG_ON(cond) do { if (cond) panic(); } while (0)
-+#else
-+#define BUG_ON(cond)
-+#endif
-+
-+bool (*user_setup)(const struct setup_request *setup);
-+void (*user_set_interface)(int nth);
-+bool (*user_get_descriptor)(uint8_t type, uint8_t index,
-+ const uint8_t **reply, uint8_t *size);
-+void (*user_reset)(void);
-+
-+
-+void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
-+ uint8_t size, void (*callback)(void *user), void *user)
-+{
-+ BUG_ON(ep->state);
-+ ep->state = state;
-+ ep->buf = buf;
-+ ep->end = buf+size;
-+ ep->callback = callback;
-+ ep->user = user;
-+ usb_ep_change(ep);
-+}
-+
-+
-+static bool get_descriptor(uint8_t type, uint8_t index, uint16_t length)
-+{
-+ const uint8_t *reply;
-+ uint8_t size;
-+
-+ switch (type) {
-+ case USB_DT_DEVICE:
-+ reply = device_descriptor;
-+ size = reply[0];
-+ break;
-+ case USB_DT_CONFIG:
-+ if (index)
-+ return 0;
-+ reply = config_descriptor;
-+ size = reply[2];
-+ break;
-+ default:
-+ if (!user_get_descriptor)
-+ return 0;
-+ if (!user_get_descriptor(type, index, &reply, &size))
-+ return 0;
-+ }
-+ if (length < size)
-+ size = length;
-+ usb_send(&eps[0], reply, size, NULL, NULL);
-+ return 1;
-+}
-+
-+
-+bool handle_setup(const struct setup_request *setup)
-+{
-+ switch (setup->bmRequestType | setup->bRequest << 8) {
-+
-+ /*
-+ * Device request
-+ *
-+ * See http://www.beyondlogic.org/usbnutshell/usb6.htm
-+ */
-+
-+ case FROM_DEVICE(GET_STATUS):
-+ if (setup->wLength != 2)
-+ return 0;
-+ usb_send(&eps[0], "\000", 2, NULL, NULL);
-+ break;
-+ case TO_DEVICE(CLEAR_FEATURE):
-+ break;
-+ case TO_DEVICE(SET_FEATURE):
-+ return 0;
-+ case TO_DEVICE(SET_ADDRESS):
-+ set_addr(setup->wValue);
-+ break;
-+ case FROM_DEVICE(GET_DESCRIPTOR):
-+ case FROM_INTERFACE(GET_DESCRIPTOR):
-+ if (!get_descriptor(setup->wValue >> 8, setup->wValue,
-+ setup->wLength))
-+ return 0;
-+ break;
-+ case TO_DEVICE(SET_DESCRIPTOR):
-+ return 0;
-+ case FROM_DEVICE(GET_CONFIGURATION):
-+ usb_send(&eps[0], "", 1, NULL, NULL);
-+ break;
-+ case TO_DEVICE(SET_CONFIGURATION):
-+ if (setup->wValue != config_descriptor[5])
-+ return 0;
-+ break;
-+
-+ /*
-+ * Interface request
-+ */
-+
-+ case FROM_INTERFACE(GET_STATUS):
-+ return 0;
-+ case TO_INTERFACE(CLEAR_FEATURE):
-+ return 0;
-+ case TO_INTERFACE(SET_FEATURE):
-+ return 0;
-+ case FROM_INTERFACE(GET_INTERFACE):
-+ return 0;
-+ case TO_INTERFACE(SET_INTERFACE):
-+ {
-+ const uint8_t *interface_descriptor =
-+ config_descriptor+9;
-+ const uint8_t *p;
-+ int i;
-+
-+ i = 0;
-+ for (p = interface_descriptor;
-+ p != config_descriptor+config_descriptor[2];
-+ p += p[0]) {
-+ if (p[1] != USB_DT_INTERFACE)
-+ continue;
-+ if (p[2] == setup->wIndex &&
-+ p[3] == setup->wValue) {
-+ if (user_set_interface)
-+ user_set_interface(i);
-+ return 1;
-+ }
-+ i++;
-+ }
-+ return 0;
-+ }
-+ break;
-+
-+ /*
-+ * Endpoint request
-+ */
-+
-+ case FROM_ENDPOINT(GET_STATUS):
-+ return 0;
-+ case TO_ENDPOINT(CLEAR_FEATURE):
-+ return 0;
-+ case TO_ENDPOINT(SET_FEATURE):
-+ return 0;
-+ case FROM_ENDPOINT(SYNCH_FRAME):
-+ return 0;
-+
-+ default:
-+ if (user_setup)
-+ return user_setup(setup);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-diff --git a/atusb/usb/usb.h b/atusb/usb/usb.h
-new file mode 100644
-index 0000000..cb40f9e
---- /dev/null
-+++ b/atusb/usb/usb.h
-@@ -0,0 +1,189 @@
-+/*
-+ * fw/usb//usb.h - USB hardware setup and standard device requests
-+ *
-+ * Written 2008, 2009, 2011, 2013, 2015 by Werner Almesberger
-+ * Copyright 2008, 2009, 2011, 2013, 2015 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 USB_H
-+#define USB_H
-+
-+
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+
-+/*
-+ * Packet identifier types
-+ */
-+
-+#define PID_OUT 0x1
-+#define PID_IN 0x9
-+#define PID_SOF 0x5
-+#define PID_SETUP 0xd
-+#define PID_DATA0 0x3
-+#define PID_DATA1 0xb
-+#define PID_ACK 0x2
-+#define PID_NAK 0xa
-+#define PID_STALL 0xe
-+
-+/*
-+ * Descriptor types
-+ *
-+ * Reuse libusb naming scheme (/usr/include/usb.h)
-+ */
-+
-+#define USB_DT_DEVICE 1
-+#define USB_DT_CONFIG 2
-+#define USB_DT_STRING 3
-+#define USB_DT_INTERFACE 4
-+#define USB_DT_ENDPOINT 5
-+
-+/*
-+ * Device classes
-+ *
-+ * Reuse libusb naming scheme (/usr/include/usb.h)
-+ */
-+
-+#define USB_CLASS_PER_INTERFACE 0
-+#define USB_CLASS_COMM 2
-+#define USB_CLASS_HID 3
-+#define USB_CLASS_MASS_STORAGE 8
-+#define USB_CLASS_HUB 9
-+#define USB_CLASS_DATA 10
-+#define USB_CLASS_APP_SPEC 0xfe
-+#define USB_CLASS_VENDOR_SPEC 0xff
-+
-+/*
-+ * Configuration attributes
-+ */
-+
-+#define USB_ATTR_BUS_POWERED 0x80
-+#define USB_ATTR_SELF_POWERED 0x40
-+#define USB_ATTR_REMOTE_WAKEUP 0x20
-+
-+/*
-+ * Endpoint type
-+ */
-+
-+#define USB_ENDPOINT_TYPE_CONTROL 0
-+#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
-+#define USB_ENDPOINT_TYPE_BULK 2
-+#define USB_ENDPOINT_TYPE_INTERRUPT 3
-+
-+/*
-+ * Setup request types
-+ */
-+
-+#define TO_DEVICE(req) (0x00 | (req) << 8)
-+#define FROM_DEVICE(req) (0x80 | (req) << 8)
-+#define TO_INTERFACE(req) (0x01 | (req) << 8)
-+#define FROM_INTERFACE(req) (0x81 | (req) << 8)
-+#define TO_ENDPOINT(req) (0x02 | (req) << 8)
-+#define FROM_ENDPOINT(req) (0x82 | (req) << 8)
-+
-+/*
-+ * Setup requests
-+ */
-+
-+#define GET_STATUS 0x00
-+#define CLEAR_FEATURE 0x01
-+#define SET_FEATURE 0x03
-+#define SET_ADDRESS 0x05
-+#define GET_DESCRIPTOR 0x06
-+#define SET_DESCRIPTOR 0x07
-+#define GET_CONFIGURATION 0x08
-+#define SET_CONFIGURATION 0x09
-+#define GET_INTERFACE 0x0a
-+#define SET_INTERFACE 0x0b
-+#define SYNCH_FRAME 0x0c
-+
-+/*
-+ * USB Language ID codes
-+ *
-+ * http://www.usb.org/developers/docs/USB_LANGIDs.pdf
-+ */
-+
-+#define USB_LANGID_ENGLISH_US 0x409
-+
-+
-+/*
-+ * Odd. sdcc seems to think "x" assumes the size of the destination, i.e.,
-+ * uint8_t. Hence the cast.
-+ */
-+
-+#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
-+
-+#define LO(x) (((uint8_t *) &(x))[0])
-+#define HI(x) (((uint8_t *) &(x))[1])
-+
-+
-+#ifdef LOW_SPEED
-+#define EP0_SIZE 8
-+#else
-+#define EP0_SIZE 64
-+#endif
-+
-+#define EP1_SIZE 64 /* simplify */
-+
-+
-+enum ep_state {
-+ EP_IDLE,
-+ EP_RX,
-+ EP_TX,
-+ EP_STALL,
-+};
-+
-+struct ep_descr {
-+ enum ep_state state;
-+ uint8_t *buf;
-+ uint8_t *end;
-+ uint8_t size;
-+ void (*callback)(void *user);
-+ void *user;
-+};
-+
-+struct setup_request {
-+ uint8_t bmRequestType;
-+ uint8_t bRequest;
-+ uint16_t wValue;
-+ uint16_t wIndex;
-+ uint16_t wLength;
-+};
-+
-+
-+extern const uint8_t device_descriptor[];
-+extern const uint8_t config_descriptor[];
-+extern struct ep_descr eps[];
-+
-+extern bool (*user_setup)(const struct setup_request *setup);
-+extern void (*user_set_interface)(int nth);
-+extern bool (*user_get_descriptor)(uint8_t type, uint8_t index,
-+ const uint8_t **reply, uint8_t *size);
-+extern void (*user_reset)(void);
-+
-+
-+#define usb_left(ep) ((ep)->end-(ep)->buf)
-+#define usb_send(ep, buf, size, callback, user) \
-+ usb_io(ep, EP_TX, (void *) buf, size, callback, user)
-+#define usb_recv(ep, buf, size, callback, user) \
-+ usb_io(ep, EP_RX, buf, size, callback, user)
-+
-+void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
-+ uint8_t size, void (*callback)(void *user), void *user);
-+
-+bool handle_setup(const struct setup_request *setup);
-+void set_addr(uint8_t addr);
-+void usb_ep_change(struct ep_descr *ep);
-+void usb_reset(void);
-+void usb_init(void);
-+
-+void ep_init(void);
-+
-+#endif /* !USB_H */
-diff --git a/atusb/version.h b/atusb/version.h
-new file mode 100644
-index 0000000..8fd6a2c
---- /dev/null
-+++ b/atusb/version.h
-@@ -0,0 +1,23 @@
-+/*
-+ * fw/version.h - Automatically generated version string
-+ *
-+ * Written 2008, 2011 by Werner Almesberger
-+ * Copyright 2008, 2011 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>
-+
-+
-+extern const char *build_date;
-+extern const uint16_t build_number;
-+
-+#endif /* !VERSION_H */
---
-2.26.0
-