Build requires SDCC, the Small Device C Compiler.
--- /dev/null
+############################################################################
+# Copyright (C) 2011 by Martin Schmoelzer #
+# <martin.schmoelzer@student.tuwien.ac.at> #
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program; if not, write to the #
+# Free Software Foundation, Inc., #
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+############################################################################
+
+# Define the name of our tools. Some distributions (e. g. Fedora) prefix
+# the SDCC executables, change this accordingly!
+PREFIX =
+
+# Small Device C Compiler: http://sdcc.sourceforge.net/
+CC = $(PREFIX)-sdcc
+
+# 8051 assembler, part of the SDCC software package.
+AS = $(PREFIX)-sdas8051
+
+# SDCC produces quite messy Intel HEX files. This tool is be used to re-format
+# those files. It is not required for the firmware download functionality in
+# the OpenOCD driver, but the resulting file is smaller.
+PACKIHX = $(PREFIX)-packihx
+
+# GNU binutils size. Used to print the size of the IHX file generated by SDCC.
+SIZE = size
+
+# Source and header directories.
+SRC_DIR = src
+INCLUDE_DIR = include
+
+CODE_SIZE = 0x1B00
+
+# Starting address of __xdata variables. Since the OpenULINK firmware does not
+# use any of the isochronous interrupts, we can use the isochronous buffer space
+# as XDATA memory.
+XRAM_LOC = 0x2000
+XRAM_SIZE = 0x0800
+
+CFLAGS = --std-sdcc99 --opt-code-size --model-small
+LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \
+ --xram-size $(XRAM_SIZE) --iram-size 256 --model-small
+
+# list of base object files
+OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel
+HEADERS = $(INCLUDE_DIR)/main.h \
+ $(INCLUDE_DIR)/usb.h \
+ $(INCLUDE_DIR)/protocol.h \
+ $(INCLUDE_DIR)/jtag.h \
+ $(INCLUDE_DIR)/delay.h \
+ $(INCLUDE_DIR)/reg_ezusb.h \
+ $(INCLUDE_DIR)/io.h \
+ $(INCLUDE_DIR)/msgtypes.h \
+ $(INCLUDE_DIR)/shorttypes.h
+
+# Disable all built-in rules.
+.SUFFIXES:
+
+# Targets which are executed even when identically named file is present.
+.PHONY: all, clean
+
+all: ulink_firmware.ihx
+ $(SIZE) ulink_firmware.ihx
+
+ulink_firmware.ihx: $(OBJECTS)
+ $(CC) -mmcs51 $(LDFLAGS) -o $@ $^
+
+# Rebuild every C module (there are only 5 of them) if any header changes.
+%.rel: $(SRC_DIR)/%.c $(HEADERS)
+ $(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $<
+
+%.rel: $(SRC_DIR)/%.a51
+ $(AS) -lsgo $@ $<
+
+clean:
+ rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lnk *.map *.mem
+
+hex: ulink_firmware.ihx
+ $(PACKIHX) ulink_firmware.ihx > ulink_firmware.hex
--- /dev/null
+This is the OpenULINK firmware for the Keil ULINK JTAG adapter.
+
+The main components of the Keil ULINK adapter are:
+- Cypress EZ-USB microcontroller: enhanced 8051 CPU + USB core (1.1 Full-Speed)
+- SRAM memory chip
+- Level shifters to support different JTAG signal voltage levels
+- Pin headers for various JTAG pin assignments
+
+This firmware can only be run on the ORIGINAL Keil ULINK adapter, not on the
+newer ULINK2, ULINK-ME or ULINK-PRO, as these adapters are based on different
+hardware.
+
+To compile the firmware, the SDCC compiler package is required. Most Linux
+distributions include SDCC in their official package repositories. The SDCC
+source code can be found at http://sdcc.sourceforge.net/
+Simply type "make hex" in the OpenULINK directory to compile the firmware.
+"make clean" will remove all generated files except the Intel HEX file required
+for downloading the firmware to the ULINK adapter.
+
+Note that the EZ-USB microcontroller does not have on-chip flash, nor does the
+Keil ULINK include on-board memory to store the firmware program of the EZ-USB.
+Instead, upon initial connection of the ULINK adapter to the host PC via USB,
+the EZ-USB core has enough intelligence to act as a stand-alone USB device,
+responding to USB control requests and allowing firmware download via a special
+VENDOR-type control request. Then, the EZ-USB microcontroller simulates a
+disconnect and re-connect to the USB bus. It may take up to two seconds for the
+host to recognize the newly connected device before OpenOCD can proceed to
+execute JTAG commands. This delay is only visible when OpenOCD first uses a
+blank (unconfigured) ULINK device.
+
+Once the user disconnects the ULINK adapter, all its memory contents are lost
+and the firmware download process has to be executed again. This also maintains
+compatibility with the original Keil uVision IDE, which will happily download
+its own firmware image to a blank ULINK adapter.
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n))
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __DELAY_H
+#define __DELAY_H
+
+#include "shorttypes.h"
+
+#define NOP {__asm nop __endasm;}
+
+void delay_5us(void);
+void delay_1ms(void);
+
+void delay_us(u16 delay);
+void delay_ms(u16 delay);
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __IO_H
+#define __IO_H
+
+#include "reg_ezusb.h"
+
+/***************************************************************************
+ * JTAG Signals: *
+ ***************************************************************************
+ * TMS ....... Test Mode Select *
+ * TCK ....... Test Clock *
+ * TDI ....... Test Data Input (from device point of view, not JTAG *
+ * adapter point of view!) *
+ * TDO ....... Test Data Output (from device point of view, not JTAG *
+ * adapter point of view!) *
+ * TRST ...... Test Reset: Used to reset the TAP Finite State Machine *
+ * into the Test Logic Reset state *
+ * RTCK ...... Return Test Clock *
+ * OCDSE ..... Enable/Disable OCDS interface (Infineon specific) - shared *
+ * with /JEN *
+ * TRAP ...... Trap Condition (Infineon specific) - shared with TSTAT *
+ * BRKIN ..... Hardware Break-In (Infineon specific) *
+ * BRKOUT .... Hardware Break-Out (Infineon specific) *
+ * /JEN ...... JTAG-Enable (STMicroelectronics specific) - shared *
+ * with OCDSE *
+ * TSTAT ..... JTAG ISP Status (STMicroelectronics specific) - shared *
+ * with TRAP *
+ * RESET ..... Chip Reset (STMicroelectronics specific) *
+ * /TERR ..... JTAG ISP Error (STMicroelectronics specific) - shared *
+ * with BRKOUT *
+ ***************************************************************************/
+
+/* PORT A */
+#define PIN_U_OE OUTA0
+// PA1 Not Connected
+#define PIN_OE OUTA2
+// PA3 Not Connected
+#define PIN_RUN_LED OUTA4
+#define PIN_TDO PINA5
+#define PIN_BRKOUT PINA6
+#define PIN_COM_LED OUTA7
+
+
+/* PORT B */
+#define PIN_TDI OUTB0
+#define PIN_TMS OUTB1
+#define PIN_TCK OUTB2
+#define PIN_TRST OUTB3
+#define PIN_BRKIN OUTB4
+#define PIN_RESET OUTB5
+#define PIN_OCDSE OUTB6
+#define PIN_TRAP PINB7
+
+/* JTAG Signals with direction 'OUT' on port B */
+#define MASK_PORTB_DIRECTION_OUT (PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE)
+
+/* PORT C */
+#define PIN_RXD0 PINC0
+#define PIN_TXD0 OUTC1
+#define PIN_RESET_2 PINC2
+// PC3 Not Connected
+// PC4 Not Connected
+#define PIN_RTCK PINC5
+#define PIN_WR OUTC6
+// PC7 Not Connected
+
+/* LED Macros */
+#define SET_RUN_LED() OUTA &= ~PIN_RUN_LED
+#define CLEAR_RUN_LED() OUTA |= PIN_RUN_LED
+
+#define SET_COM_LED() OUTA &= ~PIN_COM_LED
+#define CLEAR_COM_LED() OUTA |= PIN_COM_LED
+
+/* JTAG Pin Macros */
+#define GET_TMS() (PINSB & PIN_TMS)
+#define GET_TCK() (PINSB & PIN_TCK)
+
+#define GET_TDO() (PINSA & PIN_TDO)
+#define GET_BRKOUT() (PINSA & PIN_BRKOUT)
+#define GET_TRAP() (PINSB & PIN_TRAP)
+#define GET_RTCK() (PINSC & PIN_RTCK)
+
+#define SET_TMS_HIGH() OUTB |= PIN_TMS
+#define SET_TMS_LOW() OUTB &= ~PIN_TMS
+
+#define SET_TCK_HIGH() OUTB |= PIN_TCK
+#define SET_TCK_LOW() OUTB &= ~PIN_TCK
+
+#define SET_TDI_HIGH() OUTB |= PIN_TDI
+#define SET_TDI_LOW() OUTB &= ~PIN_TDI
+
+/* TRST and RESET are low-active and inverted by hardware. SET_HIGH de-asserts
+ * the signal (enabling reset), SET_LOW asserts the signal (disabling reset) */
+#define SET_TRST_HIGH() OUTB |= PIN_TRST
+#define SET_TRST_LOW() OUTB &= ~PIN_TRST
+
+#define SET_RESET_HIGH() OUTB |= PIN_RESET
+#define SET_RESET_LOW() OUTB &= ~PIN_RESET
+
+#define SET_OCDSE_HIGH() OUTB |= PIN_OCDSE
+#define SET_OCDSE_LOW() OUTB &= ~PIN_OCDSE
+
+#define SET_BRKIN_HIGH() OUTB |= PIN_BRKIN
+#define SET_BRKIN_LOW() OUTB &= ~PIN_BRKIN
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __JTAG_H
+#define __JTAG_H
+
+#include "shorttypes.h"
+
+#define NOP {__asm nop __endasm;}
+
+void jtag_scan_in(u8 out_offset, u8 in_offset);
+void jtag_scan_out(u8 out_offset);
+void jtag_scan_io(u8 out_offset, u8 in_offset);
+
+void jtag_slow_scan_in(u8 scan_size_bytes, u8 tdo_index, u8 scan_options);
+void jtag_slow_scan_out(u8 scan_size_bytes, u8 tdi_index, u8 scan_options);
+void jtag_slow_scan_io(u8 scan_size_bytes, u8 tdi_index, u8 tdo_index,
+ u8 scan_options);
+
+void jtag_clock_tck(u16 count);
+void jtag_clock_tms(u8 count, u8 sequence);
+void jtag_slow_clock_tms(u8 count, u8 sequence);
+
+u16 jtag_get_signals(void);
+void jtag_set_signals(u8 low, u8 high);
+
+void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms);
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __MAIN_H
+#define __MAIN_H
+
+void io_init(void);
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+/**
+ * @file Definition of the commands supported by the OpenULINK firmware.
+ *
+ * Basically, two types of commands can be distinguished:
+ * - Commands with fixed payload size
+ * - Commands with variable payload size
+ *
+ * SCAN commands (in all variations) carry payloads of variable size, all
+ * other commands carry payloads of fixed size.
+ *
+ * In the case of SCAN commands, the payload size (n) is calculated by
+ * dividing the scan_size_bits variable by 8, rounding up the result.
+ *
+ * Offset zero always contains the command ID.
+ *
+ ****************************************************************************
+ * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * *
+ * IN: *
+ * offset 0..n: TDO data *
+ ****************************************************************************
+ * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * offset 6..x: TDI data *
+ ****************************************************************************
+ * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: *
+ * *
+ * OUT: *
+ * offset 1: scan_size_bytes *
+ * offset 2: bits_last_byte *
+ * offset 3: tms_count_start + tms_count_end *
+ * offset 4: tms_sequence_start *
+ * offset 5: tms_sequence_end *
+ * offset 6..x: TDI data *
+ * *
+ * IN: *
+ * offset 0..n: TDO data *
+ ****************************************************************************
+ * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: *
+ * *
+ * OUT: *
+ * offset 1: tms_count *
+ * offset 2: tms_sequence *
+ ****************************************************************************
+ * CMD_CLOCK_TCK: *
+ * *
+ * OUT: *
+ * offset 1: low byte of tck_count *
+ * offset 2: high byte of tck_count *
+ ****************************************************************************
+ * CMD_CLOCK_SLEEP_US: *
+ * *
+ * OUT: *
+ * offset 1: low byte of sleep_us *
+ * offset 2: high byte of sleep_us *
+ ****************************************************************************
+ * CMD_CLOCK_SLEEP_MS: *
+ * *
+ * OUT: *
+ * offset 1: low byte of sleep_ms *
+ * offset 2: high byte of sleep_ms *
+ ****************************************************************************
+ * CMD_GET_SIGNALS: *
+ * *
+ * IN: *
+ * offset 0: current state of input signals *
+ * offset 1: current state of output signals *
+ ****************************************************************************
+ * CMD_SET_SIGNALS: *
+ * *
+ * OUT: *
+ * offset 1: signals that should be de-asserted *
+ * offset 2: signals that should be asserted *
+ ****************************************************************************
+ * CMD_CONFIGURE_TCK_FREQ: *
+ * *
+ * OUT: *
+ * offset 1: delay value for scan functions *
+ * offset 2: delay value for clock_tck function *
+ * offset 3: delay value for clock_tms function *
+ ****************************************************************************
+ * CMD_SET_LEDS: *
+ * *
+ * OUT: *
+ * offset 1: LED states: *
+ * Bit 0: turn COM LED on *
+ * Bit 1: turn RUN LED on *
+ * Bit 2: turn COM LED off *
+ * Bit 3: turn RUN LED off *
+ * Bits 7..4: Reserved *
+ ****************************************************************************
+ * CMD_TEST: *
+ * *
+ * OUT: *
+ * offset 1: unused dummy value *
+ ****************************************************************************
+ */
+
+#ifndef __MSGTYPES_H
+#define __MSGTYPES_H
+
+/*
+ * Command IDs:
+ *
+ * Bits 7..6: Reserved, should always be zero
+ * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs,
+ * the IDs 0x00..0x1F are commands with variable payload size,
+ * the IDs 0x20..0x3F are commands with fixed payload size.
+ */
+
+#define CMD_ID_MASK 0x3F
+
+/* Commands with variable payload size */
+#define CMD_SCAN_IN 0x00
+#define CMD_SLOW_SCAN_IN 0x01
+#define CMD_SCAN_OUT 0x02
+#define CMD_SLOW_SCAN_OUT 0x03
+#define CMD_SCAN_IO 0x04
+#define CMD_SLOW_SCAN_IO 0x05
+
+/* Commands with fixed payload size */
+#define CMD_CLOCK_TMS 0x20
+#define CMD_SLOW_CLOCK_TMS 0x21
+#define CMD_CLOCK_TCK 0x22
+#define CMD_SLEEP_US 0x23
+#define CMD_SLEEP_MS 0x24
+#define CMD_GET_SIGNALS 0x25
+#define CMD_SET_SIGNALS 0x26
+#define CMD_CONFIGURE_TCK_FREQ 0x27
+#define CMD_SET_LEDS 0x28
+#define CMD_TEST 0x29
+
+/* JTAG signal definition for jtag_get_signals() -- Input signals! */
+#define SIGNAL_TDO (1<<0)
+#define SIGNAL_BRKOUT (1<<1)
+#define SIGNAL_TRAP (1<<2)
+#define SIGNAL_RTCK (1<<3)
+
+/* JTAG signal definition for jtag_get_signals() -- Output signals! */
+#define SIGNAL_TDI (1<<0)
+#define SIGNAL_TMS (1<<1)
+#define SIGNAL_TCK (1<<2)
+#define SIGNAL_TRST (1<<3)
+#define SIGNAL_BRKIN (1<<4)
+#define SIGNAL_RESET (1<<5)
+#define SIGNAL_OCDSE (1<<6)
+
+/* LED definitions for CMD_SET_LEDS and CMD_CLEAR_LEDS commands */
+#define COM_LED_ON (1<<0)
+#define RUN_LED_ON (1<<1)
+#define COM_LED_OFF (1<<2)
+#define RUN_LED_OFF (1<<3)
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __PROTOCOL_H
+#define __PROTOCOL_H
+
+#include "shorttypes.h"
+#include "common.h"
+#include <stdbool.h>
+
+void execute_set_led_command(void);
+
+bool execute_command(void);
+void command_loop(void);
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef REG_EZUSB_H
+#define REG_EZUSB_H
+
+/**
+ * @file All information in this file was taken from the EZ-USB Technical
+ * Reference Manual, Cypress Semiconductor, 3901 North First Street
+ * San Jose, CA 95134 (www.cypress.com).
+ *
+ * The EZ-USB Technical Reference Manual is called "EZ-USB TRM" hereafter.
+ *
+ * The following bit name definitions differ from those in the EZ-USB TRM:
+ * - All lowercase characters in the EZ-USB TRM bit names have been converted
+ * to capitals (e. g. "WakeSRC" converted to "WAKESRC").
+ * - CPUCS: 8051RES is named "RES8051".
+ * - ISOCTL: Two MBZ ("Must Be Zero") bits are named "MBZ0" and "MBZ1".
+ * - I2CS: STOP and START bits are preceded by "I2C_"
+ * - INxCS, OUTxCS: the busy and stall bits are named "EPBSY" and "EPSTALL".
+ * - TOGCTL: EZ-USB TRM bit names are preceded by "TOG_".
+ */
+
+/* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */
+#include <mcs51/compiler.h>
+
+/* Bit vectors */
+#define bmBit0 0x01
+#define bmBit1 0x02
+#define bmBit2 0x04
+#define bmBit3 0x08
+#define bmBit4 0x10
+#define bmBit5 0x20
+#define bmBit6 0x40
+#define bmBit7 0x80
+
+/***************************************************************************/
+/************************ Special Function Registers ***********************/
+/***************************************************************************/
+
+/* See EZ-USB TRM, pp. A-9 - A-10 */
+
+SFR(SP, 0x81);
+SFR(DPL0, 0x82);
+SFR(DPH0, 0x83);
+SFR(DPL1, 0x84);
+SFR(DPL2, 0x85);
+
+SFR(DPS, 0x86);
+ #define SEL bmBit0
+ // Bit 1 read-only, always reads '0'
+ // Bit 2 read-only, always reads '0'
+ // Bit 3 read-only, always reads '0'
+ // Bit 4 read-only, always reads '0'
+ // Bit 5 read-only, always reads '0'
+ // Bit 6 read-only, always reads '0'
+ // Bit 7 read-only, always reads '0'
+
+SFR(PCON, 0x87);
+ #define IDLE bmBit0
+ #define STOP bmBit1
+ #define GF0 bmBit2
+ #define GF1 bmBit3
+ // Bit 4 read-only, always reads '1'
+ // Bit 5 read-only, always reads '1'
+ // Bit 6 unused
+ #define SMOD0 bmBit7
+
+SFR(TCON, 0x88);
+ SBIT(IT0, 0x88, 0);
+ SBIT(IE0, 0x88, 1);
+ SBIT(IT1, 0x88, 2);
+ SBIT(IE1, 0x88, 3);
+ SBIT(TR0, 0x88, 4);
+ SBIT(TF0, 0x88, 5);
+ SBIT(TR1, 0x88, 6);
+ SBIT(TF1, 0x88, 7);
+
+SFR(TMOD, 0x89);
+/* Some bits in this register share the same name in the EZ-USB TRM. Therefore,
+ * we add a '0'/'1' to distinguish them */
+ #define M00 bmBit0
+ #define M01 bmBit1
+ #define CT0 bmBit2
+ #define GATE0 bmBit3
+ #define M10 bmBit4
+ #define M11 bmBit5
+ #define CT1 bmBit6
+ #define GATE1 bmBit7
+
+SFR(TL0, 0x8A);
+SFR(TL1, 0x8B);
+SFR(TH0, 0x8C);
+SFR(TH1, 0x8D);
+
+SFR(CKCON, 0x8E);
+ #define MD0 bmBit0
+ #define MD1 bmBit1
+ #define MD2 bmBit2
+ #define T0M bmBit3
+ #define T1M bmBit4
+ #define T2M bmBit5
+ // Bit 6 unused
+ // Bit 7 unused
+
+SFR(SPC_FNC, 0x8D);
+ #define bmWRS bmBit0
+ // Bit 1 read-only, always reads '0'
+ // Bit 2 read-only, always reads '0'
+ // Bit 3 read-only, always reads '0'
+ // Bit 4 read-only, always reads '0'
+ // Bit 5 read-only, always reads '0'
+ // Bit 6 read-only, always reads '0'
+ // Bit 7 read-only, always reads '0'
+
+SFR(EXIF, 0x91);
+ // Bit 0 read-only, always reads '0'
+ // Bit 1 read-only, always reads '0'
+ // Bit 2 read-only, always reads '0'
+ // Bit 3 read-only, always reads '1'
+ #define USBINT bmBit4
+ #define I2CINT bmBit5
+ #define IE4 bmBit6
+ #define IE5 bmBit7
+
+/* Definition of the _XPAGE register, according to SDCC Compiler User Guide,
+ * Version 3.0.1, Chapter 4, p. 61. Also see EZ-USB TRM, p. 2-4. */
+SFR(MPAGE, 0x92);
+SFR(_XPAGE, 0x92);
+
+SFR(SCON0, 0x98);
+ SBIT(RI_0, 0x98, 0);
+ SBIT(TI_0, 0x98, 1);
+ SBIT(RB8_0, 0x98, 2);
+ SBIT(TB8_0, 0x98, 3);
+ SBIT(REN_0, 0x98, 4);
+ SBIT(SM2_0, 0x98, 5);
+ SBIT(SM1_0, 0x98, 6);
+ SBIT(SM0_0, 0x98, 7);
+
+SFR(SBUF0, 0x99);
+
+SFR(IE, 0xA8);
+ SBIT(EX0, 0xA8, 0);
+ SBIT(ET0, 0xA8, 1);
+ SBIT(EX1, 0xA8, 2);
+ SBIT(ET1, 0xA8, 3);
+ SBIT(ES0, 0xA8, 4);
+ SBIT(ET2, 0xA8, 5);
+ SBIT(ES1, 0xA8, 6);
+ SBIT(EA, 0xA8, 7);
+
+SFR(IP, 0xB8);
+ SBIT(PX0, 0xB8, 0);
+ SBIT(PT0, 0xB8, 1);
+ SBIT(PX1, 0xB8, 2);
+ SBIT(PT1, 0xB8, 3);
+ SBIT(PS0, 0xB8, 4);
+ SBIT(PT2, 0xB8, 5);
+ SBIT(PS1, 0xB8, 6);
+ // Bit 7 read-only, always reads '1'
+
+SFR(SCON1, 0xC0);
+ SBIT(RI_1, 0xC0, 0);
+ SBIT(TI_1, 0xC0, 1);
+ SBIT(RB8_1, 0xC0, 2);
+ SBIT(TB8_1, 0xC0, 3);
+ SBIT(REN_1, 0xC0, 4);
+ SBIT(SM2_1, 0xC0, 5);
+ SBIT(SM1_1, 0xC0, 6);
+ SBIT(SM0_1, 0xC0, 7);
+
+SFR(SBUF1, 0xC1);
+
+SFR(T2CON, 0xC8);
+ SBIT(CPRL2, 0xC8, 0);
+ SBIT(CT2, 0xC8, 1);
+ SBIT(TR2, 0xC8, 2);
+ SBIT(EXEN2, 0xC8, 3);
+ SBIT(TCLK, 0xC8, 4);
+ SBIT(RCLK, 0xC8, 5);
+ SBIT(EXF2, 0xC8, 6);
+ SBIT(TF2, 0xC8, 7);
+
+SFR(RCAP2L, 0xCA);
+SFR(RCAP2H, 0xCB);
+SFR(TL2, 0xCC);
+SFR(TH2, 0xCD);
+
+SFR(PSW, 0xD0);
+ SBIT(P, 0xD0, 0);
+ SBIT(F1, 0xD0, 1);
+ SBIT(OV, 0xD0, 2);
+ SBIT(RS0, 0xD0, 3);
+ SBIT(RS1, 0xD0, 4);
+ SBIT(F0, 0xD0, 5);
+ SBIT(AC, 0xD0, 6);
+ SBIT(CY, 0xD0, 7);
+
+SFR(EICON, 0xD8);
+ // Bit 0 read-only, always reads '0'
+ // Bit 1 read-only, always reads '0'
+ // Bit 2 read-only, always reads '0'
+ SBIT(INT6, 0xD8, 3);
+ SBIT(RESI, 0xD8, 4);
+ SBIT(ERESI, 0xD8, 5);
+ // Bit 6 read-only, always reads '1'
+ SBIT(SMOD1, 0xD8, 7);
+
+SFR(ACC, 0xE0);
+
+SFR(EIE, 0xE8);
+ SBIT(EUSB, 0xE8, 0);
+ SBIT(EI2C, 0xE8, 1);
+ SBIT(EX4, 0xE8, 2);
+ SBIT(EX5, 0xE8, 3);
+ SBIT(EWDI, 0xE8, 4);
+ // Bit 5 read-only, always reads '1'
+ // Bit 6 read-only, always reads '1'
+ // Bit 7 read-only, always reads '1'
+
+SFR(B, 0xF0);
+
+SFR(EIP, 0xF8);
+ SBIT(PUSB, 0xF8, 0);
+ SBIT(PI2C, 0xF8, 1);
+ SBIT(PX4, 0xF8, 2);
+ SBIT(PX5, 0xF8, 3);
+ SBIT(PX6, 0xF8, 4);
+ // Bit 5 read-only, always reads '1'
+ // Bit 6 read-only, always reads '1'
+ // Bit 7 read-only, always reads '1'
+
+/***************************************************************************/
+/***************************** XDATA Registers *****************************/
+/***************************************************************************/
+
+/************************ Endpoint 0-7 Data Buffers ************************/
+SFRX(OUT7BUF[64], 0x7B40);
+SFRX(IN7BUF[64], 0x7B80);
+SFRX(OUT6BUF[64], 0x7BC0);
+SFRX(IN6BUF[64], 0x7C00);
+SFRX(OUT5BUF[64], 0x7C40);
+SFRX(IN5BUF[64], 0x7C80);
+SFRX(OUT4BUF[64], 0x7CC0);
+SFRX(IN4BUF[64], 0x7D00);
+SFRX(OUT3BUF[64], 0x7D40);
+SFRX(IN3BUF[64], 0x7D80);
+SFRX(OUT2BUF[64], 0x7DC0);
+SFRX(IN2BUF[64], 0x7E00);
+SFRX(OUT1BUF[64], 0x7E40);
+SFRX(IN1BUF[64], 0x7E80);
+SFRX(OUT0BUF[64], 0x7EC0);
+SFRX(IN0BUF[64], 0x7F00);
+// 0x7F40 - 0x7F5F reserved
+
+/**************************** Isochronous Data *****************************/
+SFRX(OUT8DATA, 0x7F60);
+SFRX(OUT9DATA, 0x7F61);
+SFRX(OUT10DATA, 0x7F62);
+SFRX(OUT11DATA, 0x7F63);
+SFRX(OUT12DATA, 0x7F64);
+SFRX(OUT13DATA, 0x7F65);
+SFRX(OUT14DATA, 0x7F66);
+SFRX(OUT15DATA, 0x7F67);
+
+SFRX(IN8DATA, 0x7F68);
+SFRX(IN9DATA, 0x7F69);
+SFRX(IN10DATA, 0x7F6A);
+SFRX(IN11DATA, 0x7F6B);
+SFRX(IN12DATA, 0x7F6C);
+SFRX(IN13DATA, 0x7F6D);
+SFRX(IN14DATA, 0x7F6E);
+SFRX(IN15DATA, 0x7F6F);
+
+/************************* Isochronous Byte Counts *************************/
+SFRX(OUT8BCH, 0x7F70);
+SFRX(OUT8BCL, 0x7F71);
+SFRX(OUT9BCH, 0x7F72);
+SFRX(OUT9BCL, 0x7F73);
+SFRX(OUT10BCH, 0x7F74);
+SFRX(OUT10BCL, 0x7F75);
+SFRX(OUT11BCH, 0x7F76);
+SFRX(OUT11BCL, 0x7F77);
+SFRX(OUT12BCH, 0x7F78);
+SFRX(OUT12BCL, 0x7F79);
+SFRX(OUT13BCH, 0x7F7A);
+SFRX(OUT13BCL, 0x7F7B);
+SFRX(OUT14BCH, 0x7F7C);
+SFRX(OUT14BCL, 0x7F7D);
+SFRX(OUT15BCH, 0x7F7E);
+SFRX(OUT16BCL, 0x7F7F);
+
+/****************************** CPU Registers ******************************/
+SFRX(CPUCS, 0x7F92);
+ #define RES8051 bmBit0
+ #define CLK24OE bmBit1
+ // Bit 2 read-only, always reads '0'
+ // Bit 3 read-only, always reads '0'
+ // Bits 4...7: Chip Revision
+
+SFRX(PORTACFG, 0x7F93);
+ #define T0OUT bmBit0
+ #define T1OUT bmBit1
+ #define OE bmBit2
+ #define CS bmBit3
+ #define FWR bmBit4
+ #define FRD bmBit5
+ #define RXD0OUT bmBit6
+ #define RXD1OUT bmBit7
+
+SFRX(PORTBCFG, 0x7F94);
+ #define T2 bmBit0
+ #define T2EX bmBit1
+ #define RXD1 bmBit2
+ #define TXD1 bmBit3
+ #define INT4 bmBit4
+ #define INT5 bmBit5
+ #define INT6 bmBit6
+ #define T2OUT bmBit7
+
+SFRX(PORTCCFG, 0x7F95);
+ #define RXD0 bmBit0
+ #define TXD0 bmBit1
+ #define INT0 bmBit2
+ #define INT1 bmBit3
+ #define T0 bmBit4
+ #define T1 bmBit5
+ #define WR bmBit6
+ #define RD bmBit7
+
+/*********************** Input-Output Port Registers ***********************/
+SFRX(OUTA, 0x7F96);
+ #define OUTA0 bmBit0
+ #define OUTA1 bmBit1
+ #define OUTA2 bmBit2
+ #define OUTA3 bmBit3
+ #define OUTA4 bmBit4
+ #define OUTA5 bmBit5
+ #define OUTA6 bmBit6
+ #define OUTA7 bmBit7
+
+SFRX(OUTB, 0x7F97);
+ #define OUTB0 bmBit0
+ #define OUTB1 bmBit1
+ #define OUTB2 bmBit2
+ #define OUTB3 bmBit3
+ #define OUTB4 bmBit4
+ #define OUTB5 bmBit5
+ #define OUTB6 bmBit6
+ #define OUTB7 bmBit7
+
+SFRX(OUTC, 0x7F98);
+ #define OUTC0 bmBit0
+ #define OUTC1 bmBit1
+ #define OUTC2 bmBit2
+ #define OUTC3 bmBit3
+ #define OUTC4 bmBit4
+ #define OUTC5 bmBit5
+ #define OUTC6 bmBit6
+ #define OUTC7 bmBit7
+
+SFRX(PINSA, 0x7F99);
+ #define PINA0 bmBit0
+ #define PINA1 bmBit1
+ #define PINA2 bmBit2
+ #define PINA3 bmBit3
+ #define PINA4 bmBit4
+ #define PINA5 bmBit5
+ #define PINA6 bmBit6
+ #define PINA7 bmBit7
+
+SFRX(PINSB, 0x7F9A);
+ #define PINB0 bmBit0
+ #define PINB1 bmBit1
+ #define PINB2 bmBit2
+ #define PINB3 bmBit3
+ #define PINB4 bmBit4
+ #define PINB5 bmBit5
+ #define PINB6 bmBit6
+ #define PINB7 bmBit7
+
+SFRX(PINSC, 0x7F9B);
+ #define PINC0 bmBit0
+ #define PINC1 bmBit1
+ #define PINC2 bmBit2
+ #define PINC3 bmBit3
+ #define PINC4 bmBit4
+ #define PINC5 bmBit5
+ #define PINC6 bmBit6
+ #define PINC7 bmBit7
+
+SFRX(OEA, 0x7F9C);
+ #define OEA0 bmBit0
+ #define OEA1 bmBit1
+ #define OEA2 bmBit2
+ #define OEA3 bmBit3
+ #define OEA4 bmBit4
+ #define OEA5 bmBit5
+ #define OEA6 bmBit6
+ #define OEA7 bmBit7
+
+SFRX(OEB, 0x7F9D);
+ #define OEB0 bmBit0
+ #define OEB1 bmBit1
+ #define OEB2 bmBit2
+ #define OEB3 bmBit3
+ #define OEB4 bmBit4
+ #define OEB5 bmBit5
+ #define OEB6 bmBit6
+ #define OEB7 bmBit7
+
+SFRX(OEC, 0x7F9E);
+ #define OEC0 bmBit0
+ #define OEC1 bmBit1
+ #define OEC2 bmBit2
+ #define OEC3 bmBit3
+ #define OEC4 bmBit4
+ #define OEC5 bmBit5
+ #define OEC6 bmBit6
+ #define OEC7 bmBit7
+
+// 0x7F9F reserved
+
+/****************** Isochronous Control/Status Registers *******************/
+SFRX(ISOERR, 0x7FA0);
+ #define ISO8ERR bmBit0
+ #define ISO9ERR bmBit1
+ #define ISO10ERR bmBit2
+ #define ISO11ERR bmBit3
+ #define ISO12ERR bmBit4
+ #define ISO13ERR bmBit5
+ #define ISO14ERR bmBit6
+ #define ISO15ERR bmBit7
+
+SFRX(ISOCTL, 0x7FA1);
+ #define ISODISAB bmBit0
+ #define MBZ0 bmBit1
+ #define MBZ1 bmBit2
+ #define PPSTAT bmBit3
+ // Bit 4 unused
+ // Bit 5 unused
+ // Bit 6 unused
+ // Bit 7 unused
+
+SFRX(ZBCOUT, 0x7FA2);
+ #define EP8 bmBit0
+ #define EP9 bmBit1
+ #define EP10 bmBit2
+ #define EP11 bmBit3
+ #define EP12 bmBit4
+ #define EP13 bmBit5
+ #define EP14 bmBit6
+ #define EP15 bmBit7
+
+// 0x7FA3 reserved
+// 0x7FA4 reserved
+
+/****************************** I2C Registers ******************************/
+SFRX(I2CS, 0x7FA5);
+ #define DONE bmBit0
+ #define ACK bmBit1
+ #define BERR bmBit2
+ #define ID0 bmBit3
+ #define ID1 bmBit4
+ #define LASTRD bmBit5
+ #define I2C_STOP bmBit6
+ #define I2C_START bmBit7
+
+SFRX(I2DAT, 0x7FA6);
+// 0x7FA7 reserved
+
+/******************************* Interrupts ********************************/
+SFRX(IVEC, 0x7FA8);
+ // Bit 0 read-only, always reads '0'
+ // Bit 1 read-only, always reads '0'
+ #define IV0 bmBit2
+ #define IV1 bmBit3
+ #define IV2 bmBit4
+ #define IV3 bmBit5
+ #define IV4 bmBit6
+ // Bit 7 read-only, always reads '0'
+
+SFRX(IN07IRQ, 0x7FA9);
+ #define IN0IR bmBit0
+ #define IN1IR bmBit1
+ #define IN2IR bmBit2
+ #define IN3IR bmBit3
+ #define IN4IR bmBit4
+ #define IN5IR bmBit5
+ #define IN6IR bmBit6
+ #define IN7IR bmBit7
+
+SFRX(OUT07IRQ, 0x7FAA);
+ #define OUT0IR bmBit0
+ #define OUT1IR bmBit1
+ #define OUT2IR bmBit2
+ #define OUT3IR bmBit3
+ #define OUT4IR bmBit4
+ #define OUT5IR bmBit5
+ #define OUT6IR bmBit6
+ #define OUT7IR bmBit7
+
+SFRX(USBIRQ, 0x7FAB);
+ #define SUDAVIR bmBit0
+ #define SOFIR bmBit1
+ #define SUTOKIR bmBit2
+ #define SUSPIR bmBit3
+ #define URESIR bmBit4
+ // Bit 5 unused
+ // Bit 6 unused
+ // Bit 7 unused
+
+SFRX(IN07IEN, 0x7FAC);
+ #define IN0IEN bmBit0
+ #define IN1IEN bmBit1
+ #define IN2IEN bmBit2
+ #define IN3IEN bmBit3
+ #define IN4IEN bmBit4
+ #define IN5IEN bmBit5
+ #define IN6IEN bmBit6
+ #define IN7IEN bmBit7
+
+SFRX(OUT07IEN, 0x7FAD);
+ #define OUT0IEN bmBit0
+ #define OUT1IEN bmBit1
+ #define OUT2IEN bmBit2
+ #define OUT3IEN bmBit3
+ #define OUT4IEN bmBit4
+ #define OUT5IEN bmBit5
+ #define OUT6IEN bmBit6
+ #define OUT7IEN bmBit7
+
+SFRX(USBIEN, 0x7FAE);
+ #define SUDAVIE bmBit0
+ #define SOFIE bmBit1
+ #define SUTOKIE bmBit2
+ #define SUSPIE bmBit3
+ #define URESIE bmBit4
+ // Bit 5 unused
+ // Bit 6 unused
+ // Bit 7 unused
+
+SFRX(USBBAV, 0x7FAF);
+ #define AVEN bmBit0
+ #define BPEN bmBit1
+ #define BPPULSE bmBit2
+ #define BREAK bmBit3
+ // Bit 4 unused
+ // Bit 5 unused
+ // Bit 6 unused
+ // Bit 7 unused
+
+// 0x7FB0 reserved
+// 0x7FB1 reserved
+SFRX(BPADDRH, 0x7FB2);
+SFRX(BPADDRL, 0x7FB3);
+
+/****************************** Endpoints 0-7 ******************************/
+SFRX(EP0CS, 0x7FB4);
+ #define EP0STALL bmBit0
+ #define HSNAK bmBit1
+ #define IN0BSY bmBit2
+ #define OUT0BSY bmBit3
+ // Bit 4 unused
+ // Bit 5 unused
+ // Bit 6 unused
+ // Bit 7 unused
+
+SFRX(IN0BC, 0x7FB5);
+SFRX(IN1CS, 0x7FB6);
+SFRX(IN1BC, 0x7FB7);
+SFRX(IN2CS, 0x7FB8);
+SFRX(IN2BC, 0x7FB9);
+SFRX(IN3CS, 0x7FBA);
+SFRX(IN3BC, 0x7FBB);
+SFRX(IN4CS, 0x7FBC);
+SFRX(IN4BC, 0x7FBD);
+SFRX(IN5CS, 0x7FBE);
+SFRX(IN5BC, 0x7FBF);
+SFRX(IN6CS, 0x7FC0);
+SFRX(IN6BC, 0x7FC1);
+SFRX(IN7CS, 0x7FC2);
+SFRX(IN7BC, 0x7FC3);
+// 0x7FC4 reserved
+SFRX(OUT0BC, 0x7FC5);
+SFRX(OUT1CS, 0x7FC6);
+SFRX(OUT1BC, 0x7FC7);
+SFRX(OUT2CS, 0x7FC8);
+SFRX(OUT2BC, 0x7FC9);
+SFRX(OUT3CS, 0x7FCA);
+SFRX(OUT3BC, 0x7FCB);
+SFRX(OUT4CS, 0x7FCC);
+SFRX(OUT4BC, 0x7FCD);
+SFRX(OUT5CS, 0x7FCE);
+SFRX(OUT5BC, 0x7FCF);
+SFRX(OUT6CS, 0x7FD0);
+SFRX(OUT6BC, 0x7FD1);
+SFRX(OUT7CS, 0x7FD2);
+SFRX(OUT7BC, 0x7FD3);
+
+/* The INxSTALL, OUTxSTALL, INxBSY and OUTxBSY bits are the same for all
+ * INxCS/OUTxCS registers. For better readability, we define them only once */
+#define EPSTALL bmBit0
+#define EPBSY bmBit1
+
+/************************** Global USB Registers ***************************/
+SFRX(SUDPTRH, 0x7FD4);
+SFRX(SUDPTRL, 0x7FD5);
+
+SFRX(USBCS, 0x7FD6);
+ #define SIGRSUME bmBit0
+ #define RENUM bmBit1
+ #define DISCOE bmBit2
+ #define DISCON bmBit3
+ // Bit 4 unused
+ // Bit 5 unused
+ // Bit 6 unused
+ #define WAKESRC bmBit7
+
+SFRX(TOGCTL, 0x7FD7);
+ #define TOG_EP0 bmBit0
+ #define TOG_EP1 bmBit1
+ #define TOG_EP2 bmBit2
+ // Bit 3 is read-only, always reads '0'
+ #define TOG_IO bmBit4
+ #define TOG_R bmBit5
+ #define TOG_S bmBit6
+ #define TOG_Q bmBit7
+
+SFRX(USBFRAMEL, 0x7FD8);
+SFRX(USBFRAMEH, 0x7FD9);
+// 0x7FDA reserved
+SFRX(FNADDR, 0x7FDB);
+// 0x7FDC reserved
+
+SFRX(USBPAIR, 0x7FDD);
+ #define PR2IN bmBit0
+ #define PR4IN bmBit1
+ #define PR6IN bmBit2
+ #define PR2OUT bmBit3
+ #define PR4OUT bmBit4
+ #define PR6OUT bmBit5
+ // Bit 6 unused
+ #define ISOSEND0 bmBit7
+
+SFRX(IN07VAL, 0x7FDE);
+ // Bit 0 is read-only, always reads '1'
+ #define IN1VAL bmBit1
+ #define IN2VAL bmBit2
+ #define IN3VAL bmBit3
+ #define IN4VAL bmBit4
+ #define IN5VAL bmBit5
+ #define IN6VAL bmBit6
+ #define IN7VAL bmBit7
+
+SFRX(OUT07VAL, 0x7FDF);
+ // Bit 0 is read-only, always reads '1'
+ #define OUT1VAL bmBit1
+ #define OUT2VAL bmBit2
+ #define OUT3VAL bmBit3
+ #define OUT4VAL bmBit4
+ #define OUT5VAL bmBit5
+ #define OUT6VAL bmBit6
+ #define OUT7VAL bmBit7
+
+SFRX(INISOVAL, 0x7FE0);
+ #define IN8VAL bmBit0
+ #define IN9VAL bmBit1
+ #define IN10VAL bmBit2
+ #define IN11VAL bmBit3
+ #define IN12VAL bmBit4
+ #define IN13VAL bmBit5
+ #define IN14VAL bmBit6
+ #define IN15VAL bmBit7
+
+SFRX(OUTISOVAL, 0x7FE1);
+ #define OUT8VAL bmBit0
+ #define OUT9VAL bmBit1
+ #define OUT10VAL bmBit2
+ #define OUT11VAL bmBit3
+ #define OUT12VAL bmBit4
+ #define OUT13VAL bmBit5
+ #define OUT14VAL bmBit6
+ #define OUT15VAL bmBit7
+
+SFRX(FASTXFR, 0x7FE2);
+ #define WMOD0 bmBit0
+ #define WMOD1 bmBit1
+ #define WPOL bmBit2
+ #define RMOD0 bmBit3
+ #define RMOD1 bmBit4
+ #define RPOL bmBit5
+ #define FBLK bmBit6
+ #define FISO bmBit7
+
+SFRX(AUTOPTRH, 0x7FE3);
+SFRX(AUTOPTRL, 0x7FE4);
+SFRX(AUTODATA, 0x7FE5);
+// 0x7FE6 reserved
+// 0x7FE7 reserved
+
+/******************************* Setup Data ********************************/
+SFRX(SETUPDAT[8], 0x7FE8);
+
+/************************* Isochronous FIFO sizes **************************/
+SFRX(OUT8ADDR, 0x7FF0);
+SFRX(OUT9ADDR, 0x7FF1);
+SFRX(OUT10ADDR, 0x7FF2);
+SFRX(OUT11ADDR, 0x7FF3);
+SFRX(OUT12ADDR, 0x7FF4);
+SFRX(OUT13ADDR, 0x7FF5);
+SFRX(OUT14ADDR, 0x7FF6);
+SFRX(OUT15ADDR, 0x7FF7);
+
+SFRX(IN8ADDR, 0x7FF8);
+SFRX(IN9ADDR, 0x7FF9);
+SFRX(IN10ADDR, 0x7FFA);
+SFRX(IN11ADDR, 0x7FFB);
+SFRX(IN12ADDR, 0x7FFC);
+SFRX(IN13ADDR, 0x7FFD);
+SFRX(IN14ADDR, 0x7FFE);
+SFRX(IN15ADDR, 0x7FFF);
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __SHORTTYPES_H
+#define __SHORTTYPES_H
+
+#include <stdint.h>
+
+/**
+ * @file Integer type definitions for shorter code (easier to stay within 80
+ * character maximum line length).
+ */
+
+/* Signed integers */
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+
+/* Unsigned integers */
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef __USB_H
+#define __USB_H
+
+#include "shorttypes.h"
+#include "reg_ezusb.h"
+
+#include <stdbool.h>
+
+#define NULL (void*)0;
+
+/* High and Low byte of a word (u16) */
+#define HI8(word) (u8)(((u16)word >> 8) & 0xff)
+#define LO8(word) (u8)((u16)word & 0xff)
+
+/* Convenience functions */
+#define STALL_EP0() EP0CS |= EP0STALL
+#define CLEAR_IRQ() EXIF &= ~USBINT
+
+/*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/
+
+/* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */
+#define DESCRIPTOR_TYPE_DEVICE 0x01
+#define DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define DESCRIPTOR_TYPE_STRING 0x03
+#define DESCRIPTOR_TYPE_INTERFACE 0x04
+#define DESCRIPTOR_TYPE_ENDPOINT 0x05
+
+#define STR_DESCR(len,...) { len*2+2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } }
+
+/** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< DEVICE Descriptor Type.
+ u16 bcdUSB; ///< USB specification release number (BCD).
+ u8 bDeviceClass; ///< Class code.
+ u8 bDeviceSubClass; ///< Subclass code.
+ u8 bDeviceProtocol; ///< Protocol code.
+ u8 bMaxPacketSize0; ///< Maximum packet size for EP0 (8, 16, 32, 64).
+ u16 idVendor; ///< USB Vendor ID.
+ u16 idProduct; ///< USB Product ID.
+ u16 bcdDevice; ///< Device Release Number (BCD).
+ u8 iManufacturer; ///< Index of manufacturer string descriptor.
+ u8 iProduct; ///< Index of product string descriptor.
+ u8 iSerialNumber; ///< Index of string descriptor containing serial #.
+ u8 bNumConfigurations; ///< Number of possible configurations.
+} usb_device_descriptor_t;
+
+/** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< CONFIGURATION descriptor type.
+ u16 wTotalLength; ///< Combined total length of all descriptors.
+ u8 bNumInterfaces; ///< Number of interfaces in this configuration.
+ u8 bConfigurationValue; ///< Value used to select this configuration.
+ u8 iConfiguration; ///< Index of configuration string descriptor.
+ u8 bmAttributes; ///< Configuration characteristics.
+ u8 MaxPower; ///< Maximum power consumption in 2 mA units.
+} usb_config_descriptor_t;
+
+/** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< INTERFACE descriptor type.
+ u8 bInterfaceNumber; ///< Interface number.
+ u8 bAlternateSetting; ///< Value used to select alternate setting.
+ u8 bNumEndpoints; ///< Number of endpoints used by this interface.
+ u8 bInterfaceClass; ///< Class code.
+ u8 bInterfaceSubclass; ///< Subclass code.
+ u8 bInterfaceProtocol; ///< Protocol code.
+ u8 iInterface; ///< Index of interface string descriptor.
+} usb_interface_descriptor_t;
+
+/** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< ENDPOINT descriptor type.
+ u8 bEndpointAddress; ///< Endpoint Address: USB 1.1 spec, table 9-10.
+ u8 bmAttributes; ///< Endpoint Attributes: USB 1.1 spec, table 9-10.
+ u16 wMaxPacketSize; ///< Maximum packet size for this endpoint.
+ u8 bInterval; ///< Polling interval (in ms) for this endpoint.
+} usb_endpoint_descriptor_t;
+
+/** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< STRING descriptor type.
+ u16 wLANGID[]; ///< LANGID codes.
+} usb_language_descriptor_t;
+
+/** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */
+typedef struct {
+ u8 bLength; ///< Size of this descriptor in bytes.
+ u8 bDescriptorType; ///< STRING descriptor type.
+ u16 bString[]; ///< UNICODE encoded string.
+} usb_string_descriptor_t;
+
+/********************** USB Control Endpoint 0 related *********************/
+
+/** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */
+typedef struct {
+ u8 bmRequestType; ///< Characteristics of a request.
+ u8 bRequest; ///< Specific request.
+ u16 wValue; ///< Field that varies according to request.
+ u16 wIndex; ///< Field that varies according to request.
+ u16 wLength; ///< Number of bytes to transfer in data stage.
+} setup_data_t;
+
+/* External declarations for variables that need to be accessed outside of
+ * the USB module */
+extern volatile bool EP2_out;
+extern volatile bool EP2_in;
+extern volatile __xdata __at 0x7FE8 setup_data_t setup_data;
+
+/*
+ * USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2
+ *
+ * Bit 7: Data transfer direction
+ * 0 = Host-to-device
+ * 1 = Device-to-host
+ * Bit 6...5: Type
+ * 0 = Standard
+ * 1 = Class
+ * 2 = Vendor
+ * 3 = Reserved
+ * Bit 4...0: Recipient
+ * 0 = Device
+ * 1 = Interface
+ * 2 = Endpoint
+ * 3 = Other
+ * 4...31 = Reserved
+ */
+
+#define USB_DIR_OUT 0x00
+#define USB_DIR_IN 0x80
+
+#define USB_REQ_TYPE_STANDARD (0x00 << 5)
+#define USB_REQ_TYPE_CLASS (0x01 << 5)
+#define USB_REQ_TYPE_VENDOR (0x02 << 5)
+#define USB_REQ_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/* bmRequestType for USB Standard Requests */
+
+/* Clear Interface Request */
+#define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Get Configuration Request */
+#define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Get Descriptor Request */
+#define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Get Interface Request */
+#define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Get Status Request: See USB 1.1 spec, page 190 */
+#define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Set Address Request is handled by EZ-USB core */
+
+/* Set Configuration Request */
+#define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Set Descriptor Request */
+#define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+
+/* Set Feature Request */
+#define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+#define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* Set Interface Request */
+#define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Synch Frame Request */
+#define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+
+/* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+// Value '2' is reserved for future use
+#define SET_FEATURE 3
+// Value '4' is reserved for future use
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+#define SYNCH_FRAME 12
+
+/* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */
+#define DEVICE_REMOTE_WAKEUP 1
+#define ENDPOINT_HALT 0
+
+/************************** EZ-USB specific stuff **************************/
+
+/** USB Interrupts. See AN2131-TRM, page 9-4 for details */
+typedef enum {
+ SUDAV_ISR = 13,
+ SOF_ISR,
+ SUTOK_ISR,
+ SUSPEND_ISR,
+ USBRESET_ISR,
+ IBN_ISR,
+ EP0IN_ISR,
+ EP0OUT_ISR,
+ EP1IN_ISR,
+ EP1OUT_ISR,
+ EP2IN_ISR,
+ EP2OUT_ISR,
+ EP3IN_ISR,
+ EP3OUT_ISR,
+ EP4IN_ISR,
+ EP4OUT_ISR,
+ EP5IN_ISR,
+ EP5OUT_ISR,
+ EP6IN_ISR,
+ EP6OUT_ISR,
+ EP7IN_ISR,
+ EP7OUT_ISR
+} USB_ISR;
+
+/*************************** Function Prototypes ***************************/
+
+__xdata u8* usb_get_endpoint_cs_reg(u8 ep);
+void usb_reset_data_toggle(u8 ep);
+
+bool usb_handle_get_status(void);
+bool usb_handle_clear_feature(void);
+bool usb_handle_set_feature(void);
+bool usb_handle_get_descriptor(void);
+void usb_handle_set_interface(void);
+
+void usb_handle_setup_data(void);
+void usb_init(void);
+
+#endif
--- /dev/null
+;--------------------------------------------------------------------------;
+; Copyright (C) 2011 by Martin Schmoelzer ;
+; <martin.schmoelzer@student.tuwien.ac.at> ;
+; ;
+; This program is free software; you can redistribute it and/or modify ;
+; it under the terms of the GNU General Public License as published by ;
+; the Free Software Foundation; either version 2 of the License, or ;
+; (at your option) any later version. ;
+; ;
+; This program is distributed in the hope that it will be useful, ;
+; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
+; GNU General Public License for more details. ;
+; ;
+; You should have received a copy of the GNU General Public License ;
+; along with this program; if not, write to the ;
+; Free Software Foundation, Inc., ;
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;
+;--------------------------------------------------------------------------;
+
+.module JUMPTABLE
+.globl USB_AutoVector
+.globl USB_Jump_Table
+
+;--------------------------------------------------------------------------;
+; Interrupt Vectors ;
+;--------------------------------------------------------------------------;
+.area USB_JV (ABS,OVR) ; Absolute, Overlay
+.org 0x43 ; USB interrupt (INT2) jumps here
+USB_AutoVector = #. + 2
+ ljmp USB_jump_table
+
+;--------------------------------------------------------------------------;
+; USB Jump Table ;
+;--------------------------------------------------------------------------;
+.area USB_JT (ABS) ; Absolute placement
+.org 0x1B00 ; Place jump table at 0x1B00
+
+USB_jump_table: ; autovector jump table
+ ljmp _sudav_isr ; Setup Data Available
+ .db 0
+ ljmp _sof_isr ; Start of Frame
+ .db 0
+ ljmp _sutok_isr ; Setup Data Loading
+ .db 0
+ ljmp _suspend_isr ; Global Suspend
+ .db 0
+ ljmp _usbreset_isr ; USB Reset
+ .db 0
+ ljmp _ibn_isr ; IN Bulk NAK interrupt
+ .db 0
+ ljmp _ep0in_isr ; Endpoint 0 IN
+ .db 0
+ ljmp _ep0out_isr ; Endpoint 0 OUT
+ .db 0
+ ljmp _ep1in_isr ; Endpoint 1 IN
+ .db 0
+ ljmp _ep1out_isr ; Endpoint 1 OUT
+ .db 0
+ ljmp _ep2in_isr ; Endpoint 2 IN
+ .db 0
+ ljmp _ep2out_isr ; Endpoint 2 OUT
+ .db 0
+ ljmp _ep3in_isr ; Endpoint 3 IN
+ .db 0
+ ljmp _ep3out_isr ; Endpoint 3 OUT
+ .db 0
+ ljmp _ep4in_isr ; Endpoint 4 IN
+ .db 0
+ ljmp _ep4out_isr ; Endpoint 4 OUT
+ .db 0
+ ljmp _ep5in_isr ; Endpoint 5 IN
+ .db 0
+ ljmp _ep5out_isr ; Endpoint 5 OUT
+ .db 0
+ ljmp _ep6in_isr ; Endpoint 6 IN
+ .db 0
+ ljmp _ep6out_isr ; Endpoint 6 OUT
+ .db 0
+ ljmp _ep7in_isr ; Endpoint 7 IN
+ .db 0
+ ljmp _ep7out_isr ; Endpoint 7 OUT
+ .db 0
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "delay.h"
+
+void delay_5us(void)
+{
+ NOP;
+}
+
+void delay_1ms(void) {
+ u16 i;
+
+ for (i = 0; i < 598; i++);
+}
+
+void delay_us(u16 delay)
+{
+ u16 i;
+ u16 maxcount = (delay / 5);
+
+ for (i = 0; i < maxcount; i++) {
+ delay_5us();
+ }
+}
+
+void delay_ms(u16 delay)
+{
+ u16 i;
+
+ for (i = 0; i < delay; i++) {
+ delay_1ms();
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "jtag.h"
+
+#include "io.h"
+#include "msgtypes.h"
+#include "common.h"
+
+#include <stdbool.h>
+
+/** Delay value for SCAN operations with less than maximum TCK frequency */
+u8 delay_scan = 0;
+
+/** Delay value for CLOCK_TCK operations */
+u8 delay_tck = 0;
+
+/** Delay value for CLOCK_TMS operations with less than maximum frequency */
+u8 delay_tms = 0;
+
+/**
+ * Perform JTAG SCAN-IN operation at maximum TCK frequency.
+ *
+ * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and
+ * stored in the EP2 IN buffer.
+ *
+ * @param out_offset offset in OUT2BUF where payload data starts
+ */
+void jtag_scan_in(u8 out_offset, u8 in_offset)
+{
+ u8 scan_size_bytes, bits_last_byte;
+ u8 tms_count_start, tms_count_end;
+ u8 tms_sequence_start, tms_sequence_end;
+ u8 tdo_data, i, j;
+
+ u8 outb_buffer;
+
+ /* Get parameters from OUT2BUF */
+ scan_size_bytes = OUT2BUF[out_offset];
+ bits_last_byte = OUT2BUF[out_offset + 1];
+ tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = OUT2BUF[out_offset + 3];
+ tms_sequence_end = OUT2BUF[out_offset + 4];
+
+ if (tms_count_start > 0) {
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+ }
+
+ outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdo_data = 0;
+
+ for (j = 0; j < 8; j++) {
+ OUTB = outb_buffer; /* TCK changes here */
+ OUTB = (outb_buffer | PIN_TCK);
+ tdo_data = tdo_data >> 1;
+
+ if (GET_TDO()) {
+ tdo_data |= 0x80;
+ }
+ }
+
+ /* Copy TDO data to IN2BUF */
+ IN2BUF[i + in_offset] = tdo_data;
+ }
+
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ /* Assert TMS signal if requested and this is the last bit */
+ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
+ outb_buffer |= PIN_TMS;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+
+ OUTB = outb_buffer; /* TCK change here */
+ OUTB = (outb_buffer | PIN_TCK);
+ tdo_data = tdo_data >> 1;
+
+ if (GET_TDO()) {
+ tdo_data |= 0x80;
+ }
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to IN2BUF */
+ IN2BUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0) {
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+ }
+}
+
+/**
+ * Perform JTAG SCAN-OUT operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is not sampled.
+ * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * @param out_offset offset in OUT2BUF where payload data starts
+ */
+void jtag_scan_out(u8 out_offset)
+{
+ u8 scan_size_bytes, bits_last_byte;
+ u8 tms_count_start, tms_count_end;
+ u8 tms_sequence_start, tms_sequence_end;
+ u8 tdi_data, i, j;
+
+ u8 outb_buffer;
+
+ /* Get parameters from OUT2BUF */
+ scan_size_bytes = OUT2BUF[out_offset];
+ bits_last_byte = OUT2BUF[out_offset + 1];
+ tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = OUT2BUF[out_offset + 3];
+ tms_sequence_end = OUT2BUF[out_offset + 4];
+
+ if (tms_count_start > 0) {
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+ }
+
+ outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = OUT2BUF[i + out_offset + 5];
+
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01) {
+ outb_buffer |= PIN_TDI;
+ }
+ else {
+ outb_buffer &= ~PIN_TDI;
+ }
+
+ OUTB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ OUTB = (outb_buffer | PIN_TCK);
+ }
+ }
+
+ tdi_data = OUT2BUF[i + out_offset + 5];
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01) {
+ outb_buffer |= PIN_TDI;
+ }
+ else {
+ outb_buffer &= ~PIN_TDI;
+ }
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
+ outb_buffer |= PIN_TMS;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+
+ OUTB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ OUTB = (outb_buffer | PIN_TCK);
+ }
+
+ /* Move to correct end state */
+ if (tms_count_end > 0) {
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+ }
+}
+
+/**
+ * Perform bidirectional JTAG SCAN operation at maximum TCK frequency.
+ *
+ * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO
+ * data is sampled and stored in the EP2 IN buffer.
+ * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state.
+ *
+ * @param out_offset offset in OUT2BUF where payload data starts
+ */
+void jtag_scan_io(u8 out_offset, u8 in_offset)
+{
+ u8 scan_size_bytes, bits_last_byte;
+ u8 tms_count_start, tms_count_end;
+ u8 tms_sequence_start, tms_sequence_end;
+ u8 tdi_data, tdo_data, i, j;
+
+ u8 outb_buffer;
+
+ /* Get parameters from OUT2BUF */
+ scan_size_bytes = OUT2BUF[out_offset];
+ bits_last_byte = OUT2BUF[out_offset + 1];
+ tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F;
+ tms_count_end = OUT2BUF[out_offset + 2] & 0x0F;
+ tms_sequence_start = OUT2BUF[out_offset + 3];
+ tms_sequence_end = OUT2BUF[out_offset + 4];
+
+ if (tms_count_start > 0) {
+ jtag_clock_tms(tms_count_start, tms_sequence_start);
+ }
+
+ outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS);
+
+ /* Shift all bytes except the last byte */
+ for (i = 0; i < scan_size_bytes - 1; i++) {
+ tdi_data = OUT2BUF[i + out_offset + 5];
+ tdo_data = 0;
+
+ for (j = 0; j < 8; j++) {
+ if (tdi_data & 0x01) {
+ outb_buffer |= PIN_TDI;
+ }
+ else {
+ outb_buffer &= ~PIN_TDI;
+ }
+
+ OUTB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ OUTB = (outb_buffer | PIN_TCK);
+ tdo_data = tdo_data >> 1;
+
+ if (GET_TDO()) {
+ tdo_data |= 0x80;
+ }
+ }
+
+ /* Copy TDO data to IN2BUF */
+ IN2BUF[i + in_offset] = tdo_data;
+ }
+
+ tdi_data = OUT2BUF[i + out_offset + 5];
+ tdo_data = 0;
+
+ /* Shift the last byte */
+ for (j = 0; j < bits_last_byte; j++) {
+ if (tdi_data & 0x01) {
+ outb_buffer |= PIN_TDI;
+ }
+ else {
+ outb_buffer &= ~PIN_TDI;
+ }
+
+ /* Assert TMS signal if requested and this is the last bit */
+ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) {
+ outb_buffer |= PIN_TMS;
+ tms_count_end--;
+ tms_sequence_end = tms_sequence_end >> 1;
+ }
+
+ OUTB = outb_buffer; /* TDI and TCK change here */
+ tdi_data = tdi_data >> 1;
+ OUTB = (outb_buffer | PIN_TCK);
+ tdo_data = tdo_data >> 1;
+
+ if (GET_TDO()) {
+ tdo_data |= 0x80;
+ }
+ }
+ tdo_data = tdo_data >> (8 - bits_last_byte);
+
+ /* Copy TDO data to IN2BUF */
+ IN2BUF[i + in_offset] = tdo_data;
+
+ /* Move to correct end state */
+ if (tms_count_end > 0) {
+ jtag_clock_tms(tms_count_end, tms_sequence_end);
+ }
+}
+
+/**
+ * Generate TCK clock cycles.
+ *
+ * @param count number of TCK clock cyclces to generate.
+ */
+void jtag_clock_tck(u16 count)
+{
+ u16 i;
+ u8 j;
+
+ for ( i = 0; i < count; i++ ) {
+ SET_TCK_LOW();
+ for(j = 0; j < delay_tck; j++);
+
+ SET_TCK_HIGH();
+ for(j = 0; j < delay_tck; j++);
+ }
+}
+
+/**
+ * Perform TAP-FSM state transitions at maximum TCK frequency.
+ *
+ * @param count the number of state transitions to perform.
+ * @param sequence the TMS pin levels for each state transition, starting with
+ * the least-significant bit.
+ */
+void jtag_clock_tms(u8 count, u8 sequence)
+{
+ volatile u8 outb_buffer;
+ u8 i;
+
+ outb_buffer = OUTB & ~(PIN_TCK);
+
+ for ( i = 0; i < count; i++ ) {
+ /* Set TMS pin according to sequence parameter */
+ if ( sequence & 0x1 ) {
+ outb_buffer |= PIN_TMS;
+ }
+ else {
+ outb_buffer &= ~PIN_TMS;
+ }
+
+ OUTB = outb_buffer;
+ sequence = sequence >> 1;
+ OUTB = outb_buffer | PIN_TCK;
+ }
+}
+
+/**
+ * Perform TAP-FSM state transitions at less than maximum TCK frequency.
+ *
+ * @param count the number of state transitions to perform.
+ * @param sequence the TMS pin levels for each state transition, starting with
+ * the least-significant bit.
+ */
+void jtag_slow_clock_tms(u8 count, u8 sequence)
+{
+
+}
+
+/**
+ * Get current JTAG signal states.
+ *
+ * @return a 16-bit integer where the most-significant byte contains the state
+ * of the JTAG input signals and the least-significant byte cotains the state
+ * of the JTAG output signals.
+ */
+u16 jtag_get_signals(void)
+{
+ u8 input_signal_state, output_signal_state;
+
+ input_signal_state = 0;
+ output_signal_state = 0;
+
+ /* Get states of input pins */
+ if (GET_TDO()) {
+ input_signal_state |= SIGNAL_TDO;
+ }
+ if (GET_BRKOUT()) {
+ input_signal_state |= SIGNAL_BRKOUT;
+ }
+ if (GET_TRAP()) {
+ input_signal_state |= SIGNAL_TRAP;
+ }
+ if (GET_RTCK()) {
+ /* Using RTCK this way would be extremely slow,
+ * implemented only for the sake of completeness */
+ input_signal_state |= SIGNAL_RTCK;
+ }
+
+ /* Get states of output pins */
+ output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT;
+
+ return ((u16)input_signal_state << 8) | ((u16)output_signal_state);
+}
+
+/**
+ * Set state of JTAG output signals.
+ *
+ * @param low signals which should be de-asserted.
+ * @param high signals which should be asserted.
+ */
+void jtag_set_signals(u8 low, u8 high)
+{
+ OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT);
+ OUTB |= (high & MASK_PORTB_DIRECTION_OUT);
+}
+
+/**
+ * Configure TCK delay parameters.
+ *
+ * @param scan number of delay cycles in shift operations.
+ * @param tck number of delay cycles in clock_tck operations.
+ * @param tms number of delay cycles in clock_tms operations.
+ */
+void jtag_configure_tck_delay(u8 scan, u8 tck, u8 tms)
+{
+ delay_scan = scan;
+ delay_tck = tck;
+ delay_tms = tms;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "main.h"
+
+#include "shorttypes.h"
+#include "io.h"
+#include "usb.h"
+#include "protocol.h"
+
+extern void sudav_isr(void) __interrupt SUDAV_ISR;
+extern void sof_isr(void) __interrupt;
+extern void sutok_isr(void) __interrupt;
+extern void suspend_isr(void) __interrupt;
+extern void usbreset_isr(void) __interrupt;
+extern void ibn_isr(void) __interrupt;
+extern void ep0in_isr(void) __interrupt;
+extern void ep0out_isr(void) __interrupt;
+extern void ep1in_isr(void) __interrupt;
+extern void ep1out_isr(void) __interrupt;
+extern void ep2in_isr(void) __interrupt;
+extern void ep2out_isr(void) __interrupt;
+extern void ep3in_isr(void) __interrupt;
+extern void ep3out_isr(void) __interrupt;
+extern void ep4in_isr(void) __interrupt;
+extern void ep4out_isr(void) __interrupt;
+extern void ep5in_isr(void) __interrupt;
+extern void ep5out_isr(void) __interrupt;
+extern void ep6in_isr(void) __interrupt;
+extern void ep6out_isr(void) __interrupt;
+extern void ep7in_isr(void) __interrupt;
+extern void ep7out_isr(void) __interrupt;
+
+void io_init(void)
+{
+ /* PORTxCFG register bits select alternate functions (1 == alternate function,
+ * 0 == standard I/O)
+ * OEx register bits turn on/off output buffer (1 == output, 0 == input)
+ * OUTx register bits determine pin state of output
+ * PINx register bits reflect pin state (high == 1, low == 0) */
+
+ /* PORT A */
+ PORTACFG = PIN_OE;
+ OEA = PIN_U_OE | PIN_OE | PIN_RUN_LED | PIN_COM_LED;
+ OUTA = PIN_RUN_LED | PIN_COM_LED;
+
+ /* PORT B */
+ PORTBCFG = 0x00;
+ OEB = PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET
+ | PIN_OCDSE;
+
+ /* TRST and RESET signals are low-active but inverted by hardware, so we clear
+ * these signals here! */
+ OUTB = 0x00;
+
+ /* PORT C */
+ PORTCCFG = PIN_WR;
+ OEC = PIN_TXD0 | PIN_WR;
+ OUTC = 0x00;
+}
+
+int main(void)
+{
+ io_init();
+ usb_init();
+
+ /* Enable Interrupts */
+ EA = 1;
+
+ /* Begin executing command(s). This function never returns. */
+ command_loop();
+
+ /* Never reached, but SDCC complains about missing return statement */
+ return 0;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "protocol.h"
+#include "jtag.h"
+#include "delay.h"
+#include "usb.h"
+#include "io.h"
+#include "msgtypes.h"
+
+#include "reg_ezusb.h"
+
+/**
+ * @file Implementation of the OpenULINK communication protocol.
+ *
+ * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
+ * are configured to use the maximum packet size for full-speed transfers,
+ * 64 bytes. Commands always start with a command ID (see msgtypes.h for
+ * command ID definitions) and contain zero or more payload data bytes in both
+ * transfer directions (IN and OUT). The payload
+ *
+ * Almost all commands contain a fixed number of payload data bytes. The number
+ * of payload data bytes for the IN and OUT direction does not need to be the
+ * same.
+ *
+ * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
+ * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
+ * the host MUST ensure that the commands sent in the OUT packet require a
+ * maximum of 64 bytes of IN data.
+ */
+
+/** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
+volatile u8 cmd_id_index;
+
+/** Number of data bytes already in EP2 Bulk-IN buffer */
+volatile u8 payload_index_in;
+
+/**
+ * Execute a SET_LEDS command.
+ */
+void execute_set_led_command(void)
+{
+ u8 led_state = OUT2BUF[cmd_id_index + 1];
+
+ if (led_state & RUN_LED_ON) {
+ SET_RUN_LED();
+ }
+
+ if (led_state & COM_LED_ON) {
+ SET_COM_LED();
+ }
+
+ if (led_state & RUN_LED_OFF) {
+ CLEAR_RUN_LED();
+ }
+
+ if (led_state & COM_LED_OFF) {
+ CLEAR_COM_LED();
+ }
+}
+
+/**
+ * Executes one command and updates global command indexes.
+ *
+ * @param index the index of the Bulk EP2-OUT data buffer at which the
+ * command ID is stored.
+ * @return true if this command was the last command.
+ * @return false if there are more commands within the current contents of the
+ * Bulk EP2-OUT data buffer.
+ */
+bool execute_command(void)
+{
+ u8 usb_out_bytecount, usb_in_bytecount;
+ u16 signal_state;
+ u16 count;
+
+ /* Most commands do not transfer IN data. To save code space, we write 0 to
+ * usb_in_bytecount here, then modify it in the switch statement below where
+ * neccessary */
+ usb_in_bytecount = 0;
+
+ switch (OUT2BUF[cmd_id_index] /* Command ID */) {
+ case CMD_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ jtag_scan_in(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SCAN_OUT:
+ usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
+ jtag_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SCAN_IO:
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_scan_io(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
+ break;
+ case CMD_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (u16)OUT2BUF[cmd_id_index + 1];
+ count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
+ jtag_clock_tck(count);
+ break;
+ case CMD_SLEEP_US:
+ usb_out_bytecount = 2;
+ count = (u16)OUT2BUF[cmd_id_index + 1];
+ count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
+ delay_us(count);
+ break;
+ case CMD_SLEEP_MS:
+ usb_out_bytecount = 2;
+ count = (u16)OUT2BUF[cmd_id_index + 1];
+ count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
+ delay_ms(count);
+ break;
+ case CMD_GET_SIGNALS:
+ usb_out_bytecount = 0;
+ usb_in_bytecount = 2;
+ signal_state = jtag_get_signals();
+ IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
+ IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
+ break;
+ case CMD_SET_SIGNALS:
+ usb_out_bytecount = 2;
+ jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
+ break;
+ case CMD_SET_LEDS:
+ usb_out_bytecount = 1;
+ execute_set_led_command();
+ break;
+ case CMD_TEST:
+ usb_out_bytecount = 1;
+ /* Do nothing... This command is only used to test if the device is ready
+ * to accept new commands */
+ break;
+ default:
+ /* Should never be reached */
+ usb_out_bytecount = 0;
+ break;
+ }
+
+ /* Update EP2 Bulk-IN data byte count */
+ payload_index_in += usb_in_bytecount;
+
+ /* Determine if this was the last command */
+ if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) {
+ return true;
+ }
+ else {
+ /* Not the last command, update cmd_id_index */
+ cmd_id_index += (usb_out_bytecount + 1);
+ return false;
+ }
+}
+
+/**
+ * Forever wait for commands and execute them as they arrive.
+ */
+void command_loop(void)
+{
+ bool last_command;
+
+ while (1) {
+ cmd_id_index = 0;
+ payload_index_in = 0;
+
+ /* Wait until host sends EP2 Bulk-OUT packet */
+ while (!EP2_out);
+ EP2_out = 0;
+
+ /* Turn on COM LED to indicate command execution */
+ SET_COM_LED();
+
+ /* Execute the commands */
+ last_command = false;
+ while (last_command == false) {
+ last_command = execute_command();
+ }
+
+ CLEAR_COM_LED();
+
+ /* Send back EP2 Bulk-IN packet if required */
+ if (payload_index_in > 0) {
+ IN2BC = payload_index_in;
+ while (!EP2_in);
+ EP2_in = 0;
+ }
+
+ /* Re-arm EP2-OUT after command execution */
+ OUT2BC = 0;
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Martin Schmoelzer *
+ * <martin.schmoelzer@student.tuwien.ac.at> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+/**
+ * @file Defines USB descriptors, interrupt routines and helper functions.
+ * To minimize code size, we make the following assumptions:
+ * - The OpenULINK has exactly one configuration
+ * - and exactly one alternate setting
+ *
+ * Therefore, we do not have to support the Set Configuration USB request.
+ */
+
+#include "usb.h"
+#include "delay.h"
+#include "io.h"
+
+/* Also update external declarations in "include/usb.h" if making changes to
+ * these variables! */
+volatile bool EP2_out = 0;
+volatile bool EP2_in = 0;
+
+volatile __xdata __at 0x7FE8 setup_data_t setup_data;
+
+/* Define number of endpoints (except Control Endpoint 0) in a central place.
+ * Be sure to include the neccessary endpoint descriptors! */
+#define NUM_ENDPOINTS 2
+
+/*
+ * Normally, we would initialize the descriptor structures in C99 style:
+ *
+ * __code usb_device_descriptor_t device_descriptor = {
+ * .bLength = foo,
+ * .bDescriptorType = bar,
+ * .bcdUSB = 0xABCD,
+ * ...
+ * };
+ *
+ * But SDCC currently does not support this, so we have to do it the
+ * old-fashioned way...
+ */
+
+__code usb_device_descriptor_t device_descriptor = {
+ /* .bLength = */ sizeof(usb_device_descriptor_t),
+ /* .bDescriptorType = */ DESCRIPTOR_TYPE_DEVICE,
+ /* .bcdUSB = */ 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */
+ /* .bDeviceClass = */ 0xFF, /* 0xFF = vendor-specific */
+ /* .bDeviceSubClass = */ 0xFF,
+ /* .bDeviceProtocol = */ 0xFF,
+ /* .bMaxPacketSize0 = */ 64,
+ /* .idVendor = */ 0xC251,
+ /* .idProduct = */ 0x2710,
+ /* .bcdDevice = */ 0x0100,
+ /* .iManufacturer = */ 1,
+ /* .iProduct = */ 2,
+ /* .iSerialNumber = */ 3,
+ /* .bNumConfigurations = */ 1
+};
+
+/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */
+
+__code usb_config_descriptor_t config_descriptor = {
+ /* .bLength = */ sizeof(usb_config_descriptor_t),
+ /* .bDescriptorType = */ DESCRIPTOR_TYPE_CONFIGURATION,
+ /* .wTotalLength = */ sizeof(usb_config_descriptor_t) +
+ sizeof(usb_interface_descriptor_t) +
+ NUM_ENDPOINTS * sizeof(usb_endpoint_descriptor_t),
+ /* .bNumInterfaces = */ 1,
+ /* .bConfigurationValue = */ 1,
+ /* .iConfiguration = */ 4, /* String describing this configuration */
+ /* .bmAttributes = */ 0x80, /* Only MSB set according to USB spec */
+ /* .MaxPower = */ 50 /* 100 mA */
+};
+
+__code usb_interface_descriptor_t interface_descriptor00 = {
+ /* .bLength = */ sizeof(usb_interface_descriptor_t),
+ /* .bDescriptorType = */ DESCRIPTOR_TYPE_INTERFACE,
+ /* .bInterfaceNumber = */ 0,
+ /* .bAlternateSetting = */ 0,
+ /* .bNumEndpoints = */ NUM_ENDPOINTS,
+ /* .bInterfaceClass = */ 0xFF,
+ /* .bInterfaceSubclass = */ 0xFF,
+ /* .bInterfaceProtocol = */ 0xFF,
+ /* .iInterface = */ 0
+};
+
+__code usb_endpoint_descriptor_t Bulk_EP2_IN_Endpoint_Descriptor = {
+ /* .bLength = */ sizeof(usb_endpoint_descriptor_t),
+ /* .bDescriptorType = */ 0x05,
+ /* .bEndpointAddress = */ 2 | USB_DIR_IN,
+ /* .bmAttributes = */ 0x02,
+ /* .wMaxPacketSize = */ 64,
+ /* .bInterval = */ 0
+};
+
+__code usb_endpoint_descriptor_t Bulk_EP2_OUT_Endpoint_Descriptor = {
+ /* .bLength = */ sizeof(usb_endpoint_descriptor_t),
+ /* .bDescriptorType = */ 0x05,
+ /* .bEndpointAddress = */ 2 | USB_DIR_OUT,
+ /* .bmAttributes = */ 0x02,
+ /* .wMaxPacketSize = */ 64,
+ /* .bInterval = */ 0
+};
+
+__code usb_language_descriptor_t language_descriptor = {
+ /* .bLength = */ 4,
+ /* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING,
+ /* .wLANGID = */ {0x0409 /* US English */}
+};
+
+__code usb_string_descriptor_t strManufacturer = STR_DESCR(9,'O','p','e','n','U','L','I','N','K');
+__code usb_string_descriptor_t strProduct = STR_DESCR(9,'O','p','e','n','U','L','I','N','K');
+__code usb_string_descriptor_t strSerialNumber = STR_DESCR(6, '0','0','0','0','0','1');
+__code usb_string_descriptor_t strConfigDescr = STR_DESCR(12, 'J','T','A','G',' ','A','d','a','p','t','e','r');
+
+/* Table containing pointers to string descriptors */
+__code usb_string_descriptor_t* __code en_string_descriptors[4] = {
+ &strManufacturer,
+ &strProduct,
+ &strSerialNumber,
+ &strConfigDescr
+};
+
+void sudav_isr(void) __interrupt SUDAV_ISR
+{
+ CLEAR_IRQ();
+
+ usb_handle_setup_data();
+
+ USBIRQ = SUDAVIR;
+ EP0CS |= HSNAK;
+}
+
+void sof_isr(void) __interrupt SOF_ISR { }
+void sutok_isr(void) __interrupt SUTOK_ISR { }
+void suspend_isr(void) __interrupt SUSPEND_ISR { }
+void usbreset_isr(void) __interrupt USBRESET_ISR { }
+void ibn_isr(void) __interrupt IBN_ISR { }
+
+void ep0in_isr(void) __interrupt EP0IN_ISR { }
+void ep0out_isr(void) __interrupt EP0OUT_ISR { }
+void ep1in_isr(void) __interrupt EP1IN_ISR { }
+void ep1out_isr(void) __interrupt EP1OUT_ISR { }
+
+/**
+ * EP2 IN: called after the transfer from uC->Host has finished: we sent data
+ */
+void ep2in_isr(void) __interrupt EP2IN_ISR {
+ EP2_in = 1;
+
+ CLEAR_IRQ();
+ IN07IRQ = IN2IR; // Clear OUT2 IRQ
+}
+
+/**
+ * EP2 OUT: called after the transfer from Host->uC has finished: we got data
+ */
+void ep2out_isr(void) __interrupt EP2OUT_ISR {
+ EP2_out = 1;
+
+ CLEAR_IRQ();
+ OUT07IRQ = OUT2IR; // Clear OUT2 IRQ
+}
+
+void ep3in_isr(void) __interrupt EP3IN_ISR { }
+void ep3out_isr(void) __interrupt EP3OUT_ISR { }
+void ep4in_isr(void) __interrupt EP4IN_ISR { }
+void ep4out_isr(void) __interrupt EP4OUT_ISR { }
+void ep5in_isr(void) __interrupt EP5IN_ISR { }
+void ep5out_isr(void) __interrupt EP5OUT_ISR { }
+void ep6in_isr(void) __interrupt EP6IN_ISR { }
+void ep6out_isr(void) __interrupt EP6OUT_ISR { }
+void ep7in_isr(void) __interrupt EP7IN_ISR { }
+void ep7out_isr(void) __interrupt EP7OUT_ISR { }
+
+/**
+ * Return the control/status register for an endpoint
+ *
+ * @param ep endpoint address
+ * @return on success: pointer to Control & Status register for endpoint
+ * specified in \a ep
+ * @return on failure: NULL
+ */
+__xdata u8* usb_get_endpoint_cs_reg(u8 ep)
+{
+ /* Mask direction bit */
+ u8 ep_num = ep & 0x7F;
+
+ switch (ep_num) {
+ case 0:
+ return &EP0CS;
+ break;
+ case 1:
+ return ep & 0x80 ? &IN1CS : &OUT1CS;
+ break;
+ case 2:
+ return ep & 0x80 ? &IN2CS : &OUT2CS;
+ break;
+ case 3:
+ return ep & 0x80 ? &IN3CS : &OUT3CS;
+ break;
+ case 4:
+ return ep & 0x80 ? &IN4CS : &OUT4CS;
+ break;
+ case 5:
+ return ep & 0x80 ? &IN5CS : &OUT5CS;
+ break;
+ case 6:
+ return ep & 0x80 ? &IN6CS : &OUT6CS;
+ break;
+ case 7:
+ return ep & 0x80 ? &IN7CS : &OUT7CS;
+ break;
+ }
+
+ return NULL;
+}
+
+void usb_reset_data_toggle(u8 ep)
+{
+ /* TOGCTL register:
+ +----+-----+-----+------+-----+-------+-------+-------+
+ | Q | S | R | IO | 0 | EP2 | EP1 | EP0 |
+ +----+-----+-----+------+-----+-------+-------+-------+
+
+ To reset data toggle bits, we have to write the endpoint direction (IN/OUT)
+ to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a
+ separate write cycle, the R bit needs to be set.
+ */
+ u8 togctl_value = (ep & 0x80 >> 3) | (ep & 0x7);
+
+ /* First step: Write EP number and direction bit */
+ TOGCTL = togctl_value;
+
+ /* Second step: Set R bit */
+ togctl_value |= TOG_R;
+ TOGCTL = togctl_value;
+}
+
+/**
+ * Handle GET_STATUS request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_status(void)
+{
+ u8 *ep_cs;
+
+ switch (setup_data.bmRequestType) {
+ case GS_DEVICE:
+ /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup.
+ * Byte 1: reserved, reset to zero */
+ IN0BUF[0] = 0;
+ IN0BUF[1] = 0;
+
+ /* Send response */
+ IN0BC = 2;
+ break;
+ case GS_INTERFACE:
+ /* Always return two zero bytes according to USB 1.1 spec, p. 191 */
+ IN0BUF[0] = 0;
+ IN0BUF[1] = 0;
+
+ /* Send response */
+ IN0BC = 2;
+ break;
+ case GS_ENDPOINT:
+ /* Get stall bit for endpoint specified in low byte of wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex & 0xff);
+
+ if (*ep_cs & EPSTALL) {
+ IN0BUF[0] = 0x01;
+ }
+ else {
+ IN0BUF[0] = 0x00;
+ }
+
+ /* Second byte sent has to be always zero */
+ IN0BUF[1] = 0;
+
+ /* Send response */
+ IN0BC = 2;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * Handle CLEAR_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_clear_feature(void)
+{
+ __xdata u8 *ep_cs;
+
+ switch (setup_data.bmRequestType) {
+ case CF_DEVICE:
+ /* Clear remote wakeup not supported: stall EP0 */
+ STALL_EP0();
+ break;
+ case CF_ENDPOINT:
+ if (setup_data.wValue == 0) {
+ /* Unstall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
+ if (!ep_cs) {
+ return false;
+ }
+ *ep_cs &= ~EPSTALL;
+ }
+ else {
+ /* Unsupported feature, stall EP0 */
+ STALL_EP0();
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ }
+
+ return true;
+}
+
+/**
+ * Handle SET_FEATURE request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_set_feature(void)
+{
+ __xdata u8 *ep_cs;
+
+ switch (setup_data.bmRequestType) {
+ case SF_DEVICE:
+ if (setup_data.wValue == 2) {
+ return true;
+ }
+ break;
+ case SF_ENDPOINT:
+ if (setup_data.wValue == 0) {
+ /* Stall the endpoint specified in wIndex */
+ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex);
+ if (!ep_cs) {
+ return false;
+ }
+ *ep_cs |= EPSTALL;
+ }
+ else {
+ /* Unsupported endpoint feature */
+ return false;
+ }
+ break;
+ default:
+ /* Vendor commands... */
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * Handle GET_DESCRIPTOR request.
+ *
+ * @return on success: true
+ * @return on failure: false
+ */
+bool usb_handle_get_descriptor(void)
+{
+ __xdata u8 descriptor_type;
+ __xdata u8 descriptor_index;
+
+ descriptor_type = (setup_data.wValue & 0xff00) >> 8;
+ descriptor_index = setup_data.wValue & 0x00ff;
+
+ switch (descriptor_type) {
+ case DESCRIPTOR_TYPE_DEVICE:
+ SUDPTRH = HI8(&device_descriptor);
+ SUDPTRL = LO8(&device_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_CONFIGURATION:
+ SUDPTRH = HI8(&config_descriptor);
+ SUDPTRL = LO8(&config_descriptor);
+ break;
+ case DESCRIPTOR_TYPE_STRING:
+ if (setup_data.wIndex == 0) {
+ /* Supply language descriptor */
+ SUDPTRH = HI8(&language_descriptor);
+ SUDPTRL = LO8(&language_descriptor);
+ }
+ else if (setup_data.wIndex == 0x0409 /* US English */) {
+ /* Supply string descriptor */
+ SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]);
+ SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]);
+ }
+ else {
+ return false;
+ }
+ break;
+ default:
+ /* Unsupported descriptor type */
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * Handle SET_INTERFACE request.
+ */
+void usb_handle_set_interface(void)
+{
+ /* Reset Data Toggle */
+ usb_reset_data_toggle(USB_DIR_IN | 2);
+ usb_reset_data_toggle(USB_DIR_OUT | 2);
+
+ /* Unstall & clear busy flag of all valid IN endpoints */
+ IN2CS = 0 | EPBSY;
+
+ /* Unstall all valid OUT endpoints, reset bytecounts */
+ OUT2CS = 0;
+ OUT2BC = 0;
+}
+
+/**
+ * Handle the arrival of a USB Control Setup Packet.
+ */
+void usb_handle_setup_data(void)
+{
+ switch (setup_data.bRequest) {
+ case GET_STATUS:
+ if (!usb_handle_get_status()) {
+ STALL_EP0();
+ }
+ break;
+ case CLEAR_FEATURE:
+ if (!usb_handle_clear_feature()) {
+ STALL_EP0();
+ }
+ break;
+ case 2: case 4:
+ /* Reserved values */
+ STALL_EP0();
+ break;
+ case SET_FEATURE:
+ if (!usb_handle_set_feature()) {
+ STALL_EP0();
+ }
+ break;
+ case SET_ADDRESS:
+ /* Handled by USB core */
+ break;
+ case SET_DESCRIPTOR:
+ /* Set Descriptor not supported. */
+ STALL_EP0();
+ break;
+ case GET_DESCRIPTOR:
+ if (!usb_handle_get_descriptor()) {
+ STALL_EP0();
+ }
+ break;
+ case GET_CONFIGURATION:
+ /* OpenULINK has only one configuration, return its index */
+ IN0BUF[0] = config_descriptor.bConfigurationValue;
+ IN0BC = 1;
+ break;
+ case SET_CONFIGURATION:
+ /* OpenULINK has only one configuration -> nothing to do */
+ break;
+ case GET_INTERFACE:
+ /* OpenULINK only has one interface, return its number */
+ IN0BUF[0] = interface_descriptor00.bInterfaceNumber;
+ IN0BC = 1;
+ break;
+ case SET_INTERFACE:
+ usb_handle_set_interface();
+ break;
+ case SYNCH_FRAME:
+ /* Isochronous endpoints not used -> nothing to do */
+ break;
+ default:
+ /* Any other requests: do nothing */
+ break;
+ }
+}
+
+/**
+ * USB initialization. Configures USB interrupts, endpoints and performs
+ * ReNumeration.
+ */
+void usb_init(void) {
+ /* Mark endpoint 2 IN & OUT as valid */
+ IN07VAL = IN2VAL;
+ OUT07VAL = OUT2VAL;
+
+ /* Make sure no isochronous endpoints are marked valid */
+ INISOVAL = 0;
+ OUTISOVAL = 0;
+
+ /* Disable isochronous endpoints. This makes the isochronous data buffers
+ * available as 8051 XDATA memory at address 0x2000 - 0x27FF */
+ ISOCTL = ISODISAB;
+
+ /* Enable USB Autovectoring */
+ USBBAV |= AVEN;
+
+ /* Enable SUDAV interrupt */
+ USBIEN |= SUDAVIE;
+
+ /* Enable EP2 OUT & IN interrupts */
+ OUT07IEN = OUT2IEN;
+ IN07IEN = IN2IEN;
+
+ /* Enable USB interrupt (EIE register) */
+ EUSB = 1;
+
+ /* Perform ReNumeration */
+ USBCS = DISCON | RENUM;
+ delay_ms(200);
+ USBCS = DISCOE | RENUM;
+}
--- /dev/null
+:040000000200733255
+:01000B0032C2
+:0100130032BA
+:01001B0032B2
+:0100230032AA
+:01002B0032A2
+:01003300329A
+:01003B003292
+:01004300328A
+:01004B003282
+:01005300327A
+:01005B003272
+:01006300326A
+:03006B0002011F70
+:0300D90002006EB4
+:05006E0012011080FEEC
+:1000DC00907F937404F0907F9C7495F0907F96744D
+:1000EC0090F0907F94E4F0907F9D747FF0907F97D8
+:1000FC00E4F0907F957440F0907F9E7442F0907F76
+:10010C0098E4F0221200DC1204FCD2AF1207C89063
+:03011C00000022BE
+:0400CC00C200C201AB
+:10011F00C021C0E0C0F0C082C083C002C003C004D1
+:10012F00C005C006C007C000C001C0D075D00053C5
+:10013F0091EF120455907FAB7401F0907FB4E044BF
+:10014F0002F0D0D0D001D000D007D006D005D00417
+:10015F00D003D002D083D082D0F0D0E0D021323281
+:10016F003232323232323232C0E0C082C083D201F8
+:10017F005391EF907FA97404F0D083D082D0E032F6
+:10018F00C0E0C082C083D2005391EF907FAA740465
+:10019F00F0D083D082D0E032323232323232323249
+:1001AF003232AA82747F5AFB7407B50300500302E0
+:1001BF000269EB2B2B9001C8730201E00201E402EC
+:1001CF0001F702020A02021D02023002024302027A
+:1001DF0056907FB422EA30E7067BB67C7F80047BA3
+:1001EF00C67C7F8B828C8322EA30E7067BB87C7FCC
+:1001FF0080047BC87C7F8B828C8322EA30E7067B6E
+:10020F00BA7C7F80047BCA7C7F8B828C8322EA300E
+:10021F00E7067BBC7C7F80047BCC7C7F8B828C83CE
+:10022F0022EA30E7067BBE7C7F80047BCE7C7F8B0F
+:10023F00828C8322EA30E7067BC07C7F80047BD0F0
+:10024F007C7F8B828C8322EA30E7067AC27B7F80A9
+:10025F00047AD27B7F8A828B832290000022AA822B
+:10026F0074105AFB74075A4203907FD7EBF0742037
+:10027F004BF022907FE8E0FABA8002800ABA81023E
+:10028F008016BA825D8022907F00E4F0907F01F0AB
+:10029F00907FB57402F0804C907F00E4F0907F0166
+:1002AF00F0907FB57402F0803B907FECE0FAA3E012
+:1002BF008A821201B1AA82AB837C008A828B838CE3
+:1002CF00F0120D90FA30E008907F007401F0800575
+:1002DF00907F00E4F0907F01E4F0907FB57402F01E
+:1002EF008002C322D322907FE8E0FA6005BA02466B
+:1002FF00800A907FB4E0FA4401F0803A907FEAE000
+:10030F00FAA3E0FB4A7027907FECE0FAA3E08A8221
+:10031F001201B1AA82AB83EA4B7002C3228A828B8D
+:10032F0083E0FC5304FE8A828B83ECF08008907F7D
+:10033F00B4E0FA4401F0D322907FE8E0FA6005BA06
+:10034F0002468010907FEAE0FAA3E0FBBA0239BBC5
+:10035F000036D322907FEAE0FAA3E0FB4A702790A1
+:10036F007FECE0FAA3E08A821201B1AA82AB83EAA2
+:10037F004B7002C3228A828B83E0FC4304018A8282
+:10038F008B83ECF08002C322D322907FEAE0A3E0BC
+:10039F00FA907FEAE0FBA3E07C00BA0102800CBA7E
+:1003AF000202801DBA0302802E807B7AB07C0D90F2
+:1003BF007FD4ECF07AB07C0D7C00907FD5EAF08092
+:1003CF00677AC27C0D907FD4ECF07AC27C0D7C00F2
+:1003DF00907FD5EAF08051907FECE0FAA3E0FC4AE1
+:1003EF0070167AE27C0D907FD4ECF07AE27C0D7C73
+:1003FF0000907FD5EAF08030907FECE0FAA3E0FC2C
+:10040F00BA0921BC041E1BEB2BFA900E3693CAA31C
+:10041F0093FB8A048B05907FD4EDF07B00907FD502
+:10042F00EAF08004C322C322D32275828212026DA6
+:10043F0075820212026D907FB87402F0907FC8E44B
+:10044F00F0907FC9F022907FE9E0FA740CB50200BA
+:10045F00500122EA2A2A9004697302049002049E32
+:10046F000204AC0204B40204AC0204C10204CA02C6
+:10047F0004C20204D70204E70204E80204F80204EB
+:10048F00FB120282500122907FB4E04401F022124D
+:10049F0002F5500122907FB4E04401F022907FB426
+:1004AF00E04401F0221203474042907FB4E0440140
+:1004BF00F02222907FB4E04401F022120399402CE5
+:1004CF00907FB4E04401F022900DC7E493907F0039
+:1004DF00F0907FB57401F02222900DCDE493907FC0
+:1004EF0000F0907FB57401F02212043922907FDE64
+:1004FF007404F0907FDF7404F0907FE0E4F0907F5D
+:10050F00E1F0907FA17401F0907FAFE04401F09093
+:10051F007FAEE04401F0907FAD7404F0907FAC7437
+:10052F0004F0D2E8907FD6740AF09000C8120D3D07
+:07053F00907FD67406F02244
+:100DB00012011001FFFFFF4051C210270001010284
+:100DC000030109022000010104803209040000022D
+:100DD000FFFFFF00070582024000000705020240F6
+:100DE00000000403090414034F00700065006E0046
+:100DF00055004C0049004E004B0014034F0070009A
+:100E000065006E0055004C0049004E004B000E037B
+:100E10003000300030003000300031001A034A004A
+:100E20005400410047002000410064006100700050
+:0E0E3000740065007200E60DFA0D0E0E1C0E29
+:10054600E5080424C0F582E4347DF583E0FA30E161
+:1005560008907F96E0FB54EFF0EA30E008907F9633
+:10056600E0FB547FF0EA30E308907F96E0FB44100E
+:10057600F0EA30E208907F96E0FA4480F0227A00B2
+:10058600E50824C0F582E4347DF583E0FB603EBBDC
+:100596000202805FBB040302061CBB200302064363
+:1005A600BB2203020673BB23030206ACBB24030271
+:1005B60006E5BB250302071DBB260302074CBB2825
+:1005C6000302077BBB290302078A02078E7B05E528
+:1005D600080424C0F582E4347DF583E0FAE50804D6
+:1005E600F58285090DC002C003120805D003D002AA
+:1005F600020790E5080424C0F582E4347DF583E023
+:100606002405FBE50804F582C002C003120951D097
+:1006160003D002020790E5080424C0F582E4347D85
+:10062600F583E0FA2405FBE50804F582850917C081
+:1006360002C003120A83D003D0020207907B02E5B0
+:10064600080424C0F582E4347DF583E0FC740225B9
+:100656000824C0F582E4347DF583E0F5228C82C05F
+:1006660002C003120C5BD003D0020207907B02E5A6
+:10067600080424C0F582E4347DF583E0FC7D007433
+:1006860002250824C0F582E4347DF583E0FFE442C8
+:1006960004EF42058C828D83C002C003120C20D069
+:1006A60003D0020207907B02E5080424C0F582E429
+:1006B600347DF583E0FC7D007402250824C0F582B4
+:1006C600E4347DF583E0FFE44204EF42058C828D3D
+:1006D60083C002C003120D0AD003D0020207907B2A
+:1006E60002E5080424C0F582E4347DF583E0FC7D50
+:1006F600007402250824C0F582E4347DF583E0FF0A
+:10070600E44204EF42058C828D83C002C003120DC1
+:100716003DD003D00280737B007A02C002C0031270
+:100726000C95AC82AD83D003D00285098275837E99
+:100736008D06EEF0E509042400F582E4347EF583A7
+:100746007D00ECF080447B02E5080424C0F582E4D9
+:10075600347DF583E0FC7402250824C0F582E43478
+:100766007DF583E0F5228C82C002C003120CD8D03E
+:1007760003D00280157B01C002C003120546D003D8
+:10078600D00280067B0180027B00EA2509F509AAD2
+:10079600087C008B057E00ED2AFAEE3CFC0ABA00C6
+:1007A600010C907FC9E0FD7E00C3EA9DEC64808E5B
+:1007B600F063F08095F04002D322EB042508F5089B
+:1007C600C32275080075090010000280FB907F9611
+:1007D600E0FA547FF0C202200207120584920280DA
+:1007E600F6907F96E0FA4480F0E509600B907FB9B9
+:0F07F600E509F010010280FB907FC9E4F080C399
+:0900D000750A00750B00750C00A7
+:10080500E582FA24C0F582E4347DF583E0F50EEA4D
+:100815000424C0F582E4347DF583E0F50F74022AE3
+:10082500FD24C0F582E4347DF583E0C4540FFE5306
+:10083500060FED24C0F582E4347DF583E0FD740FE9
+:100845005DF51074032A24C0F582E4347DF583E058
+:10085500FF74042A24C0F582E4347DF583E0F511A4
+:10086500EE60078F228E82120C5B907F97E0FE531D
+:1008750006F87F0074044EF87900AD0E7B001DBDAF
+:10088500FF011B89027C00C3EA9DEC64808BF06349
+:10089500F08095F050357A007B00BB080050199028
+:1008A5007F97EEF0E8F0EAC313FA907F99E0FC3009
+:1008B500E5034302800B80E2E50D292400F582E47F
+:1008C500347EF583EAF009890780AF89077A00ABA2
+:1008D50010751200E512B50F00503EAD0F78001DE2
+:1008E500BDFF0118A9127C00E9B50511ECB5000D95
+:1008F500EB600A4306021BE511C313F511907F97C0
+:10090500EEF074044EF0EAC313FA907F99E0FC30E0
+:10091500E503430280051280BBAC0F7D007408C35C
+:100925009CFCE49DFD8CF005F0EA8002C313D5F034
+:10093500FBFAE50D2F2400F582E4347EF583EAF019
+:10094500EB60088511228B82020C5B22E582FA247A
+:10095500C0F582E4347DF583E0F513EA0424C0F59F
+:1009650082E4347DF583E0F51474022AFD24C0F594
+:1009750082E4347DF583E0C4540FFE53060FED2465
+:10098500C0F582E4347DF583E0FD740F5DF51574E3
+:10099500032A24C0F582E4347DF583E0FF74042A3C
+:1009A50024C0F582E4347DF583E0F516EE600B8F07
+:1009B500228E82C002120C5BD002907F97E0FE531C
+:1009C50006F97F00A9137D0019B9FF011D8F037872
+:1009D50000C3EB99E864808DF063F08095F05038A2
+:1009E500EA2F240524C0F582E4347DF583E0FB7D00
+:1009F50000BD0800501FEB30E0054306018003539E
+:100A050006FE907F97EEF0EBC313FB907F9774047F
+:100A15004EF00D80DC0F80ACEA2F240524C0F58252
+:100A2500E4347DF583E0FBAA157D00EDB514005097
+:100A350041EB30E00543060180035306FEAF147811
+:100A4500001FBFFF01188D017C00E9B50711ECB54A
+:100A5500000DEA600A4306021AE516C313F516905F
+:100A65007F97EEF0EBC313FB907F9774044EF00D68
+:100A750080B9EA60088516228A82020C5B22E5822B
+:100A8500F51824C0F582E4347DF583E0F519E51801
+:100A95000424C0F582E4347DF583E0F51A7402255B
+:100AA50018FD24C0F582E4347DF583E0C4540FFEBF
+:100AB50053060FED24C0F582E4347DF583E0FD7423
+:100AC5000F5DF51B7403251824C0F582E4347DF50C
+:100AD50083E0FF7404251824C0F582E4347DF58392
+:100AE500E0F51CEE60078F228E82120C5B907F97DB
+:100AF500E0FE5306F97F007900AD197B001DBDFFAF
+:100B0500011B89007A00C3E89DEA64808BF063F0DD
+:100B15008095F0505EE51829240524C0F582E4345B
+:100B25007DF583E0F51D7B007D00BD08005031E5B6
+:100B35001D30E00543060180035306FE907F97EEC6
+:100B4500F0E51DC313F51D907F9774044EF0EBC3BC
+:100B550013FB907F99E0F830E5034303800D80CACD
+:100B6500E517292400F582E4347EF583EBF0098945
+:100B75000780868907E51829240524C0F582E43411
+:100B85007DF583E0F51D7B00AD1B751E00E51EB5EB
+:100B95001A005054E51D30E0054306018003530655
+:100BA500FEA91A7C0019B9FF011CA81E7A00E8B538
+:100BB5000111EAB5040DED600A4306021DE51CC3EB
+:100BC50013F51C907F97EEF0E51DC313F51D907F7F
+:100BD5009774044EF0EBC313FB907F99E0FA30E570
+:100BE50003430380051E80A5AC1A7A007408C39CD4
+:100BF500FCE49AFA8CF005F0EB8002C313D5F0FB08
+:100C0500FBE5172F2400F582E4347EF583EBF0ED48
+:100C15006008851C228D82020C5B22AA82AB837C34
+:100C2500007D00C3EC9AED9B502B907F97E054FB21
+:100C3500F07E00EEB50B0050030E80F7907F97E035
+:100C45004404F07E00EEB50B0050030E80F70CBC9B
+:100C550000D10D80CE22AA82907F97E0FB74FB5BCA
+:100C6500F5237B00EBB502005024E52230E0054377
+:100C7500230280035323FD907F97E523F0E522C3EC
+:100C850013F522907F9774044523F00B80D622221A
+:100C95007A00907F99E0FB30E5027A01907F99E038
+:100CA500FB30E603430202907F9AE0FB30E7034303
+:100CB5000204907F9BE0FB30E503430208907F9A96
+:100CC500E0FB53037F8A04E4FAFDEB4AF582ED4C21
+:100CD500F58322E582547FF4FA907F97E05AF07409
+:100CE5007F5522FA907F97E04AF02285820A852275
+:100CF5000B85230C2200227A567B021ABAFF011BB0
+:100D0500EA4B70F722752205752300120D67AA823A
+:100D1500AB837C007D00C3EC9AED9B501AC002C0EA
+:100D250003C004C005120CFAD005D004D003D002CC
+:100D35000CBC00E20D80DF22AA82AB837C007D0023
+:100D4500C3EC9AED9B501AC002C003C004C0051243
+:100D55000CFCD005D004D003D0020CBC00E20D8001
+:020D6500DF228B
+:03004300021B009D
+:101B000002011F0002016E0002016F00020170005D
+:101B100002017100020172000201730002017400EF
+:101B200002017500020176000201770002018F00B8
+:101B30000201A7000201A8000201A9000201AA00F7
+:101B40000201AB000201AC000201AD000201AE00D7
+:081B50000201AF000201B00028
+:100D67007A10E4FBFCE58225E0F582E58333F58321
+:100D7700EB33FBEC33FCEB9522F5F0EC95234006C7
+:090D8700FCABF0438201DADD222D
+:0600A200E478FFF6D8FD32
+:100080007900E94400601B7A00900E3E780075927A
+:1000900020E493F2A308B800020592D9F4DAF275CD
+:0200A00092FFCD
+:1000A8007800E84400600A7900759220E4F309D8E2
+:1000B800FC7800E84400600C7900902000E4F0A38C
+:0400C800D8FCD9FA8D
+:0D007300758123120DACE582600302006E62
+:100D900020F71430F6148883A88220F507E6A8838C
+:100DA00075830022E280F7E49322E022758200221C
+:00000001FF