diff options
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.patch | 4893 |
1 files changed, 4893 insertions, 0 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 new file mode 100644 index 000000000..aa4cb07dc --- /dev/null +++ b/libre/linux-libre-firmware/0002-Add-firmware-for-the-ATUSB-IEEE-802.15.4-USB-Adapter.patch @@ -0,0 +1,4893 @@ +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 + |