From fbcb466855a1594d8d0c55df0d33b661e40902ec Mon Sep 17 00:00:00 2001 From: Stefan Krulj Date: Sat, 30 Jun 2012 15:17:31 +0200 Subject: [PATCH] Working, needs button code, sending keys kinda slow --- libcrypt/Makefile | 49 +- libcrypt/README | 73 +++ libcrypt/buffer/buffer.c | 54 ++ libcrypt/buffer/buffer.h | 16 + libcrypt/kbd_layouts/README | 9 + libcrypt/kbd_layouts/de.h | 162 ++++++ libcrypt/kbd_layouts/us.h | 163 ++++++ libcrypt/main.c | 96 +++- libcrypt/main.h | 12 +- libcrypt/usb_callback.c | 3 +- libcrypt/usb_key_codes.h | 10 + libcrypt/usbdrv/USB-ID-FAQ.txt | 149 ++++++ libcrypt/usbdrv/USB-IDs-for-free.txt | 154 ++++++ libcrypt/usbdrv/usbdrvasm128.inc | 750 +++++++++++++++++++++++++++ libcrypt/usbdrv/usbdrvasm18-crc.inc | 707 +++++++++++++++++++++++++ libcrypt/usbdrv/usbdrvasm20.inc | 360 +++++++++++++ libcrypt/usbdrv/usbportability.h | 144 +++++ 17 files changed, 2850 insertions(+), 61 deletions(-) create mode 100644 libcrypt/README create mode 100644 libcrypt/buffer/buffer.c create mode 100644 libcrypt/buffer/buffer.h create mode 100644 libcrypt/kbd_layouts/README create mode 100644 libcrypt/kbd_layouts/de.h create mode 100644 libcrypt/kbd_layouts/us.h create mode 100644 libcrypt/usb_key_codes.h create mode 100644 libcrypt/usbdrv/USB-ID-FAQ.txt create mode 100644 libcrypt/usbdrv/USB-IDs-for-free.txt create mode 100644 libcrypt/usbdrv/usbdrvasm128.inc create mode 100644 libcrypt/usbdrv/usbdrvasm18-crc.inc create mode 100644 libcrypt/usbdrv/usbdrvasm20.inc create mode 100644 libcrypt/usbdrv/usbportability.h diff --git a/libcrypt/Makefile b/libcrypt/Makefile index e2fcfc9..44ad4f7 100644 --- a/libcrypt/Makefile +++ b/libcrypt/Makefile @@ -6,9 +6,18 @@ # check shows md5 and sha1 sum of uploaded code # clean remove obj- and temporary files # -# change PROJNAME for new projects -# add your object files to OBJS # +#------------------------------------------------------------------------- +# User defines +#------------------------------------------------------------------------- + +SECRET = -DSECLEN=6 -DSECRET="{0xC0, 0xFF, 0xEE, 0xDE, 0xCA, 0xDE}" +DEFINES = -DDEBUG -DF_CPU=16000000 -DKBD_DE -DEEPROM_SIZE=512 $(SECRET) + +#DEFINES = -DDEBUG -DCALIB -DF_CPU=16500000 -DKBD_US -DEEPROM_SIZE=512 + +# target architecture +MCU = atmega168 #------------------------------------------------------------------------- # project specific things @@ -20,28 +29,20 @@ OBJS = main.o \ trunc.o \ calib.o \ usb_callback.o \ + buffer/buffer.o \ sha1/sha1-asm.o \ hmac-sha1/hmac-sha1.o \ - mem_eval/mem_eval.o \ usbdrv/usbdrv.o \ usbdrv/oddebug.o \ - usbdrv/usbdrvasm.o \ - usart/usart.o - -INCLUDE = -Isha1 -Ihmac-sha1 -Iusbdrv -Iusart -Imem_eval - -DEBUG = -DDEBUG -DF_CPU=16000000 -#DEBUG = -DDEBUG -DCALIB -DF_CPU=16000000 + usbdrv/usbdrvasm.o -# target architecture -MCU = atmega168 +INCLUDE = -Isha1 -Ihmac-sha1 -Iusbdrv -Imem_eval -Ibuffer #------------------------------------------------------------------------- # macros for the tools #------------------------------------------------------------------------- BAUD = 19200 - BINFORMAT = ihex # programmer format, this depends on programmer or bootloader you're using @@ -71,7 +72,7 @@ PROGR = lboot #PROGR = avrdude # Flags -CFLAGS = -Wall -Os -mmcu=$(MCU) $(DEBUG) +CFLAGS = -Wall -Os -mmcu=$(MCU) $(DEFINES) LDFLAGS = -Wl,-Map=$*.map -mmcu=$(MCU) OCFLAGS = -O $(BINFORMAT) # at16prog @@ -89,37 +90,23 @@ all: $(PROJNAME).hex $(PROJNAME).elf $(OBJS) %.hex: %.elf $(OBJCOPY) $(OCFLAGS) $< $@ @chmod ugo-x $@ - %.elf: $(OBJS) $(CC) $(OBJS) $(LIBS) $(LDFLAGS) -o $@ - %.o: %.c $(CC) $(CFLAGS) $(INCLUDE) -Wa,-a=$*.list -c -o $@ $< - %.o: %.S $(CC) $(CFLAGS) $(INCLUDE) -Wa,-a=$*.list -c -o $@ $< + install: $(PROJNAME).hex $(PROGR) $(PRFLAGS) -p $(PROJNAME).hex -#$(PROGR) $(PRFLAGS) -U flash:w:$(PROJNAME).hex - -download: $(PROJNAME).down.hex - echo "" - -$(PROJNAME).down.hex: - $(PROGR) $(PRFLAGS) -U flash:r:$(PROJNAME).down.hex:i - -check:$(PROJNAME).down.hex $(PROJNAME).hex - $(PROGR) $(PRFLAGS) -v $(PROJNAME).hex - + #$(PROGR) $(PRFLAGS) -U flash:w:$(PROJNAME).hex + TMP=*.hex *.elf *.map *.list *.o *~ - define TMPCLEAN @cd $(dir); rm -f $(TMP) endef -SCHLIMM=cd $(dir);echo $(dir)$(TMP) - clean: $(foreach dir,$(dir $(OBJS)), $(TMPCLEAN)) diff --git a/libcrypt/README b/libcrypt/README new file mode 100644 index 0000000..3cec4dc --- /dev/null +++ b/libcrypt/README @@ -0,0 +1,73 @@ + +What is this thing? +------------------- + +This device is a hash-based-one-time-password (=HOTP, RFC 4226) generator. You +can use them to make an existing authentication more secure or as a single +authentication barrier to enter a system. You can easily do both on linux +machines using the oath toolkit (http://www.nongnu.org/oath-toolkit/). + +How does it work? +----------------- + +The device is an USB-Stick, which opearates as a virtual keyboard. A login +sequence usually happens like this: + + 1. When asked for the OTP, plug in the device and wait a few seconds + 2. The device should generate a few keystrokes - this is the token + 3. Confirm the login by pressing the button on the device this will + generate an ENTER-keystroke and the internal counter is icremented + by one. + 4. Pressing the button again reset the device, and the sequence + repeats. Otherwise just unplug it. + +How to install the firmware? +---------------------------- + +You will need the avr-gcc toolchain (avr-gcc, avr-binutils and the avrlibc). +Go to the source tree (the same directory where this file should be). Now edit +the Makefile. If you don't know what you're doing simply edit the "SECRET" +define: + + SECRET = -DSECLEN=6 -DSECRET="{0xC0, 0xFF, 0xEE, 0xDE, 0xCA, 0xDE}" + +It is recomended to take a secret of length 20 (longer secrets are supported but +do not provide additional security). This is basically a sha1 digest. I usually +do the following to generate secrets: + + + +type make. If the compilation runs well, you will end up with some .hex files: + - The main file: hotp.hex (this goes to the flash) + - The eeprom init: eeprom.hex (this goes to the internal eeprom) + +Security considerations: +------------------------ + +If you're interested in HOTP security in general, pleas read the corresponding +sections in the RFC 4226. This section deals with the security of the device +hardware. + +The device was designed in order to provide additional security, not as the +only protection from attacking/entering your system. If your entire +authentication is based on this device you should consider the following: + +Anyone who obtains a one time passwordt(=token) from the device, will be able +to authenticate as you until the system and the token-generator get synchronized +(i.e. your next legitimate login)! + +The ATtiny85 contains two Lock bits which can be programmed (=set to 0) in order +to protect the program and EEPROM memory. While the program contains the shared +secret, the EEPROM contains the counter used to compute the. Although the shared +secret is a little more critical, nobody should know either one of them. You +should therefore enable the two lock bits. + +If you lose the token-generator it might be hard to get into the system. You +could ask the super user, to look up the counter and secret or disable the +HOTP login method. If you lost your super users token-generator and you have +physical access to the device you can use a live-cd to rescue your system. +There are several tutorials on the web that describe how to do that. And if +you don't have physical access or can't ask your super user I can only recomend +not to loose the token-generator. + + diff --git a/libcrypt/buffer/buffer.c b/libcrypt/buffer/buffer.c new file mode 100644 index 0000000..1575455 --- /dev/null +++ b/libcrypt/buffer/buffer.c @@ -0,0 +1,54 @@ +#include "buffer.h" + +uint8_t buff_empty=1; +static uint8_t buff_start; +static uint8_t buff_end; + +static uint8_t buffer[BUFFER_SIZE]; + +uint8_t readBuffer(void){ + uint8_t ret; + if(buff_empty){ + return 0; + } + ret=buffer[buff_end]; + buff_end++; + if(buff_end==BUFFER_SIZE){ + buff_end=0; + } + if(buff_end==buff_start){ + buff_empty=1; + } + return ret; +} + +void writeToBuffer(uint8_t data){ + if(buff_start==buff_end && !buff_empty){ + /*overrun*/ + return; + } + buffer[buff_start]=data; + buff_start++; + if(buff_start==BUFFER_SIZE){ + buff_start=0; + } + buff_empty=0; +} + +void buffer_unum(uint32_t num){ + uint8_t text[8] = {0,0,0,0,0,0,0,0}; + uint8_t i; + + for(i=1;i<=8;i++){ + /*calculate scancode from digit*/ + text[8-i] = USB_KEY_1-1+((num)%10); + if(text[8-i]==USB_KEY_1-1){ + text[8-i]=USB_KEY_0; + } + num/=10; + } + for(i=0;i<8;i++){ + writeToBuffer(text[i]); + } +} + diff --git a/libcrypt/buffer/buffer.h b/libcrypt/buffer/buffer.h new file mode 100644 index 0000000..331e04d --- /dev/null +++ b/libcrypt/buffer/buffer.h @@ -0,0 +1,16 @@ +#ifndef _BUFFER_H +#define _BUFFER_H + +#include "../usb_key_codes.h" +#include + +#define BUFFER_SIZE 10 + +extern uint8_t buff_empty; +uint8_t readBuffer(void); +void writeToBuffer(uint8_t data); +void buffer_unum(uint32_t num); + +#endif //_BUFFER_H + + diff --git a/libcrypt/kbd_layouts/README b/libcrypt/kbd_layouts/README new file mode 100644 index 0000000..0622498 --- /dev/null +++ b/libcrypt/kbd_layouts/README @@ -0,0 +1,9 @@ +Author: Stefan Krulj aka powertomato@gmail.com + +The layouts were all derived from the US layout which has been taken from the +PS/2 to USB Keyboard scancode transition table which can be found at: + + http://www.microsoft.com/taiwan/whdc/archive/scancode.mspx#ENB + +I didn't test most of the codes so use them with care. If you find any errors +please feel free to email me. diff --git a/libcrypt/kbd_layouts/de.h b/libcrypt/kbd_layouts/de.h new file mode 100644 index 0000000..a6d27b8 --- /dev/null +++ b/libcrypt/kbd_layouts/de.h @@ -0,0 +1,162 @@ +#ifndef _USB_KEY_CODES_H +#define _USB_KEY_CODES_H + +//DE Layout + +#define USB_MOD_CONTROL_LEFT (1<<0) +#define USB_MOD_SHIFT_LEFT (1<<1) +#define USB_MOD_ALT_LEFT (1<<2) +#define USB_MOD_GUI_LEFT (1<<3) +#define USB_MOD_CONTROL_RIGHT (1<<4) +#define USB_MOD_SHIFT_RIGHT (1<<5) +#define USB_MOD_ALT_RIGHT (1<<6) +#define USB_MOD_GUI_RIGHT (1<<7) + +#define USB_KEY_NOP 0x00 +#define USB_KEY_OVERRUN 0x01 +#define USB_KEY_POST_FAIL 0x02 +#define USB_KEY_ERR_UNDEF 0x03 + +#define USB_KEY_A 0x04 +#define USB_KEY_B 0x05 +#define USB_KEY_C 0x06 +#define USB_KEY_D 0x07 +#define USB_KEY_E 0x08 +#define USB_KEY_F 0x09 +#define USB_KEY_G 0x0A +#define USB_KEY_H 0x0B +#define USB_KEY_I 0x0C +#define USB_KEY_J 0x0D +#define USB_KEY_K 0x0E +#define USB_KEY_L 0x0F +#define USB_KEY_M 0x10 +#define USB_KEY_N 0x11 +#define USB_KEY_O 0x12 +#define USB_KEY_P 0x13 +#define USB_KEY_Q 0x14 +#define USB_KEY_R 0x15 +#define USB_KEY_S 0x16 +#define USB_KEY_T 0x17 +#define USB_KEY_U 0x18 +#define USB_KEY_V 0x19 +#define USB_KEY_W 0x1A +#define USB_KEY_X 0x1B +#define USB_KEY_Z 0x1C +#define USB_KEY_Y 0x1D + +#define USB_KEY_1 0x1E +#define USB_KEY_2 0x1F +#define USB_KEY_3 0x20 +#define USB_KEY_4 0x21 +#define USB_KEY_5 0x22 +#define USB_KEY_6 0x23 +#define USB_KEY_7 0x24 +#define USB_KEY_8 0x25 +#define USB_KEY_9 0x26 +#define USB_KEY_0 0x27 + +#define USB_KEY_ENTER 0x28 +#define USB_KEY_ESC 0x29 +#define USB_KEY_BSPACE 0x2A +#define USB_KEY_TAB 0x2B +#define USB_KEY_SPACE 0x2C + +#define USB_KEY_SZ 0x2D +#define USB_KEY_AOSTROPHE 0x2E +#define USB_KEY_UE 0x2F +#define USB_KEY_PLUS 0x30 +#define USB_KEY_NUM_SIGN_ALT 0x31 +#define USB_KEY_NUM_SIGN 0x32 +#define USB_KEY_OE 0x33 +#define USB_KEY_AE 0x34 +#define USB_KEY_CIRCUMFLEX 0x35 +#define USB_KEY_COMMA 0x36 +#define USB_KEY_DOT 0x37 +#define USB_KEY_MINUS 0x38 + +#define USB_KEY_F1 0x3A +#define USB_KEY_F2 0x3B +#define USB_KEY_F3 0x3C +#define USB_KEY_F4 0x3D +#define USB_KEY_F5 0x3E +#define USB_KEY_F6 0x3F +#define USB_KEY_F7 0x40 +#define USB_KEY_F8 0x41 +#define USB_KEY_F9 0x42 +#define USB_KEY_F10 0x43 +#define USB_KEY_F11 0x44 +#define USB_KEY_F12 0x45 + +#define USB_KEY_PRINT 0x46 +#define USB_KEY_PAUSE 0x48 +#define USB_KEY_INSERT 0x49 +#define USB_KEY_HOME 0x4A +#define USB_KEY_PAGE_UP 0x4B +#define USB_KEY_DEL 0x4C +#define USB_KEY_END 0x4D +#define USB_KEY_PAGE_DOWN 0x4E + +#define USB_KEY_RIGHT 0x4F +#define USB_KEY_LEFT 0x50 +#define USB_KEY_DOWN 0x51 +#define USB_KEY_UP 0x52 + +#define USB_KEY_NUM_LOCK 0x53 +#define USB_KEY_CAPS_LOCK 0x39 +#define USB_KEY_SCROLL_LOCK 0x47 + +#define USB_KEY_KP_SLASH 0x54 +#define USB_KEY_KP_ASTERISK 0x55 +#define USB_KEY_KP_MINUS 0x56 +#define USB_KEY_KP_PLUS 0x57 +#define USB_KEY_KP_ENTER 0x58 +#define USB_KEY_KP_1 0x59 +#define USB_KEY_KP_2 0x5A +#define USB_KEY_KP_3 0x5B +#define USB_KEY_KP_4 0x5C +#define USB_KEY_KP_5 0x5D +#define USB_KEY_KP_6 0x5E +#define USB_KEY_KP_7 0x5F +#define USB_KEY_KP_8 0x60 +#define USB_KEY_KP_9 0x61 +#define USB_KEY_KP_0 0x62 +#define USB_KEY_KP_DOT 0x63 + +#define USB_KEY_LT 0x64 + +//Special & media-keys +#define USB_KEY_NEXT_TRACK 0x00B5 +#define USB_KEY_PREV_TRACK 0x00B6 + +#define USB_KEY_STOP 0x00B7 +#define USB_KEY_PLAY_PAUSE 0x00CD +#define USB_KEY_MUTE 0x00E2 + +#define USB_KEY_BASS_BOOST 0x00E5 +#define USB_KEY_LOUDNESS 0x00E7 + +#define USB_KEY_VOL_UP 0x00E9 +#define USB_KEY_VOL_DOWN 0x00EA + +#define USB_KEY_BASS_UP 0x0152 +#define USB_KEY_BASS_DOWN 0x0153 + +#define USB_KEY_TREBLE_UP 0x0154 +#define USB_KEY_TREBLE_DOWN 0x0155 + +#define USB_KEY_MEDIA_SELECT 0x0183 + +#define USB_KEY_MAIL 0x018A +#define USB_KEY_CALC 0x0192 +#define USB_KEY_PLACES 0x0194 +#define USB_KEY_MY_COMPUTER 0x0194 + +#define USB_KEY_WWW_SEARCH 0x0221 +#define USB_KEY_WWW_HOME 0x0223 +#define USB_KEY_WWW_BACK 0x0224 +#define USB_KEY_WWW_FORWARD 0x0225 +#define USB_KEY_WWW_STOP 0x0226 +#define USB_KEY_WWW_REFRESH 0x0227 +#define USB_KEY_WWW_BOOKMARKS 0x022A + +#endif //_USB_KEY_CODES_H*** diff --git a/libcrypt/kbd_layouts/us.h b/libcrypt/kbd_layouts/us.h new file mode 100644 index 0000000..4ddfed0 --- /dev/null +++ b/libcrypt/kbd_layouts/us.h @@ -0,0 +1,163 @@ +#ifndef _USB_KEY_CODES_H +#define _USB_KEY_CODES_H + +//US Layout + +#define USB_MOD_CONTROL_LEFT (1<<0) +#define USB_MOD_SHIFT_LEFT (1<<1) +#define USB_MOD_ALT_LEFT (1<<2) +#define USB_MOD_GUI_LEFT (1<<3) +#define USB_MOD_CONTROL_RIGHT (1<<4) +#define USB_MOD_SHIFT_RIGHT (1<<5) +#define USB_MOD_ALT_RIGHT (1<<6) +#define USB_MOD_GUI_RIGHT (1<<7) + +#define USB_KEY_NOP 0x00 +#define USB_KEY_OVERRUN 0x01 +#define USB_KEY_POST_FAIL 0x02 +#define USB_KEY_ERR_UNDEF 0x03 + +#define USB_KEY_A 0x04 +#define USB_KEY_B 0x05 +#define USB_KEY_C 0x06 +#define USB_KEY_D 0x07 +#define USB_KEY_E 0x08 +#define USB_KEY_F 0x09 +#define USB_KEY_G 0x0A +#define USB_KEY_H 0x0B +#define USB_KEY_I 0x0C +#define USB_KEY_J 0x0D +#define USB_KEY_K 0x0E +#define USB_KEY_L 0x0F +#define USB_KEY_M 0x10 +#define USB_KEY_N 0x11 +#define USB_KEY_O 0x12 +#define USB_KEY_P 0x13 +#define USB_KEY_Q 0x14 +#define USB_KEY_R 0x15 +#define USB_KEY_S 0x16 +#define USB_KEY_T 0x17 +#define USB_KEY_U 0x18 +#define USB_KEY_V 0x19 +#define USB_KEY_W 0x1A +#define USB_KEY_X 0x1B +#define USB_KEY_Y 0x1C +#define USB_KEY_Z 0x1D + +#define USB_KEY_1 0x1E +#define USB_KEY_2 0x1F +#define USB_KEY_3 0x20 +#define USB_KEY_4 0x21 +#define USB_KEY_5 0x22 +#define USB_KEY_6 0x23 +#define USB_KEY_7 0x24 +#define USB_KEY_8 0x25 +#define USB_KEY_9 0x26 +#define USB_KEY_0 0x27 + +#define USB_KEY_ENTER 0x28 +#define USB_KEY_ESC 0x29 +#define USB_KEY_BSPACE 0x2A +#define USB_KEY_TAB 0x2B +#define USB_KEY_SPACE 0x2C + +#define USB_KEY_MINUS 0x2D +#define USB_KEY_EQ 0x2E +#define USB_KEY_BRACKET_O 0x2F +#define USB_KEY_BRACKET_C 0x30 +#define USB_KEY_BSLASH 0x31 +#define USB_KEY_EURO1 0x32 +#define USB_KEY_SEMICOL 0x33 +#define USB_KEY_QUOT 0x34 +#define USB_KEY_GRAVIS 0x35 +#define USB_KEY_BTICK 0x35 +#define USB_KEY_COMMA 0x36 +#define USB_KEY_DOT 0x37 +#define USB_KEY_SLASH 0x38 + +#define USB_KEY_F1 0x3A +#define USB_KEY_F2 0x3B +#define USB_KEY_F3 0x3C +#define USB_KEY_F4 0x3D +#define USB_KEY_F5 0x3E +#define USB_KEY_F6 0x3F +#define USB_KEY_F7 0x40 +#define USB_KEY_F8 0x41 +#define USB_KEY_F9 0x42 +#define USB_KEY_F10 0x43 +#define USB_KEY_F11 0x44 +#define USB_KEY_F12 0x45 + +#define USB_KEY_PRINT 0x46 +#define USB_KEY_PAUSE 0x48 +#define USB_KEY_INSERT 0x49 +#define USB_KEY_HOME 0x4A +#define USB_KEY_PAGE_UP 0x4B +#define USB_KEY_DEL 0x4C +#define USB_KEY_END 0x4D +#define USB_KEY_PAGE_DOWN 0x4E + +#define USB_KEY_RIGHT 0x4F +#define USB_KEY_LEFT 0x50 +#define USB_KEY_DOWN 0x51 +#define USB_KEY_UP 0x52 + +#define USB_KEY_NUM_LOCK 0x53 +#define USB_KEY_CAPS_LOCK 0x39 +#define USB_KEY_SCROLL_LOCK 0x47 + +#define USB_KEY_KP_SLASH 0x54 +#define USB_KEY_KP_ASTERISK 0x55 +#define USB_KEY_KP_MINUS 0x56 +#define USB_KEY_KP_PLUS 0x57 +#define USB_KEY_KP_ENTER 0x58 +#define USB_KEY_KP_1 0x59 +#define USB_KEY_KP_2 0x5A +#define USB_KEY_KP_3 0x5B +#define USB_KEY_KP_4 0x5C +#define USB_KEY_KP_5 0x5D +#define USB_KEY_KP_6 0x5E +#define USB_KEY_KP_7 0x5F +#define USB_KEY_KP_8 0x60 +#define USB_KEY_KP_9 0x61 +#define USB_KEY_KP_0 0x62 +#define USB_KEY_KP_DOT 0x63 + +#define USB_KEY_EURO2 0x64 + +//Special & media-keys +#define USB_KEY_NEXT_TRACK 0x00B5 +#define USB_KEY_PREV_TRACK 0x00B6 + +#define USB_KEY_STOP 0x00B7 +#define USB_KEY_PLAY_PAUSE 0x00CD +#define USB_KEY_MUTE 0x00E2 + +#define USB_KEY_BASS_BOOST 0x00E5 +#define USB_KEY_LOUDNESS 0x00E7 + +#define USB_KEY_VOL_UP 0x00E9 +#define USB_KEY_VOL_DOWN 0x00EA + +#define USB_KEY_BASS_UP 0x0152 +#define USB_KEY_BASS_DOWN 0x0153 + +#define USB_KEY_TREBLE_UP 0x0154 +#define USB_KEY_TREBLE_DOWN 0x0155 + +#define USB_KEY_MEDIA_SELECT 0x0183 + +#define USB_KEY_MAIL 0x018A +#define USB_KEY_CALC 0x0192 +#define USB_KEY_PLACES 0x0194 +#define USB_KEY_MY_COMPUTER 0x0194 + +#define USB_KEY_WWW_SEARCH 0x0221 +#define USB_KEY_WWW_HOME 0x0223 +#define USB_KEY_WWW_BACK 0x0224 +#define USB_KEY_WWW_FORWARD 0x0225 +#define USB_KEY_WWW_STOP 0x0226 +#define USB_KEY_WWW_REFRESH 0x0227 +#define USB_KEY_WWW_BOOKMARKS 0x022A + +#endif //_USB_KEY_CODES_H*** diff --git a/libcrypt/main.c b/libcrypt/main.c index 48f245e..e2a8fe7 100644 --- a/libcrypt/main.c +++ b/libcrypt/main.c @@ -6,9 +6,6 @@ */ #include "main.h" -#define SECRET {'J', 'e', 'f', 'e'}; -#define SECLEN 20 - #define MSG "what do ya want for nothing?" #include @@ -19,34 +16,65 @@ #include #include -#include "usbdrv.h" -#include "usb_key_codes.h" - uint8_t reportBuffer[2]; /* buffer for HID reports */ uint8_t idleRate; +static uint8_t kbd_event_state=0; + +uint32_t get_cnt(){ + void* p=(void*)eeprom_read_word(CNTPOS_PTR); + return eeprom_read_dword(p); +} + +uint8_t inc_cnt(){ + uint32_t cnt; + void* p=(void*)eeprom_read_word(CNTPOS_PTR); + cnt=eeprom_read_dword(p); + if(cnt==UINT32_MAX){ + eeprom_write_word(CNTPOS_PTR,ERROR); + return 0; + } + eeprom_write_dword(p,cnt+1); + + retry: + if(eeprom_read_dword(p)!=cnt+1){ + eeprom_write_dword(p,cnt+1); + if(eeprom_read_dword(p)!=cnt+1){ + /*Probabbly the EEPROM position is bad, try an other*/ + p+=4; + if(p+4>(void*)EEPROM_SIZE){ + eeprom_write_word(CNTPOS_PTR,ERROR); + return 0; + } + eeprom_write_word(CNTPOS_PTR,(uint16_t)p); + + /* I know some people don't like goto because of dijkstra's + legendary article "goto considered harmfull". The truth is he + didn't want us to stop using goto at all, but to think if it + is appropriate. The alternative here would be a loop around + this whole block and some well-placed "break" and "continue" + kbd_event_statements - I think that would be even worse than the goto*/ + + goto retry; + } + } + return 1; +} + void buildReport(uint8_t mod, uint8_t key){ reportBuffer[0] = mod; reportBuffer[1] = key; } - int main(void){ #ifdef CALIB uint8_t calibrationValue; #endif - uint8_t *p; - uint16_t siz; uint8_t sec[SECLEN]=SECRET; - - /*InitializeMemory(); - - initUSART(); - tx('+'); - sendunum( get_otp_from_cnt(777,8,sec,SECLEN) );*/ - + uint32_t cnt; + #ifdef CALIB /* oszillator calibration */ calibrationValue = eeprom_read_byte(0); /* calibration value from last time */ @@ -54,29 +82,43 @@ int main(void){ OSCCAL = calibrationValue; } #endif //CALLIB - //odDebugInit(); + usbDeviceDisconnect(); _delay_ms(300); /* mustn't be that exact */ usbDeviceConnect(); - uint8_t foo=0; + wdt_enable(WDTO_500MS); + + writeToBuffer(USB_KEY_NOP); + writeToBuffer(USB_KEY_NOP); + + if( eeprom_read_word(CNTPOS_PTR)==ERROR ){ + writeToBuffer(USB_KEY_E); + writeToBuffer(USB_KEY_R); + writeToBuffer(USB_KEY_R); + writeToBuffer(USB_KEY_O); + writeToBuffer(USB_KEY_R); + }else{ + cnt = get_cnt(); + buffer_unum(get_otp_from_cnt(cnt,8,sec,SECLEN)); + //inc_cnt(); + } + usbInit(); sei(); - for(;;){ /* main event loop */ + for(;;){ + wdt_reset(); usbPoll(); /* we can send another key */ if(usbInterruptIsReady()){ - foo=!foo; - if(foo) - buildReport(0x00, USB_KEY_1); - else + kbd_event_state=!kbd_event_state; + if(kbd_event_state && !buff_empty){ + buildReport(0x00, readBuffer()); + }else{ buildReport(0x00, 0x00); + } usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); } - - /*AnalyzeMemory(&p,&siz); - sendunum(siz); - _delay_ms(2000);*/ } return 0; } diff --git a/libcrypt/main.h b/libcrypt/main.h index 62d8c5c..0e4a5d7 100644 --- a/libcrypt/main.h +++ b/libcrypt/main.h @@ -1,8 +1,9 @@ #include "sha1/sha1.h" #include "hmac-sha1/hmac-sha1.h" -#include "mem_eval/mem_eval.h" #include "trunc.h" -#include "usart.h" +#include "buffer.h" +#include "usbdrv.h" +#include "usb_key_codes.h" #include #include @@ -15,3 +16,10 @@ #define P_BTN P_PORT_BTN_NUM_BTN #define BTN_VECT INT_NUM_BTN_vect +#define CNTPOS_PTR ((void*)1) +#define ERROR 32202 + +#ifndef UINT32_MAX +#define UINT32_MAX 4294967296 +#endif + diff --git a/libcrypt/usb_callback.c b/libcrypt/usb_callback.c index 7fd6416..d52839f 100644 --- a/libcrypt/usb_callback.c +++ b/libcrypt/usb_callback.c @@ -2,6 +2,7 @@ #include #include #include "usbdrv.h" +#include "usb_key_codes.h" extern void buildReport(uint8_t mod,uint8_t key); extern uint8_t reportBuffer[2]; @@ -13,7 +14,7 @@ uint8_t usbFunctionSetup(uint8_t data[8]){ if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ /* we only have one report type, so don't look at wValue */ - buildReport(0x00,0x00); + buildReport(0x00, 0x00); return sizeof(reportBuffer); }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ usbMsgPtr = &idleRate; diff --git a/libcrypt/usb_key_codes.h b/libcrypt/usb_key_codes.h new file mode 100644 index 0000000..d50c38d --- /dev/null +++ b/libcrypt/usb_key_codes.h @@ -0,0 +1,10 @@ + +#ifdef KBD_DE +#include "kbd_layouts/de.h" +#endif + +#if KBD_US +#include "kbd_layouts/us.h" +#endif + + diff --git a/libcrypt/usbdrv/USB-ID-FAQ.txt b/libcrypt/usbdrv/USB-ID-FAQ.txt new file mode 100644 index 0000000..d1de8fb --- /dev/null +++ b/libcrypt/usbdrv/USB-ID-FAQ.txt @@ -0,0 +1,149 @@ +Version 2009-08-22 + +========================== +WHY DO WE NEED THESE IDs? +========================== + +USB is more than a low level protocol for data transport. It also defines a +common set of requests which must be understood by all devices. And as part +of these common requests, the specification defines data structures, the +USB Descriptors, which are used to describe the properties of the device. + +From the perspective of an operating system, it is therefore possible to find +out basic properties of a device (such as e.g. the manufacturer and the name +of the device) without a device-specific driver. This is essential because +the operating system can choose a driver to load based on this information +(Plug-And-Play). + +Among the most important properties in the Device Descriptor are the USB +Vendor- and Product-ID. Both are 16 bit integers. The most simple form of +driver matching is based on these IDs. The driver announces the Vendor- and +Product-IDs of the devices it can handle and the operating system loads the +appropriate driver when the device is connected. + +It is obvious that this technique only works if the pair Vendor- plus +Product-ID is unique: Only devices which require the same driver can have the +same pair of IDs. + + +===================================================== +HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? +===================================================== + +Since it is so important that USB IDs are unique, the USB Implementers Forum, +Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by +law to build a device and assign it any random numbers as IDs. Usb.org +therefore needs an agreement to regulate the use of USB IDs. The agreement +binds only parties who agreed to it, of course. Everybody else is free to use +any numbers for their IDs. + +So how can usb.org ensure that every manufacturer of USB devices enters into +an agreement with them? They do it via trademark licensing. Usb.org has +registered the trademark "USB", all associated logos and related terms. If +you want to put an USB logo on your product or claim that it is USB +compliant, you must license these trademarks from usb.org. And this is where +you enter into an agreement. See the "USB-IF Trademark License Agreement and +Usage Guidelines for the USB-IF Logo" at +http://www.usb.org/developers/logo_license/. + +Licensing the USB trademarks requires that you buy a USB Vendor-ID from +usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org +(yearly fee of ca. 4,000 USD) and that you meet all the technical +specifications from the USB spec. + +This means that most hobbyists and small companies will never be able to +become USB compliant, just because membership is so expensive. And you can't +be compliant with a driver based on V-USB anyway, because the AVR's port pins +don't meet the electrical specifications for USB. So, in principle, all +hobbyists and small companies are free to choose any random numbers for their +IDs. They have nothing to lose... + +There is one exception worth noting, though: If you use a sub-component which +implements USB, the vendor of the sub-components may guarantee USB +compliance. This might apply to some or all of FTDI's solutions. + + +======================================================================= +WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? +======================================================================= + +You have learned in the previous section that you are free to choose any +numbers for your IDs anyway. So why not do exactly this? There is still the +technical issue. If you choose IDs which are already in use by somebody else, +operating systems will load the wrong drivers and your device won't work. +Even if you choose IDs which are not currently in use, they may be in use in +the next version of the operating system or even after an automatic update. + +So what you need is a pair of Vendor- and Product-IDs for which you have the +guarantee that no USB compliant product uses them. This implies that no +operating system will ever ship with drivers responsible for these IDs. + + +============================================== +HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? +============================================== + +Objective Development gives away pairs of USB-IDs with their V-USB licenses. +In order to ensure that these IDs are unique, Objective Development has an +agreement with the company/person who has bought the USB Vendor-ID from +usb.org. This agreement ensures that a range of USB Product-IDs is reserved +for assignment by Objective Development and that the owner of the Vendor-ID +won't give it to anybody else. + +This means that you have to trust three parties to ensure uniqueness of +your IDs: + + - Objective Development, that they don't give the same PID to more than + one person. + - The owner of the Vendor-ID that they don't assign PIDs from the range + assigned to Objective Development to anybody else. + - Usb.org that they don't assign the same Vendor-ID a second time. + + +================================== +WHO IS THE OWNER OF THE VENDOR-ID? +================================== + +Objective Development has obtained ranges of USB Product-IDs under two +Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen +Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason +Kotzin (Clay Logic, www.claylogic.com). Both VID owners have received their +Vendor-ID directly from usb.org. + + +========================================================================= +CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? +========================================================================= + +The short answer is: Yes. All you get is a guarantee that the IDs are never +assigned to anybody else. What more do you need? + + +============================ +WHAT ABOUT SHARED ID PAIRS? +============================ + +Objective Development has reserved some PID/VID pairs for shared use. You +have no guarantee of uniqueness for them, except that no USB compliant device +uses them. In order to avoid technical problems, we must ensure that all +devices with the same pair of IDs use the same driver on kernel level. For +details, see the file USB-IDs-for-free.txt. + + +====================================================== +I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? +====================================================== + +A 16 bit integer number cannot be protected by copyright laws. It is not +sufficiently complex. And since none of the parties involved entered into the +USB-IF Trademark License Agreement, we are not bound by this agreement. So +there is no reason why it should be illegal to sub-license USB-IDs. + + +============================================= +WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? +============================================= + +Objective Development disclaims all liabilities which might arise from the +assignment of IDs. If you guarantee product features to your customers +without proper disclaimer, YOU are liable for that. diff --git a/libcrypt/usbdrv/USB-IDs-for-free.txt b/libcrypt/usbdrv/USB-IDs-for-free.txt new file mode 100644 index 0000000..d46517d --- /dev/null +++ b/libcrypt/usbdrv/USB-IDs-for-free.txt @@ -0,0 +1,154 @@ +Version 2009-08-22 + +=========================== +FREE USB-IDs FOR SHARED USE +=========================== + +Objective Development has reserved a set of USB Product-IDs for use according +to the guidelines outlined below. For more information about the concept of +USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees +that the IDs listed below are not used by any USB compliant devices. + + +==================== +MECHANISM OF SHARING +==================== + +From a technical point of view, two different devices can share the same USB +Vendor- and Product-ID if they require the same driver on operating system +level. We make use of this fact by assigning separate IDs for various device +classes. On application layer, devices must be distinguished by their textual +name or serial number. We offer separate sets of IDs for discrimination by +textual name and for serial number. + +Examples for shared use of USB IDs are included with V-USB in the "examples" +subdirectory. + + +====================================== +IDs FOR DISCRIMINATION BY TEXTUAL NAME +====================================== + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the manufacturer +and product identification. The manufacturer identification MUST be available +at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail +address under your control (e.g. "myname@gmx.net"). You can embed the domain +name or e-mail address in any string you like, e.g. "Objective Development +http://www.obdev.at/vusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as long +as this string is unique within the scope of your textual manufacturer +identification. + +(5) Application side device look-up MUST be based on the textual manufacturer +and product identification in addition to VID/PID matching. The driver +matching MUST be a comparison of the entire strings, NOT a sub-string match. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +Table if IDs for discrimination by textual name: + +PID dec (hex) | VID dec (hex) | Description of use +==============+===============+============================================ +1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb +--------------+---------------+-------------------------------------------- +1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +--------------+---------------+-------------------------------------------- +1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +--------------+---------------+-------------------------------------------- +1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices +--------------+---------------+-------------------------------------------- + +Note that Windows caches the textual product- and vendor-description for +mice, keyboards and joysticks. Name-bsed discrimination is therefore not +recommended for these device classes. + + +======================================= +IDs FOR DISCRIMINATION BY SERIAL NUMBER +======================================= + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the serial +number, unless ONLY the operating system's default class driver is used. +The serial number string MUST be available at least in USB language 0x0409 +(English/US). + +(2) The serial number MUST start with either an Internet domain name (e.g. +"mycompany.com") registered and owned by you, or an e-mail address under your +control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. +You MAY append any string you like for further discrimination of your devices. + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(5) Application side device look-up MUST be based on the serial number string +in addition to VID/PID matching. The matching must start at the first +character of the serial number string and include the colon character +terminating your domain or e-mail address. It MAY stop anywhere after that. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +(7) If ONLY the operating system's default class driver is used, e.g. for +mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an +application is needed, the serial number may be omitted. + + +Table if IDs for discrimination by serial number string: + +PID dec (hex) | VID dec (hex) | Description of use +===============+===============+=========================================== +10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb +---------------+---------------+------------------------------------------- +10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +---------------+---------------+------------------------------------------- +10202 (0x27da) | 5824 (0x16c0) | For USB Mice +---------------+---------------+------------------------------------------- +10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards +---------------+---------------+------------------------------------------- +10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks +---------------+---------------+------------------------------------------- +10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +---------------+---------------+------------------------------------------- +10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices +---------------+---------------+------------------------------------------- + + +================= +ORIGIN OF USB-IDs +================= + +OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed +here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. +Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. +(see www.usb.org). The VID is registered for the company name "Van Ooijen +Technische Informatica". + + +========== +DISCLAIMER +========== + +OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. diff --git a/libcrypt/usbdrv/usbdrvasm128.inc b/libcrypt/usbdrv/usbdrvasm128.inc new file mode 100644 index 0000000..122cc75 --- /dev/null +++ b/libcrypt/usbdrv/usbdrvasm128.inc @@ -0,0 +1,750 @@ +/* Name: usbdrvasm128.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2008-10-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 12.8 MHz version of the USB driver. It is intended for use +with the internal RC oscillator. Although 12.8 MHz is outside the guaranteed +calibration range of the oscillator, almost all AVRs can reach this frequency. +This version contains a phase locked loop in the receiver routine to cope with +slight clock rate deviations of up to +/- 1%. + +See usbdrv.h for a description of the entire driver. + +LIMITATIONS +=========== +Although it may seem very handy to save the crystal and use the internal +RC oscillator of the CPU, this method (and this module) has some serious +limitations: +(1) The guaranteed calibration range of the oscillator is only 8.1 MHz. +They typical range is 14.5 MHz and most AVRs can actually reach this rate. +(2) Writing EEPROM and Flash may be unreliable (short data lifetime) since +the write procedure is timed from the RC oscillator. +(3) End Of Packet detection (SE0) should be in bit 1, bit it is only checked +if bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This may +cause problems with old hubs which delay SE0 by up to one cycle. +(4) Code size is much larger than that of the other modules. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! + +Implementation notes: +====================== +min frequency: 67 cycles for 8 bit -> 12.5625 MHz +max frequency: 69.286 cycles for 8 bit -> 12.99 MHz +nominal frequency: 12.77 MHz ( = sqrt(min * max)) + +sampling positions: (next even number in range [+/- 0.5]) +cycle index range: 0 ... 66 +bits: +.5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125 +[0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59] + +bit number: 0 1 2 3 4 5 6 7 +spare cycles 1 2 1 2 1 1 1 0 + +operations to perform: duration cycle + ---------------- + eor fix, shift 1 -> 00 + andi phase, USBMASK 1 -> 08 + breq se0 1 -> 16 (moved to 11) + st y+, data 2 -> 24, 25 + mov data, fix 1 -> 33 + ser data 1 -> 41 + subi cnt, 1 1 -> 49 + brcs overflow 1 -> 50 + +layout of samples and operations: +[##] = sample bit +<##> = sample phase +*##* = operation + +0: *00* [01] 02 03 04 <05> 06 07 +1: *08* [09] 10 11 12 <13> 14 15 *16* +2: [17] 18 19 20 <21> 22 23 +3: *24* *25* [26] 27 28 29 <30> 31 32 +4: *33* [34] 35 36 37 <38> 39 40 +5: *41* [42] 43 44 45 <46> 47 48 +6: *49* *50* [51] 52 53 54 <55> 56 57 58 +7: [59] 60 61 62 <63> 64 65 66 +*****************************************************************************/ + +/* we prefer positive expressions (do if condition) instead of negative + * (skip if condition), therefore use defines for skip instructions: + */ +#define ifioclr sbis +#define ifioset sbic +#define ifrclr sbrs +#define ifrset sbrc + +/* The registers "fix" and "data" swap their meaning during the loop. Use + * defines to keep their name constant. + */ +#define fix x2 +#define data x1 +#undef phase /* phase has a default definition to x4 */ +#define phase x3 + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0 + push YL ;2 push only what is necessary to sync with edge ASAP + in YL, SREG ;1 + push YL ;2 +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS ;[0] + rjmp foundK ;[1] +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError + +foundK: +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push YH ;[2] + lds YL, usbInputBufOffset;[4] + clr YH ;[6] + subi YL, lo8(-(usbRxBuf));[7] + sbci YH, hi8(-(usbRxBuf));[8] + + sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5] + rjmp haveTwoBitsK ;[10] + pop YH ;[11] undo the push from before + rjmp waitForK ;[13] this was not the end of sync, retry +haveTwoBitsK: +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +#define fix x2 +#define data x1 + + push shift ;[12] + push x1 ;[14] + push x2 ;[16] + ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0 + ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5] + ori shift, 1<<0 ;[02] + push x3 ;[03] + push cnt ;[05] + push r0 ;[07] + ifioset USBIN, USBMINUS ;[09] <--- bit 1 + ori shift, 1<<1 ;[10] + ser fix ;[11] + ldi cnt, USB_BUFSIZE ;[12] + mov data, shift ;[13] + lsl shift ;[14] + nop2 ;[15] + ifioset USBIN, USBMINUS ;[17] <--- bit 2 + ori data, 3<<2 ;[18] store in bit 2 AND bit 3 + eor shift, data ;[19] do nrzi decoding + andi data, 1<<3 ;[20] + in phase, USBIN ;[21] <- phase + brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1 + nop ;[23] + rjmp entryAfterClr ;[24] +jumpToEntryAfterSet: + rjmp entryAfterSet ;[24] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +#undef fix +#define fix x1 +#undef data +#define data x2 + +bit7IsSet: + ifrclr phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump +bit0AfterSet: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioclr USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsClr ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0s ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterSet ;[06] +unstuff0s: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsClr ;[02] executed if first expr false or second true +se0AndStore: ; executed only if both bits 0 + st y+, x1 ;[15/17] cycles after start of byte + rjmp se0 ;[17/19] + +bit0IsClr: + ifrset phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterClr: + andi phase, USBMASK ;[08] + ifioset USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsSet ;[10] + breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0 + andi shift, ~(7 << 1) ;[12] + in phase, USBIN ;[13] <- phase + breq unstuff1c ;[14] + rjmp bit2AfterClr ;[15] +unstuff1c: + andi fix, ~(1 << 1) ;[16] + nop2 ;[08] + nop2 ;[10] +bit1IsSet: + ifrclr phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterSet: + ifioclr USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsClr ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2s ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterSet ;[22] +unstuff2s: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsClr: + ifrset phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterClr: + st y+, data ;[24] +entryAfterClr: + ifioset USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsSet ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3c ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterClr ;[31] +unstuff3c: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsSet: + ifrclr phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterSet: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioclr USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsClr ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4s ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterSet ;[39] +unstuff4s: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsClr: + ifrset phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterClr: + ser data ;[41] + ifioset USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsSet ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5c ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterClr ;[47] +unstuff5c: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsSet: + ifrclr phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterSet: + subi cnt, 1 ;[49] + brcs jumpToOverflow ;[50] + ifioclr USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsClr ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6s ;[56] + rjmp bit7AfterSet ;[57] + +jumpToOverflow: + rjmp overflow + +unstuff6s: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsClr: + ifrset phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] + nop ;[58] +bit7AfterClr: + ifioset USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsSet ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7c ;[64] + rjmp bit0AfterClr ;[65] -> [00] == [67] +unstuff7c: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsSet ;[60] + +bit7IsClr: + ifrset phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump +bit0AfterClr: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioset USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsSet ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0c ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterClr ;[06] +unstuff0c: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsSet ;[02] executed if first expr false or second true + rjmp se0AndStore ;[03] executed only if both bits 0 +bit0IsSet: + ifrclr phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterSet: + andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr + ifioclr USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsClr ;[10] + breq unstuff1s ;[11] + nop2 ;[12] do not check for SE0 if bit 0 was 1 + in phase, USBIN ;[14] <- phase (one cycle too late) + rjmp bit2AfterSet ;[15] +unstuff1s: + in phase, USBIN ;[13] <- phase + andi fix, ~(1 << 1) ;[14] + lpm ;[07] + nop2 ;[10] +bit1IsClr: + ifrset phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterClr: + ifioset USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsSet ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2c ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterClr ;[22] +unstuff2c: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsSet: + ifrclr phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterSet: + st y+, data ;[24] +entryAfterSet: + ifioclr USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsClr ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3s ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterSet ;[31] +unstuff3s: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsClr: + ifrset phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterClr: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioset USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsSet ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4c ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterClr ;[39] +unstuff4c: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsSet: + ifrclr phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterSet: + ser data ;[41] + ifioclr USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsClr ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5s ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterSet ;[47] +unstuff5s: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsClr: + ifrset phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterClr: + subi cnt, 1 ;[49] + brcs overflow ;[50] + ifioset USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsSet ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6c ;[56] + rjmp bit7AfterClr ;[57] +unstuff6c: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsSet: + ifrclr phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] +bit7AfterSet: + ifioclr USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsClr ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7s ;[64] + rjmp bit0AfterSet ;[65] -> [00] == [67] +unstuff7s: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsClr ;[60] + +macro POP_STANDARD ; 14 cycles + pop r0 + pop cnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;---------------------------------------------------------------------------- +; Transmitting data +;---------------------------------------------------------------------------- + +txByteLoop: +txBitloop: +stuffN1Delay: ; [03] + ror shift ;[-5] [11] [63] + brcc doExorN1 ;[-4] [64] + subi x3, 1 ;[-3] + brne commonN1 ;[-2] + lsl shift ;[-1] compensate ror after rjmp stuffDelay + nop ;[00] stuffing consists of just waiting 8 cycles + rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear + +sendNakAndReti: + ldi cnt, USBPID_NAK ;[-19] + rjmp sendCntAndReti ;[-18] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov r0, cnt ;[-16] + ldi YL, 0 ;[-15] R0 address is 0 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte +;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt] +;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) +usbSendAndReti: + in x2, USBDDR ;[-10] 10 cycles until SOP + ori x2, USBMASK ;[-9] + sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups) + out USBDDR, x2 ;[-6] <--- acquire bus + in x1, USBOUT ;[-5] port mirror for tx loop + ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror) + ldi x2, USBMASK ;[-3] +doExorN1: + eor x1, x2 ;[-2] [06] [62] + ldi x3, 6 ;[-1] [07] [63] +commonN1: +stuffN2Delay: + out USBOUT, x1 ;[00] [08] [64] <--- set bit + ror shift ;[01] + brcc doExorN2 ;[02] + subi x3, 1 ;[03] + brne commonN2 ;[04] + lsl shift ;[05] compensate ror after rjmp stuffDelay + rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear +doExorN2: + eor x1, x2 ;[04] [12] + ldi x3, 6 ;[05] [13] +commonN2: + nop2 ;[06] [14] + subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1 + out USBOUT, x1 ;[09] [17] <--- set bit + brcs txBitloop ;[10] [27] [44] + +stuff6Delay: + ror shift ;[45] [53] + brcc doExor6 ;[46] + subi x3, 1 ;[47] + brne common6 ;[48] + lsl shift ;[49] compensate ror after rjmp stuffDelay + nop ;[50] stuffing consists of just waiting 8 cycles + rjmp stuff6Delay ;[51] after ror, C bit is reliably clear +doExor6: + eor x1, x2 ;[48] [56] + ldi x3, 6 ;[49] +common6: +stuff7Delay: + ror shift ;[50] [58] + out USBOUT, x1 ;[51] <--- set bit + brcc doExor7 ;[52] + subi x3, 1 ;[53] + brne common7 ;[54] + lsl shift ;[55] compensate ror after rjmp stuffDelay + rjmp stuff7Delay ;[56] after ror, C bit is reliably clear +doExor7: + eor x1, x2 ;[54] [62] + ldi x3, 6 ;[55] +common7: + ld shift, y+ ;[56] + nop ;[58] + tst cnt ;[59] + out USBOUT, x1 ;[60] [00]<--- set bit + brne txByteLoop ;[61] [01] +;make SE0: + cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles] + lds x2, usbNewDeviceAddr;[03] + lsl x2 ;[05] we compare with left shifted address + subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0 + sbci YH, 0 ;[07] + out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 0) + echo "$s\n"; + } +} + +function printBit($isAfterSet, $bitNum) +{ + ob_start(); + if($isAfterSet){ +?> + ifioclr USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsClr ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#s ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterSet ;[05] +unstuff#s: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsClr: + ifrset phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + + ifioset USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsSet ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#c ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterClr ;[05] +unstuff#c: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsSet: + ifrclr phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + +*****************************************************************************/ diff --git a/libcrypt/usbdrv/usbdrvasm18-crc.inc b/libcrypt/usbdrv/usbdrvasm18-crc.inc new file mode 100644 index 0000000..dde09da --- /dev/null +++ b/libcrypt/usbdrv/usbdrvasm18-crc.inc @@ -0,0 +1,707 @@ +/* Name: usbdrvasm18.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Lukas Schrittwieser (based on 20 MHz usbdrvasm20.inc by Jeroen Benschop) + * Creation Date: 2009-01-20 + * Tabsize: 4 + * Copyright: (c) 2008 by Lukas Schrittwieser and OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * Revision: $Id$ + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 18 MHz version of the asssembler part of the USB driver. It +requires a 18 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + + +;max stack usage: [ret(2), YL, SREG, YH, [sofError], bitcnt(x5), shift, x1, x2, x3, x4, cnt, ZL, ZH] = 14 bytes +;nominal frequency: 18 MHz -> 12 cycles per bit +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop to receive the data bytes: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; cnt holds the number of bytes left in the receive buffer +; x3 holds the higher crc byte (see algorithm below) +; x4 is used as temporary register for the crc algorithm +; x5 is used for unstuffing: when unstuffing the last received bit is inverted in shift (to prevent further +; unstuffing calls. In the same time the corresponding bit in x5 is cleared to mark the bit as beening iverted +; zl lower crc value and crc table index +; zh used for crc table accesses + +;-------------------------------------------------------------------------------------------------------------- +; CRC mods: +; table driven crc checker, Z points to table in prog space +; ZL is the lower crc byte, x3 is the higher crc byte +; x4 is used as temp register to store different results +; the initialization of the crc register is not 0xFFFF but 0xFE54. This is because during the receipt of the +; first data byte an virtual zero data byte is added to the crc register, this results in the correct initial +; value of 0xFFFF at beginning of the second data byte before the first data byte is added to the crc. +; The magic number 0xFE54 results form the crc table: At tabH[0x54] = 0xFF = crcH (required) and +; tabL[0x54] = 0x01 -> crcL = 0x01 xor 0xFE = 0xFF +; bitcnt is renamed to x5 and is used for unstuffing purposes, the unstuffing works like in the 12MHz version +;-------------------------------------------------------------------------------------------------------------- +; CRC algorithm: +; The crc register is formed by x3 (higher byte) and ZL (lower byte). The algorithm uses a 'reversed' form +; i.e. that it takes the least significant bit first and shifts to the right. So in fact the highest order +; bit seen from the polynomial devision point of view is the lsb of ZL. (If this sounds strange to you i +; propose a research on CRC :-) ) +; Each data byte received is xored to ZL, the lower crc byte. This byte now builds the crc +; table index. Next the new high byte is loaded from the table and stored in x4 until we have space in x3 +; (its destination). +; Afterwards the lower table is loaded from the table and stored in ZL (the old index is overwritten as +; we don't need it anymore. In fact this is a right shift by 8 bits.) Now the old crc high value is xored +; to ZL, this is the second shift of the old crc value. Now x4 (the temp reg) is moved to x3 and the crc +; calculation is done. +; Prior to the first byte the two CRC register have to be initialized to 0xFFFF (as defined in usb spec) +; however the crc engine also runs during the receipt of the first byte, therefore x3 and zl are initialized +; to a magic number which results in a crc value of 0xFFFF after the first complete byte. +; +; This algorithm is split into the extra cycles of the different bits: +; bit7: XOR the received byte to ZL +; bit5: load the new high byte to x4 +; bit6: load the lower xor byte from the table, xor zl and x3, store result in zl (=the new crc low value) +; move x4 (the new high byte) to x3, the crc value is ready +; + + +macro POP_STANDARD ; 18 cycles + pop ZH + pop ZL + pop cnt + pop x5 + pop x3 + pop x2 + pop x1 + pop shift + pop x4 + endm +macro POP_RETI ; 7 cycles + pop YH + pop YL + out SREG, YL + pop YL + endm + +macro CRC_CLEANUP_AND_CHECK + ; the last byte has already been xored with the lower crc byte, we have to do the table lookup and xor + ; x3 is the higher crc byte, zl the lower one + ldi ZH, hi8(usbCrcTableHigh);[+1] get the new high byte from the table + lpm x2, Z ;[+2][+3][+4] + ldi ZH, hi8(usbCrcTableLow);[+5] get the new low xor byte from the table + lpm ZL, Z ;[+6][+7][+8] + eor ZL, x3 ;[+7] xor the old high byte with the value from the table, x2:ZL now holds the crc value + cpi ZL, 0x01 ;[+8] if the crc is ok we have a fixed remainder value of 0xb001 in x2:ZL (see usb spec) + brne ignorePacket ;[+9] detected a crc fault -> paket is ignored and retransmitted by the host + cpi x2, 0xb0 ;[+10] + brne ignorePacket ;[+11] detected a crc fault -> paket is ignored and retransmitted by the host + endm + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG, YH, [sofError], x4, shift, x1, x2, x3, x5, cnt, ZL, ZH + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-17] + rjmp foundK ;[-16] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-15] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 30 (2.5 bits) for center sampling. Currently at 4 so 26 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push x4 ;[-14] +; [---] ;[-13] + lds YL, usbInputBufOffset;[-12] used to toggle the two usb receive buffers +; [---] ;[-11] + clr YH ;[-10] + subi YL, lo8(-(usbRxBuf));[-9] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-8] [rx loop init] + push shift ;[-7] +; [---] ;[-6] + ldi shift, 0x80 ;[-5] the last bit is the end of byte marker for the pid receiver loop + clc ;[-4] the carry has to be clear for receipt of pid bit 0 + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop x4 ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 24 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] crc high byte + ldi x2, 1< jump back and store the byte + ori shift, 0x01 ;[11] invert the last received bit to prevent furhter unstuffing + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + andi x5, 0xFE ;[1] mark this bit as inverted (will be corrected before storing shift) + eor x1, x2 ;[2] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[3] mask the interesting bits + breq stuffErr ;[4] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[5] the next bit expects the last state to be in x1 + rjmp didunstuff0 ;[6] + ;[7] jump delay of rjmp didunstuffX + +unstuff1: ;[11] this is the jump delay of breq unstuffX + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + ori shift, 0x02 ;[1] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFD ;[2] mark this bit as inverted (will be corrected before storing shift) + eor x2, x1 ;[3] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[4] mask the interesting bits + breq stuffErr ;[5] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[6] the next bit expects the last state to be in x2 + nop2 ;[7] + ;[8] + rjmp didunstuff1 ;[9] + ;[10] jump delay of rjmp didunstuffX + +unstuff2: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x04 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFB ;[11] mark this bit as inverted (will be corrected before storing shift) + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x1, x2 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[4] the next bit expects the last state to be in x1 + nop2 ;[5] + ;[6] + rjmp didunstuff2 ;[7] + ;[8] jump delay of rjmp didunstuffX + +unstuff3: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x08 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xF7 ;[11] mark this bit as inverted (will be corrected before storing shift) + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x2, x1 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[4] the next bit expects the last state to be in x2 + nop2 ;[5] + ;[6] + rjmp didunstuff3 ;[7] + ;[8] jump delay of rjmp didunstuffX + + + +; the include has to be here due to branch distance restirctions +#define __USE_CRC__ +#include "asmcommon.inc" + + + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies +; 7.5 bit times is 90 cycles. ...there is plenty of time + + +sendNakAndReti: + ldi x3, USBPID_NAK ;[-18] + rjmp sendX3AndReti ;[-17] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov x3, cnt ;[-16] +sendX3AndReti: + ldi YL, 20 ;[-15] x3==r20 address is 20 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent + +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-6] <- acquire bus + ldi x2, 0 ;[-6] init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-5] exor mask + ldi shift, 0x80 ;[-4] sync byte is first byte sent +txByteLoop: + ldi bitcnt, 0x40 ;[-3]=[9] binary 01000000 +txBitLoop: ; the loop sends the first 7 bits of the byte + sbrs shift, 0 ;[-2]=[10] if we have to send a 1 don't change the line state + eor x1, x4 ;[-1]=[11] + out USBOUT, x1 ;[0] + ror shift ;[1] + ror x2 ;[2] transfers the last sent bit to the stuffing history +didStuffN: + nop ;[3] + nop ;[4] + cpi x2, 0xfc ;[5] if we sent six consecutive ones + brcc bitstuffN ;[6] + lsr bitcnt ;[7] + brne txBitLoop ;[8] restart the loop while the 1 is still in the bitcount + +; transmit bit 7 + sbrs shift, 0 ;[9] + eor x1, x4 ;[10] +didStuff7: + ror shift ;[11] + out USBOUT, x1 ;[0] transfer bit 7 to the pins + ror x2 ;[1] move the bit into the stuffing history + cpi x2, 0xfc ;[2] + brcc bitstuff7 ;[3] + ld shift, y+ ;[4] get next byte to transmit + dec cnt ;[5] decrement byte counter + brne txByteLoop ;[7] if we have more bytes start next one + ;[8] branch delay + +;make SE0: + cbr x1, USBMASK ;[8] prepare SE0 [spec says EOP may be 25 to 30 cycles] + lds x2, usbNewDeviceAddr;[9] + lsl x2 ;[11] we compare with left shifted address + out USBOUT, x1 ;[0] <-- out SE0 -- from now 2 bits = 24 cycles until bus idle + subi YL, 20 + 2 ;[1] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[2] +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[3] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< +int main (int argc, char **argv) +{ + int i, j; + for (i=0; i<512; i++){ + unsigned short crc = i & 0xff; + for(j=0; j<8; j++) crc = (crc >> 1) ^ ((crc & 1) ? 0xa001 : 0); + if((i & 7) == 0) printf("\n.byte "); + printf("0x%02x, ", (i > 0xff ? (crc >> 8) : crc) & 0xff); + if(i == 255) printf("\n"); + } + return 0; +} + +// Use the following algorithm to compute CRC values: +ushort computeCrc(uchar *msg, uchar msgLen) +{ + uchar i; + ushort crc = 0xffff; + for(i = 0; i < msgLen; i++) + crc = usbCrcTable16[lo8(crc) ^ msg[i]] ^ hi8(crc); + return crc; +} +*/ + +.balign 256 +usbCrcTableLow: +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 + +; .balign 256 +usbCrcTableHigh: +.byte 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2 +.byte 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04 +.byte 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E +.byte 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8 +.byte 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A +.byte 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC +.byte 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6 +.byte 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10 +.byte 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32 +.byte 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4 +.byte 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE +.byte 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38 +.byte 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA +.byte 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C +.byte 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26 +.byte 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0 +.byte 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62 +.byte 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4 +.byte 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE +.byte 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68 +.byte 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA +.byte 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C +.byte 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76 +.byte 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0 +.byte 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92 +.byte 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54 +.byte 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E +.byte 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98 +.byte 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A +.byte 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C +.byte 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86 +.byte 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 + diff --git a/libcrypt/usbdrv/usbdrvasm20.inc b/libcrypt/usbdrv/usbdrvasm20.inc new file mode 100644 index 0000000..0c74679 --- /dev/null +++ b/libcrypt/usbdrv/usbdrvasm20.inc @@ -0,0 +1,360 @@ +/* Name: usbdrvasm20.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Jeroen Benschop + * Based on usbdrvasm16.inc from Christian Starkjohann + * Creation Date: 2008-03-05 + * Tabsize: 4 + * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * Revision: $Id$ + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 20 MHz version of the asssembler part of the USB driver. It +requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +#define leap2 x3 +#ifdef __IAR_SYSTEMS_ASM__ +#define nextInst $+2 +#else +#define nextInst .+0 +#endif + +;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; x4 (leap) is used to add a leap cycle once every three bytes received +; X3 (leap2) is used to add a leap cycle once every three stuff bits received +; bitcnt is used to determine when a stuff bit is due +; cnt holds the number of bytes left in the receive buffer + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-19] + rjmp foundK ;[-18] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-16] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push bitcnt ;[-16] +; [---] ;[-15] + lds YL, usbInputBufOffset;[-14] +; [---] ;[-13] + clr YH ;[-12] + subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] + push shift ;[-9] +; [---] ;[-8] + ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected + nop2 ;[-6] +; [---] ;[-5] + ldi bitcnt, 5 ;[-4] [rx loop init] + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop bitcnt ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 27 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] (leap2) + ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit + push x4 ;[7] == leap + ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received + push cnt ;[10] + ldi cnt, USB_BUFSIZE ;[12] [rx loop init] + ldi x2, 1< +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) /* not supported on IAR */ + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ /* IAR does not define standard macro for asm */ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +/* The following definitions are not needed by the driver, but may be of some + * help if you port a gcc based project to IAR. + */ +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() +#define _BV(x) (1 << (x)) + +/* assembler compatibility macros */ +#define nop2 rjmp $+2 /* jump to next instruction */ +#define XL r26 +#define XH r27 +#define YL r28 +#define YH r29 +#define ZL r30 +#define ZH r31 +#define lo8(x) LOW(x) +#define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ + +/* Depending on the device you use, you may get problems with the way usbdrv.h + * handles the differences between devices. Since IAR does not use #defines + * for MCU registers, we can't check for the existence of a particular + * register with an #ifdef. If the autodetection mechanism fails, include + * definitions for the required USB_INTR_* macros in your usbconfig.h. See + * usbconfig-prototype.h and usbdrv.h for details. + */ + +/* ------------------------------------------------------------------------- */ +#elif __CODEVISIONAVR__ /* check for CodeVision AVR */ +/* ------------------------------------------------------------------------- */ +/* This port is not working (yet) */ + +/* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ + +#include +#include + +#define __attribute__(arg) /* not supported on IAR */ + +#define PROGMEM __flash +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +#ifndef __ASSEMBLER__ +static inline void cli(void) +{ + #asm("cli"); +} +static inline void sei(void) +{ + #asm("sei"); +} +#endif +#define _delay_ms(t) delay_ms(t) +#define _BV(x) (1 << (x)) +#define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ + +#define macro .macro +#define endm .endmacro +#define nop2 rjmp .+0 /* jump to next instruction */ + +/* ------------------------------------------------------------------------- */ +#else /* default development environment is avr-gcc/avr-libc */ +/* ------------------------------------------------------------------------- */ + +#include +#ifdef __ASSEMBLER__ +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +#else +# include +#endif + +#if USB_CFG_DRIVER_FLASH_PAGE +# define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) +#else +# define USB_READ_FLASH(addr) pgm_read_byte(addr) +#endif + +#define macro .macro +#define endm .endm +#define nop2 rjmp .+0 /* jump to next instruction */ + +#endif /* development environment */ + +/* for conveniecne, ensure that PRG_RDB exists */ +#ifndef PRG_RDB +# define PRG_RDB(addr) USB_READ_FLASH(addr) +#endif +#endif /* __usbportability_h_INCLUDED__ */