├── commandline ├── bootloadHID.exe ├── Makefile.windows ├── usbcalls.c ├── Makefile ├── hidsdi.h ├── usbcalls.h ├── usb-windows.c ├── usb-libusb.c └── main.c ├── .gitattributes ├── firmware ├── usbdrv │ ├── usbdrvasm.asm │ ├── oddebug.c │ ├── oddebug.h │ ├── usbportability.h │ ├── USB-ID-FAQ.txt │ ├── USB-IDs-for-free.txt │ ├── CommercialLicense.txt │ ├── asmcommon.inc │ ├── Readme.txt │ ├── usbdrvasm.S │ ├── usbdrvasm16.inc │ ├── Changelog.txt │ ├── usbdrvasm20.inc │ ├── usbdrvasm12.inc │ └── usbdrvasm165.inc ├── Makefile ├── main.c ├── bootloaderconfig.h └── usbconfig.h ├── Changelog.txt ├── .gitignore └── Readme.txt /commandline/bootloadHID.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteneon/bootloadHID/HEAD/commandline/bootloadHID.exe -------------------------------------------------------------------------------- /commandline/Makefile.windows: -------------------------------------------------------------------------------- 1 | # Name: Makefile.windows 2 | # Project: Automator 3 | # Author: Christian Starkjohann 4 | # Creation Date: 2006-02-20 5 | # Tabsize: 4 6 | # Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | # License: Proprietary, free under certain conditions. See Documentation. 8 | # This Revision: $Id$ 9 | 10 | # You may use this file with 11 | # make -f Makefile.windows 12 | # on Windows with MinGW instead of editing the main Makefile. 13 | 14 | include Makefile 15 | 16 | USBFLAGS= 17 | USBLIBS= -lhid -lusb -lsetupapi 18 | EXE_SUFFIX= .exe 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /commandline/usbcalls.c: -------------------------------------------------------------------------------- 1 | /* Name: usbcalls.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* This file includes the appropriate implementation based on platform 12 | * specific defines. 13 | */ 14 | 15 | #if defined(WIN32) 16 | # include "usb-windows.c" 17 | #else 18 | /* e.g. defined(__APPLE__) */ 19 | # include "usb-libusb.c" 20 | #endif 21 | -------------------------------------------------------------------------------- /firmware/usbdrv/usbdrvasm.asm: -------------------------------------------------------------------------------- 1 | /* Name: usbdrvasm.asm 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-03-01 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* 11 | General Description: 12 | The IAR compiler/assembler system prefers assembler files with file extension 13 | ".asm". We simply provide this file as an alias for usbdrvasm.S. 14 | 15 | Thanks to Oleg Semyonov for his help with the IAR tools port! 16 | */ 17 | 18 | #include "usbdrvasm.S" 19 | 20 | end 21 | -------------------------------------------------------------------------------- /firmware/usbdrv/oddebug.c: -------------------------------------------------------------------------------- 1 | /* Name: oddebug.c 2 | * Project: AVR library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2005-01-16 5 | * Tabsize: 4 6 | * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | #include "oddebug.h" 11 | 12 | #if DEBUG_LEVEL > 0 13 | 14 | #warning "Never compile production devices with debugging enabled" 15 | 16 | static void uartPutc(char c) 17 | { 18 | while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ 19 | ODDBG_UDR = c; 20 | } 21 | 22 | static uchar hexAscii(uchar h) 23 | { 24 | h &= 0xf; 25 | if(h >= 10) 26 | h += 'a' - (uchar)10 - '0'; 27 | h += '0'; 28 | return h; 29 | } 30 | 31 | static void printHex(uchar c) 32 | { 33 | uartPutc(hexAscii(c >> 4)); 34 | uartPutc(hexAscii(c)); 35 | } 36 | 37 | void odDebug(uchar prefix, uchar *data, uchar len) 38 | { 39 | printHex(prefix); 40 | uartPutc(':'); 41 | while(len--){ 42 | uartPutc(' '); 43 | printHex(*data++); 44 | } 45 | uartPutc('\r'); 46 | uartPutc('\n'); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /commandline/Makefile: -------------------------------------------------------------------------------- 1 | # Name: Makefile 2 | # Project: Automator 3 | # Author: Christian Starkjohann 4 | # Creation Date: 2006-02-01 5 | # Tabsize: 4 6 | # Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | # License: Proprietary, free under certain conditions. See Documentation. 8 | # This Revision: $Id$ 9 | 10 | # Please read the definitions below and edit them as appropriate for your 11 | # system: 12 | 13 | # Use the following 3 lines on Unix and Mac OS X: 14 | USBFLAGS= `libusb-config --cflags` 15 | USBLIBS= `libusb-config --libs` 16 | EXE_SUFFIX= 17 | 18 | # Use the following 3 lines on Windows and comment out the 3 above: 19 | #USBFLAGS= 20 | #USBLIBS= -lhid -lusb -lsetupapi 21 | #EXE_SUFFIX= .exe 22 | 23 | CC= gcc 24 | CXX= g++ 25 | CFLAGS= -O2 -Wall $(USBFLAGS) 26 | LIBS= $(USBLIBS) 27 | ARCH_COMPILE= 28 | ARCH_LINK= 29 | 30 | OBJ= main.o usbcalls.o 31 | PROGRAM= bootloadHID$(EXE_SUFFIX) 32 | 33 | all: $(PROGRAM) 34 | 35 | $(PROGRAM): $(OBJ) 36 | $(CC) $(ARCH_LINK) $(CFLAGS) -o $(PROGRAM) $(OBJ) $(LIBS) 37 | 38 | 39 | strip: $(PROGRAM) 40 | strip $(PROGRAM) 41 | 42 | clean: 43 | rm -f $(OBJ) $(PROGRAM) 44 | 45 | .c.o: 46 | $(CC) $(ARCH_COMPILE) $(CFLAGS) -c $*.c -o $*.o 47 | -------------------------------------------------------------------------------- /Changelog.txt: -------------------------------------------------------------------------------- 1 | This file documents changes in the software and firmware of bootloaderHID. 2 | New entries are always appended to the end of the file. Scroll down to the 3 | bottom to see the most recent changes. 4 | 5 | 6 | * Release 2007-06-25 7 | 8 | - Added command line option to leave boot loader. 9 | - Added compile time option in firmware whether "-r" option is supported. 10 | Saves code size if not supported. 11 | - Define USB_PUBLIC to static and include usbdrv.c in order to save code size 12 | This is necessary so that even gcc 4 generated code fits into 2k flash. 13 | - Fixed FLASHEND computation for >32k devices (cast to long). 14 | - Updated to newest version of driver. 15 | 16 | * Release 2007-10-23 17 | 18 | - Updated to newest USB driver. 19 | - Ported back some improvements from USBaspLoader. 20 | - Code size optimization to make this boot loader usable with the 12.8 MHz 21 | module. 22 | 23 | * Release 2008-10-22 24 | 25 | - Code size improvements. 26 | - Don't add 0x20 if I/O registers are in memory addressable area in usbconfig.h 27 | - Example config should check jumper status on PIND, not PORTD. 28 | 29 | * Release 2008-11-26 30 | 31 | - Allow option "-r" to bootloadHID alone, even without uploading a file. 32 | - Added optimizations for gcc 4.3. 33 | 34 | * Release 2010-07-29 35 | 36 | - Updated to latest driver. 37 | - Fixed compiler errors in latest gcc/avr-libc. 38 | 39 | * Release 2012-12-08 40 | -------------------------------------------------------------------------------- /commandline/hidsdi.h: -------------------------------------------------------------------------------- 1 | /* Name: hidsdi.h 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description 13 | This file is a replacement for hidsdi.h from the Windows DDK. It defines some 14 | of the types and function prototypes of this header for our project. If you 15 | have the Windows DDK version of this file or a version shipped with MinGW, use 16 | that instead. 17 | */ 18 | 19 | #ifndef _HIDSDI_H 20 | #define _HIDSDI_H 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | typedef struct{ 28 | ULONG Size; 29 | USHORT VendorID; 30 | USHORT ProductID; 31 | USHORT VersionNumber; 32 | }HIDD_ATTRIBUTES; 33 | 34 | void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid); 35 | 36 | BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes); 37 | 38 | BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 39 | BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 40 | BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 41 | 42 | BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen); 43 | BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen); 44 | 45 | BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers); 46 | BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers); 47 | 48 | #include 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /firmware/usbdrv/oddebug.h: -------------------------------------------------------------------------------- 1 | /* Name: oddebug.h 2 | * Project: AVR library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2005-01-16 5 | * Tabsize: 4 6 | * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | #ifndef __oddebug_h_included__ 11 | #define __oddebug_h_included__ 12 | 13 | /* 14 | General Description: 15 | This module implements a function for debug logs on the serial line of the 16 | AVR microcontroller. Debugging can be configured with the define 17 | 'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging 18 | calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is 19 | 2, DBG1 and DBG2 logs will be printed. 20 | 21 | A debug log consists of a label ('prefix') to indicate which debug log created 22 | the output and a memory block to dump in hex ('data' and 'len'). 23 | */ 24 | 25 | 26 | #ifndef F_CPU 27 | # define F_CPU 12000000 /* 12 MHz */ 28 | #endif 29 | 30 | /* make sure we have the UART defines: */ 31 | #include "usbportability.h" 32 | 33 | #ifndef uchar 34 | # define uchar unsigned char 35 | #endif 36 | 37 | #if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ 38 | # warning "Debugging disabled because device has no UART" 39 | # undef DEBUG_LEVEL 40 | #endif 41 | 42 | #ifndef DEBUG_LEVEL 43 | # define DEBUG_LEVEL 0 44 | #endif 45 | 46 | /* ------------------------------------------------------------------------- */ 47 | 48 | #if DEBUG_LEVEL > 0 49 | # define DBG1(prefix, data, len) odDebug(prefix, data, len) 50 | #else 51 | # define DBG1(prefix, data, len) 52 | #endif 53 | 54 | #if DEBUG_LEVEL > 1 55 | # define DBG2(prefix, data, len) odDebug(prefix, data, len) 56 | #else 57 | # define DBG2(prefix, data, len) 58 | #endif 59 | 60 | /* ------------------------------------------------------------------------- */ 61 | 62 | #if DEBUG_LEVEL > 0 63 | extern void odDebug(uchar prefix, uchar *data, uchar len); 64 | 65 | /* Try to find our control registers; ATMEL likes to rename these */ 66 | 67 | #if defined UBRR 68 | # define ODDBG_UBRR UBRR 69 | #elif defined UBRRL 70 | # define ODDBG_UBRR UBRRL 71 | #elif defined UBRR0 72 | # define ODDBG_UBRR UBRR0 73 | #elif defined UBRR0L 74 | # define ODDBG_UBRR UBRR0L 75 | #endif 76 | 77 | #if defined UCR 78 | # define ODDBG_UCR UCR 79 | #elif defined UCSRB 80 | # define ODDBG_UCR UCSRB 81 | #elif defined UCSR0B 82 | # define ODDBG_UCR UCSR0B 83 | #endif 84 | 85 | #if defined TXEN 86 | # define ODDBG_TXEN TXEN 87 | #else 88 | # define ODDBG_TXEN TXEN0 89 | #endif 90 | 91 | #if defined USR 92 | # define ODDBG_USR USR 93 | #elif defined UCSRA 94 | # define ODDBG_USR UCSRA 95 | #elif defined UCSR0A 96 | # define ODDBG_USR UCSR0A 97 | #endif 98 | 99 | #if defined UDRE 100 | # define ODDBG_UDRE UDRE 101 | #else 102 | # define ODDBG_UDRE UDRE0 103 | #endif 104 | 105 | #if defined UDR 106 | # define ODDBG_UDR UDR 107 | #elif defined UDR0 108 | # define ODDBG_UDR UDR0 109 | #endif 110 | 111 | static inline void odDebugInit(void) 112 | { 113 | ODDBG_UCR |= (1<8M crystal) 35 | # | | +--------------- SUT 1..0 (crystal osc, BOD enabled) 36 | # | +------------------ BODEN (BrownOut Detector enabled) 37 | # +-------------------- BODLEVEL (2.7V) 38 | 39 | ############################################################################### 40 | 41 | AVRDUDE = avrdude -c usbtiny -p $(DEVICE) 42 | 43 | LDFLAGS += -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS) 44 | 45 | # Omit -fno-* options when using gcc 3, it does not support them. 46 | COMPILE = avr-gcc -Wall -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -Iusbdrv -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DDEBUG_LEVEL=0 # -DTEST_MODE 47 | # NEVER compile the final product with debugging! Any debug output will 48 | # distort timing so that the specs can't be met. 49 | 50 | OBJECTS = usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o 51 | 52 | 53 | # symbolic targets: 54 | all: main.hex 55 | 56 | .c.o: 57 | $(COMPILE) -c $< -o $@ 58 | 59 | .S.o: 60 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 61 | # "-x assembler-with-cpp" should not be necessary since this is the default 62 | # file type for the .S (with capital S) extension. However, upper case 63 | # characters are not always preserved on Windows. To ensure WinAVR 64 | # compatibility define the file type manually. 65 | 66 | .c.s: 67 | $(COMPILE) -S $< -o $@ 68 | 69 | flash: all 70 | $(AVRDUDE) -U flash:w:main.hex:i 71 | 72 | readflash: 73 | $(AVRDUDE) -U flash:r:read.hex:i 74 | 75 | fuse: 76 | $(AVRDUDE) -U hfuse:w:$(FUSEH):m -U lfuse:w:$(FUSEL):m 77 | 78 | lock: 79 | $(AVRDUDE) -U lock:w:0x2f:m 80 | 81 | read_fuses: 82 | $(UISP) --rd_fuses 83 | 84 | clean: 85 | rm -f main.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s 86 | 87 | # file targets: 88 | main.bin: $(OBJECTS) 89 | $(COMPILE) -o main.bin $(OBJECTS) $(LDFLAGS) 90 | 91 | main.hex: main.bin 92 | rm -f main.hex main.eep.hex 93 | avr-objcopy -j .text -j .data -O ihex main.bin main.hex 94 | avr-size main.hex 95 | 96 | disasm: main.bin 97 | avr-objdump -d main.bin 98 | 99 | cpp: 100 | $(COMPILE) -E main.c 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /commandline/usbcalls.h: -------------------------------------------------------------------------------- 1 | /* Name: usbcalls.h 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | #ifndef __usbcalls_h_INCLUDED__ 12 | #define __usbcalls_h_INCLUDED__ 13 | 14 | /* 15 | General Description: 16 | This module implements an abstraction layer for access to USB/HID communication 17 | functions. An implementation based on libusb (portable to Linux, FreeBSD and 18 | Mac OS X) and a native implementation for Windows are provided. 19 | */ 20 | 21 | /* ------------------------------------------------------------------------ */ 22 | 23 | #define USB_HID_REPORT_TYPE_INPUT 1 24 | #define USB_HID_REPORT_TYPE_OUTPUT 2 25 | #define USB_HID_REPORT_TYPE_FEATURE 3 26 | /* Numeric constants for 'reportType' parameters */ 27 | 28 | #define USB_ERROR_NONE 0 29 | #define USB_ERROR_ACCESS 1 30 | #define USB_ERROR_NOTFOUND 2 31 | #define USB_ERROR_BUSY 16 32 | #define USB_ERROR_IO 5 33 | /* These are the error codes which can be returned by functions of this 34 | * module. 35 | */ 36 | 37 | /* ------------------------------------------------------------------------ */ 38 | 39 | typedef struct usbDevice usbDevice_t; 40 | /* This type represents a USB device internally. Only opaque pointers to this 41 | * type are available outside the module implementation. 42 | */ 43 | 44 | /* ------------------------------------------------------------------------ */ 45 | 46 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs); 47 | /* This function opens a USB device. 'vendor' and 'product' are the numeric 48 | * Vendor-ID and Product-ID of the device we want to open. If 'vendorName' and 49 | * 'productName' are both not NULL, only devices with matching manufacturer- 50 | * and product name strings are accepted. If the device uses report IDs, 51 | * 'usesReportIDs' must be set to a non-zero value. 52 | * Returns: If a matching device has been found, USB_ERROR_NONE is returned and 53 | * '*device' is set to an opaque pointer representing the device. The device 54 | * must be closed with usbCloseDevice(). If the device has not been found or 55 | * opening failed, an error code is returned. 56 | */ 57 | void usbCloseDevice(usbDevice_t *device); 58 | /* Every device opened with usbOpenDevice() must be closed with this function. 59 | */ 60 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len); 61 | /* This function sends a report to the device. 'reportType' specifies the type 62 | * of report (see USB_HID_REPORT_TYPE* constants). The report ID must be in the 63 | * first byte of buffer and the length 'len' of the report is specified 64 | * including this report ID. If no report IDs are used, buffer[0] must be set 65 | * to 0 (dummy report ID). 66 | * Returns: 0 on success, an error code otherwise. 67 | */ 68 | int usbGetReport(usbDevice_t *device, int reportType, int reportID, char *buffer, int *len); 69 | /* This function obtains a report from the device. 'reportType' specifies the 70 | * type of report (see USB_HID_REPORT_TYPE* constants). The requested report ID 71 | * is passed in 'reportID'. The caller must pass a buffer of the size of the 72 | * expected report in 'buffer' and initialize the variable in '*len' to the 73 | * total size of this buffer. Upon successful return, the report (prefixed with 74 | * a report ID) is in 'buffer' and the actual length of the report is returned 75 | * in '*len'. 76 | * Returns: 0 on success, an error code otherwise. 77 | */ 78 | 79 | /* ------------------------------------------------------------------------ */ 80 | 81 | #endif /* __usbcalls_h_INCLUDED__ */ 82 | -------------------------------------------------------------------------------- /firmware/usbdrv/usbportability.h: -------------------------------------------------------------------------------- 1 | /* Name: usbportability.h 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2008-06-17 5 | * Tabsize: 4 6 | * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* 11 | General Description: 12 | This header is intended to contain all (or at least most of) the compiler 13 | and library dependent stuff. The C code is written for avr-gcc and avr-libc. 14 | The API of other development environments is converted to gcc's and avr-libc's 15 | API by means of defines. 16 | 17 | This header also contains all system includes since they depend on the 18 | development environment. 19 | 20 | Thanks to Oleg Semyonov for his help with the IAR tools port! 21 | */ 22 | 23 | #ifndef __usbportability_h_INCLUDED__ 24 | #define __usbportability_h_INCLUDED__ 25 | 26 | /* We check explicitly for IAR and CodeVision. Default is avr-gcc/avr-libc. */ 27 | 28 | /* ------------------------------------------------------------------------- */ 29 | #if defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ /* check for IAR */ 30 | /* ------------------------------------------------------------------------- */ 31 | 32 | #ifndef ENABLE_BIT_DEFINITIONS 33 | # define ENABLE_BIT_DEFINITIONS 1 /* Enable bit definitions */ 34 | #endif 35 | 36 | /* Include IAR headers */ 37 | #include 38 | #ifndef __IAR_SYSTEMS_ASM__ 39 | # include 40 | #endif 41 | 42 | #define __attribute__(arg) /* not supported on IAR */ 43 | 44 | #ifdef __IAR_SYSTEMS_ASM__ 45 | # define __ASSEMBLER__ /* IAR does not define standard macro for asm */ 46 | #endif 47 | 48 | #ifdef __HAS_ELPM__ 49 | # define PROGMEM __farflash 50 | #else 51 | # define PROGMEM __flash 52 | #endif 53 | 54 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 55 | 56 | /* The following definitions are not needed by the driver, but may be of some 57 | * help if you port a gcc based project to IAR. 58 | */ 59 | #define cli() __disable_interrupt() 60 | #define sei() __enable_interrupt() 61 | #define wdt_reset() __watchdog_reset() 62 | #define _BV(x) (1 << (x)) 63 | 64 | /* assembler compatibility macros */ 65 | #define nop2 rjmp $+2 /* jump to next instruction */ 66 | #define XL r26 67 | #define XH r27 68 | #define YL r28 69 | #define YH r29 70 | #define ZL r30 71 | #define ZH r31 72 | #define lo8(x) LOW(x) 73 | #define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ 74 | 75 | /* Depending on the device you use, you may get problems with the way usbdrv.h 76 | * handles the differences between devices. Since IAR does not use #defines 77 | * for MCU registers, we can't check for the existence of a particular 78 | * register with an #ifdef. If the autodetection mechanism fails, include 79 | * definitions for the required USB_INTR_* macros in your usbconfig.h. See 80 | * usbconfig-prototype.h and usbdrv.h for details. 81 | */ 82 | 83 | /* ------------------------------------------------------------------------- */ 84 | #elif __CODEVISIONAVR__ /* check for CodeVision AVR */ 85 | /* ------------------------------------------------------------------------- */ 86 | /* This port is not working (yet) */ 87 | 88 | /* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ 89 | 90 | #include 91 | #include 92 | 93 | #define __attribute__(arg) /* not supported on IAR */ 94 | 95 | #define PROGMEM __flash 96 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 97 | 98 | #ifndef __ASSEMBLER__ 99 | static inline void cli(void) 100 | { 101 | #asm("cli"); 102 | } 103 | static inline void sei(void) 104 | { 105 | #asm("sei"); 106 | } 107 | #endif 108 | #define _delay_ms(t) delay_ms(t) 109 | #define _BV(x) (1 << (x)) 110 | #define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ 111 | 112 | #define macro .macro 113 | #define endm .endmacro 114 | #define nop2 rjmp .+0 /* jump to next instruction */ 115 | 116 | /* ------------------------------------------------------------------------- */ 117 | #else /* default development environment is avr-gcc/avr-libc */ 118 | /* ------------------------------------------------------------------------- */ 119 | 120 | #include 121 | #ifdef __ASSEMBLER__ 122 | # define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ 123 | #else 124 | # include 125 | #endif 126 | 127 | #if USB_CFG_DRIVER_FLASH_PAGE 128 | # define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) 129 | #else 130 | # define USB_READ_FLASH(addr) pgm_read_byte(addr) 131 | #endif 132 | 133 | #define macro .macro 134 | #define endm .endm 135 | #define nop2 rjmp .+0 /* jump to next instruction */ 136 | 137 | #endif /* development environment */ 138 | 139 | /* for conveniecne, ensure that PRG_RDB exists */ 140 | #ifndef PRG_RDB 141 | # define PRG_RDB(addr) USB_READ_FLASH(addr) 142 | #endif 143 | #endif /* __usbportability_h_INCLUDED__ */ 144 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | This is the README file for bootloadHID. 2 | 3 | BootloadHID is a USB boot loader for AVR microcontrollers. It can be used on 4 | all AVRs with at least 2 kB of boot loader section, e.g. the popular ATMega8. 5 | The firmware is flashed into the upper 2 kB of the flash memory and takes 6 | control immediately after reset. If a certain hardware condition is met 7 | (this condition can be configured, e.g. a jumper), the boot loader waits for 8 | data on the USB interface and loads it into the remaining part of the flash 9 | memory. If the condition is not met, control is passed to the loaded firmware. 10 | 11 | This boot loader is similar to Thomas Fischl's avrusbboot, except that it 12 | is built on top of the HID device class. This implementation is more user 13 | friendly on Windows, since no kernel level drivers need to be installed. 14 | 15 | 16 | FILES IN THE DISTRIBUTION 17 | ========================= 18 | Readme.txt ........ The file you are currently reading. 19 | firmware .......... Source code of the controller firmware. 20 | firmware/usbdrv ... USB driver -- See Readme.txt in that directory for info 21 | commandline ....... Source code of the host software (downloader). 22 | License.txt ....... Public license (GPL2) for all contents of this project. 23 | Changelog.txt ..... Logfile documenting changes in soft-, firm- and hardware. 24 | 25 | 26 | BUILDING AND INSTALLING 27 | ======================= 28 | This project can be built on Unix (Linux, FreeBSD or Mac OS X) or Windows. 29 | 30 | For all platforms, you must first describe your hardware in the file 31 | "firmware/bootloaderconfig.h". See the documentation in the example provided 32 | with this distribution for details. Then edit "firmware/Makefile" to reflect 33 | the target device, the device's boot loader address and fuse bit values. Our 34 | examples are for an ATMega8. 35 | 36 | Building on Windows: 37 | You need WinAVR for the firmware and MinGW and MSYS for the host software. 38 | Visual C++ instead of MinGW might work as well, but we prefer free development 39 | environments. The packages can be downloaded from: 40 | WinAVR: http://winavr.sourceforge.net/ 41 | MinGW and MSYS: http://www.mingw.org/ 42 | Install the packages in any order and follow the installation instructions 43 | of the respective package. Hint: Use the big ready-made archives for MinGW 44 | and MSYS, not the individual packages. You can identify these by their file 45 | size. 46 | 47 | To build the firmware with WinAVR, change into the "firmware" directory, 48 | check whether you need to edit the "Makefile" (e.g. change the ISP upload 49 | tool) and type "make" to compile the source code. Before you upload the code 50 | to the device with "make flash", you should set the fuses with "make fuse". 51 | To protect the boot loader from overwriting itself, set the lock bits with 52 | "make lock" after uploading the firmware. 53 | 54 | In order to build the command line tool, change to the "commandline" directory 55 | and edit the "Makefile". Comment out the definitions which are for Unix only 56 | and uncomment those for Windows. Then type "make" to build "bootloadHID.exe". 57 | Alternatively, if everything is installed in the default locations, you 58 | can type "make -f Makefile.windows". 59 | 60 | Building on Unix (Linux, FreeBSD and Mac): 61 | You need the GNU toolchain and avr-libc for the firmware and libusb for the 62 | command line tool. The packages can be downloaded from: 63 | GNU toolchain and avr-libc: See 64 | http://www.nongnu.org/avr-libc/user-manual/install_tools.html 65 | libusb: http://libusb.sourceforge.net/ 66 | Install the packages in any order and follow the instructions for the 67 | respective package. 68 | 69 | To build the firmware, change to the "firmware" directory, edit "Makefile" 70 | to use the programmer of your choice and type "make" to compile the source 71 | code. Before you upload the code to the device with "make flash", you 72 | should set the fuses with "make fuse". Then protect the boot loader firmware 73 | with "make lock". 74 | 75 | In order to build the application, make sure that the command 'libusb-config' 76 | is in your search path. Then change directory to "commandline", check whether 77 | you need to edit "Makefile" (should not be necessary on Unix) and type "make" 78 | to build the "bootloadHID" tool. 79 | 80 | 81 | WORKING WITH THE BOOT LOADER 82 | ============================ 83 | The boot loader is quite easy to use. Set the jumper (or whatever condition 84 | you have configured) for boot loading on the target hardware, connect it to 85 | the host computer and (if not bus powered) issue a Reset on the AVR. 86 | 87 | The firmware can now be flashed with the "bootloadHID" tool. It accepts only 88 | one parameter: an Intel-Hex file containing the code to be loaded. 89 | 90 | 91 | USING THE USB DRIVER FOR YOUR OWN PROJECTS 92 | ========================================== 93 | This project is not intended as a reference implementation. If you want to 94 | use AVR-USB in your own projects, please see 95 | * PowerSwitch for the most basic example, 96 | * Automator for an HID example or 97 | * AVR-Doper for a very complex example on how to simulate a serial 98 | interface (virtual COM port). 99 | All these projects can be downloaded from http://www.obdev.at/avrusb/ 100 | 101 | 102 | ABOUT THE LICENSE 103 | ================= 104 | It is our intention to make our USB driver and this demo application 105 | available to everyone. Moreover, we want to make a broad range of USB 106 | projects and ideas for USB devices available to the general public. We 107 | therefore want that all projects built with our USB driver are published 108 | under an Open Source license. Our license for the USB driver and demo code is 109 | the GNU General Public License Version 2 (GPL2). See the file "License.txt" 110 | for details. 111 | 112 | If you don't want to publish your source code under the GPL2, you can simply 113 | pay money for AVR-USB. As an additional benefit you get USB PIDs for free, 114 | licensed exclusively to you. See the file "CommercialLicense.txt" for details. 115 | 116 | 117 | MORE INFORMATION 118 | ================ 119 | For more information about Objective Development's firmware-only USB driver 120 | for Atmel's AVR microcontrollers please visit the URL 121 | 122 | http://www.obdev.at/products/avrusb/ 123 | 124 | A technical documentation of the driver's interface can be found in the 125 | file "firmware/usbdrv/usbdrv.h". 126 | 127 | 128 | -- 129 | (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH. 130 | http://www.obdev.at/ 131 | -------------------------------------------------------------------------------- /commandline/usb-windows.c: -------------------------------------------------------------------------------- 1 | /* Name: usb-windows.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description: 13 | This module implements USB HID report receiving and sending with native 14 | Windows API functions. If you compile with MinGW, no software from Microsoft 15 | (no DDK) is needed. We supply the missing types and function prototypes in 16 | hidsdi.h. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include "hidsdi.h" 23 | #include 24 | 25 | #include "usbcalls.h" 26 | 27 | #ifdef DEBUG 28 | #define DEBUG_PRINT(arg) printf arg 29 | #else 30 | #define DEBUG_PRINT(arg) 31 | #endif 32 | 33 | /* ------------------------------------------------------------------------ */ 34 | 35 | static void convertUniToAscii(char *buffer) 36 | { 37 | unsigned short *uni = (void *)buffer; 38 | char *ascii = buffer; 39 | 40 | while(*uni != 0){ 41 | if(*uni >= 256){ 42 | *ascii++ = '?'; 43 | }else{ 44 | *ascii++ = *uni++; 45 | } 46 | } 47 | *ascii++ = 0; 48 | } 49 | 50 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs) 51 | { 52 | GUID hidGuid; /* GUID for HID driver */ 53 | HDEVINFO deviceInfoList; 54 | SP_DEVICE_INTERFACE_DATA deviceInfo; 55 | SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL; 56 | DWORD size; 57 | int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */ 58 | int errorCode = USB_ERROR_NOTFOUND; 59 | HANDLE handle = INVALID_HANDLE_VALUE; 60 | HIDD_ATTRIBUTES deviceAttributes; 61 | 62 | HidD_GetHidGuid(&hidGuid); 63 | deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 64 | deviceInfo.cbSize = sizeof(deviceInfo); 65 | for(i=0;;i++){ 66 | if(handle != INVALID_HANDLE_VALUE){ 67 | CloseHandle(handle); 68 | handle = INVALID_HANDLE_VALUE; 69 | } 70 | if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) 71 | break; /* no more entries */ 72 | /* first do a dummy call just to determine the actual size required */ 73 | SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL); 74 | if(deviceDetails != NULL) 75 | free(deviceDetails); 76 | deviceDetails = malloc(size); 77 | deviceDetails->cbSize = sizeof(*deviceDetails); 78 | /* this call is for real: */ 79 | SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL); 80 | DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath)); 81 | /* attempt opening for R/W -- we don't care about devices which can't be accessed */ 82 | handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); 83 | if(handle == INVALID_HANDLE_VALUE){ 84 | DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError())); 85 | /* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */ 86 | continue; 87 | } 88 | deviceAttributes.Size = sizeof(deviceAttributes); 89 | HidD_GetAttributes(handle, &deviceAttributes); 90 | DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes.VendorID, deviceAttributes.ProductID)); 91 | if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product) 92 | continue; /* ignore this device */ 93 | errorCode = USB_ERROR_NOTFOUND; 94 | if(vendorName != NULL && productName != NULL){ 95 | char buffer[512]; 96 | if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ 97 | DEBUG_PRINT(("error obtaining vendor name\n")); 98 | errorCode = USB_ERROR_IO; 99 | continue; 100 | } 101 | convertUniToAscii(buffer); 102 | DEBUG_PRINT(("vendorName = \"%s\"\n", buffer)); 103 | if(strcmp(vendorName, buffer) != 0) 104 | continue; 105 | if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){ 106 | DEBUG_PRINT(("error obtaining product name\n")); 107 | errorCode = USB_ERROR_IO; 108 | continue; 109 | } 110 | convertUniToAscii(buffer); 111 | DEBUG_PRINT(("productName = \"%s\"\n", buffer)); 112 | if(strcmp(productName, buffer) != 0) 113 | continue; 114 | } 115 | break; /* we have found the device we are looking for! */ 116 | } 117 | SetupDiDestroyDeviceInfoList(deviceInfoList); 118 | if(deviceDetails != NULL) 119 | free(deviceDetails); 120 | if(handle != INVALID_HANDLE_VALUE){ 121 | *device = (usbDevice_t *)handle; 122 | errorCode = 0; 123 | } 124 | return errorCode; 125 | } 126 | 127 | /* ------------------------------------------------------------------------ */ 128 | 129 | void usbCloseDevice(usbDevice_t *device) 130 | { 131 | CloseHandle((HANDLE)device); 132 | } 133 | 134 | /* ------------------------------------------------------------------------ */ 135 | 136 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) 137 | { 138 | HANDLE handle = (HANDLE)device; 139 | BOOLEAN rval = 0; 140 | DWORD bytesWritten; 141 | 142 | switch(reportType){ 143 | case USB_HID_REPORT_TYPE_INPUT: 144 | break; 145 | case USB_HID_REPORT_TYPE_OUTPUT: 146 | rval = WriteFile(handle, buffer, len, &bytesWritten, NULL); 147 | break; 148 | case USB_HID_REPORT_TYPE_FEATURE: 149 | rval = HidD_SetFeature(handle, buffer, len); 150 | break; 151 | } 152 | return rval == 0 ? USB_ERROR_IO : 0; 153 | } 154 | 155 | /* ------------------------------------------------------------------------ */ 156 | 157 | int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) 158 | { 159 | HANDLE handle = (HANDLE)device; 160 | BOOLEAN rval = 0; 161 | DWORD bytesRead; 162 | 163 | switch(reportType){ 164 | case USB_HID_REPORT_TYPE_INPUT: 165 | buffer[0] = reportNumber; 166 | rval = ReadFile(handle, buffer, *len, &bytesRead, NULL); 167 | if(rval) 168 | *len = bytesRead; 169 | break; 170 | case USB_HID_REPORT_TYPE_OUTPUT: 171 | break; 172 | case USB_HID_REPORT_TYPE_FEATURE: 173 | buffer[0] = reportNumber; 174 | rval = HidD_GetFeature(handle, buffer, *len); 175 | break; 176 | } 177 | return rval == 0 ? USB_ERROR_IO : 0; 178 | } 179 | 180 | /* ------------------------------------------------------------------------ */ 181 | -------------------------------------------------------------------------------- /firmware/usbdrv/USB-ID-FAQ.txt: -------------------------------------------------------------------------------- 1 | Version 2012-07-09 2 | 3 | ========================== 4 | WHY DO WE NEED THESE IDs? 5 | ========================== 6 | 7 | USB is more than a low level protocol for data transport. It also defines a 8 | common set of requests which must be understood by all devices. And as part 9 | of these common requests, the specification defines data structures, the 10 | USB Descriptors, which are used to describe the properties of the device. 11 | 12 | From the perspective of an operating system, it is therefore possible to find 13 | out basic properties of a device (such as e.g. the manufacturer and the name 14 | of the device) without a device-specific driver. This is essential because 15 | the operating system can choose a driver to load based on this information 16 | (Plug-And-Play). 17 | 18 | Among the most important properties in the Device Descriptor are the USB 19 | Vendor- and Product-ID. Both are 16 bit integers. The most simple form of 20 | driver matching is based on these IDs. The driver announces the Vendor- and 21 | Product-IDs of the devices it can handle and the operating system loads the 22 | appropriate driver when the device is connected. 23 | 24 | It is obvious that this technique only works if the pair Vendor- plus 25 | Product-ID is unique: Only devices which require the same driver can have the 26 | same pair of IDs. 27 | 28 | 29 | ===================================================== 30 | HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? 31 | ===================================================== 32 | 33 | Since it is so important that USB IDs are unique, the USB Implementers Forum, 34 | Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by 35 | law to build a device and assign it any random numbers as IDs. Usb.org 36 | therefore needs an agreement to regulate the use of USB IDs. The agreement 37 | binds only parties who agreed to it, of course. Everybody else is free to use 38 | any numbers for their IDs. 39 | 40 | So how can usb.org ensure that every manufacturer of USB devices enters into 41 | an agreement with them? They do it via trademark licensing. Usb.org has 42 | registered the trademark "USB", all associated logos and related terms. If 43 | you want to put an USB logo on your product or claim that it is USB 44 | compliant, you must license these trademarks from usb.org. And this is where 45 | you enter into an agreement. See the "USB-IF Trademark License Agreement and 46 | Usage Guidelines for the USB-IF Logo" at 47 | http://www.usb.org/developers/logo_license/. 48 | 49 | Licensing the USB trademarks requires that you buy a USB Vendor-ID from 50 | usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org 51 | (yearly fee of ca. 4,000 USD) and that you meet all the technical 52 | specifications from the USB spec. 53 | 54 | This means that most hobbyists and small companies will never be able to 55 | become USB compliant, just because membership is so expensive. And you can't 56 | be compliant with a driver based on V-USB anyway, because the AVR's port pins 57 | don't meet the electrical specifications for USB. So, in principle, all 58 | hobbyists and small companies are free to choose any random numbers for their 59 | IDs. They have nothing to lose... 60 | 61 | There is one exception worth noting, though: If you use a sub-component which 62 | implements USB, the vendor of the sub-components may guarantee USB 63 | compliance. This might apply to some or all of FTDI's solutions. 64 | 65 | 66 | ======================================================================= 67 | WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? 68 | ======================================================================= 69 | 70 | You have learned in the previous section that you are free to choose any 71 | numbers for your IDs anyway. So why not do exactly this? There is still the 72 | technical issue. If you choose IDs which are already in use by somebody else, 73 | operating systems will load the wrong drivers and your device won't work. 74 | Even if you choose IDs which are not currently in use, they may be in use in 75 | the next version of the operating system or even after an automatic update. 76 | 77 | So what you need is a pair of Vendor- and Product-IDs for which you have the 78 | guarantee that no USB compliant product uses them. This implies that no 79 | operating system will ever ship with drivers responsible for these IDs. 80 | 81 | 82 | ============================================== 83 | HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? 84 | ============================================== 85 | 86 | Objective Development gives away pairs of USB-IDs with their V-USB licenses. 87 | In order to ensure that these IDs are unique, Objective Development has an 88 | agreement with the company/person who has bought the USB Vendor-ID from 89 | usb.org. This agreement ensures that a range of USB Product-IDs is reserved 90 | for assignment by Objective Development and that the owner of the Vendor-ID 91 | won't give it to anybody else. 92 | 93 | This means that you have to trust three parties to ensure uniqueness of 94 | your IDs: 95 | 96 | - Objective Development, that they don't give the same PID to more than 97 | one person. 98 | - The owner of the Vendor-ID that they don't assign PIDs from the range 99 | assigned to Objective Development to anybody else. 100 | - Usb.org that they don't assign the same Vendor-ID a second time. 101 | 102 | 103 | ================================== 104 | WHO IS THE OWNER OF THE VENDOR-ID? 105 | ================================== 106 | 107 | Objective Development has obtained ranges of USB Product-IDs under two 108 | Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen 109 | Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason 110 | Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID 111 | directly from usb.org. 112 | 113 | 114 | ========================================================================= 115 | CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? 116 | ========================================================================= 117 | 118 | The short answer is: Yes. All you get is a guarantee that the IDs are never 119 | assigned to anybody else. What more do you need? 120 | 121 | 122 | ============================ 123 | WHAT ABOUT SHARED ID PAIRS? 124 | ============================ 125 | 126 | Objective Development has reserved some PID/VID pairs for shared use. You 127 | have no guarantee of uniqueness for them, except that no USB compliant device 128 | uses them. In order to avoid technical problems, we must ensure that all 129 | devices with the same pair of IDs use the same driver on kernel level. For 130 | details, see the file USB-IDs-for-free.txt. 131 | 132 | 133 | ====================================================== 134 | I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? 135 | ====================================================== 136 | 137 | A 16 bit integer number cannot be protected by copyright laws. It is not 138 | sufficiently complex. And since none of the parties involved entered into the 139 | USB-IF Trademark License Agreement, we are not bound by this agreement. So 140 | there is no reason why it should be illegal to sub-license USB-IDs. 141 | 142 | 143 | ============================================= 144 | WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? 145 | ============================================= 146 | 147 | Objective Development disclaims all liabilities which might arise from the 148 | assignment of IDs. If you guarantee product features to your customers 149 | without proper disclaimer, YOU are liable for that. 150 | -------------------------------------------------------------------------------- /firmware/usbdrv/USB-IDs-for-free.txt: -------------------------------------------------------------------------------- 1 | Version 2009-08-22 2 | 3 | =========================== 4 | FREE USB-IDs FOR SHARED USE 5 | =========================== 6 | 7 | Objective Development has reserved a set of USB Product-IDs for use according 8 | to the guidelines outlined below. For more information about the concept of 9 | USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees 10 | that the IDs listed below are not used by any USB compliant devices. 11 | 12 | 13 | ==================== 14 | MECHANISM OF SHARING 15 | ==================== 16 | 17 | From a technical point of view, two different devices can share the same USB 18 | Vendor- and Product-ID if they require the same driver on operating system 19 | level. We make use of this fact by assigning separate IDs for various device 20 | classes. On application layer, devices must be distinguished by their textual 21 | name or serial number. We offer separate sets of IDs for discrimination by 22 | textual name and for serial number. 23 | 24 | Examples for shared use of USB IDs are included with V-USB in the "examples" 25 | subdirectory. 26 | 27 | 28 | ====================================== 29 | IDs FOR DISCRIMINATION BY TEXTUAL NAME 30 | ====================================== 31 | 32 | If you use one of the IDs listed below, your device and host-side software 33 | must conform to these rules: 34 | 35 | (1) The USB device MUST provide a textual representation of the manufacturer 36 | and product identification. The manufacturer identification MUST be available 37 | at least in USB language 0x0409 (English/US). 38 | 39 | (2) The textual manufacturer identification MUST contain either an Internet 40 | domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail 41 | address under your control (e.g. "myname@gmx.net"). You can embed the domain 42 | name or e-mail address in any string you like, e.g. "Objective Development 43 | http://www.obdev.at/vusb/". 44 | 45 | (3) You are responsible for retaining ownership of the domain or e-mail 46 | address for as long as any of your products are in use. 47 | 48 | (4) You may choose any string for the textual product identification, as long 49 | as this string is unique within the scope of your textual manufacturer 50 | identification. 51 | 52 | (5) Application side device look-up MUST be based on the textual manufacturer 53 | and product identification in addition to VID/PID matching. The driver 54 | matching MUST be a comparison of the entire strings, NOT a sub-string match. 55 | 56 | (6) For devices which implement a particular USB device class (e.g. HID), the 57 | operating system's default class driver MUST be used. If an operating system 58 | driver for Vendor Class devices is needed, this driver must be libusb or 59 | libusb-win32 (see http://libusb.org/ and 60 | http://libusb-win32.sourceforge.net/). 61 | 62 | Table if IDs for discrimination by textual name: 63 | 64 | PID dec (hex) | VID dec (hex) | Description of use 65 | ==============+===============+============================================ 66 | 1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb 67 | --------------+---------------+-------------------------------------------- 68 | 1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are 69 | | | NOT mice, keyboards or joysticks) 70 | --------------+---------------+-------------------------------------------- 71 | 1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) 72 | --------------+---------------+-------------------------------------------- 73 | 1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices 74 | --------------+---------------+-------------------------------------------- 75 | 76 | Note that Windows caches the textual product- and vendor-description for 77 | mice, keyboards and joysticks. Name-bsed discrimination is therefore not 78 | recommended for these device classes. 79 | 80 | 81 | ======================================= 82 | IDs FOR DISCRIMINATION BY SERIAL NUMBER 83 | ======================================= 84 | 85 | If you use one of the IDs listed below, your device and host-side software 86 | must conform to these rules: 87 | 88 | (1) The USB device MUST provide a textual representation of the serial 89 | number, unless ONLY the operating system's default class driver is used. 90 | The serial number string MUST be available at least in USB language 0x0409 91 | (English/US). 92 | 93 | (2) The serial number MUST start with either an Internet domain name (e.g. 94 | "mycompany.com") registered and owned by you, or an e-mail address under your 95 | control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. 96 | You MAY append any string you like for further discrimination of your devices. 97 | 98 | (3) You are responsible for retaining ownership of the domain or e-mail 99 | address for as long as any of your products are in use. 100 | 101 | (5) Application side device look-up MUST be based on the serial number string 102 | in addition to VID/PID matching. The matching must start at the first 103 | character of the serial number string and include the colon character 104 | terminating your domain or e-mail address. It MAY stop anywhere after that. 105 | 106 | (6) For devices which implement a particular USB device class (e.g. HID), the 107 | operating system's default class driver MUST be used. If an operating system 108 | driver for Vendor Class devices is needed, this driver must be libusb or 109 | libusb-win32 (see http://libusb.org/ and 110 | http://libusb-win32.sourceforge.net/). 111 | 112 | (7) If ONLY the operating system's default class driver is used, e.g. for 113 | mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an 114 | application is needed, the serial number may be omitted. 115 | 116 | 117 | Table if IDs for discrimination by serial number string: 118 | 119 | PID dec (hex) | VID dec (hex) | Description of use 120 | ===============+===============+=========================================== 121 | 10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb 122 | ---------------+---------------+------------------------------------------- 123 | 10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are 124 | | | NOT mice, keyboards or joysticks) 125 | ---------------+---------------+------------------------------------------- 126 | 10202 (0x27da) | 5824 (0x16c0) | For USB Mice 127 | ---------------+---------------+------------------------------------------- 128 | 10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards 129 | ---------------+---------------+------------------------------------------- 130 | 10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks 131 | ---------------+---------------+------------------------------------------- 132 | 10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) 133 | ---------------+---------------+------------------------------------------- 134 | 10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices 135 | ---------------+---------------+------------------------------------------- 136 | 137 | 138 | ================= 139 | ORIGIN OF USB-IDs 140 | ================= 141 | 142 | OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed 143 | here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. 144 | Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. 145 | (see www.usb.org). The VID is registered for the company name "Van Ooijen 146 | Technische Informatica". 147 | 148 | 149 | ========== 150 | DISCLAIMER 151 | ========== 152 | 153 | OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any 154 | problems which are caused by the shared use of these VID/PID pairs. 155 | -------------------------------------------------------------------------------- /firmware/usbdrv/CommercialLicense.txt: -------------------------------------------------------------------------------- 1 | V-USB Driver Software License Agreement 2 | Version 2012-07-09 3 | 4 | THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN 5 | ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING 6 | THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. 7 | 8 | 9 | 1 DEFINITIONS 10 | 11 | 1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, 12 | Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. 13 | 14 | 1.2 "You" shall mean the Licensee. 15 | 16 | 1.3 "V-USB" shall mean all files included in the package distributed under 17 | the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/) 18 | unless otherwise noted. This includes the firmware-only USB device 19 | implementation for Atmel AVR microcontrollers, some simple device examples 20 | and host side software examples and libraries. 21 | 22 | 23 | 2 LICENSE GRANTS 24 | 25 | 2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source 26 | code of V-USB. 27 | 28 | 2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the 29 | non-exclusive right to use, copy and distribute V-USB with your hardware 30 | product(s), restricted by the limitations in section 3 below. 31 | 32 | 2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify 33 | the source code and your copy of V-USB according to your needs. 34 | 35 | 2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB 36 | Product ID(s), sent to you in e-mail. These Product IDs are reserved 37 | exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID 38 | ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen 39 | Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from 40 | Jason Kotzin (now flirc.tv, Inc.). Both owners of the Vendor IDs have 41 | obtained these IDs from the USB Implementers Forum, Inc. (www.usb.org). 42 | OBJECTIVE DEVELOPMENT disclaims all liability which might arise from the 43 | assignment of USB IDs. 44 | 45 | 2.5 USB Certification. Although not part of this agreement, we want to make 46 | it clear that you cannot become USB certified when you use V-USB or a USB 47 | Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't 48 | meet the electrical specifications required by the USB specification and 49 | the USB Implementers Forum certifies only members who bought a Vendor ID of 50 | their own. 51 | 52 | 53 | 3 LICENSE RESTRICTIONS 54 | 55 | 3.1 Number of Units. Only one of the following three definitions is 56 | applicable. Which one is determined by the amount you pay to OBJECTIVE 57 | DEVELOPMENT, see section 4 ("Payment") below. 58 | 59 | Hobby License: You may use V-USB according to section 2 above in no more 60 | than 5 hardware units. These units must not be sold for profit. 61 | 62 | Entry Level License: You may use V-USB according to section 2 above in no 63 | more than 150 hardware units. 64 | 65 | Professional License: You may use V-USB according to section 2 above in 66 | any number of hardware units, except for large scale production ("unlimited 67 | fair use"). Quantities below 10,000 units are not considered large scale 68 | production. If your reach quantities which are obviously large scale 69 | production, you must pay a license fee of 0.10 EUR per unit for all units 70 | above 10,000. 71 | 72 | 3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber 73 | any copy of V-USB, or any of the rights granted herein. 74 | 75 | 3.3 Transfer. You may not transfer your rights under this Agreement to 76 | another party without OBJECTIVE DEVELOPMENT's prior written consent. If 77 | such consent is obtained, you may permanently transfer this License to 78 | another party. The recipient of such transfer must agree to all terms and 79 | conditions of this Agreement. 80 | 81 | 3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not 82 | expressly granted. 83 | 84 | 3.5 Non-Exclusive Rights. Your license rights under this Agreement are 85 | non-exclusive. 86 | 87 | 3.6 Third Party Rights. This Agreement cannot grant you rights controlled 88 | by third parties. In particular, you are not allowed to use the USB logo or 89 | other trademarks owned by the USB Implementers Forum, Inc. without their 90 | consent. Since such consent depends on USB certification, it should be 91 | noted that V-USB will not pass certification because it does not 92 | implement checksum verification and the microcontroller ports do not meet 93 | the electrical specifications. 94 | 95 | 96 | 4 PAYMENT 97 | 98 | The payment amount depends on the variation of this agreement (according to 99 | section 3.1) into which you want to enter. Concrete prices are listed on 100 | OBJECTIVE DEVELOPMENT's web site, usually at 101 | http://www.obdev.at/vusb/license.html. You agree to pay the amount listed 102 | there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor 103 | or reseller. 104 | 105 | 106 | 5 COPYRIGHT AND OWNERSHIP 107 | 108 | V-USB is protected by copyright laws and international copyright 109 | treaties, as well as other intellectual property laws and treaties. V-USB 110 | is licensed, not sold. 111 | 112 | 113 | 6 TERM AND TERMINATION 114 | 115 | 6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE 116 | DEVELOPMENT may terminate this Agreement and revoke the granted license and 117 | USB-IDs if you fail to comply with any of its terms and conditions. 118 | 119 | 6.2 Survival of Terms. All provisions regarding secrecy, confidentiality 120 | and limitation of liability shall survive termination of this agreement. 121 | 122 | 123 | 7 DISCLAIMER OF WARRANTY AND LIABILITY 124 | 125 | LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 126 | KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE 127 | DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER 128 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 129 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 130 | NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE 131 | TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL 132 | RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO 133 | STATE/JURISDICTION. 134 | 135 | LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, 136 | IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY 137 | SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER 138 | (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, 139 | BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY 140 | LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE 141 | PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE 142 | DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY 143 | CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS 144 | AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB. 145 | 146 | 147 | 8 MISCELLANEOUS TERMS 148 | 149 | 8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing 150 | purposes that you entered into this agreement. 151 | 152 | 8.2 Entire Agreement. This document represents the entire agreement between 153 | OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by 154 | an authorized representative of both, OBJECTIVE DEVELOPMENT and you. 155 | 156 | 8.3 Severability. In case a provision of these terms and conditions should 157 | be or become partly or entirely invalid, ineffective, or not executable, 158 | the validity of all other provisions shall not be affected. 159 | 160 | 8.4 Applicable Law. This agreement is governed by the laws of the Republic 161 | of Austria. 162 | 163 | 8.5 Responsible Courts. The responsible courts in Vienna/Austria will have 164 | exclusive jurisdiction regarding all disputes in connection with this 165 | agreement. 166 | 167 | -------------------------------------------------------------------------------- /firmware/main.c: -------------------------------------------------------------------------------- 1 | /* Name: main.c 2 | * Project: AVR bootloader HID 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-03-19 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt) 8 | * This Revision: $Id$ 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | static void leaveBootloader() __attribute__((__noreturn__)); 20 | 21 | #include "bootloaderconfig.h" 22 | #include "usbdrv.c" 23 | 24 | /* ------------------------------------------------------------------------ */ 25 | 26 | #ifndef ulong 27 | # define ulong unsigned long 28 | #endif 29 | #ifndef uint 30 | # define uint unsigned int 31 | #endif 32 | 33 | #if (FLASHEND) > 0xffff /* we need long addressing */ 34 | # define addr_t ulong 35 | #else 36 | # define addr_t uint 37 | #endif 38 | 39 | static addr_t currentAddress; /* in bytes */ 40 | static uchar offset; /* data already processed in current transfer */ 41 | #if BOOTLOADER_CAN_EXIT 42 | static uchar exitMainloop; 43 | #endif 44 | 45 | 46 | const PROGMEM char usbHidReportDescriptor[33] = { 47 | 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 48 | 0x09, 0x01, // USAGE (Vendor Usage 1) 49 | 0xa1, 0x01, // COLLECTION (Application) 50 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 51 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 52 | 0x75, 0x08, // REPORT_SIZE (8) 53 | 54 | 0x85, 0x01, // REPORT_ID (1) 55 | 0x95, 0x06, // REPORT_COUNT (6) 56 | 0x09, 0x00, // USAGE (Undefined) 57 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 58 | 59 | 0x85, 0x02, // REPORT_ID (2) 60 | 0x95, 0x83, // REPORT_COUNT (131) 61 | 0x09, 0x00, // USAGE (Undefined) 62 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 63 | 0xc0 // END_COLLECTION 64 | }; 65 | 66 | /* allow compatibility with avrusbboot's bootloaderconfig.h: */ 67 | #ifdef BOOTLOADER_INIT 68 | # define bootLoaderInit() BOOTLOADER_INIT 69 | #endif 70 | #ifdef BOOTLOADER_CONDITION 71 | # define bootLoaderCondition() BOOTLOADER_CONDITION 72 | #endif 73 | 74 | /* compatibility with ATMega88 and other new devices: */ 75 | #ifndef TCCR0 76 | #define TCCR0 TCCR0B 77 | #endif 78 | #ifndef GICR 79 | #define GICR MCUCR 80 | #endif 81 | 82 | static void (*nullVector)(void) __attribute__((__noreturn__)); 83 | 84 | static void leaveBootloader() 85 | { 86 | DBG1(0x01, 0, 0); 87 | cli(); 88 | usbDeviceDisconnect(); 89 | bootLoaderExit(); 90 | boot_rww_enable(); 91 | USB_INTR_ENABLE = 0; 92 | USB_INTR_CFG = 0; /* also reset config bits */ 93 | #if F_CPU == 12800000 94 | TCCR0 = 0; /* default value */ 95 | #endif 96 | GICR = (1 << IVCE); /* enable change of interrupt vectors */ 97 | GICR = (0 << IVSEL); /* move interrupts to application flash section */ 98 | /* We must go through a global function pointer variable instead of writing 99 | * ((void (*)(void))0)(); 100 | * because the compiler optimizes a constant 0 to "rcall 0" which is not 101 | * handled correctly by the assembler. 102 | */ 103 | nullVector(); 104 | } 105 | 106 | uchar usbFunctionSetup(uchar data[8]) 107 | { 108 | usbRequest_t *rq = (void *)data; 109 | static uchar replyBuffer[7] = { 110 | 1, /* report ID */ 111 | SPM_PAGESIZE & 0xff, 112 | SPM_PAGESIZE >> 8, 113 | ((long)FLASHEND + 1) & 0xff, 114 | (((long)FLASHEND + 1) >> 8) & 0xff, 115 | (((long)FLASHEND + 1) >> 16) & 0xff, 116 | (((long)FLASHEND + 1) >> 24) & 0xff 117 | }; 118 | 119 | if(rq->bRequest == USBRQ_HID_SET_REPORT){ 120 | if(rq->wValue.bytes[0] == 2){ 121 | offset = 0; 122 | return USB_NO_MSG; 123 | } 124 | #if BOOTLOADER_CAN_EXIT 125 | else{ 126 | exitMainloop = 1; 127 | } 128 | #endif 129 | }else if(rq->bRequest == USBRQ_HID_GET_REPORT){ 130 | usbMsgPtr = (usbMsgPtr_t)replyBuffer; 131 | return 7; 132 | } 133 | return 0; 134 | } 135 | 136 | uchar usbFunctionWrite(uchar *data, uchar len) 137 | { 138 | union { 139 | addr_t l; 140 | uint s[sizeof(addr_t)/2]; 141 | uchar c[sizeof(addr_t)]; 142 | } address; 143 | uchar isLast; 144 | 145 | address.l = currentAddress; 146 | if(offset == 0){ 147 | DBG1(0x30, data, 3); 148 | address.c[0] = data[1]; 149 | address.c[1] = data[2]; 150 | #if (FLASHEND) > 0xffff /* we need long addressing */ 151 | address.c[2] = data[3]; 152 | address.c[3] = 0; 153 | #endif 154 | data += 4; 155 | len -= 4; 156 | } 157 | DBG1(0x31, (void *)¤tAddress, 4); 158 | offset += len; 159 | isLast = offset & 0x80; /* != 0 if last block received */ 160 | do{ 161 | addr_t prevAddr; 162 | #if SPM_PAGESIZE > 256 163 | uint pageAddr; 164 | #else 165 | uchar pageAddr; 166 | #endif 167 | DBG1(0x32, 0, 0); 168 | pageAddr = address.s[0] & (SPM_PAGESIZE - 1); 169 | if(pageAddr == 0){ /* if page start: erase */ 170 | DBG1(0x33, 0, 0); 171 | #ifndef TEST_MODE 172 | cli(); 173 | boot_page_erase(address.l); /* erase page */ 174 | sei(); 175 | boot_spm_busy_wait(); /* wait until page is erased */ 176 | #endif 177 | } 178 | cli(); 179 | boot_page_fill(address.l, *(short *)data); 180 | sei(); 181 | prevAddr = address.l; 182 | address.l += 2; 183 | data += 2; 184 | /* write page when we cross page boundary */ 185 | pageAddr = address.s[0] & (SPM_PAGESIZE - 1); 186 | if(pageAddr == 0){ 187 | DBG1(0x34, 0, 0); 188 | #ifndef TEST_MODE 189 | cli(); 190 | boot_page_write(prevAddr); 191 | sei(); 192 | boot_spm_busy_wait(); 193 | #endif 194 | } 195 | len -= 2; 196 | }while(len); 197 | currentAddress = address.l; 198 | DBG1(0x35, (void *)¤tAddress, 4); 199 | return isLast; 200 | } 201 | 202 | static void initForUsbConnectivity(void) 203 | { 204 | uchar i = 0; 205 | 206 | #if F_CPU == 12800000 207 | TCCR0 = 3; /* 1/64 prescaler */ 208 | #endif 209 | usbInit(); 210 | /* enforce USB re-enumerate: */ 211 | usbDeviceDisconnect(); /* do this while interrupts are disabled */ 212 | do{ /* fake USB disconnect for > 250 ms */ 213 | wdt_reset(); 214 | _delay_ms(1); 215 | }while(--i); 216 | usbDeviceConnect(); 217 | sei(); 218 | } 219 | 220 | int __attribute__((noreturn)) main(void) 221 | { 222 | /* initialize hardware */ 223 | bootLoaderInit(); 224 | odDebugInit(); 225 | DBG1(0x00, 0, 0); 226 | /* jump to application if jumper is set */ 227 | if(bootLoaderCondition()){ 228 | uchar i = 0, j = 0; 229 | #ifndef TEST_MODE 230 | GICR = (1 << IVCE); /* enable change of interrupt vectors */ 231 | GICR = (1 << IVSEL); /* move interrupts to boot flash section */ 232 | #endif 233 | initForUsbConnectivity(); 234 | do{ /* main event loop */ 235 | wdt_reset(); 236 | usbPoll(); 237 | #if BOOTLOADER_CAN_EXIT 238 | if(exitMainloop){ 239 | #if F_CPU == 12800000 240 | break; /* memory is tight at 12.8 MHz, save exit delay below */ 241 | #endif 242 | if(--i == 0){ 243 | if(--j == 0) 244 | break; 245 | } 246 | } 247 | #endif 248 | }while(bootLoaderCondition()); 249 | } 250 | leaveBootloader(); 251 | } 252 | 253 | -------------------------------------------------------------------------------- /firmware/bootloaderconfig.h: -------------------------------------------------------------------------------- 1 | /* Name: bootloaderconfig.h 2 | * Project: AVR bootloader HID 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-03-19 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt) 8 | * This Revision: $Id$ 9 | */ 10 | 11 | #ifndef __bootloaderconfig_h_included__ 12 | #define __bootloaderconfig_h_included__ 13 | 14 | /* 15 | General Description: 16 | This file (together with some settings in Makefile) configures the boot loader 17 | according to the hardware. 18 | 19 | This file contains (besides the hardware configuration normally found in 20 | usbconfig.h) two functions or macros: bootLoaderInit() and 21 | bootLoaderCondition(). Whether you implement them as macros or as static 22 | inline functions is up to you, decide based on code size and convenience. 23 | 24 | bootLoaderInit() is called as one of the first actions after reset. It should 25 | be a minimum initialization of the hardware so that the boot loader condition 26 | can be read. This will usually consist of activating a pull-up resistor for an 27 | external jumper which selects boot loader mode. You may call leaveBootloader() 28 | from this function if you know that the main code should run. 29 | 30 | bootLoaderCondition() is called immediately after initialization and in each 31 | main loop iteration. If it returns TRUE, the boot loader will be active. If it 32 | returns FALSE, the boot loader jumps to address 0 (the loaded application) 33 | immediately. 34 | 35 | For compatibility with Thomas Fischl's avrusbboot, we also support the macro 36 | names BOOTLOADER_INIT and BOOTLOADER_CONDITION for this functionality. If 37 | these macros are defined, the boot loader usees them. 38 | */ 39 | 40 | /* ---------------------------- Macro Magic ---------------------------- */ 41 | #define PIN_CONCAT(a,b) a ## b 42 | #define PIN_CONCAT3(a,b,c) a ## b ## c 43 | 44 | #define PIN_PORT(a) PIN_CONCAT(PORT, a) 45 | #define PIN_PIN(a) PIN_CONCAT(PIN, a) 46 | #define PIN_DDR(a) PIN_CONCAT(DDR, a) 47 | 48 | #define PIN(a, b) PIN_CONCAT3(P, a, b) 49 | 50 | /* ---------------------------- Hardware Config ---------------------------- */ 51 | 52 | #define USB_CFG_IOPORTNAME D 53 | /* This is the port where the USB bus is connected. When you configure it to 54 | * "B", the registers PORTB, PINB and DDRB will be used. 55 | */ 56 | #define USB_CFG_DMINUS_BIT 7 57 | /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. 58 | * This may be any bit in the port. 59 | */ 60 | #define USB_CFG_DPLUS_BIT 2 61 | /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. 62 | * This may be any bit in the port. Please note that D+ must also be connected 63 | * to interrupt pin INT0! [You can also use other interrupts, see section 64 | * "Optional MCU Description" below, or you can connect D- to the interrupt, as 65 | * it is required if you use the USB_COUNT_SOF feature. If you use D- for the 66 | * interrupt, the USB interrupt will also be triggered at Start-Of-Frame 67 | * markers every millisecond.] 68 | */ 69 | #ifndef JUMPER_PORT 70 | #define JUMPER_PORT USB_CFG_IOPORTNAME 71 | #endif 72 | /* 73 | * jumper is connected to this port 74 | */ 75 | 76 | #ifndef LED_PORT 77 | #define LED_PORT USB_CFG_IOPORTNAME 78 | #endif 79 | /* 80 | * Bootloader indicator LED port 81 | */ 82 | 83 | 84 | #ifndef JUMPER_BIT 85 | /* This is Revision 3 and later (where PD6 and PD7 were swapped */ 86 | #define JUMPER_BIT 6 /* Rev.2 and previous was 7 */ 87 | #endif 88 | /* 89 | * jumper is connected to this bit in port "JUMPER_PORT", active low 90 | */ 91 | 92 | 93 | #ifndef LED_BIT 94 | #define LED_BIT 5 95 | #endif 96 | /* 97 | * Bootloader indicator LED bit 98 | */ 99 | 100 | #define USB_CFG_CLOCK_KHZ (F_CPU/1000) 101 | /* Clock rate of the AVR in MHz. Legal values are 12000, 12800, 15000, 16000, 102 | * 16500 and 20000. The 12.8 MHz and 16.5 MHz versions of the code require no 103 | * crystal, they tolerate +/- 1% deviation from the nominal frequency. All 104 | * other rates require a precision of 2000 ppm and thus a crystal! 105 | * Default if not specified: 12 MHz 106 | */ 107 | 108 | /* ----------------------- Optional Hardware Config ------------------------ */ 109 | 110 | #define USB_CFG_PULLUP_IOPORTNAME B 111 | /* If you connect the 1.5k pullup resistor from D- to a port pin instead of 112 | * V+, you can connect and disconnect the device from firmware by calling 113 | * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). 114 | * This constant defines the port on which the pullup resistor is connected. 115 | */ 116 | #define USB_CFG_PULLUP_BIT 0 117 | /* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined 118 | * above) where the 1.5k pullup resistor is connected. See description 119 | * above for details. 120 | */ 121 | 122 | /* --------------------------- Functional Range ---------------------------- */ 123 | 124 | #define BOOTLOADER_CAN_EXIT 1 125 | /* If this macro is defined to 1, the boot loader command line utility can 126 | * initiate a reboot after uploading the FLASH when the "-r" command line 127 | * option is given. If you define it to 0 or leave it undefined, the "-r" 128 | * option won't work and you save a couple of bytes in the boot loader. This 129 | * may be of advantage if you compile with gcc 4 instead of gcc 3 because it 130 | * generates slightly larger code. 131 | * If you need to save even more memory, consider using your own vector table. 132 | * Since only the reset vector and INT0 (the first two vectors) are used, 133 | * this saves quite a bit of flash. See Alexander Neumann's boot loader for 134 | * an example: http://git.lochraster.org:2080/?p=fd0/usbload;a=tree 135 | */ 136 | 137 | /* ------------------------------------------------------------------------- */ 138 | 139 | /* Example configuration: Port D bit 3 is connected to a jumper which ties 140 | * this pin to GND if the boot loader is requested. Initialization allows 141 | * several clock cycles for the input voltage to stabilize before 142 | * bootLoaderCondition() samples the value. 143 | * We use a function for bootLoaderInit() for convenience and a macro for 144 | * bootLoaderCondition() for efficiency. 145 | */ 146 | 147 | #ifndef __ASSEMBLER__ /* assembler cannot parse function definitions */ 148 | #ifndef MCUCSR /* compatibility between ATMega8 and ATMega88 */ 149 | # define MCUCSR MCUSR 150 | #endif 151 | #include 152 | /* Original func 153 | static inline void bootLoaderInit(void) 154 | { 155 | PORTD = 1 << 6; // activate pull-up for key 156 | _delay_us(10); // wait for levels to stabilize 157 | } */ 158 | 159 | static inline void bootLoaderInit(void) 160 | { 161 | /* Deactivated by following 4 lines to activate status LED 162 | PIN_DDR(JUMPER_PORT) = 0; 163 | PIN_PORT(JUMPER_PORT) = (1<< PIN(JUMPER_PORT, JUMPER_BIT)); // activate pull-up 164 | */ 165 | 166 | PIN_DDR(JUMPER_PORT) &= ~_BV(JUMPER_BIT); 167 | PIN_DDR(LED_PORT) |= _BV(LED_BIT); 168 | PIN_PORT(JUMPER_PORT) |= _BV(JUMPER_BIT); 169 | PIN_PORT(LED_PORT) |= _BV(LED_BIT); 170 | //PIN_DDR(D) = 0b00100000; 171 | //PIN_PORT(D) = 0b01100000; 172 | 173 | 174 | // deactivated by Stephan - reset after each avrdude op is annoing! 175 | // if(!(MCUCSR & (1 << EXTRF))) /* If this was not an external reset, ignore */ 176 | // leaveBootloader(); 177 | 178 | MCUCSR = 0; /* clear all reset flags for next time */ 179 | } 180 | 181 | static inline void bootLoaderExit(void) 182 | { 183 | PIN_PORT(LED_PORT) = 0; 184 | PIN_PORT(JUMPER_PORT) = 0; 185 | PIN_DDR(LED_PORT) = 0; 186 | PIN_DDR(JUMPER_PORT) = 0; /* undo bootLoaderInit() changes */ 187 | 188 | } 189 | 190 | 191 | //#define bootLoaderCondition() ((PIND & (1 << 6)) == 0) /* True if jumper is set */ 192 | #define bootLoaderCondition() ((PIN_PIN(JUMPER_PORT) & (1 << PIN(JUMPER_PORT, JUMPER_BIT))) == 0) 193 | 194 | #endif 195 | 196 | /* ------------------------------------------------------------------------- */ 197 | 198 | #endif /* __bootloader_h_included__ */ 199 | -------------------------------------------------------------------------------- /commandline/usb-libusb.c: -------------------------------------------------------------------------------- 1 | /* Name: usb-libusb.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description: 13 | This module implements USB HID report receiving/sending based on libusb. It 14 | does not read and parse the report descriptor. You must therefore be careful 15 | to pass correctly formatted data blocks of correct size. In order to be 16 | compatible with the Windows implementation, we add a zero report ID for all 17 | reports which don't have an ID. Since we don't parse the descriptor, the caller 18 | must tell us whether report IDs are used or not in usbOpenDevice(). 19 | 20 | The implementation of dummy report IDs is a hack. Whether they are used is 21 | stored in a global variable, not in the device structure (just laziness, don't 22 | want to allocate memory for that). If you open more than one device and the 23 | devices differ in report ID usage, you must change the code. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #define usbDevice usb_dev_handle /* use libusb's device structure */ 31 | #include "usbcalls.h" 32 | 33 | /* ------------------------------------------------------------------------- */ 34 | 35 | #define USBRQ_HID_GET_REPORT 0x01 36 | #define USBRQ_HID_SET_REPORT 0x09 37 | 38 | static int usesReportIDs; 39 | 40 | /* ------------------------------------------------------------------------- */ 41 | 42 | static int usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen) 43 | { 44 | char buffer[256]; 45 | int rval, i; 46 | 47 | if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0) 48 | return rval; 49 | if(buffer[1] != USB_DT_STRING) 50 | return 0; 51 | if((unsigned char)buffer[0] < rval) 52 | rval = (unsigned char)buffer[0]; 53 | rval /= 2; 54 | /* lossy conversion to ISO Latin1 */ 55 | for(i=1;i buflen) /* destination buffer overflow */ 57 | break; 58 | buf[i-1] = buffer[2 * i]; 59 | if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ 60 | buf[i-1] = '?'; 61 | } 62 | buf[i-1] = 0; 63 | return i-1; 64 | } 65 | 66 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs) 67 | { 68 | struct usb_bus *bus; 69 | struct usb_device *dev; 70 | usb_dev_handle *handle = NULL; 71 | int errorCode = USB_ERROR_NOTFOUND; 72 | static int didUsbInit = 0; 73 | 74 | if(!didUsbInit){ 75 | usb_init(); 76 | didUsbInit = 1; 77 | } 78 | usb_find_busses(); 79 | usb_find_devices(); 80 | for(bus=usb_get_busses(); bus; bus=bus->next){ 81 | for(dev=bus->devices; dev; dev=dev->next){ 82 | if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){ 83 | char string[256]; 84 | int len; 85 | handle = usb_open(dev); /* we need to open the device in order to query strings */ 86 | if(!handle){ 87 | errorCode = USB_ERROR_ACCESS; 88 | fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); 89 | continue; 90 | } 91 | if(vendorName == NULL && productName == NULL){ /* name does not matter */ 92 | break; 93 | } 94 | /* now check whether the names match: */ 95 | len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string)); 96 | if(len < 0){ 97 | errorCode = USB_ERROR_IO; 98 | fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); 99 | }else{ 100 | errorCode = USB_ERROR_NOTFOUND; 101 | /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ 102 | if(strcmp(string, vendorName) == 0){ 103 | len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string)); 104 | if(len < 0){ 105 | errorCode = USB_ERROR_IO; 106 | fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); 107 | }else{ 108 | errorCode = USB_ERROR_NOTFOUND; 109 | /* fprintf(stderr, "seen product ->%s<-\n", string); */ 110 | if(strcmp(string, productName) == 0) 111 | break; 112 | } 113 | } 114 | } 115 | usb_close(handle); 116 | handle = NULL; 117 | } 118 | } 119 | if(handle) 120 | break; 121 | } 122 | if(handle != NULL){ 123 | int rval, retries = 3; 124 | if(usb_set_configuration(handle, 1)){ 125 | fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); 126 | } 127 | /* now try to claim the interface and detach the kernel HID driver on 128 | * linux and other operating systems which support the call. 129 | */ 130 | while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){ 131 | #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 132 | if(usb_detach_kernel_driver_np(handle, 0) < 0){ 133 | fprintf(stderr, "Warning: could not detach kernel HID driver: %s\n", usb_strerror()); 134 | } 135 | #endif 136 | } 137 | #ifndef __APPLE__ 138 | if(rval != 0) 139 | fprintf(stderr, "Warning: could not claim interface\n"); 140 | #endif 141 | /* Continue anyway, even if we could not claim the interface. Control transfers 142 | * should still work. 143 | */ 144 | errorCode = 0; 145 | *device = handle; 146 | usesReportIDs = _usesReportIDs; 147 | } 148 | return errorCode; 149 | } 150 | 151 | /* ------------------------------------------------------------------------- */ 152 | 153 | void usbCloseDevice(usbDevice_t *device) 154 | { 155 | if(device != NULL) 156 | usb_close(device); 157 | } 158 | 159 | /* ------------------------------------------------------------------------- */ 160 | 161 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) 162 | { 163 | int bytesSent; 164 | 165 | if(!usesReportIDs){ 166 | buffer++; /* skip dummy report ID */ 167 | len--; 168 | } 169 | bytesSent = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, reportType << 8 | buffer[0], 0, buffer, len, 5000); 170 | if(bytesSent != len){ 171 | if(bytesSent < 0) 172 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); 173 | return USB_ERROR_IO; 174 | } 175 | return 0; 176 | } 177 | 178 | /* ------------------------------------------------------------------------- */ 179 | 180 | int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) 181 | { 182 | int bytesReceived, maxLen = *len; 183 | 184 | if(!usesReportIDs){ 185 | buffer++; /* make room for dummy report ID */ 186 | maxLen--; 187 | } 188 | bytesReceived = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, reportType << 8 | reportNumber, 0, buffer, maxLen, 5000); 189 | if(bytesReceived < 0){ 190 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); 191 | return USB_ERROR_IO; 192 | } 193 | *len = bytesReceived; 194 | if(!usesReportIDs){ 195 | buffer[-1] = reportNumber; /* add dummy report ID */ 196 | *len++; 197 | } 198 | return 0; 199 | } 200 | 201 | /* ------------------------------------------------------------------------- */ 202 | 203 | 204 | -------------------------------------------------------------------------------- /firmware/usbdrv/asmcommon.inc: -------------------------------------------------------------------------------- 1 | /* Name: asmcommon.inc 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-11-05 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* Do not link this file! Link usbdrvasm.S instead, which includes the 11 | * appropriate implementation! 12 | */ 13 | 14 | /* 15 | General Description: 16 | This file contains assembler code which is shared among the USB driver 17 | implementations for different CPU cocks. Since the code must be inserted 18 | in the middle of the module, it's split out into this file and #included. 19 | 20 | Jump destinations called from outside: 21 | sofError: Called when no start sequence was found. 22 | se0: Called when a package has been successfully received. 23 | overflow: Called when receive buffer overflows. 24 | doReturn: Called after sending data. 25 | 26 | Outside jump destinations used by this module: 27 | waitForJ: Called to receive an already arriving packet. 28 | sendAckAndReti: 29 | sendNakAndReti: 30 | sendCntAndReti: 31 | usbSendAndReti: 32 | 33 | The following macros must be defined before this file is included: 34 | .macro POP_STANDARD 35 | .endm 36 | .macro POP_RETI 37 | .endm 38 | */ 39 | 40 | #define token x1 41 | 42 | overflow: 43 | ldi x2, 1< 12 | #include 13 | #include 14 | #include 15 | #include "usbcalls.h" 16 | 17 | #define IDENT_VENDOR_NUM 0x16c0 18 | #define IDENT_VENDOR_STRING "obdev.at" 19 | #define IDENT_PRODUCT_NUM 1503 20 | #define IDENT_PRODUCT_STRING "HIDBoot" 21 | 22 | /* ------------------------------------------------------------------------- */ 23 | 24 | static char dataBuffer[65536 + 256]; /* buffer for file data */ 25 | static int startAddress, endAddress; 26 | static char leaveBootLoader = 0; 27 | 28 | /* ------------------------------------------------------------------------- */ 29 | 30 | static int parseUntilColon(FILE *fp) 31 | { 32 | int c; 33 | 34 | do{ 35 | c = getc(fp); 36 | }while(c != ':' && c != EOF); 37 | return c; 38 | } 39 | 40 | static int parseHex(FILE *fp, int numDigits) 41 | { 42 | int i; 43 | char temp[9]; 44 | 45 | for(i = 0; i < numDigits; i++) 46 | temp[i] = getc(fp); 47 | temp[i] = 0; 48 | return strtol(temp, NULL, 16); 49 | } 50 | 51 | /* ------------------------------------------------------------------------- */ 52 | 53 | static int parseIntelHex(char *hexfile, char buffer[65536 + 256], int *startAddr, int *endAddr) 54 | { 55 | int address, base, d, segment, i, lineLen, sum; 56 | FILE *input; 57 | 58 | input = fopen(hexfile, "r"); 59 | if(input == NULL){ 60 | fprintf(stderr, "error opening %s: %s\n", hexfile, strerror(errno)); 61 | return 1; 62 | } 63 | while(parseUntilColon(input) == ':'){ 64 | sum = 0; 65 | sum += lineLen = parseHex(input, 2); 66 | base = address = parseHex(input, 4); 67 | sum += address >> 8; 68 | sum += address; 69 | sum += segment = parseHex(input, 2); /* segment value? */ 70 | if(segment != 0) /* ignore lines where this byte is not 0 */ 71 | continue; 72 | for(i = 0; i < lineLen ; i++){ 73 | d = parseHex(input, 2); 74 | buffer[address++] = d; 75 | sum += d; 76 | } 77 | sum += parseHex(input, 2); 78 | if((sum & 0xff) != 0){ 79 | fprintf(stderr, "Warning: Checksum error between address 0x%x and 0x%x\n", base, address); 80 | } 81 | if(*startAddr > base) 82 | *startAddr = base; 83 | if(*endAddr < address) 84 | *endAddr = address; 85 | } 86 | fclose(input); 87 | return 0; 88 | } 89 | 90 | /* ------------------------------------------------------------------------- */ 91 | 92 | char *usbErrorMessage(int errCode) 93 | { 94 | static char buffer[80]; 95 | 96 | switch(errCode){ 97 | case USB_ERROR_ACCESS: return "Access to device denied"; 98 | case USB_ERROR_NOTFOUND: return "The specified device was not found"; 99 | case USB_ERROR_BUSY: return "The device is used by another application"; 100 | case USB_ERROR_IO: return "Communication error with device"; 101 | default: 102 | sprintf(buffer, "Unknown USB error %d", errCode); 103 | return buffer; 104 | } 105 | return NULL; /* not reached */ 106 | } 107 | 108 | static int getUsbInt(char *buffer, int numBytes) 109 | { 110 | int shift = 0, value = 0, i; 111 | 112 | for(i = 0; i < numBytes; i++){ 113 | value |= ((int)*buffer & 0xff) << shift; 114 | shift += 8; 115 | buffer++; 116 | } 117 | return value; 118 | } 119 | 120 | static void setUsbInt(char *buffer, int value, int numBytes) 121 | { 122 | int i; 123 | 124 | for(i = 0; i < numBytes; i++){ 125 | *buffer++ = value; 126 | value >>= 8; 127 | } 128 | } 129 | 130 | /* ------------------------------------------------------------------------- */ 131 | 132 | typedef struct deviceInfo{ 133 | char reportId; 134 | char pageSize[2]; 135 | char flashSize[4]; 136 | }deviceInfo_t; 137 | 138 | typedef struct deviceData{ 139 | char reportId; 140 | char address[3]; 141 | char data[128]; 142 | }deviceData_t; 143 | 144 | static int uploadData(char *dataBuffer, int startAddr, int endAddr) 145 | { 146 | usbDevice_t *dev = NULL; 147 | int err = 0, len, mask, pageSize, deviceSize; 148 | union{ 149 | char bytes[1]; 150 | deviceInfo_t info; 151 | deviceData_t data; 152 | } buffer; 153 | 154 | if((err = usbOpenDevice(&dev, IDENT_VENDOR_NUM, IDENT_VENDOR_STRING, IDENT_PRODUCT_NUM, IDENT_PRODUCT_STRING, 1)) != 0){ 155 | fprintf(stderr, "Error opening HIDBoot device: %s\n", usbErrorMessage(err)); 156 | goto errorOccurred; 157 | } 158 | len = sizeof(buffer); 159 | if(endAddr > startAddr){ // we need to upload data 160 | if((err = usbGetReport(dev, USB_HID_REPORT_TYPE_FEATURE, 1, buffer.bytes, &len)) != 0){ 161 | fprintf(stderr, "Error reading page size: %s\n", usbErrorMessage(err)); 162 | goto errorOccurred; 163 | } 164 | if(len < sizeof(buffer.info)){ 165 | fprintf(stderr, "Not enough bytes in device info report (%d instead of %d)\n", len, (int)sizeof(buffer.info)); 166 | err = -1; 167 | goto errorOccurred; 168 | } 169 | pageSize = getUsbInt(buffer.info.pageSize, 2); 170 | deviceSize = getUsbInt(buffer.info.flashSize, 4); 171 | printf("Page size = %d (0x%x)\n", pageSize, pageSize); 172 | printf("Device size = %d (0x%x); %d bytes remaining\n", deviceSize, deviceSize, deviceSize - 2048); 173 | if(endAddr > deviceSize - 2048){ 174 | fprintf(stderr, "Data (%d bytes) exceeds remaining flash size!\n", endAddr); 175 | err = -1; 176 | goto errorOccurred; 177 | } 178 | if(pageSize < 128){ 179 | mask = 127; 180 | }else{ 181 | mask = pageSize - 1; 182 | } 183 | startAddr &= ~mask; /* round down */ 184 | endAddr = (endAddr + mask) & ~mask; /* round up */ 185 | printf("Uploading %d (0x%x) bytes starting at %d (0x%x)\n", endAddr - startAddr, endAddr - startAddr, startAddr, startAddr); 186 | while(startAddr < endAddr){ 187 | buffer.data.reportId = 2; 188 | memcpy(buffer.data.data, dataBuffer + startAddr, 128); 189 | setUsbInt(buffer.data.address, startAddr, 3); 190 | printf("\r0x%05x ... 0x%05x", startAddr, startAddr + (int)sizeof(buffer.data.data)); 191 | fflush(stdout); 192 | if((err = usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.data))) != 0){ 193 | fprintf(stderr, "Error uploading data block: %s\n", usbErrorMessage(err)); 194 | goto errorOccurred; 195 | } 196 | startAddr += sizeof(buffer.data.data); 197 | } 198 | printf("\n"); 199 | } 200 | if(leaveBootLoader){ 201 | /* and now leave boot loader: */ 202 | buffer.info.reportId = 1; 203 | usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.info)); 204 | /* Ignore errors here. If the device reboots before we poll the response, 205 | * this request fails. 206 | */ 207 | } 208 | errorOccurred: 209 | if(dev != NULL) 210 | usbCloseDevice(dev); 211 | return err; 212 | } 213 | 214 | /* ------------------------------------------------------------------------- */ 215 | 216 | static void printUsage(char *pname) 217 | { 218 | fprintf(stderr, "usage: %s [-r] []\n", pname); 219 | } 220 | 221 | int main(int argc, char **argv) 222 | { 223 | char *file = NULL; 224 | 225 | if(argc < 2){ 226 | printUsage(argv[0]); 227 | return 1; 228 | } 229 | if(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0){ 230 | printUsage(argv[0]); 231 | return 1; 232 | } 233 | if(strcmp(argv[1], "-r") == 0){ 234 | leaveBootLoader = 1; 235 | if(argc >= 3){ 236 | file = argv[2]; 237 | } 238 | }else{ 239 | file = argv[1]; 240 | } 241 | startAddress = sizeof(dataBuffer); 242 | endAddress = 0; 243 | if(file != NULL){ // an upload file was given, load the data 244 | memset(dataBuffer, -1, sizeof(dataBuffer)); 245 | if(parseIntelHex(file, dataBuffer, &startAddress, &endAddress)) 246 | return 1; 247 | if(startAddress >= endAddress){ 248 | fprintf(stderr, "No data in input file, exiting.\n"); 249 | return 0; 250 | } 251 | } 252 | // if no file was given, endAddress is less than startAddress and no data is uploaded 253 | if(uploadData(dataBuffer, startAddress, endAddress)) 254 | return 1; 255 | return 0; 256 | } 257 | 258 | /* ------------------------------------------------------------------------- */ 259 | 260 | 261 | -------------------------------------------------------------------------------- /firmware/usbdrv/usbdrvasm.S: -------------------------------------------------------------------------------- 1 | /* Name: usbdrvasm.S 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-06-13 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* 11 | General Description: 12 | This module is the assembler part of the USB driver. This file contains 13 | general code (preprocessor acrobatics and CRC computation) and then includes 14 | the file appropriate for the given clock rate. 15 | */ 16 | 17 | #define __SFR_OFFSET 0 /* used by avr-libc's register definitions */ 18 | #include "usbportability.h" 19 | #include "usbdrv.h" /* for common defs */ 20 | 21 | /* register names */ 22 | #define x1 r16 23 | #define x2 r17 24 | #define shift r18 25 | #define cnt r19 26 | #define x3 r20 27 | #define x4 r21 28 | #define x5 r22 29 | #define bitcnt x5 30 | #define phase x4 31 | #define leap x4 32 | 33 | /* Some assembler dependent definitions and declarations: */ 34 | 35 | #ifdef __IAR_SYSTEMS_ASM__ 36 | extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset 37 | extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen 38 | extern usbTxBuf, usbTxStatus1, usbTxStatus3 39 | # if USB_COUNT_SOF 40 | extern usbSofCount 41 | # endif 42 | public usbCrc16 43 | public usbCrc16Append 44 | 45 | COMMON INTVEC 46 | # ifndef USB_INTR_VECTOR 47 | ORG INT0_vect 48 | # else /* USB_INTR_VECTOR */ 49 | ORG USB_INTR_VECTOR 50 | # undef USB_INTR_VECTOR 51 | # endif /* USB_INTR_VECTOR */ 52 | # define USB_INTR_VECTOR usbInterruptHandler 53 | rjmp USB_INTR_VECTOR 54 | RSEG CODE 55 | 56 | #else /* __IAR_SYSTEMS_ASM__ */ 57 | 58 | # ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ 59 | # ifdef INT0_vect 60 | # define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector 61 | # else 62 | # define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector 63 | # endif 64 | # endif 65 | .text 66 | .global USB_INTR_VECTOR 67 | .type USB_INTR_VECTOR, @function 68 | .global usbCrc16 69 | .global usbCrc16Append 70 | #endif /* __IAR_SYSTEMS_ASM__ */ 71 | 72 | 73 | #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */ 74 | # define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING 75 | # define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg 76 | #else /* It's a memory address, use lds and sts */ 77 | # define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING 78 | # define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg 79 | #endif 80 | 81 | #define usbTxLen1 usbTxStatus1 82 | #define usbTxBuf1 (usbTxStatus1 + 1) 83 | #define usbTxLen3 usbTxStatus3 84 | #define usbTxBuf3 (usbTxStatus3 + 1) 85 | 86 | 87 | ;---------------------------------------------------------------------------- 88 | ; Utility functions 89 | ;---------------------------------------------------------------------------- 90 | 91 | #ifdef __IAR_SYSTEMS_ASM__ 92 | /* Register assignments for usbCrc16 on IAR cc */ 93 | /* Calling conventions on IAR: 94 | * First parameter passed in r16/r17, second in r18/r19 and so on. 95 | * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) 96 | * Result is passed in r16/r17 97 | * In case of the "tiny" memory model, pointers are only 8 bit with no 98 | * padding. We therefore pass argument 1 as "16 bit unsigned". 99 | */ 100 | RTMODEL "__rt_version", "3" 101 | /* The line above will generate an error if cc calling conventions change. 102 | * The value "3" above is valid for IAR 4.10B/W32 103 | */ 104 | # define argLen r18 /* argument 2 */ 105 | # define argPtrL r16 /* argument 1 */ 106 | # define argPtrH r17 /* argument 1 */ 107 | 108 | # define resCrcL r16 /* result */ 109 | # define resCrcH r17 /* result */ 110 | 111 | # define ptrL ZL 112 | # define ptrH ZH 113 | # define ptr Z 114 | # define byte r22 115 | # define bitCnt r19 116 | # define polyL r20 117 | # define polyH r21 118 | # define scratch r23 119 | 120 | #else /* __IAR_SYSTEMS_ASM__ */ 121 | /* Register assignments for usbCrc16 on gcc */ 122 | /* Calling conventions on gcc: 123 | * First parameter passed in r24/r25, second in r22/23 and so on. 124 | * Callee must preserve r1-r17, r28/r29 125 | * Result is passed in r24/r25 126 | */ 127 | # define argLen r22 /* argument 2 */ 128 | # define argPtrL r24 /* argument 1 */ 129 | # define argPtrH r25 /* argument 1 */ 130 | 131 | # define resCrcL r24 /* result */ 132 | # define resCrcH r25 /* result */ 133 | 134 | # define ptrL XL 135 | # define ptrH XH 136 | # define ptr x 137 | # define byte r18 138 | # define bitCnt r19 139 | # define polyL r20 140 | # define polyH r21 141 | # define scratch r23 142 | 143 | #endif 144 | 145 | #if USB_USE_FAST_CRC 146 | 147 | ; This implementation is faster, but has bigger code size 148 | ; Thanks to Slawomir Fras (BoskiDialer) for this code! 149 | ; It implements the following C pseudo-code: 150 | ; unsigned table(unsigned char x) 151 | ; { 152 | ; unsigned value; 153 | ; 154 | ; value = (unsigned)x << 6; 155 | ; value ^= (unsigned)x << 7; 156 | ; if(parity(x)) 157 | ; value ^= 0xc001; 158 | ; return value; 159 | ; } 160 | ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen) 161 | ; { 162 | ; unsigned crc = 0xffff; 163 | ; 164 | ; while(argLen--) 165 | ; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc); 166 | ; return ~crc; 167 | ; } 168 | 169 | ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); 170 | ; argPtr r24+25 / r16+r17 171 | ; argLen r22 / r18 172 | ; temp variables: 173 | ; byte r18 / r22 174 | ; scratch r23 175 | ; resCrc r24+r25 / r16+r17 176 | ; ptr X / Z 177 | usbCrc16: 178 | mov ptrL, argPtrL 179 | mov ptrH, argPtrH 180 | ldi resCrcL, 0xFF 181 | ldi resCrcH, 0xFF 182 | rjmp usbCrc16LoopTest 183 | usbCrc16ByteLoop: 184 | ld byte, ptr+ 185 | eor resCrcL, byte ; resCrcL is now 'x' in table() 186 | mov byte, resCrcL ; compute parity of 'x' 187 | swap byte 188 | eor byte, resCrcL 189 | mov scratch, byte 190 | lsr byte 191 | lsr byte 192 | eor byte, scratch 193 | inc byte 194 | lsr byte 195 | andi byte, 1 ; byte is now parity(x) 196 | mov scratch, resCrcL 197 | mov resCrcL, resCrcH 198 | eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001; 199 | neg byte 200 | andi byte, 0xc0 201 | mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001; 202 | clr byte 203 | lsr scratch 204 | ror byte 205 | eor resCrcH, scratch 206 | eor resCrcL, byte 207 | lsr scratch 208 | ror byte 209 | eor resCrcH, scratch 210 | eor resCrcL, byte 211 | usbCrc16LoopTest: 212 | subi argLen, 1 213 | brsh usbCrc16ByteLoop 214 | com resCrcL 215 | com resCrcH 216 | ret 217 | 218 | #else /* USB_USE_FAST_CRC */ 219 | 220 | ; This implementation is slower, but has less code size 221 | ; 222 | ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); 223 | ; argPtr r24+25 / r16+r17 224 | ; argLen r22 / r18 225 | ; temp variables: 226 | ; byte r18 / r22 227 | ; bitCnt r19 228 | ; poly r20+r21 229 | ; scratch r23 230 | ; resCrc r24+r25 / r16+r17 231 | ; ptr X / Z 232 | usbCrc16: 233 | mov ptrL, argPtrL 234 | mov ptrH, argPtrH 235 | ldi resCrcL, 0 236 | ldi resCrcH, 0 237 | ldi polyL, lo8(0xa001) 238 | ldi polyH, hi8(0xa001) 239 | com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set 240 | ldi bitCnt, 0 ; loop counter with starnd condition = end condition 241 | rjmp usbCrcLoopEntry 242 | usbCrcByteLoop: 243 | ld byte, ptr+ 244 | eor resCrcL, byte 245 | usbCrcBitLoop: 246 | ror resCrcH ; carry is always set here (see brcs jumps to here) 247 | ror resCrcL 248 | brcs usbCrcNoXor 249 | eor resCrcL, polyL 250 | eor resCrcH, polyH 251 | usbCrcNoXor: 252 | subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times 253 | brcs usbCrcBitLoop 254 | usbCrcLoopEntry: 255 | subi argLen, -1 256 | brcs usbCrcByteLoop 257 | usbCrcReady: 258 | ret 259 | ; Thanks to Reimar Doeffinger for optimizing this CRC routine! 260 | 261 | #endif /* USB_USE_FAST_CRC */ 262 | 263 | ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len); 264 | usbCrc16Append: 265 | rcall usbCrc16 266 | st ptr+, resCrcL 267 | st ptr+, resCrcH 268 | ret 269 | 270 | #undef argLen 271 | #undef argPtrL 272 | #undef argPtrH 273 | #undef resCrcL 274 | #undef resCrcH 275 | #undef ptrL 276 | #undef ptrH 277 | #undef ptr 278 | #undef byte 279 | #undef bitCnt 280 | #undef polyL 281 | #undef polyH 282 | #undef scratch 283 | 284 | 285 | #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH 286 | #ifdef __IAR_SYSTEMS_ASM__ 287 | /* Register assignments for usbMeasureFrameLength on IAR cc */ 288 | /* Calling conventions on IAR: 289 | * First parameter passed in r16/r17, second in r18/r19 and so on. 290 | * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) 291 | * Result is passed in r16/r17 292 | * In case of the "tiny" memory model, pointers are only 8 bit with no 293 | * padding. We therefore pass argument 1 as "16 bit unsigned". 294 | */ 295 | # define resL r16 296 | # define resH r17 297 | # define cnt16L r30 298 | # define cnt16H r31 299 | # define cntH r18 300 | 301 | #else /* __IAR_SYSTEMS_ASM__ */ 302 | /* Register assignments for usbMeasureFrameLength on gcc */ 303 | /* Calling conventions on gcc: 304 | * First parameter passed in r24/r25, second in r22/23 and so on. 305 | * Callee must preserve r1-r17, r28/r29 306 | * Result is passed in r24/r25 307 | */ 308 | # define resL r24 309 | # define resH r25 310 | # define cnt16L r24 311 | # define cnt16H r25 312 | # define cntH r26 313 | #endif 314 | # define cnt16 cnt16L 315 | 316 | ; extern unsigned usbMeasurePacketLength(void); 317 | ; returns time between two idle strobes in multiples of 7 CPU clocks 318 | .global usbMeasureFrameLength 319 | usbMeasureFrameLength: 320 | ldi cntH, 6 ; wait ~ 10 ms for D- == 0 321 | clr cnt16L 322 | clr cnt16H 323 | usbMFTime16: 324 | dec cntH 325 | breq usbMFTimeout 326 | usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe) 327 | sbiw cnt16, 1 ;[0] [6] 328 | breq usbMFTime16 ;[2] 329 | sbic USBIN, USBMINUS ;[3] 330 | rjmp usbMFWaitStrobe ;[4] 331 | usbMFWaitIdle: ; then wait until idle again 332 | sbis USBIN, USBMINUS ;1 wait for D- == 1 333 | rjmp usbMFWaitIdle ;2 334 | ldi cnt16L, 1 ;1 represents cycles so far 335 | clr cnt16H ;1 336 | usbMFWaitLoop: 337 | in cntH, USBIN ;[0] [7] 338 | adiw cnt16, 1 ;[1] 339 | breq usbMFTimeout ;[3] 340 | andi cntH, USBMASK ;[4] 341 | brne usbMFWaitLoop ;[5] 342 | usbMFTimeout: 343 | #if resL != cnt16L 344 | mov resL, cnt16L 345 | mov resH, cnt16H 346 | #endif 347 | ret 348 | 349 | #undef resL 350 | #undef resH 351 | #undef cnt16 352 | #undef cnt16L 353 | #undef cnt16H 354 | #undef cntH 355 | 356 | #endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ 357 | 358 | ;---------------------------------------------------------------------------- 359 | ; Now include the clock rate specific code 360 | ;---------------------------------------------------------------------------- 361 | 362 | #ifndef USB_CFG_CLOCK_KHZ 363 | # ifdef F_CPU 364 | # define USB_CFG_CLOCK_KHZ (F_CPU/1000) 365 | # else 366 | # error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" 367 | # endif 368 | #endif 369 | 370 | #if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */ 371 | # if USB_CFG_CLOCK_KHZ == 18000 372 | # include "usbdrvasm18-crc.inc" 373 | # else 374 | # error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!" 375 | # endif 376 | #else /* USB_CFG_CHECK_CRC */ 377 | # if USB_CFG_CLOCK_KHZ == 12000 378 | # include "usbdrvasm12.inc" 379 | # elif USB_CFG_CLOCK_KHZ == 12800 380 | # include "usbdrvasm128.inc" 381 | # elif USB_CFG_CLOCK_KHZ == 15000 382 | # include "usbdrvasm15.inc" 383 | # elif USB_CFG_CLOCK_KHZ == 16000 384 | # include "usbdrvasm16.inc" 385 | # elif USB_CFG_CLOCK_KHZ == 16500 386 | # include "usbdrvasm165.inc" 387 | # elif USB_CFG_CLOCK_KHZ == 20000 388 | # include "usbdrvasm20.inc" 389 | # else 390 | # error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!" 391 | # endif 392 | #endif /* USB_CFG_CHECK_CRC */ 393 | -------------------------------------------------------------------------------- /firmware/usbconfig.h: -------------------------------------------------------------------------------- 1 | /* Name: usbconfig.h 2 | * Project: AVR USB driver 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-03-13 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt) 8 | * This Revision: $Id$ 9 | */ 10 | 11 | #ifndef __usbconfig_h_included__ 12 | #define __usbconfig_h_included__ 13 | 14 | /* 15 | General Description: 16 | This file contains the configuration options for the USB driver. 17 | 18 | Please note that the usbdrv contains a usbconfig-prototype.h file now. We 19 | recommend that you use that file as a template because it will always list 20 | the newest features and options. 21 | */ 22 | 23 | /* Fetch the hardware configuration from bootloaderconfig.h so that we have a 24 | * single file where hardware settings are stored. 25 | * Do not edit the functional settings below. 26 | */ 27 | #include "bootloaderconfig.h" 28 | 29 | #define USB_PUBLIC static 30 | /* Use the define above if you #include usbdrv.c instead of linking against it. 31 | * This technique saves a couple of bytes in flash memory. 32 | */ 33 | 34 | /* --------------------------- Functional Range ---------------------------- */ 35 | 36 | #define USB_CFG_HAVE_INTRIN_ENDPOINT 1 37 | /* Define this to 1 if you want to compile a version with two endpoints: The 38 | * default control endpoint 0 and an interrupt-in endpoint 1. 39 | */ 40 | #define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 41 | /* Define this to 1 if you want to compile a version with three endpoints: The 42 | * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in 43 | * endpoint 3. You must also enable endpoint 1 above. 44 | */ 45 | #define USB_CFG_SUPPRESS_INTR_CODE 1 46 | /* Define this to 1 if you want to declare interrupt-in endpoints, but don't 47 | * want to send any data over them. If this macro is defined to 1, functions 48 | * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if 49 | * you need the interrupt-in endpoints in order to comply to an interface 50 | * (e.g. HID), but never want to send any data. This option saves a couple 51 | * of bytes in flash memory and the transmit buffers in RAM. 52 | */ 53 | #define USB_CFG_IMPLEMENT_HALT 0 54 | /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature 55 | * for endpoint 1 (interrupt endpoint). Although you may not need this feature, 56 | * it is required by the standard. We have made it a config option because it 57 | * bloats the code considerably. 58 | */ 59 | #define USB_CFG_INTR_POLL_INTERVAL 200 60 | /* If you compile a version with endpoint 1 (interrupt-in), this is the poll 61 | * interval. The value is in milliseconds and must not be less than 10 ms for 62 | * low speed devices. 63 | */ 64 | #define USB_CFG_IS_SELF_POWERED 0 65 | /* Define this to 1 if the device has its own power supply. Set it to 0 if the 66 | * device is powered from the USB bus. 67 | */ 68 | #define USB_CFG_MAX_BUS_POWER 100 69 | /* Set this variable to the maximum USB bus power consumption of your device. 70 | * The value is in milliamperes. [It will be divided by two since USB 71 | * communicates power requirements in units of 2 mA.] 72 | */ 73 | #define USB_CFG_IMPLEMENT_FN_WRITE 1 74 | /* Set this to 1 if you want usbFunctionWrite() to be called for control-out 75 | * transfers. Set it to 0 if you don't need it and want to save a couple of 76 | * bytes. 77 | */ 78 | #define USB_CFG_IMPLEMENT_FN_READ 0 79 | /* Set this to 1 if you need to send control replies which are generated 80 | * "on the fly" when usbFunctionRead() is called. If you only want to send 81 | * data from a static buffer, set it to 0 and return the data from 82 | * usbFunctionSetup(). This saves a couple of bytes. 83 | */ 84 | #define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 85 | /* Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1. 86 | * You must implement the function usbFunctionWriteOut() which receives all 87 | * interrupt/bulk data sent to endpoint 1. 88 | */ 89 | #define USB_CFG_HAVE_FLOWCONTROL 0 90 | /* Define this to 1 if you want flowcontrol over USB data. See the definition 91 | * of the macros usbDisableAllRequests() and usbEnableAllRequests() in 92 | * usbdrv.h. 93 | */ 94 | #define TIMER0_PRESCALING 64 /* must match the configuration for TIMER0 in main */ 95 | #define TOLERATED_DEVIATION_PPT 5 /* max clock deviation before we tune in 1/10 % */ 96 | /* derived constants: */ 97 | #define EXPECTED_TIMER0_INCREMENT ((F_CPU / (1000 * TIMER0_PRESCALING)) & 0xff) 98 | #define TOLERATED_DEVIATION (TOLERATED_DEVIATION_PPT * F_CPU / (1000000 * TIMER0_PRESCALING)) 99 | #ifdef __ASSEMBLER__ 100 | macro tuneOsccal 101 | push YH ;[0] 102 | clr YH ;[2] 103 | in YL, TCNT0 ;[3] 104 | out TCNT0, YH ;[4] 105 | subi YL, EXPECTED_TIMER0_INCREMENT ;[5] 106 | #if OSCCAL > 0x3f 107 | lds YH, OSCCAL ;[6] 108 | #else 109 | in YH, OSCCAL ;[6] 110 | #endif 111 | cpi YL, TOLERATED_DEVIATION + 1 ;[7] 112 | brmi notTooHigh ;[8] 113 | subi YH, 1 ;[9] clock rate was too high 114 | rjmp osctuneDone ;[10] 115 | notTooHigh: 116 | cpi YL, -TOLERATED_DEVIATION ;[10] 117 | brpl osctuneDone ;[11] not too low 118 | inc YH ;[12] clock rate was too low 119 | osctuneDone: 120 | #if OSCCAL > 0x3f 121 | sts OSCCAL, YH ;[12-13] store tuned value 122 | #else 123 | out OSCCAL, YH ;[12-13] store tuned value 124 | #endif 125 | tuningOverflow: 126 | pop YH ;[14] 127 | endm ;[16] max number of cycles 128 | #endif 129 | #if F_CPU == 12800000 130 | # define USB_SOF_HOOK tuneOsccal 131 | #endif 132 | /* This macro (if defined) is executed in the assembler module when a 133 | * Start Of Frame condition is detected. It is recommended to define it to 134 | * the name of an assembler macro which is defined here as well so that more 135 | * than one assembler instruction can be used. The macro may use the register 136 | * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages 137 | * immediately after an SOF pulse may be lost and must be retried by the host. 138 | * What can you do with this hook? Since the SOF signal occurs exactly every 139 | * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in 140 | * designs running on the internal RC oscillator. 141 | * Please note that Start Of Frame detection works only if D- is wired to the 142 | * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! 143 | */ 144 | 145 | /* -------------------------- Device Description --------------------------- */ 146 | 147 | #define USB_CFG_VENDOR_ID 0xc0, 0x16 148 | /* USB vendor ID for the device, low byte first. If you have registered your 149 | * own Vendor ID, define it here. Otherwise you use obdev's free shared 150 | * VID/PID pair. Be sure to read USBID-License.txt for rules! 151 | */ 152 | #define USB_CFG_DEVICE_ID 0xdf, 0x05 153 | /* This is the ID of the product, low byte first. It is interpreted in the 154 | * scope of the vendor ID. If you have registered your own VID with usb.org 155 | * or if you have licensed a PID from somebody else, define it here. Otherwise 156 | * you use obdev's free shared VID/PID pair. Be sure to read the rules in 157 | * USBID-License.txt! 158 | */ 159 | #define USB_CFG_DEVICE_VERSION 0x00, 0x01 160 | /* Version number of the device: Minor number first, then major number. 161 | */ 162 | #define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' 163 | #define USB_CFG_VENDOR_NAME_LEN 8 164 | /* These two values define the vendor name returned by the USB device. The name 165 | * must be given as a list of characters under single quotes. The characters 166 | * are interpreted as Unicode (UTF-16) entities. 167 | * If you don't want a vendor name string, undefine these macros. 168 | * ALWAYS define a vendor name containing your Internet domain name if you use 169 | * obdev's free shared VID/PID pair. See the file USBID-License.txt for 170 | * details. 171 | */ 172 | #define USB_CFG_DEVICE_NAME 'H', 'I', 'D', 'B', 'o', 'o', 't' 173 | #define USB_CFG_DEVICE_NAME_LEN 7 174 | /* Same as above for the device name. If you don't want a device name, undefine 175 | * the macros. See the file USBID-License.txt before you assign a name if you 176 | * use a shared VID/PID. 177 | */ 178 | /*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ 179 | /*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ 180 | /* Same as above for the serial number. If you don't want a serial number, 181 | * undefine the macros. 182 | * It may be useful to provide the serial number through other means than at 183 | * compile time. See the section about descriptor properties below for how 184 | * to fine tune control over USB descriptors such as the string descriptor 185 | * for the serial number. 186 | */ 187 | #define USB_CFG_DEVICE_CLASS 0 188 | #define USB_CFG_DEVICE_SUBCLASS 0 189 | /* See USB specification if you want to conform to an existing device class. 190 | */ 191 | #define USB_CFG_INTERFACE_CLASS 3 /* HID */ 192 | #define USB_CFG_INTERFACE_SUBCLASS 0 193 | #define USB_CFG_INTERFACE_PROTOCOL 0 194 | /* See USB specification if you want to conform to an existing device class or 195 | * protocol. 196 | */ 197 | #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 33 /* total length of report descriptor */ 198 | /* Define this to the length of the HID report descriptor, if you implement 199 | * an HID device. Otherwise don't define it or define it to 0. 200 | */ 201 | 202 | /* ------------------- Fine Control over USB Descriptors ------------------- */ 203 | /* If you don't want to use the driver's default USB descriptors, you can 204 | * provide our own. These can be provided as (1) fixed length static data in 205 | * flash memory, (2) fixed length static data in RAM or (3) dynamically at 206 | * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more 207 | * information about this function. 208 | * Descriptor handling is configured through the descriptor's properties. If 209 | * no properties are defined or if they are 0, the default descriptor is used. 210 | * Possible properties are: 211 | * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched 212 | * at runtime via usbFunctionDescriptor(). 213 | * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found 214 | * in static memory is in RAM, not in flash memory. 215 | * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), 216 | * the driver must know the descriptor's length. The descriptor itself is 217 | * found at the address of a well known identifier (see below). 218 | * List of static descriptor names (must be declared PROGMEM if in flash): 219 | * char usbDescriptorDevice[]; 220 | * char usbDescriptorConfiguration[]; 221 | * char usbDescriptorHidReport[]; 222 | * char usbDescriptorString0[]; 223 | * int usbDescriptorStringVendor[]; 224 | * int usbDescriptorStringDevice[]; 225 | * int usbDescriptorStringSerialNumber[]; 226 | * Other descriptors can't be provided statically, they must be provided 227 | * dynamically at runtime. 228 | * 229 | * Descriptor properties are or-ed or added together, e.g.: 230 | * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) 231 | * 232 | * The following descriptors are defined: 233 | * USB_CFG_DESCR_PROPS_DEVICE 234 | * USB_CFG_DESCR_PROPS_CONFIGURATION 235 | * USB_CFG_DESCR_PROPS_STRINGS 236 | * USB_CFG_DESCR_PROPS_STRING_0 237 | * USB_CFG_DESCR_PROPS_STRING_VENDOR 238 | * USB_CFG_DESCR_PROPS_STRING_PRODUCT 239 | * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 240 | * USB_CFG_DESCR_PROPS_HID 241 | * USB_CFG_DESCR_PROPS_HID_REPORT 242 | * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) 243 | * 244 | */ 245 | 246 | #define USB_CFG_DESCR_PROPS_DEVICE 0 247 | #define USB_CFG_DESCR_PROPS_CONFIGURATION 0 248 | #define USB_CFG_DESCR_PROPS_STRINGS 0 249 | #define USB_CFG_DESCR_PROPS_STRING_0 0 250 | #define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 251 | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 252 | #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 253 | #define USB_CFG_DESCR_PROPS_HID 0 254 | #define USB_CFG_DESCR_PROPS_HID_REPORT 0 255 | #define USB_CFG_DESCR_PROPS_UNKNOWN 0 256 | 257 | #define usbMsgPtr_t unsigned short /* Use scalar type in order to save a couple of bytes */ 258 | 259 | /* ----------------------- Optional MCU Description ------------------------ */ 260 | 261 | /* The following configurations have working defaults in usbdrv.h. You 262 | * usually don't need to set them explicitly. Only if you want to run 263 | * the driver on a device which is not yet supported or with a compiler 264 | * which is not fully supported (such as IAR C) or if you use a differnt 265 | * interrupt than INT0, you may have to define some of these. 266 | */ 267 | /* #define USB_INTR_CFG MCUCR */ 268 | /* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */ 269 | /* #define USB_INTR_CFG_CLR 0 */ 270 | /* #define USB_INTR_ENABLE GIMSK */ 271 | /* #define USB_INTR_ENABLE_BIT INT0 */ 272 | /* #define USB_INTR_PENDING GIFR */ 273 | /* #define USB_INTR_PENDING_BIT INTF0 */ 274 | 275 | #endif /* __usbconfig_h_included__ */ 276 | -------------------------------------------------------------------------------- /firmware/usbdrv/usbdrvasm16.inc: -------------------------------------------------------------------------------- 1 | /* Name: usbdrvasm16.inc 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-06-15 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* Do not link this file! Link usbdrvasm.S instead, which includes the 11 | * appropriate implementation! 12 | */ 13 | 14 | /* 15 | General Description: 16 | This file is the 16 MHz version of the asssembler part of the USB driver. It 17 | requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC 18 | oscillator). 19 | 20 | See usbdrv.h for a description of the entire driver. 21 | 22 | Since almost all of this code is timing critical, don't change unless you 23 | really know what you are doing! Many parts require not only a maximum number 24 | of CPU cycles, but even an exact number of cycles! 25 | */ 26 | 27 | ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes 28 | ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte 29 | ; Numbers in brackets are clocks counted from center of last sync bit 30 | ; when instruction starts 31 | 32 | USB_INTR_VECTOR: 33 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 34 | push YL ;[-25] push only what is necessary to sync with edge ASAP 35 | in YL, SREG ;[-23] 36 | push YL ;[-22] 37 | push YH ;[-20] 38 | ;---------------------------------------------------------------------------- 39 | ; Synchronize with sync pattern: 40 | ;---------------------------------------------------------------------------- 41 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 42 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 43 | ;The first part waits at most 1 bit long since we must be in sync pattern. 44 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 45 | ;waitForJ, ensure that this prerequisite is met. 46 | waitForJ: 47 | inc YL 48 | sbis USBIN, USBMINUS 49 | brne waitForJ ; just make sure we have ANY timeout 50 | waitForK: 51 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 52 | sbis USBIN, USBMINUS ;[-15] 53 | rjmp foundK ;[-14] 54 | sbis USBIN, USBMINUS 55 | rjmp foundK 56 | sbis USBIN, USBMINUS 57 | rjmp foundK 58 | sbis USBIN, USBMINUS 59 | rjmp foundK 60 | sbis USBIN, USBMINUS 61 | rjmp foundK 62 | sbis USBIN, USBMINUS 63 | rjmp foundK 64 | #if USB_COUNT_SOF 65 | lds YL, usbSofCount 66 | inc YL 67 | sts usbSofCount, YL 68 | #endif /* USB_COUNT_SOF */ 69 | #ifdef USB_SOF_HOOK 70 | USB_SOF_HOOK 71 | #endif 72 | rjmp sofError 73 | foundK: ;[-12] 74 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] 75 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 76 | ;are cycles from center of first sync (double K) bit after the instruction 77 | push bitcnt ;[-12] 78 | ; [---] ;[-11] 79 | lds YL, usbInputBufOffset;[-10] 80 | ; [---] ;[-9] 81 | clr YH ;[-8] 82 | subi YL, lo8(-(usbRxBuf));[-7] [rx loop init] 83 | sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init] 84 | push shift ;[-5] 85 | ; [---] ;[-4] 86 | ldi bitcnt, 0x55 ;[-3] [rx loop init] 87 | sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) 88 | rjmp haveTwoBitsK ;[-1] 89 | pop shift ;[0] undo the push from before 90 | pop bitcnt ;[2] undo the push from before 91 | rjmp waitForK ;[4] this was not the end of sync, retry 92 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 93 | ; bit times (= 21 cycles). 94 | 95 | ;---------------------------------------------------------------------------- 96 | ; push more registers and initialize values while we sample the first bits: 97 | ;---------------------------------------------------------------------------- 98 | haveTwoBitsK: 99 | push x1 ;[1] 100 | push x2 ;[3] 101 | push x3 ;[5] 102 | ldi shift, 0 ;[7] 103 | ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that 104 | push x4 ;[9] == leap 105 | 106 | in x1, USBIN ;[11] <-- sample bit 0 107 | andi x1, USBMASK ;[12] 108 | bst x1, USBMINUS ;[13] 109 | bld shift, 7 ;[14] 110 | push cnt ;[15] 111 | ldi leap, 0 ;[17] [rx loop init] 112 | ldi cnt, USB_BUFSIZE;[18] [rx loop init] 113 | rjmp rxbit1 ;[19] arrives at [21] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap" 120 | ; accordingly to approximate this value in the long run. 121 | 122 | unstuff6: 123 | andi x2, USBMASK ;[03] 124 | ori x3, 1<<6 ;[04] will not be shifted any more 125 | andi shift, ~0x80;[05] 126 | mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6 127 | subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3 128 | rjmp didUnstuff6 ;[08] 129 | 130 | unstuff7: 131 | ori x3, 1<<7 ;[09] will not be shifted any more 132 | in x2, USBIN ;[00] [10] re-sample bit 7 133 | andi x2, USBMASK ;[01] 134 | andi shift, ~0x80;[02] 135 | subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 136 | rjmp didUnstuff7 ;[04] 137 | 138 | unstuffEven: 139 | ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0 140 | in x1, USBIN ;[00] [10] 141 | andi shift, ~0x80;[01] 142 | andi x1, USBMASK ;[02] 143 | breq se0 ;[03] 144 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 145 | nop2 ;[05] 146 | rjmp didUnstuffE ;[06] 147 | 148 | unstuffOdd: 149 | ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1 150 | in x2, USBIN ;[00] [10] 151 | andi shift, ~0x80;[01] 152 | andi x2, USBMASK ;[02] 153 | breq se0 ;[03] 154 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 155 | nop2 ;[05] 156 | rjmp didUnstuffO ;[06] 157 | 158 | rxByteLoop: 159 | andi x1, USBMASK ;[03] 160 | eor x2, x1 ;[04] 161 | subi leap, 1 ;[05] 162 | brpl skipLeap ;[06] 163 | subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte 164 | nop ;1 165 | skipLeap: 166 | subi x2, 1 ;[08] 167 | ror shift ;[09] 168 | didUnstuff6: 169 | cpi shift, 0xfc ;[10] 170 | in x2, USBIN ;[00] [11] <-- sample bit 7 171 | brcc unstuff6 ;[01] 172 | andi x2, USBMASK ;[02] 173 | eor x1, x2 ;[03] 174 | subi x1, 1 ;[04] 175 | ror shift ;[05] 176 | didUnstuff7: 177 | cpi shift, 0xfc ;[06] 178 | brcc unstuff7 ;[07] 179 | eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others 180 | st y+, x3 ;[09] store data 181 | rxBitLoop: 182 | in x1, USBIN ;[00] [11] <-- sample bit 0/2/4 183 | andi x1, USBMASK ;[01] 184 | eor x2, x1 ;[02] 185 | andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7 186 | subi x2, 1 ;[04] 187 | ror shift ;[05] 188 | cpi shift, 0xfc ;[06] 189 | brcc unstuffEven ;[07] 190 | didUnstuffE: 191 | lsr x3 ;[08] 192 | lsr x3 ;[09] 193 | rxbit1: 194 | in x2, USBIN ;[00] [10] <-- sample bit 1/3/5 195 | andi x2, USBMASK ;[01] 196 | breq se0 ;[02] 197 | eor x1, x2 ;[03] 198 | subi x1, 1 ;[04] 199 | ror shift ;[05] 200 | cpi shift, 0xfc ;[06] 201 | brcc unstuffOdd ;[07] 202 | didUnstuffO: 203 | subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 204 | brcs rxBitLoop ;[09] 205 | 206 | subi cnt, 1 ;[10] 207 | in x1, USBIN ;[00] [11] <-- sample bit 6 208 | brcc rxByteLoop ;[01] 209 | rjmp overflow 210 | 211 | macro POP_STANDARD ; 14 cycles 212 | pop cnt 213 | pop x4 214 | pop x3 215 | pop x2 216 | pop x1 217 | pop shift 218 | pop bitcnt 219 | endm 220 | macro POP_RETI ; 7 cycles 221 | pop YH 222 | pop YL 223 | out SREG, YL 224 | pop YL 225 | endm 226 | 227 | #include "asmcommon.inc" 228 | 229 | ; USB spec says: 230 | ; idle = J 231 | ; J = (D+ = 0), (D- = 1) 232 | ; K = (D+ = 1), (D- = 0) 233 | ; Spec allows 7.5 bit times from EOP to SOP for replies 234 | 235 | bitstuffN: 236 | eor x1, x4 ;[5] 237 | ldi x2, 0 ;[6] 238 | nop2 ;[7] 239 | nop ;[9] 240 | out USBOUT, x1 ;[10] <-- out 241 | rjmp didStuffN ;[0] 242 | 243 | bitstuff6: 244 | eor x1, x4 ;[5] 245 | ldi x2, 0 ;[6] Carry is zero due to brcc 246 | rol shift ;[7] compensate for ror shift at branch destination 247 | rjmp didStuff6 ;[8] 248 | 249 | bitstuff7: 250 | ldi x2, 0 ;[2] Carry is zero due to brcc 251 | rjmp didStuff7 ;[3] 252 | 253 | 254 | sendNakAndReti: 255 | ldi x3, USBPID_NAK ;[-18] 256 | rjmp sendX3AndReti ;[-17] 257 | sendAckAndReti: 258 | ldi cnt, USBPID_ACK ;[-17] 259 | sendCntAndReti: 260 | mov x3, cnt ;[-16] 261 | sendX3AndReti: 262 | ldi YL, 20 ;[-15] x3==r20 address is 20 263 | ldi YH, 0 ;[-14] 264 | ldi cnt, 2 ;[-13] 265 | ; rjmp usbSendAndReti fallthrough 266 | 267 | ;usbSend: 268 | ;pointer to data in 'Y' 269 | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] 270 | ;uses: x1...x4, btcnt, shift, cnt, Y 271 | ;Numbers in brackets are time since first bit of sync pattern is sent 272 | ;We don't match the transfer rate exactly (don't insert leap cycles every third 273 | ;byte) because the spec demands only 1.5% precision anyway. 274 | usbSendAndReti: ; 12 cycles until SOP 275 | in x2, USBDDR ;[-12] 276 | ori x2, USBMASK ;[-11] 277 | sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 278 | in x1, USBOUT ;[-8] port mirror for tx loop 279 | out USBDDR, x2 ;[-7] <- acquire bus 280 | ; need not init x2 (bitstuff history) because sync starts with 0 281 | ldi x4, USBMASK ;[-6] exor mask 282 | ldi shift, 0x80 ;[-5] sync byte is first byte sent 283 | txByteLoop: 284 | ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101 285 | txBitLoop: 286 | sbrs shift, 0 ;[-3] [7] 287 | eor x1, x4 ;[-2] [8] 288 | out USBOUT, x1 ;[-1] [9] <-- out N 289 | ror shift ;[0] [10] 290 | ror x2 ;[1] 291 | didStuffN: 292 | cpi x2, 0xfc ;[2] 293 | brcc bitstuffN ;[3] 294 | lsr bitcnt ;[4] 295 | brcc txBitLoop ;[5] 296 | brne txBitLoop ;[6] 297 | 298 | sbrs shift, 0 ;[7] 299 | eor x1, x4 ;[8] 300 | didStuff6: 301 | out USBOUT, x1 ;[-1] [9] <-- out 6 302 | ror shift ;[0] [10] 303 | ror x2 ;[1] 304 | cpi x2, 0xfc ;[2] 305 | brcc bitstuff6 ;[3] 306 | ror shift ;[4] 307 | didStuff7: 308 | ror x2 ;[5] 309 | sbrs x2, 7 ;[6] 310 | eor x1, x4 ;[7] 311 | nop ;[8] 312 | cpi x2, 0xfc ;[9] 313 | out USBOUT, x1 ;[-1][10] <-- out 7 314 | brcc bitstuff7 ;[0] [11] 315 | ld shift, y+ ;[1] 316 | dec cnt ;[3] 317 | brne txByteLoop ;[4] 318 | ;make SE0: 319 | cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] 320 | lds x2, usbNewDeviceAddr;[6] 321 | lsl x2 ;[8] we compare with left shifted address 322 | subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3 323 | sbci YH, 0 ;[10] 324 | out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle 325 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 326 | ;set address only after data packet was sent, not after handshake 327 | breq skipAddrAssign ;[0] 328 | sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer 329 | skipAddrAssign: 330 | ;end of usbDeviceAddress transfer 331 | ldi x2, 1< when compiling with IAR. 107 | - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each 108 | USB descriptor should be handled. It is now possible to provide descriptor 109 | data in Flash, RAM or dynamically at runtime. 110 | - STALL is now a status in usbTxLen* instead of a message. We can now conform 111 | to the spec and leave the stall status pending until it is cleared. 112 | - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the 113 | application code to reset data toggling on interrupt pipes. 114 | 115 | * Release 2006-07-18 116 | 117 | - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes 118 | an assembler error. 119 | - usbDeviceDisconnect() takes pull-up resistor to high impedance now. 120 | 121 | * Release 2007-02-01 122 | 123 | - Merged in some code size improvements from usbtiny (thanks to Dick 124 | Streefland for these optimizations!) 125 | - Special alignment requirement for usbRxBuf not required any more. Thanks 126 | again to Dick Streefland for this hint! 127 | - Reverted to "#warning" instead of unused static variables -- new versions 128 | of IAR CC should handle this directive. 129 | - Changed Open Source license to GNU GPL v2 in order to make linking against 130 | other free libraries easier. We no longer require publication of the 131 | circuit diagrams, but we STRONGLY encourage it. If you improve the driver 132 | itself, PLEASE grant us a royalty free license to your changes for our 133 | commercial license. 134 | 135 | * Release 2007-03-29 136 | 137 | - New configuration option "USB_PUBLIC" in usbconfig.h. 138 | - Set USB version number to 1.10 instead of 1.01. 139 | - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and 140 | USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences 141 | to USB_CFG_DESCR_PROPS_STRING_PRODUCT. 142 | - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver 143 | code. 144 | - New assembler module for 16 MHz crystal. 145 | - usbdrvasm.S contains common code only, clock-specific parts have been moved 146 | to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. 147 | 148 | * Release 2007-06-25 149 | 150 | - 16 MHz module: Do SE0 check in stuffed bits as well. 151 | 152 | * Release 2007-07-07 153 | 154 | - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary 155 | for negative values. 156 | - Added 15 MHz module contributed by V. Bosch. 157 | - Interrupt vector name can now be configured. This is useful if somebody 158 | wants to use a different hardware interrupt than INT0. 159 | 160 | * Release 2007-08-07 161 | 162 | - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is 163 | not exceeded. 164 | - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, 165 | USB_COUNT_SOF 166 | - USB_INTR_PENDING can now be a memory address, not just I/O 167 | 168 | * Release 2007-09-19 169 | 170 | - Split out common parts of assembler modules into separate include file 171 | - Made endpoint numbers configurable so that given interface definitions 172 | can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. 173 | - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() 174 | can handle any number of endpoints. 175 | - Define usbDeviceConnect() and usbDeviceDisconnect() even if no 176 | USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this 177 | case. 178 | 179 | * Release 2007-12-01 180 | 181 | - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size 182 | when USB_CFG_PULLUP_IOPORTNAME is not defined. 183 | 184 | * Release 2007-12-13 185 | 186 | - Renamed all include-only assembler modules from *.S to *.inc so that 187 | people don't add them to their project sources. 188 | - Distribute leap bits in tx loop more evenly for 16 MHz module. 189 | - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR 190 | - Avoid compiler warnings for constant expr range by casting some values in 191 | USB descriptors. 192 | 193 | * Release 2008-01-21 194 | 195 | - Fixed bug in 15 and 16 MHz module where the new address set with 196 | SET_ADDRESS was already accepted at the next NAK or ACK we send, not at 197 | the next data packet we send. This caused problems when the host polled 198 | too fast. Thanks to Alexander Neumann for his help and patience debugging 199 | this issue! 200 | 201 | * Release 2008-02-05 202 | 203 | - Fixed bug in 16.5 MHz module where a register was used in the interrupt 204 | handler before it was pushed. This bug was introduced with version 205 | 2007-09-19 when common parts were moved to a separate file. 206 | - Optimized CRC routine (thanks to Reimar Doeffinger). 207 | 208 | * Release 2008-02-16 209 | 210 | - Removed outdated IAR compatibility stuff (code sections). 211 | - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). 212 | - Added optional routine usbMeasureFrameLength() for calibration of the 213 | internal RC oscillator. 214 | 215 | * Release 2008-02-28 216 | 217 | - USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we 218 | start with sending USBPID_DATA0. 219 | - Changed defaults in usbconfig-prototype.h 220 | - Added free USB VID/PID pair for MIDI class devices 221 | - Restructured AVR-USB as separate package, not part of PowerSwitch any more. 222 | 223 | * Release 2008-04-18 224 | 225 | - Restructured usbdrv.c so that it is easier to read and understand. 226 | - Better code optimization with gcc 4. 227 | - If a second interrupt in endpoint is enabled, also add it to config 228 | descriptor. 229 | - Added config option for long transfers (above 254 bytes), see 230 | USB_CFG_LONG_TRANSFERS in usbconfig.h. 231 | - Added 20 MHz module contributed by Jeroen Benschop. 232 | 233 | * Release 2008-05-13 234 | 235 | - Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length 236 | was not incremented, pointer to length was incremented instead. 237 | - Added code to command line tool(s) which claims an interface. This code 238 | is disabled by default, but may be necessary on newer Linux kernels. 239 | - Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING". 240 | - New header "usbportability.h" prepares ports to other development 241 | environments. 242 | - Long transfers (above 254 bytes) did not work when usbFunctionRead() was 243 | used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!] 244 | - In hiddata.c (example code for sending/receiving data over HID), use 245 | USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so 246 | that we need not claim the interface. 247 | - in usbPoll() loop 20 times polling for RESET state instead of 10 times. 248 | This accounts for the higher clock rates we now support. 249 | - Added a module for 12.8 MHz RC oscillator with PLL in receiver loop. 250 | - Added hook to SOF code so that oscillator can be tuned to USB frame clock. 251 | - Added timeout to waitForJ loop. Helps preventing unexpected hangs. 252 | - Added example code for oscillator tuning to libs-device (thanks to 253 | Henrik Haftmann for the idea to this routine). 254 | - Implemented option USB_CFG_SUPPRESS_INTR_CODE. 255 | 256 | * Release 2008-10-22 257 | 258 | - Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and 259 | similar, not offset of 0x20 needs to be added. 260 | - Allow distribution under GPLv3 for those who have to link against other 261 | code distributed under GPLv3. 262 | 263 | * Release 2008-11-26 264 | 265 | - Removed libusb-win32 dependency for hid-data example in Makefile.windows. 266 | It was never required and confused many people. 267 | - Added extern uchar usbRxToken to usbdrv.h. 268 | - Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser. 269 | 270 | * Release 2009-03-23 271 | 272 | - Hid-mouse example used settings from hid-data example, fixed that. 273 | - Renamed project to V-USB due to a trademark issue with Atmel(r). 274 | - Changed CommercialLicense.txt and USBID-License.txt to make the 275 | background of USB ID registration clearer. 276 | 277 | * Release 2009-04-15 278 | 279 | - Changed CommercialLicense.txt to reflect the new range of PIDs from 280 | Jason Kotzin. 281 | - Removed USBID-License.txt in favor of USB-IDs-for-free.txt and 282 | USB-ID-FAQ.txt 283 | - Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in 284 | the center between bit 0 and 1 of each byte. This is where the data lines 285 | are expected to change and the sampled data may therefore be nonsense. 286 | We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-. 287 | - Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed, 288 | the unstuffing code in the receiver routine was 1 cycle too long. If 289 | multiple bytes had the unstuffing in bit 6, the error summed up until the 290 | receiver was out of sync. 291 | - Included option for faster CRC routine. 292 | Thanks to Slawomir Fras (BoskiDialer) for this code! 293 | - Updated bits in Configuration Descriptor's bmAttributes according to 294 | USB 1.1 (in particular bit 7, it is a must-be-set bit now). 295 | 296 | * Release 2009-08-22 297 | 298 | - Moved first DBG1() after odDebugInit() in all examples. 299 | - Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes 300 | V-USB compatible with the new "p" suffix devices (e.g. ATMega328p). 301 | - USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any 302 | more). 303 | - New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with 304 | more than 64 kB flash. 305 | - Built-in configuration descriptor allows custom definition for second 306 | endpoint now. 307 | 308 | * Release 2010-07-15 309 | 310 | - Fixed bug in usbDriverSetup() which prevented descriptor sizes above 255 311 | bytes. 312 | - Avoid a compiler warning for unused parameter in usbHandleResetHook() when 313 | compiler option -Wextra is enabled. 314 | - Fixed wrong hex value for some IDs in USB-IDs-for-free.txt. 315 | - Keep a define for USBATTR_BUSPOWER, although the flag does not exist 316 | in USB 1.1 any more. Set it to 0. This is for backward compatibility. 317 | 318 | * Release 2012-01-09 319 | 320 | - Define a separate (defined) type for usbMsgPtr so that projects using a 321 | tiny memory model can define it to an 8 bit type in usbconfig.h. This 322 | change also saves a couple of bytes when using a scalar 16 bit type. 323 | - Inserted "const" keyword for all PROGMEM declarations because new GCC 324 | requires it. 325 | - Fixed problem with dependence of usbportability.h on usbconfig.h. This 326 | problem occurred with IAR CC only. 327 | - Prepared repository for github.com. 328 | 329 | * Release 2012-12-06 -------------------------------------------------------------------------------- /firmware/usbdrv/usbdrvasm20.inc: -------------------------------------------------------------------------------- 1 | /* Name: usbdrvasm20.inc 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Jeroen Benschop 4 | * Based on usbdrvasm16.inc from Christian Starkjohann 5 | * Creation Date: 2008-03-05 6 | * Tabsize: 4 7 | * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH 8 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 9 | */ 10 | 11 | /* Do not link this file! Link usbdrvasm.S instead, which includes the 12 | * appropriate implementation! 13 | */ 14 | 15 | /* 16 | General Description: 17 | This file is the 20 MHz version of the asssembler part of the USB driver. It 18 | requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC 19 | oscillator). 20 | 21 | See usbdrv.h for a description of the entire driver. 22 | 23 | Since almost all of this code is timing critical, don't change unless you 24 | really know what you are doing! Many parts require not only a maximum number 25 | of CPU cycles, but even an exact number of cycles! 26 | */ 27 | 28 | #define leap2 x3 29 | #ifdef __IAR_SYSTEMS_ASM__ 30 | #define nextInst $+2 31 | #else 32 | #define nextInst .+0 33 | #endif 34 | 35 | ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes 36 | ;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte 37 | ; Numbers in brackets are clocks counted from center of last sync bit 38 | ; when instruction starts 39 | ;register use in receive loop: 40 | ; shift assembles the byte currently being received 41 | ; x1 holds the D+ and D- line state 42 | ; x2 holds the previous line state 43 | ; x4 (leap) is used to add a leap cycle once every three bytes received 44 | ; X3 (leap2) is used to add a leap cycle once every three stuff bits received 45 | ; bitcnt is used to determine when a stuff bit is due 46 | ; cnt holds the number of bytes left in the receive buffer 47 | 48 | USB_INTR_VECTOR: 49 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 50 | push YL ;[-28] push only what is necessary to sync with edge ASAP 51 | in YL, SREG ;[-26] 52 | push YL ;[-25] 53 | push YH ;[-23] 54 | ;---------------------------------------------------------------------------- 55 | ; Synchronize with sync pattern: 56 | ;---------------------------------------------------------------------------- 57 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 58 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 59 | ;The first part waits at most 1 bit long since we must be in sync pattern. 60 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 61 | ;waitForJ, ensure that this prerequisite is met. 62 | waitForJ: 63 | inc YL 64 | sbis USBIN, USBMINUS 65 | brne waitForJ ; just make sure we have ANY timeout 66 | waitForK: 67 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 68 | sbis USBIN, USBMINUS ;[-19] 69 | rjmp foundK ;[-18] 70 | sbis USBIN, USBMINUS 71 | rjmp foundK 72 | sbis USBIN, USBMINUS 73 | rjmp foundK 74 | sbis USBIN, USBMINUS 75 | rjmp foundK 76 | sbis USBIN, USBMINUS 77 | rjmp foundK 78 | sbis USBIN, USBMINUS 79 | rjmp foundK 80 | sbis USBIN, USBMINUS 81 | rjmp foundK 82 | sbis USBIN, USBMINUS 83 | rjmp foundK 84 | sbis USBIN, USBMINUS 85 | rjmp foundK 86 | #if USB_COUNT_SOF 87 | lds YL, usbSofCount 88 | inc YL 89 | sts usbSofCount, YL 90 | #endif /* USB_COUNT_SOF */ 91 | #ifdef USB_SOF_HOOK 92 | USB_SOF_HOOK 93 | #endif 94 | rjmp sofError 95 | foundK: ;[-16] 96 | ;{3, 5} after falling D- edge, average delay: 4 cycles 97 | ;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample 98 | ;use 1 bit time for setup purposes, then sample again. Numbers in brackets 99 | ;are cycles from center of first sync (double K) bit after the instruction 100 | push bitcnt ;[-16] 101 | ; [---] ;[-15] 102 | lds YL, usbInputBufOffset;[-14] 103 | ; [---] ;[-13] 104 | clr YH ;[-12] 105 | subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] 106 | sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] 107 | push shift ;[-9] 108 | ; [---] ;[-8] 109 | ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected 110 | nop2 ;[-6] 111 | ; [---] ;[-5] 112 | ldi bitcnt, 5 ;[-4] [rx loop init] 113 | sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) 114 | rjmp haveTwoBitsK ;[-2] 115 | pop shift ;[-1] undo the push from before 116 | pop bitcnt ;[1] 117 | rjmp waitForK ;[3] this was not the end of sync, retry 118 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 119 | ; bit times (= 27 cycles). 120 | 121 | ;---------------------------------------------------------------------------- 122 | ; push more registers and initialize values while we sample the first bits: 123 | ;---------------------------------------------------------------------------- 124 | haveTwoBitsK: 125 | push x1 ;[0] 126 | push x2 ;[2] 127 | push x3 ;[4] (leap2) 128 | ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit 129 | push x4 ;[7] == leap 130 | ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received 131 | push cnt ;[10] 132 | ldi cnt, USB_BUFSIZE ;[12] [rx loop init] 133 | ldi x2, 1< max 25 cycles interrupt disable 38 | ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes 39 | ;Numbers in brackets are maximum cycles since SOF. 40 | USB_INTR_VECTOR: 41 | ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt 42 | push YL ;2 [35] push only what is necessary to sync with edge ASAP 43 | in YL, SREG ;1 [37] 44 | push YL ;2 [39] 45 | ;---------------------------------------------------------------------------- 46 | ; Synchronize with sync pattern: 47 | ;---------------------------------------------------------------------------- 48 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 49 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 50 | ;The first part waits at most 1 bit long since we must be in sync pattern. 51 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 52 | ;waitForJ, ensure that this prerequisite is met. 53 | waitForJ: 54 | inc YL 55 | sbis USBIN, USBMINUS 56 | brne waitForJ ; just make sure we have ANY timeout 57 | waitForK: 58 | ;The following code results in a sampling window of 1/4 bit which meets the spec. 59 | sbis USBIN, USBMINUS 60 | rjmp foundK 61 | sbis USBIN, USBMINUS 62 | rjmp foundK 63 | sbis USBIN, USBMINUS 64 | rjmp foundK 65 | sbis USBIN, USBMINUS 66 | rjmp foundK 67 | sbis USBIN, USBMINUS 68 | rjmp foundK 69 | #if USB_COUNT_SOF 70 | lds YL, usbSofCount 71 | inc YL 72 | sts usbSofCount, YL 73 | #endif /* USB_COUNT_SOF */ 74 | #ifdef USB_SOF_HOOK 75 | USB_SOF_HOOK 76 | #endif 77 | rjmp sofError 78 | foundK: 79 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] 80 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 81 | ;are cycles from center of first sync (double K) bit after the instruction 82 | push YH ;2 [2] 83 | lds YL, usbInputBufOffset;2 [4] 84 | clr YH ;1 [5] 85 | subi YL, lo8(-(usbRxBuf));1 [6] 86 | sbci YH, hi8(-(usbRxBuf));1 [7] 87 | 88 | sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] 89 | rjmp haveTwoBitsK ;2 [10] 90 | pop YH ;2 [11] undo the push from before 91 | rjmp waitForK ;2 [13] this was not the end of sync, retry 92 | haveTwoBitsK: 93 | ;---------------------------------------------------------------------------- 94 | ; push more registers and initialize values while we sample the first bits: 95 | ;---------------------------------------------------------------------------- 96 | push shift ;2 [16] 97 | push x1 ;2 [12] 98 | push x2 ;2 [14] 99 | 100 | in x1, USBIN ;1 [17] <-- sample bit 0 101 | ldi shift, 0xff ;1 [18] 102 | bst x1, USBMINUS ;1 [19] 103 | bld shift, 0 ;1 [20] 104 | push x3 ;2 [22] 105 | push cnt ;2 [24] 106 | 107 | in x2, USBIN ;1 [25] <-- sample bit 1 108 | ser x3 ;1 [26] [inserted init instruction] 109 | eor x1, x2 ;1 [27] 110 | bst x1, USBMINUS ;1 [28] 111 | bld shift, 1 ;1 [29] 112 | ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] 113 | rjmp rxbit2 ;2 [32] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | unstuff0: ;1 (branch taken) 120 | andi x3, ~0x01 ;1 [15] 121 | mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit 122 | in x2, USBIN ;1 [17] <-- sample bit 1 again 123 | ori shift, 0x01 ;1 [18] 124 | rjmp didUnstuff0 ;2 [20] 125 | 126 | unstuff1: ;1 (branch taken) 127 | mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit 128 | andi x3, ~0x02 ;1 [22] 129 | ori shift, 0x02 ;1 [23] 130 | nop ;1 [24] 131 | in x1, USBIN ;1 [25] <-- sample bit 2 again 132 | rjmp didUnstuff1 ;2 [27] 133 | 134 | unstuff2: ;1 (branch taken) 135 | andi x3, ~0x04 ;1 [29] 136 | ori shift, 0x04 ;1 [30] 137 | mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit 138 | nop ;1 [32] 139 | in x2, USBIN ;1 [33] <-- sample bit 3 140 | rjmp didUnstuff2 ;2 [35] 141 | 142 | unstuff3: ;1 (branch taken) 143 | in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] 144 | andi x3, ~0x08 ;1 [35] 145 | ori shift, 0x08 ;1 [36] 146 | rjmp didUnstuff3 ;2 [38] 147 | 148 | unstuff4: ;1 (branch taken) 149 | andi x3, ~0x10 ;1 [40] 150 | in x1, USBIN ;1 [41] <-- sample stuffed bit 4 151 | ori shift, 0x10 ;1 [42] 152 | rjmp didUnstuff4 ;2 [44] 153 | 154 | unstuff5: ;1 (branch taken) 155 | andi x3, ~0x20 ;1 [48] 156 | in x2, USBIN ;1 [49] <-- sample stuffed bit 5 157 | ori shift, 0x20 ;1 [50] 158 | rjmp didUnstuff5 ;2 [52] 159 | 160 | unstuff6: ;1 (branch taken) 161 | andi x3, ~0x40 ;1 [56] 162 | in x1, USBIN ;1 [57] <-- sample stuffed bit 6 163 | ori shift, 0x40 ;1 [58] 164 | rjmp didUnstuff6 ;2 [60] 165 | 166 | ; extra jobs done during bit interval: 167 | ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] 168 | ; bit 1: se0 check 169 | ; bit 2: overflow check 170 | ; bit 3: recovery from delay [bit 0 tasks took too long] 171 | ; bit 4: none 172 | ; bit 5: none 173 | ; bit 6: none 174 | ; bit 7: jump, eor 175 | rxLoop: 176 | eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others 177 | in x1, USBIN ;1 [1] <-- sample bit 0 178 | st y+, x3 ;2 [3] store data 179 | ser x3 ;1 [4] 180 | nop ;1 [5] 181 | eor x2, x1 ;1 [6] 182 | bst x2, USBMINUS;1 [7] 183 | bld shift, 0 ;1 [8] 184 | in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) 185 | andi x2, USBMASK ;1 [10] 186 | breq se0 ;1 [11] SE0 check for bit 1 187 | andi shift, 0xf9 ;1 [12] 188 | didUnstuff0: 189 | breq unstuff0 ;1 [13] 190 | eor x1, x2 ;1 [14] 191 | bst x1, USBMINUS;1 [15] 192 | bld shift, 1 ;1 [16] 193 | rxbit2: 194 | in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) 195 | andi shift, 0xf3 ;1 [18] 196 | breq unstuff1 ;1 [19] do remaining work for bit 1 197 | didUnstuff1: 198 | subi cnt, 1 ;1 [20] 199 | brcs overflow ;1 [21] loop control 200 | eor x2, x1 ;1 [22] 201 | bst x2, USBMINUS;1 [23] 202 | bld shift, 2 ;1 [24] 203 | in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) 204 | andi shift, 0xe7 ;1 [26] 205 | breq unstuff2 ;1 [27] 206 | didUnstuff2: 207 | eor x1, x2 ;1 [28] 208 | bst x1, USBMINUS;1 [29] 209 | bld shift, 3 ;1 [30] 210 | didUnstuff3: 211 | andi shift, 0xcf ;1 [31] 212 | breq unstuff3 ;1 [32] 213 | in x1, USBIN ;1 [33] <-- sample bit 4 214 | eor x2, x1 ;1 [34] 215 | bst x2, USBMINUS;1 [35] 216 | bld shift, 4 ;1 [36] 217 | didUnstuff4: 218 | andi shift, 0x9f ;1 [37] 219 | breq unstuff4 ;1 [38] 220 | nop2 ;2 [40] 221 | in x2, USBIN ;1 [41] <-- sample bit 5 222 | eor x1, x2 ;1 [42] 223 | bst x1, USBMINUS;1 [43] 224 | bld shift, 5 ;1 [44] 225 | didUnstuff5: 226 | andi shift, 0x3f ;1 [45] 227 | breq unstuff5 ;1 [46] 228 | nop2 ;2 [48] 229 | in x1, USBIN ;1 [49] <-- sample bit 6 230 | eor x2, x1 ;1 [50] 231 | bst x2, USBMINUS;1 [51] 232 | bld shift, 6 ;1 [52] 233 | didUnstuff6: 234 | cpi shift, 0x02 ;1 [53] 235 | brlo unstuff6 ;1 [54] 236 | nop2 ;2 [56] 237 | in x2, USBIN ;1 [57] <-- sample bit 7 238 | eor x1, x2 ;1 [58] 239 | bst x1, USBMINUS;1 [59] 240 | bld shift, 7 ;1 [60] 241 | didUnstuff7: 242 | cpi shift, 0x04 ;1 [61] 243 | brsh rxLoop ;2 [63] loop control 244 | unstuff7: 245 | andi x3, ~0x80 ;1 [63] 246 | ori shift, 0x80 ;1 [64] 247 | in x2, USBIN ;1 [65] <-- sample stuffed bit 7 248 | nop ;1 [66] 249 | rjmp didUnstuff7 ;2 [68] 250 | 251 | macro POP_STANDARD ; 12 cycles 252 | pop cnt 253 | pop x3 254 | pop x2 255 | pop x1 256 | pop shift 257 | pop YH 258 | endm 259 | macro POP_RETI ; 5 cycles 260 | pop YL 261 | out SREG, YL 262 | pop YL 263 | endm 264 | 265 | #include "asmcommon.inc" 266 | 267 | ;---------------------------------------------------------------------------- 268 | ; Transmitting data 269 | ;---------------------------------------------------------------------------- 270 | 271 | txByteLoop: 272 | txBitloop: 273 | stuffN1Delay: ; [03] 274 | ror shift ;[-5] [11] [59] 275 | brcc doExorN1 ;[-4] [60] 276 | subi x4, 1 ;[-3] 277 | brne commonN1 ;[-2] 278 | lsl shift ;[-1] compensate ror after rjmp stuffDelay 279 | nop ;[00] stuffing consists of just waiting 8 cycles 280 | rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear 281 | 282 | sendNakAndReti: ;0 [-19] 19 cycles until SOP 283 | ldi x3, USBPID_NAK ;1 [-18] 284 | rjmp usbSendX3 ;2 [-16] 285 | sendAckAndReti: ;0 [-19] 19 cycles until SOP 286 | ldi x3, USBPID_ACK ;1 [-18] 287 | rjmp usbSendX3 ;2 [-16] 288 | sendCntAndReti: ;0 [-17] 17 cycles until SOP 289 | mov x3, cnt ;1 [-16] 290 | usbSendX3: ;0 [-16] 291 | ldi YL, 20 ;1 [-15] 'x3' is R20 292 | ldi YH, 0 ;1 [-14] 293 | ldi cnt, 2 ;1 [-13] 294 | ; rjmp usbSendAndReti fallthrough 295 | 296 | ; USB spec says: 297 | ; idle = J 298 | ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 299 | ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 300 | ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) 301 | 302 | ;usbSend: 303 | ;pointer to data in 'Y' 304 | ;number of bytes in 'cnt' -- including sync byte 305 | ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] 306 | ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) 307 | usbSendAndReti: 308 | in x2, USBDDR ;[-12] 12 cycles until SOP 309 | ori x2, USBMASK ;[-11] 310 | sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 311 | out USBDDR, x2 ;[-8] <--- acquire bus 312 | in x1, USBOUT ;[-7] port mirror for tx loop 313 | ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror) 314 | ldi x2, USBMASK ;[-5] 315 | push x4 ;[-4] 316 | doExorN1: 317 | eor x1, x2 ;[-2] [06] [62] 318 | ldi x4, 6 ;[-1] [07] [63] 319 | commonN1: 320 | stuffN2Delay: 321 | out USBOUT, x1 ;[00] [08] [64] <--- set bit 322 | ror shift ;[01] 323 | brcc doExorN2 ;[02] 324 | subi x4, 1 ;[03] 325 | brne commonN2 ;[04] 326 | lsl shift ;[05] compensate ror after rjmp stuffDelay 327 | rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear 328 | doExorN2: 329 | eor x1, x2 ;[04] [12] 330 | ldi x4, 6 ;[05] [13] 331 | commonN2: 332 | nop ;[06] [14] 333 | subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1 334 | out USBOUT, x1 ;[08] [16] <--- set bit 335 | brcs txBitloop ;[09] [25] [41] 336 | 337 | stuff6Delay: 338 | ror shift ;[42] [50] 339 | brcc doExor6 ;[43] 340 | subi x4, 1 ;[44] 341 | brne common6 ;[45] 342 | lsl shift ;[46] compensate ror after rjmp stuffDelay 343 | nop ;[47] stuffing consists of just waiting 8 cycles 344 | rjmp stuff6Delay ;[48] after ror, C bit is reliably clear 345 | doExor6: 346 | eor x1, x2 ;[45] [53] 347 | ldi x4, 6 ;[46] 348 | common6: 349 | stuff7Delay: 350 | ror shift ;[47] [55] 351 | out USBOUT, x1 ;[48] <--- set bit 352 | brcc doExor7 ;[49] 353 | subi x4, 1 ;[50] 354 | brne common7 ;[51] 355 | lsl shift ;[52] compensate ror after rjmp stuffDelay 356 | rjmp stuff7Delay ;[53] after ror, C bit is reliably clear 357 | doExor7: 358 | eor x1, x2 ;[51] [59] 359 | ldi x4, 6 ;[52] 360 | common7: 361 | ld shift, y+ ;[53] 362 | tst cnt ;[55] 363 | out USBOUT, x1 ;[56] <--- set bit 364 | brne txByteLoop ;[57] 365 | 366 | ;make SE0: 367 | cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] 368 | lds x2, usbNewDeviceAddr;[59] 369 | lsl x2 ;[61] we compare with left shifted address 370 | subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3 371 | sbci YH, 0 ;[63] 372 | out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle 373 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 374 | ;set address only after data packet was sent, not after handshake 375 | breq skipAddrAssign ;[01] 376 | sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer 377 | skipAddrAssign: 378 | ;end of usbDeviceAddress transfer 379 | ldi x2, 1< max 52 cycles interrupt disable 31 | ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes 32 | ;nominal frequency: 16.5 MHz -> 11 cycles per bit 33 | ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%) 34 | ; Numbers in brackets are clocks counted from center of last sync bit 35 | ; when instruction starts 36 | 37 | 38 | USB_INTR_VECTOR: 39 | ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt 40 | push YL ;[-23] push only what is necessary to sync with edge ASAP 41 | in YL, SREG ;[-21] 42 | push YL ;[-20] 43 | ;---------------------------------------------------------------------------- 44 | ; Synchronize with sync pattern: 45 | ;---------------------------------------------------------------------------- 46 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 47 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 48 | ;The first part waits at most 1 bit long since we must be in sync pattern. 49 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 50 | ;waitForJ, ensure that this prerequisite is met. 51 | waitForJ: 52 | inc YL 53 | sbis USBIN, USBMINUS 54 | brne waitForJ ; just make sure we have ANY timeout 55 | waitForK: 56 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 57 | sbis USBIN, USBMINUS ;[-15] 58 | rjmp foundK ;[-14] 59 | sbis USBIN, USBMINUS 60 | rjmp foundK 61 | sbis USBIN, USBMINUS 62 | rjmp foundK 63 | sbis USBIN, USBMINUS 64 | rjmp foundK 65 | sbis USBIN, USBMINUS 66 | rjmp foundK 67 | sbis USBIN, USBMINUS 68 | rjmp foundK 69 | #if USB_COUNT_SOF 70 | lds YL, usbSofCount 71 | inc YL 72 | sts usbSofCount, YL 73 | #endif /* USB_COUNT_SOF */ 74 | #ifdef USB_SOF_HOOK 75 | USB_SOF_HOOK 76 | #endif 77 | rjmp sofError 78 | foundK: ;[-12] 79 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] 80 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 81 | ;are cycles from center of first sync (double K) bit after the instruction 82 | push r0 ;[-12] 83 | ; [---] ;[-11] 84 | push YH ;[-10] 85 | ; [---] ;[-9] 86 | lds YL, usbInputBufOffset;[-8] 87 | ; [---] ;[-7] 88 | clr YH ;[-6] 89 | subi YL, lo8(-(usbRxBuf));[-5] [rx loop init] 90 | sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init] 91 | mov r0, x2 ;[-3] [rx loop init] 92 | sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) 93 | rjmp haveTwoBitsK ;[-1] 94 | pop YH ;[0] undo the pushes from before 95 | pop r0 ;[2] 96 | rjmp waitForK ;[4] this was not the end of sync, retry 97 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 98 | ; bit times (= 22 cycles). 99 | 100 | ;---------------------------------------------------------------------------- 101 | ; push more registers and initialize values while we sample the first bits: 102 | ;---------------------------------------------------------------------------- 103 | haveTwoBitsK: ;[1] 104 | push shift ;[1] 105 | push x1 ;[3] 106 | push x2 ;[5] 107 | push x3 ;[7] 108 | ldi shift, 0xff ;[9] [rx loop init] 109 | ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag 110 | 111 | in x1, USBIN ;[11] <-- sample bit 0 112 | bst x1, USBMINUS ;[12] 113 | bld shift, 0 ;[13] 114 | push x4 ;[14] == phase 115 | ; [---] ;[15] 116 | push cnt ;[16] 117 | ; [---] ;[17] 118 | ldi phase, 0 ;[18] [rx loop init] 119 | ldi cnt, USB_BUFSIZE;[19] [rx loop init] 120 | rjmp rxbit1 ;[20] 121 | ; [---] ;[21] 122 | 123 | ;---------------------------------------------------------------------------- 124 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 125 | ;---------------------------------------------------------------------------- 126 | /* 127 | byte oriented operations done during loop: 128 | bit 0: store data 129 | bit 1: SE0 check 130 | bit 2: overflow check 131 | bit 3: catch up 132 | bit 4: rjmp to achieve conditional jump range 133 | bit 5: PLL 134 | bit 6: catch up 135 | bit 7: jump, fixup bitstuff 136 | ; 87 [+ 2] cycles 137 | ------------------------------------------------------------------ 138 | */ 139 | continueWithBit5: 140 | in x2, USBIN ;[055] <-- bit 5 141 | eor r0, x2 ;[056] 142 | or phase, r0 ;[057] 143 | sbrc phase, USBMINUS ;[058] 144 | lpm ;[059] optional nop3; modifies r0 145 | in phase, USBIN ;[060] <-- phase 146 | eor x1, x2 ;[061] 147 | bst x1, USBMINUS ;[062] 148 | bld shift, 5 ;[063] 149 | andi shift, 0x3f ;[064] 150 | in x1, USBIN ;[065] <-- bit 6 151 | breq unstuff5 ;[066] *** unstuff escape 152 | eor phase, x1 ;[067] 153 | eor x2, x1 ;[068] 154 | bst x2, USBMINUS ;[069] 155 | bld shift, 6 ;[070] 156 | didUnstuff6: ;[ ] 157 | in r0, USBIN ;[071] <-- phase 158 | cpi shift, 0x02 ;[072] 159 | brlo unstuff6 ;[073] *** unstuff escape 160 | didUnstuff5: ;[ ] 161 | nop2 ;[074] 162 | ; [---] ;[075] 163 | in x2, USBIN ;[076] <-- bit 7 164 | eor x1, x2 ;[077] 165 | bst x1, USBMINUS ;[078] 166 | bld shift, 7 ;[079] 167 | didUnstuff7: ;[ ] 168 | eor r0, x2 ;[080] 169 | or phase, r0 ;[081] 170 | in r0, USBIN ;[082] <-- phase 171 | cpi shift, 0x04 ;[083] 172 | brsh rxLoop ;[084] 173 | ; [---] ;[085] 174 | unstuff7: ;[ ] 175 | andi x3, ~0x80 ;[085] 176 | ori shift, 0x80 ;[086] 177 | in x2, USBIN ;[087] <-- sample stuffed bit 7 178 | nop ;[088] 179 | rjmp didUnstuff7 ;[089] 180 | ; [---] ;[090] 181 | ;[080] 182 | 183 | unstuff5: ;[067] 184 | eor phase, x1 ;[068] 185 | andi x3, ~0x20 ;[069] 186 | ori shift, 0x20 ;[070] 187 | in r0, USBIN ;[071] <-- phase 188 | mov x2, x1 ;[072] 189 | nop ;[073] 190 | nop2 ;[074] 191 | ; [---] ;[075] 192 | in x1, USBIN ;[076] <-- bit 6 193 | eor r0, x1 ;[077] 194 | or phase, r0 ;[078] 195 | eor x2, x1 ;[079] 196 | bst x2, USBMINUS ;[080] 197 | bld shift, 6 ;[081] no need to check bitstuffing, we just had one 198 | in r0, USBIN ;[082] <-- phase 199 | rjmp didUnstuff5 ;[083] 200 | ; [---] ;[084] 201 | ;[074] 202 | 203 | unstuff6: ;[074] 204 | andi x3, ~0x40 ;[075] 205 | in x1, USBIN ;[076] <-- bit 6 again 206 | ori shift, 0x40 ;[077] 207 | nop2 ;[078] 208 | ; [---] ;[079] 209 | rjmp didUnstuff6 ;[080] 210 | ; [---] ;[081] 211 | ;[071] 212 | 213 | unstuff0: ;[013] 214 | eor r0, x2 ;[014] 215 | or phase, r0 ;[015] 216 | andi x2, USBMASK ;[016] check for SE0 217 | in r0, USBIN ;[017] <-- phase 218 | breq didUnstuff0 ;[018] direct jump to se0 would be too long 219 | andi x3, ~0x01 ;[019] 220 | ori shift, 0x01 ;[020] 221 | mov x1, x2 ;[021] mov existing sample 222 | in x2, USBIN ;[022] <-- bit 1 again 223 | rjmp didUnstuff0 ;[023] 224 | ; [---] ;[024] 225 | ;[014] 226 | 227 | unstuff1: ;[024] 228 | eor r0, x1 ;[025] 229 | or phase, r0 ;[026] 230 | andi x3, ~0x02 ;[027] 231 | in r0, USBIN ;[028] <-- phase 232 | ori shift, 0x02 ;[029] 233 | mov x2, x1 ;[030] 234 | rjmp didUnstuff1 ;[031] 235 | ; [---] ;[032] 236 | ;[022] 237 | 238 | unstuff2: ;[035] 239 | eor r0, x2 ;[036] 240 | or phase, r0 ;[037] 241 | andi x3, ~0x04 ;[038] 242 | in r0, USBIN ;[039] <-- phase 243 | ori shift, 0x04 ;[040] 244 | mov x1, x2 ;[041] 245 | rjmp didUnstuff2 ;[042] 246 | ; [---] ;[043] 247 | ;[033] 248 | 249 | unstuff3: ;[043] 250 | in x2, USBIN ;[044] <-- bit 3 again 251 | eor r0, x2 ;[045] 252 | or phase, r0 ;[046] 253 | andi x3, ~0x08 ;[047] 254 | ori shift, 0x08 ;[048] 255 | nop ;[049] 256 | in r0, USBIN ;[050] <-- phase 257 | rjmp didUnstuff3 ;[051] 258 | ; [---] ;[052] 259 | ;[042] 260 | 261 | unstuff4: ;[053] 262 | andi x3, ~0x10 ;[054] 263 | in x1, USBIN ;[055] <-- bit 4 again 264 | ori shift, 0x10 ;[056] 265 | rjmp didUnstuff4 ;[057] 266 | ; [---] ;[058] 267 | ;[048] 268 | 269 | rxLoop: ;[085] 270 | eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others 271 | in x1, USBIN ;[000] <-- bit 0 272 | st y+, x3 ;[001] 273 | ; [---] ;[002] 274 | eor r0, x1 ;[003] 275 | or phase, r0 ;[004] 276 | eor x2, x1 ;[005] 277 | in r0, USBIN ;[006] <-- phase 278 | ser x3 ;[007] 279 | bst x2, USBMINUS ;[008] 280 | bld shift, 0 ;[009] 281 | andi shift, 0xf9 ;[010] 282 | rxbit1: ;[ ] 283 | in x2, USBIN ;[011] <-- bit 1 284 | breq unstuff0 ;[012] *** unstuff escape 285 | andi x2, USBMASK ;[013] SE0 check for bit 1 286 | didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff 287 | breq se0 ;[014] 288 | eor r0, x2 ;[015] 289 | or phase, r0 ;[016] 290 | in r0, USBIN ;[017] <-- phase 291 | eor x1, x2 ;[018] 292 | bst x1, USBMINUS ;[019] 293 | bld shift, 1 ;[020] 294 | andi shift, 0xf3 ;[021] 295 | didUnstuff1: ;[ ] 296 | in x1, USBIN ;[022] <-- bit 2 297 | breq unstuff1 ;[023] *** unstuff escape 298 | eor r0, x1 ;[024] 299 | or phase, r0 ;[025] 300 | subi cnt, 1 ;[026] overflow check 301 | brcs overflow ;[027] 302 | in r0, USBIN ;[028] <-- phase 303 | eor x2, x1 ;[029] 304 | bst x2, USBMINUS ;[030] 305 | bld shift, 2 ;[031] 306 | andi shift, 0xe7 ;[032] 307 | didUnstuff2: ;[ ] 308 | in x2, USBIN ;[033] <-- bit 3 309 | breq unstuff2 ;[034] *** unstuff escape 310 | eor r0, x2 ;[035] 311 | or phase, r0 ;[036] 312 | eor x1, x2 ;[037] 313 | bst x1, USBMINUS ;[038] 314 | in r0, USBIN ;[039] <-- phase 315 | bld shift, 3 ;[040] 316 | andi shift, 0xcf ;[041] 317 | didUnstuff3: ;[ ] 318 | breq unstuff3 ;[042] *** unstuff escape 319 | nop ;[043] 320 | in x1, USBIN ;[044] <-- bit 4 321 | eor x2, x1 ;[045] 322 | bst x2, USBMINUS ;[046] 323 | bld shift, 4 ;[047] 324 | didUnstuff4: ;[ ] 325 | eor r0, x1 ;[048] 326 | or phase, r0 ;[049] 327 | in r0, USBIN ;[050] <-- phase 328 | andi shift, 0x9f ;[051] 329 | breq unstuff4 ;[052] *** unstuff escape 330 | rjmp continueWithBit5;[053] 331 | ; [---] ;[054] 332 | 333 | macro POP_STANDARD ; 16 cycles 334 | pop cnt 335 | pop x4 336 | pop x3 337 | pop x2 338 | pop x1 339 | pop shift 340 | pop YH 341 | pop r0 342 | endm 343 | macro POP_RETI ; 5 cycles 344 | pop YL 345 | out SREG, YL 346 | pop YL 347 | endm 348 | 349 | #include "asmcommon.inc" 350 | 351 | 352 | ; USB spec says: 353 | ; idle = J 354 | ; J = (D+ = 0), (D- = 1) 355 | ; K = (D+ = 1), (D- = 0) 356 | ; Spec allows 7.5 bit times from EOP to SOP for replies 357 | 358 | bitstuff7: 359 | eor x1, x4 ;[4] 360 | ldi x2, 0 ;[5] 361 | nop2 ;[6] C is zero (brcc) 362 | rjmp didStuff7 ;[8] 363 | 364 | bitstuffN: 365 | eor x1, x4 ;[5] 366 | ldi x2, 0 ;[6] 367 | lpm ;[7] 3 cycle NOP, modifies r0 368 | out USBOUT, x1 ;[10] <-- out 369 | rjmp didStuffN ;[0] 370 | 371 | #define bitStatus x3 372 | 373 | sendNakAndReti: 374 | ldi cnt, USBPID_NAK ;[-19] 375 | rjmp sendCntAndReti ;[-18] 376 | sendAckAndReti: 377 | ldi cnt, USBPID_ACK ;[-17] 378 | sendCntAndReti: 379 | mov r0, cnt ;[-16] 380 | ldi YL, 0 ;[-15] R0 address is 0 381 | ldi YH, 0 ;[-14] 382 | ldi cnt, 2 ;[-13] 383 | ; rjmp usbSendAndReti fallthrough 384 | 385 | ;usbSend: 386 | ;pointer to data in 'Y' 387 | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] 388 | ;uses: x1...x4, shift, cnt, Y 389 | ;Numbers in brackets are time since first bit of sync pattern is sent 390 | usbSendAndReti: ; 12 cycles until SOP 391 | in x2, USBDDR ;[-12] 392 | ori x2, USBMASK ;[-11] 393 | sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 394 | in x1, USBOUT ;[-8] port mirror for tx loop 395 | out USBDDR, x2 ;[-7] <- acquire bus 396 | ; need not init x2 (bitstuff history) because sync starts with 0 397 | ldi x4, USBMASK ;[-6] exor mask 398 | ldi shift, 0x80 ;[-5] sync byte is first byte sent 399 | ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes 400 | byteloop: 401 | bitloop: 402 | sbrs shift, 0 ;[8] [-3] 403 | eor x1, x4 ;[9] [-2] 404 | out USBOUT, x1 ;[10] [-1] <-- out 405 | ror shift ;[0] 406 | ror x2 ;[1] 407 | didStuffN: 408 | cpi x2, 0xfc ;[2] 409 | brcc bitstuffN ;[3] 410 | nop ;[4] 411 | subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37 412 | brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value 413 | sbrs shift, 0 ;[7] 414 | eor x1, x4 ;[8] 415 | ror shift ;[9] 416 | didStuff7: 417 | out USBOUT, x1 ;[10] <-- out 418 | ror x2 ;[0] 419 | cpi x2, 0xfc ;[1] 420 | brcc bitstuff7 ;[2] 421 | ld shift, y+ ;[3] 422 | dec cnt ;[5] 423 | brne byteloop ;[6] 424 | ;make SE0: 425 | cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] 426 | lds x2, usbNewDeviceAddr;[8] 427 | lsl x2 ;[10] we compare with left shifted address 428 | out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle 429 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 430 | ;set address only after data packet was sent, not after handshake 431 | subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0 432 | sbci YH, 0 ;[1] 433 | breq skipAddrAssign ;[2] 434 | sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer 435 | skipAddrAssign: 436 | ;end of usbDeviceAddress transfer 437 | ldi x2, 1<