diff --git a/libcrypt/Makefile b/libcrypt/Makefile new file mode 100644 index 0000000..e2fcfc9 --- /dev/null +++ b/libcrypt/Makefile @@ -0,0 +1,125 @@ +# +# Targets: +# generate flash file +# install generate flash +# download download flash +# 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 +# + +#------------------------------------------------------------------------- +# project specific things +# change these definitions for new projects +#------------------------------------------------------------------------- + +PROJNAME = arduino_HOTP +OBJS = main.o \ + trunc.o \ + calib.o \ + usb_callback.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 + +# target architecture +MCU = atmega168 + +#------------------------------------------------------------------------- +# macros for the tools +#------------------------------------------------------------------------- + +BAUD = 19200 + +BINFORMAT = ihex + +# programmer format, this depends on programmer or bootloader you're using +#PROGFORMAT = dasa2 +#PROGFORMAT = dapa +#PROGFORMAT = stk200 +#PROGFORMAT = usbtiny +PROGFORMAT = stk500v2 + +# programmer-device-file +#IFCTYPE = /dev/ttyS0 +#IFCTYPE = /dev/ttyS1 +#IFCTYPE = /dev/ttyACM0 +#IFCTYPE = /dev/ttyACM1 +IFCTYPE = /dev/ttyUSB0 +#IFCTYPE = /dev/ttyUSB1 + +# Tools +AS = avr-as +ASLD = avr-gcc -x assembler +LD = avr-ld +CC = avr-gcc +OBJCOPY = avr-objcopy +#PROGR = uisp +#PROGR = at16prog +PROGR = lboot +#PROGR = avrdude + +# Flags +CFLAGS = -Wall -Os -mmcu=$(MCU) $(DEBUG) +LDFLAGS = -Wl,-Map=$*.map -mmcu=$(MCU) +OCFLAGS = -O $(BINFORMAT) +# at16prog +#PRFLAGS = $(IFCTYPE) -dprog=$(PROGFORMAT) -dpart=$(MCU) +# avrdude +#PRFLAGS = -F -p $(MCU) -P $(IFCTYPE) -c $(PROGFORMAT) -b $(BAUD) +PRFLAGS = -d $(IFCTYPE) -b $(BAUD) + +#------------------------------------------------------------------------- +# the targets +#------------------------------------------------------------------------- + +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 + + +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/calib.c b/libcrypt/calib.c new file mode 100644 index 0000000..a56751f --- /dev/null +++ b/libcrypt/calib.c @@ -0,0 +1,63 @@ +#ifdef CALIB + +/* +Note: This calibration algorithm may try OSCCAL values of up to 192 even if +the optimum value is far below 192. It may therefore exceed the allowed clock +frequency of the CPU in low voltage designs! +You may replace this search algorithm with any other algorithm you like if +you have additional constraints such as a maximum CPU clock. +For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g. +ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in +both regions. +*/ +void usbEventResetReady(void){ + calibrateOscillator(); + /*first read the oscilator; if the value differs then we change it*/ + if(eeprom_read_byte(0)!=OSCCAL){ + /* store the calibrated value in EEPROM */ + eeprom_write_byte(0, OSCCAL); + } +} + +/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is + * derived from the 66 MHz peripheral clock by dividing. Our timing reference + * is the Start Of Frame signal (a single SE0 bit) available immediately after + * a USB RESET. We first do a binary search for the OSCCAL value and then + * optimize this value with a neighboorhod search. + * This algorithm may also be used to calibrate the RC oscillator directly to + * 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this + * is wide outside the spec for the OSCCAL value and the required precision for + * the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for + * experimental purposes only! + */ +static void calibrateOscillator(void){ + uint8_t step = 128; + uint8_t trialValue = 0, optimumValue; + int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); + /* do a binary search: */ + do{ + OSCCAL = trialValue + step; + x = usbMeasureFrameLength(); /* proportional to current real frequency */ + if(x < targetValue) /* frequency still too low */ + trialValue += step; + step >>= 1; + }while(step > 0); + /* We have a precision of +/- 1 for optimum OSCCAL here */ + /* now do a neighborhood search for optimum value */ + optimumValue = trialValue; + optimumDev = x; /* this is certainly far away from optimum */ + for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){ + x = usbMeasureFrameLength() - targetValue; + if(x < 0) + x = -x; + if(x < optimumDev){ + optimumDev = x; + optimumValue = OSCCAL; + } + } + OSCCAL = optimumValue; +} + +#else +void usbEventResetReady(void){} +#endif //CALIB diff --git a/libcrypt/hmac-sha1/config.h b/libcrypt/hmac-sha1/config.h new file mode 100644 index 0000000..1b18504 --- /dev/null +++ b/libcrypt/hmac-sha1/config.h @@ -0,0 +1,46 @@ +/* config.h */ +/* + This file is part of the AVR-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ +#include +//#define F_CPU 20000000 +// #define F_CPU 16000000 /* oscillator-frequency in Hz */ +// #define F_CPU 14745600 + +#define DEBUG_METHOD uart + +/*#include "uart_defs.h" + +#define UART0_I 1 +#ifndef UART0_BAUD_RATE +#define UART0_BAUD_RATE 115200 +#endif +#define UART0_PARATY UART_PARATY_NONE +#define UART0_STOPBITS UART_STOPBITS_1 +#define UART0_DATABITS UART_DATABITS_8 +#define UART0_RXBUFFER_SIZE 255 +#define UART0_TXBUFFER_SIZE 120 +#define UART0_SWFLOWCTRL 1 +#define UART0_THRESH_LOW 0 +#define UART0_THRESH_HIGH 32*/ + +#define CLI_AUTO_HELP + +#endif + diff --git a/libcrypt/hmac-sha1/hmac-sha1.c b/libcrypt/hmac-sha1/hmac-sha1.c new file mode 100644 index 0000000..3ac8872 --- /dev/null +++ b/libcrypt/hmac-sha1/hmac-sha1.c @@ -0,0 +1,131 @@ +/* hmac-sha1.c */ +/* + This file is part of the AVR-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * + * implementation of HMAC as described in RFC2104 + * Author: Daniel Otte + * email: daniel.otte@rub.de + * License: GPLv3 or later + **/ + +/* + * hmac = hash ( k^opad , hash( k^ipad , msg)) + */ + +#include +#include +#include "config.h" +#include "sha1.h" +#include "hmac-sha1.h" + +#define IPAD 0x36 +#define OPAD 0x5C + + +#ifndef HMAC_SHORTONLY + +void hmac_sha1_init(hmac_sha1_ctx_t *s, const void* key, uint16_t keylength_b){ + uint8_t buffer[SHA1_BLOCK_BYTES]; + uint8_t i; + + memset(buffer, 0, SHA1_BLOCK_BYTES); + if (keylength_b > SHA1_BLOCK_BITS){ + sha1((void*)buffer, key, keylength_b); + } else { + memcpy(buffer, key, (keylength_b+7)/8); + } + + for (i=0; ia)); + sha1_nextBlock(&(s->a), buffer); + + for (i=0; ib)); + sha1_nextBlock(&(s->b), buffer); + + +#if defined SECURE_WIPE_BUFFER + memset(buffer, 0, SHA1_BLOCK_BYTES); +#endif +} + +void hmac_sha1_nextBlock(hmac_sha1_ctx_t *s, const void* block){ + sha1_nextBlock(&(s->a), block); +} +void hmac_sha1_lastBlock(hmac_sha1_ctx_t *s, const void* block, uint16_t length_b){ + while(length_b>=SHA1_BLOCK_BITS){ + sha1_nextBlock(&s->a, block); + block = (uint8_t*)block + SHA1_BLOCK_BYTES; + length_b -= SHA1_BLOCK_BITS; + } + sha1_lastBlock(&s->a, block, length_b); +} + +void hmac_sha1_final(void* dest, hmac_sha1_ctx_t *s){ + sha1_ctx2hash(dest, &s->a); + sha1_lastBlock(&s->b, dest, SHA1_HASH_BITS); + sha1_ctx2hash(dest, &(s->b)); +} + +#endif + +/* + * keylength in bits! + * message length in bits! + */ +void hmac_sha1(void* dest, const void* key, uint16_t keylength_b, const void* msg, uint32_t msglength_b){ /* a one-shot*/ + sha1_ctx_t s; + uint8_t i; + uint8_t buffer[SHA1_BLOCK_BYTES]; + + memset(buffer, 0, SHA1_BLOCK_BYTES); + + /* if key is larger than a block we have to hash it*/ + if (keylength_b > SHA1_BLOCK_BITS){ + sha1((void*)buffer, key, keylength_b); + } else { + memcpy(buffer, key, (keylength_b+7)/8); + } + + for (i=0; i= SHA1_BLOCK_BITS){ + sha1_nextBlock(&s, msg); + msg = (uint8_t*)msg + SHA1_BLOCK_BYTES; + msglength_b -= SHA1_BLOCK_BITS; + } + sha1_lastBlock(&s, msg, msglength_b); + /* since buffer still contains key xor ipad we can do ... */ + for (i=0; i. +*/ +#ifndef HMACSHA1_H_ +#define HMACSHA1_H_ + +#include "sha1.h" + +#define HMAC_SHA1_BITS SHA1_HASH_BITS +#define HMAC_SHA1_BYTES SHA1_HASH_BYTES +#define HMAC_SHA1_BLOCK_BITS SHA1_BLOCK_BITS +#define HMAC_SHA1_BLOCK_BYTES SHA1_BLOCK_BYTES + +typedef struct{ + sha1_ctx_t a, b; +} hmac_sha1_ctx_t; + + +void hmac_sha1_init(hmac_sha1_ctx_t *s, const void* key, uint16_t keylength_b); +void hmac_sha1_nextBlock(hmac_sha1_ctx_t *s, const void* block); +void hmac_sha1_lastBlock(hmac_sha1_ctx_t *s, const void* block, uint16_t length_b); +void hmac_sha1_final(void* dest, hmac_sha1_ctx_t *s); + +void hmac_sha1(void* dest, const void* key, uint16_t keylength_b, const void* msg, uint32_t msglength_b); + +#endif /*HMACSHA1_H_*/ diff --git a/libcrypt/main.c b/libcrypt/main.c new file mode 100644 index 0000000..cef1961 --- /dev/null +++ b/libcrypt/main.c @@ -0,0 +1,77 @@ +/* + * This code is based on seveal VUSB-Examples the + * HID was taken from the CapsLocker code from macetech + * http://macetech.com/blog/?q=node/46 + * + */ +#include "main.h" + +#define SECRET {'J', 'e', 'f', 'e'}; +#define SECLEN 20 + +#define MSG "what do ya want for nothing?" + +#include +#include +#include +#include +#include +#include +#include + +#include "usbdrv.h" + +uint8_t reportBuffer[2]; /* buffer for HID reports */ +uint8_t idleRate; + +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) ); + + #ifdef CALIB + /* oszillator calibration */ + calibrationValue = eeprom_read_byte(0); /* calibration value from last time */ + if(calibrationValue != 0xff){ + OSCCAL = calibrationValue; + } + #endif //CALLIB + //odDebugInit(); + usbDeviceDisconnect(); + _delay_ms(300); /* mustn't be that exact */ + usbDeviceConnect(); + + usbInit(); + sei(); + for(;;){ /* main event loop */ + usbPoll(); + /* we can send another key */ + if(usbInterruptIsReady()){ + buildReport(0x00, 'A'); + usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); + } + + AnalyzeMemory(&p,&siz); + sendunum(siz); + _delay_ms(2000); + } + return 0; +} + diff --git a/libcrypt/main.h b/libcrypt/main.h new file mode 100644 index 0000000..3386e5e --- /dev/null +++ b/libcrypt/main.h @@ -0,0 +1,18 @@ +#include "sha1/sha1.h" +#include "hmac-sha1/hmac-sha1.h" +#include "mem_eval/mem_eval.h" +#include "trunc.h" +#include "usart.h" + +#include +#include + +#define _PORT_BTN B +#define _NUM_BTN 3 + +#define PORT_BTN PORT_PORT_BTN +#define DDR_BTN DDR_PORT_BTN +#define P_BTN P_PORT_BTN_NUM_BTN +#define BTN_VECT INT_NUM_BTN_vect + + diff --git a/libcrypt/mem_eval/mem_eval.c b/libcrypt/mem_eval/mem_eval.c new file mode 100755 index 0000000..02b4e23 --- /dev/null +++ b/libcrypt/mem_eval/mem_eval.c @@ -0,0 +1,68 @@ +/*==========================================================================*/ +/* Project: AVR-GCC SRAM Memory Evaluation */ +/* Title: Memory Init and Anlyze Functions */ +/* Purpose: SRAM memory ressource analysis of Atmel programs */ +/* */ +/* File: mem_eval.c */ +/* Revision 0.1 */ +/* Date: 10/2003 */ +/* */ +/* Description: Provides an initialization and memory analyzation function */ +/* Software: AVR-GCC */ +/* Hardware: AVR AT90 and ATmega series */ +/* */ +/* Authors: Wilfried Elmenreich */ +/* TU Vienna, Real Time Group */ +/*==========================================================================*/ + +///////////////////////////////////////////////////////////////////////////// +// HEADER FILES // +///////////////////////////////////////////////////////////////////////////// + +#include "mem_eval.h" + +///////////////////////////////////////////////////////////////////////////// +// FUNCTIONS // +///////////////////////////////////////////////////////////////////////////// + +void InitializeMemory() +{ + uint8_t *memptr; + + for(memptr = EndOfUsedMem(); memptr < GetStackPtr(); memptr++) + *memptr = (uint16_t)memptr & 0xFF; +} + +void AnalyzeMemory(uint8_t **largest_begin,uint16_t *largest_size) +{ + uint8_t *memptr, *endptr, *section_begin; + uint16_t section_size; + + *largest_size=0; + memptr = *largest_begin = EndOfUsedMem(); + endptr = GetStackPtr(); + + while(memptr < endptr) + { + if (*memptr == ((uint16_t)memptr & 0xFF)) + { + section_begin = memptr; + while(1) + { + memptr++; + //*largest_begin = (uint8_t *) 1; + if ((*memptr != ((uint16_t)memptr & 0xFF)) || (memptr == endptr-1)) + { + //*largest_begin = (uint8_t *) 2; + if ((section_size = (memptr - section_begin)) > *largest_size) + { + *largest_size = section_size; + *largest_begin = section_begin; + } + break; + } + } /* while(1) */ + } + memptr++; + } /* while(memptr < endptr) */ +} diff --git a/libcrypt/mem_eval/mem_eval.h b/libcrypt/mem_eval/mem_eval.h new file mode 100755 index 0000000..921d84e --- /dev/null +++ b/libcrypt/mem_eval/mem_eval.h @@ -0,0 +1,56 @@ +/*==========================================================================*/ +/* Project: AVR-GCC SRAM Memory Evaluation */ +/* Title: Memory Pointer Functions */ +/* Purpose: SRAM memory ressource analysis of Atmel programs */ +/* */ +/* File: mem_eval.h */ +/* Revision 0.1 */ +/* Date: 10/2003 */ +/* */ +/* Description: Provides macros for reading the stackpointer and the end of */ +/* variable data segment */ +/* Software: AVR-GCC */ +/* Hardware: AVR AT90 and ATmega series */ +/* */ +/* Authors: Wilfried Elmenreich, Wolfgang Haidinger */ +/* TU Vienna, Real Time Group */ +/*==========================================================================*/ + +#ifndef MEMEVAL + #define MEMEVAL + + #include + + #ifdef __AVR_AT90S4433__ + #undef SPH + #endif + + #ifdef SPH + #define GetStackPtr()({uint8_t *__StackPtr; \ + asm volatile("in\t%A0,__SP_L__\n\t" \ + "in\t%B0,__SP_H__" \ + : "=r" (__StackPtr) \ + : /*"I" (SPL), "I" (SPH)*/ \ + ); \ + __StackPtr;}) + #else + #define GetStackPtr() ({uint8_t *__StackPtr; \ + asm volatile("in\t%A0,__SP_L__\n\t" \ + "clr\t%B0" \ + : "=r" (__StackPtr) \ + : /* "I" (SPL) */ ); \ + __StackPtr;}) + #endif + + #define EndOfUsedMem()({uint8_t *__EndOfUsedMemPtr; \ + asm volatile("ldi\t%A0,lo8(__bss_end)\n\t" \ + "ldi\t%B0,hi8(__bss_end)" \ + : "=r" (__EndOfUsedMemPtr) \ + ); \ + __EndOfUsedMemPtr;}) +#endif + + +extern void InitializeMemory(void); +extern void AnalyzeMemory(uint8_t **largest_begin,uint16_t *largest_size); + diff --git a/libcrypt/sha1/sha1-asm.S b/libcrypt/sha1/sha1-asm.S new file mode 100644 index 0000000..4d185f9 --- /dev/null +++ b/libcrypt/sha1/sha1-asm.S @@ -0,0 +1,883 @@ +/* sha1-asm.S */ +/* + This file is part of the AVR-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/* + * Author: Daniel Otte + * + * License: GPLv3 or later +*/ +; SHA1 implementation in assembler for AVR +SHA1_BLOCK_BITS = 512 +SHA1_HASH_BITS = 160 + +.macro precall + /* push r18 - r27, r30 - r31*/ + push r0 + push r1 + push r18 + push r19 + push r20 + push r21 + push r22 + push r23 + push r24 + push r25 + push r26 + push r27 + push r30 + push r31 + clr r1 +.endm + +.macro postcall + pop r31 + pop r30 + pop r27 + pop r26 + pop r25 + pop r24 + pop r23 + pop r22 + pop r21 + pop r20 + pop r19 + pop r18 + pop r1 + pop r0 +.endm + + +.macro hexdump length + push r27 + push r26 + ldi r25, '\r' + mov r24, r25 + call uart_putc + ldi r25, '\n' + mov r24, r25 + call uart_putc + pop r26 + pop r27 + movw r24, r26 +.if \length > 16 + ldi r22, lo8(16) + ldi r23, hi8(16) + push r27 + push r26 + call uart_hexdump + pop r26 + pop r27 + adiw r26, 16 + hexdump \length-16 +.else + ldi r22, lo8(\length) + ldi r23, hi8(\length) + call uart_hexdump +.endif +.endm + +.macro delay +/* + push r0 + push r1 + clr r0 +1: clr r1 +2: dec r1 + brne 2b + dec r0 + brne 1b + pop r1 + pop r0 // */ +.endm + +/* X points to Block */ +.macro dbg_hexdump length +/* + precall + hexdump \length + postcall + // */ +.endm + + + +.section .text + +SPL = 0x3D +SPH = 0x3E +SREG = 0x3F + + +; +;sha1_ctx_t is: +; +; [h0][h1][h2][h3][h4][length] +; hn is 32 bit large, length is 64 bit large + +;########################################################### + +.global sha1_ctx2hash +; === sha1_ctx2hash === +; this function converts a state into a normal hash (bytestring) +; param1: the 16-bit destination pointer +; given in r25,r24 (r25 is most significant) +; param2: the 16-bit pointer to sha1_ctx structure +; given in r23,r22 +sha1_ctx2hash: + movw r26, r22 + movw r30, r24 + ldi r21, 5 + sbiw r26, 4 +1: + ldi r20, 4 + adiw r26, 8 +2: + ld r0, -X + st Z+, r0 + dec r20 + brne 2b + + dec r21 + brne 1b + + ret + +;########################################################### + +.global sha1 +; === sha1 === +; this function calculates SHA-1 hashes from messages in RAM +; param1: the 16-bit hash destination pointer +; given in r25,r24 (r25 is most significant) +; param2: the 16-bit pointer to message +; given in r23,r22 +; param3: 32-bit length value (length of message in bits) +; given in r21,r20,r19,r18 +sha1: +sha1_prolog: + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r16 + push r17 + in r30, SPL + in r31, SPH + sbiw r30, 5*4+8 + in r0, SREG + cli + out SPL, r30 + out SREG, r0 + out SPH, r31 + + push r25 + push r24 + adiw r30, 1 + movw r16, r30 + + movw r8, r18 /* backup of length*/ + movw r10, r20 + + movw r12, r22 /* backup pf msg-ptr */ + + movw r24, r16 + rcall sha1_init + /* if length >= 512 */ +1: + tst r11 + brne 2f + tst r10 + breq 4f +2: + movw r24, r16 + movw r22, r12 + rcall sha1_nextBlock + ldi r19, 64 + add r12, r19 + adc r13, r1 + /* length -= 512 */ + ldi r19, 0x02 + sub r9, r19 + sbc r10, r1 + sbc r11, r1 + rjmp 1b + +4: + movw r24, r16 + movw r22, r12 + movw r20, r8 + rcall sha1_lastBlock + + pop r24 + pop r25 + movw r22, r16 + rcall sha1_ctx2hash + +sha1_epilog: + in r30, SPL + in r31, SPH + adiw r30, 5*4+8 + in r0, SREG + cli + out SPL, r30 + out SREG, r0 + out SPH, r31 + pop r17 + pop r16 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + ret + +;########################################################### + + +; block MUST NOT be larger than 64 bytes + +.global sha1_lastBlock +; === sha1_lastBlock === +; this function does padding & Co. for calculating SHA-1 hashes +; param1: the 16-bit pointer to sha1_ctx structure +; given in r25,r24 (r25 is most significant) +; param2: an 16-bit pointer to 64 byte block to hash +; given in r23,r22 +; param3: an 16-bit integer specifing length of block in bits +; given in r21,r20 +sha1_lastBlock_localSpace = (SHA1_BLOCK_BITS/8+1) + + +sha1_lastBlock: + cpi r21, 0x02 + brlo sha1_lastBlock_prolog + push r25 + push r24 + push r23 + push r22 + push r21 + push r20 + rcall sha1_nextBlock + pop r20 + pop r21 + pop r22 + pop r23 + pop r24 + pop r25 + subi r21, 2 + ldi r19, 64 + sub r22, r19 + sbc r23, r1 + rjmp sha1_lastBlock +sha1_lastBlock_prolog: + /* allocate space on stack */ + in r30, SPL + in r31, SPH + in r0, SREG + subi r30, lo8(64) + sbci r31, hi8(64) /* ??? */ + cli + out SPL, r30 + out SREG, r0 + out SPH, r31 + + adiw r30, 1 /* SP points to next free byte on stack */ + mov r18, r20 /* r20 = LSB(length) */ + lsr r18 + lsr r18 + lsr r18 + bst r21, 0 /* may be we should explain this ... */ + bld r18, 5 /* now: r18 == length/8 (aka. length in bytes) */ + + + movw r26, r22 /* X points to begin of msg */ + tst r18 + breq sha1_lastBlock_post_copy + mov r1, r18 +sha1_lastBlock_copy_loop: + ld r0, X+ + st Z+, r0 + dec r1 + brne sha1_lastBlock_copy_loop +sha1_lastBlock_post_copy: +sha1_lastBlock_insert_stuffing_bit: + ldi r19, 0x80 + mov r0,r19 + ldi r19, 0x07 + and r19, r20 /* if we are in bitmode */ + breq 2f /* no bitmode */ +1: + lsr r0 + dec r19 + brne 1b + ld r19, X +/* maybe we should do some ANDing here, just for safety */ + or r0, r19 +2: + st Z+, r0 + inc r18 + +/* checking stuff here */ + cpi r18, 64-8+1 + brsh 0f + rjmp sha1_lastBlock_insert_zeros +0: + /* oh shit, we landed here */ + /* first we have to fill it up with zeros */ + ldi r19, 64 + sub r19, r18 + breq 2f +1: + st Z+, r1 + dec r19 + brne 1b +2: + sbiw r30, 63 + sbiw r30, 1 + movw r22, r30 + + push r31 + push r30 + push r25 + push r24 + push r21 + push r20 + rcall sha1_nextBlock + pop r20 + pop r21 + pop r24 + pop r25 + pop r30 + pop r31 + + /* now we should subtract 512 from length */ + movw r26, r24 + adiw r26, 4*5+1 /* we can skip the lowest byte */ + ld r19, X + subi r19, hi8(512) + st X+, r19 + ldi r18, 6 +1: + ld r19, X + sbci r19, 0 + st X+, r19 + dec r18 + brne 1b + +; clr r18 /* not neccessary ;-) */ + /* reset Z pointer to begin of block */ + +sha1_lastBlock_insert_zeros: + ldi r19, 64-8 + sub r19, r18 + breq sha1_lastBlock_insert_length + clr r1 +1: + st Z+, r1 /* r1 is still zero */ + dec r19 + brne 1b + +; rjmp sha1_lastBlock_epilog +sha1_lastBlock_insert_length: + movw r26, r24 /* X points to state */ + adiw r26, 5*4 /* X points to (state.length) */ + adiw r30, 8 /* Z points one after the last byte of block */ + ld r0, X+ + add r0, r20 + st -Z, r0 + ld r0, X+ + adc r0, r21 + st -Z, r0 + ldi r19, 6 +1: + ld r0, X+ + adc r0, r1 + st -Z, r0 + dec r19 + brne 1b + + sbiw r30, 64-8 + movw r22, r30 + rcall sha1_nextBlock + +sha1_lastBlock_epilog: + in r30, SPL + in r31, SPH + in r0, SREG + adiw r30, 63 ; lo8(64) + adiw r30, 1 ; hi8(64) + cli + out SPL, r30 + out SREG, r0 + out SPH, r31 + clr r1 + ret + +/**/ +;########################################################### + +.global sha1_nextBlock +; === sha1_nextBlock === +; this is the core function for calculating SHA-1 hashes +; param1: the 16-bit pointer to sha1_ctx structure +; given in r25,r24 (r25 is most significant) +; param2: an 16-bit pointer to 64 byte block to hash +; given in r23,r22 +sha1_nextBlock_localSpace = (16+5+1)*4 ; 16 32-bit values for w array and 5 32-bit values for a array (total 84 byte) + +xtmp = 0 +xNULL = 1 +W1 = 10 +W2 = 11 +T1 = 12 +T2 = 13 +T3 = 14 +T4 = 15 +LoopC = 16 +S = 17 +tmp1 = 18 +tmp2 = 19 +tmp3 = 20 +tmp4 = 21 +F1 = 22 +F2 = 23 +F3 = 24 +F4 = 25 + +/* byteorder: high number <--> high significance */ +sha1_nextBlock: + ; initial, let's make some space ready for local vars + /* replace push & pop by mem ops? */ + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push r16 + push r17 + push r28 + push r29 + in r20, SPL + in r21, SPH + movw r18, r20 ;backup SP +; movw r26, r20 ; X points to free space on stack /* maybe removeable? */ + movw r30, r22 ; Z points to message + subi r20, lo8(sha1_nextBlock_localSpace) ;sbiw can do only up to 63 + sbci r21, hi8(sha1_nextBlock_localSpace) + movw r26, r20 ; X points to free space on stack + in r0, SREG + cli ; we want to be uninterrupted while updating SP + out SPL, r20 + out SREG, r0 + out SPH, r21 + + push r18 + push r19 /* push old SP on new stack */ + push r24 + push r25 /* param1 will be needed later */ + + /* load a[] with state */ + movw 28, r24 /* load pointer to state in Y */ + adiw r26, 1 ; X++ + + ldi LoopC, 5*4 +1: ld tmp1, Y+ + st X+, tmp1 + dec LoopC + brne 1b + + movw W1, r26 /* save pointer to w[0] */ + /* load w[] with endian fixed message */ + /* we might also use the changeendian32() function at bottom */ + movw r30, r22 /* mv param2 (ponter to msg) to Z */ + ldi LoopC, 16 +1: + ldd tmp1, Z+3 + st X+, tmp1 + ldd tmp1, Z+2 + st X+, tmp1 + ldd tmp1, Z+1 + st X+, tmp1 + ld tmp1, Z + st X+, tmp1 + adiw r30, 4 + dec LoopC + brne 1b + + ;clr LoopC /* LoopC is named t in FIPS 180-2 */ + clr xtmp +sha1_nextBlock_mainloop: + mov S, LoopC + lsl S + lsl S + andi S, 0x3C /* S is a bytepointer so *4 */ + /* load w[s] */ + movw r26, W1 + add r26, S /* X points at w[s] */ + adc r27, xNULL + ld T1, X+ + ld T2, X+ + ld T3, X+ + ld T4, X+ + +/* + push r26 + push r27 + push T4 + push T3 + push T2 + push T1 + in r26, SPL + in r27, SPH + adiw r26, 1 + dbg_hexdump 4 + pop T1 + pop T2 + pop T3 + pop T4 + pop r27 + pop r26 +*/ + + cpi LoopC, 16 + brlt sha1_nextBlock_mainloop_core + /* update w[s] */ + ldi tmp1, 2*4 + rcall 1f + ldi tmp1, 8*4 + rcall 1f + ldi tmp1, 13*4 + rcall 1f + rjmp 2f +1: /* this might be "outsourced" to save the jump above */ + add tmp1, S + andi tmp1, 0x3f + movw r26, W1 + add r26, tmp1 + adc r27, xNULL + ld tmp2, X+ + eor T1, tmp2 + ld tmp2, X+ + eor T2, tmp2 + ld tmp2, X+ + eor T3, tmp2 + ld tmp2, X+ + eor T4, tmp2 + ret +2: /* now we just hav to do a ROTL(T) and save T back */ + mov tmp2, T4 + rol tmp2 + rol T1 + rol T2 + rol T3 + rol T4 + movw r26, W1 + add r26, S + adc r27, xNULL + st X+, T1 + st X+, T2 + st X+, T3 + st X+, T4 + +sha1_nextBlock_mainloop_core: /* ther core function; T=ROTL5(a) ....*/ + /* T already contains w[s] */ + movw r26, W1 + sbiw r26, 4*1 /* X points at a[4] aka e */ + ld tmp1, X+ + add T1, tmp1 + ld tmp1, X+ + adc T2, tmp1 + ld tmp1, X+ + adc T3, tmp1 + ld tmp1, X+ + adc T4, tmp1 /* T = w[s]+e */ + sbiw r26, 4*5 /* X points at a[0] aka a */ + ld F1, X+ + ld F2, X+ + ld F3, X+ + ld F4, X+ + mov tmp1, F4 /* X points at a[1] aka b */ + ldi tmp2, 5 +1: + rol tmp1 + rol F1 + rol F2 + rol F3 + rol F4 + dec tmp2 + brne 1b + + add T1, F1 + adc T2, F2 + adc T3, F3 + adc T4, F4 /* T = ROTL(a,5) + e + w[s] */ + + /* now we have to do this fucking conditional stuff */ + ldi r30, lo8(sha1_nextBlock_xTable) + ldi r31, hi8(sha1_nextBlock_xTable) + add r30, xtmp + adc r31, xNULL + lpm tmp1, Z + cp tmp1, LoopC + brne 1f + inc xtmp +1: ldi r30, lo8(sha1_nextBlock_KTable) + ldi r31, hi8(sha1_nextBlock_KTable) + lsl xtmp + lsl xtmp + add r30, xtmp + adc r31, xNULL + lsr xtmp + lsr xtmp + + lpm tmp1, Z+ + add T1, tmp1 + lpm tmp1, Z+ + adc T2, tmp1 + lpm tmp1, Z+ + adc T3, tmp1 + lpm tmp1, Z+ + adc T4, tmp1 + /* T = ROTL(a,5) + e + kt + w[s] */ + + /* Z-4 is just pointing to kt ... */ + movw r28, r26 /* copy X in Y */ + adiw r30, 3*4 /* now Z points to the rigth locatin in our jump-vector-table */ + lsr r31 + ror r30 + + icall + mov F1, tmp1 + icall + mov F2, tmp1 + icall + mov F3, tmp1 + icall + + add T1, F1 + adc T2, F2 + adc T3, F3 + adc T4, tmp1 /* T = ROTL5(a) + f_t(b,c,d) + e + k_t + w[s] */ + /* X points still at a[1] aka b, Y points at a[2] aka c */ + /* update a[] */ +sha1_nextBlock_update_a: + /*first we move all vars in a[] "one up" e=d, d=c, c=b, b=a*/ + //adiw r28, 3*4 /* Y should point at a[4] aka e */ + movw r28, W1 + sbiw r28, 4 + + ldi tmp2, 4*4 +1: + ld tmp1, -Y + std Y+4, tmp1 + dec tmp2 + brne 1b + /* Y points at a[0] aka a*/ + + movw r28, W1 + sbiw r28, 5*4 + /* store T in a[0] aka a */ + st Y+, T1 + st Y+, T2 + st Y+, T3 + st Y+, T4 + /* Y points at a[1] aka b*/ + + /* rotate c */ + ldd T1, Y+1*4 + ldd T2, Y+1*4+1 + ldd T3, Y+1*4+2 + ldd T4, Y+1*4+3 + mov tmp1, T1 + ldi tmp2, 2 +1: ror tmp1 + ror T4 + ror T3 + ror T2 + ror T1 + dec tmp2 + brne 1b + std Y+1*4+0, T1 + std Y+1*4+1, T2 + std Y+1*4+2, T3 + std Y+1*4+3, T4 +/* + push r27 + push r26 + movw r26, W1 + sbiw r26, 4*5 + dbg_hexdump 4*5 + pop r26 + pop r27 +*/ + inc LoopC + cpi LoopC, 80 + brge 1f + rjmp sha1_nextBlock_mainloop +/**************************************/ +1: + /* littel patch */ + sbiw r28, 4 + +/* add a[] to state and inc length */ + pop r27 + pop r26 /* now X points to state (and Y still at a[0]) */ + ldi tmp4, 5 +1: clc + ldi tmp3, 4 +2: ld tmp1, X + ld tmp2, Y+ + adc tmp1, tmp2 + st X+, tmp1 + dec tmp3 + brne 2b + dec tmp4 + brne 1b + + /* now length += 512 */ + adiw r26, 1 /* we skip the least significant byte */ + ld tmp1, X + ldi tmp2, hi8(512) /* 2 */ + add tmp1, tmp2 + st X+, tmp1 + ldi tmp2, 6 +1: + ld tmp1, X + adc tmp1, xNULL + st X+, tmp1 + dec tmp2 + brne 1b + +; EPILOG +sha1_nextBlock_epilog: +/* now we should clean up the stack */ + pop r21 + pop r20 + in r0, SREG + cli ; we want to be uninterrupted while updating SP + out SPL, r20 + out SREG, r0 + out SPH, r21 + + clr r1 + pop r29 + pop r28 + pop r17 + pop r16 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + ret + +sha1_nextBlock_xTable: +.byte 20,40,60,0 +sha1_nextBlock_KTable: +.int 0x5a827999 +.int 0x6ed9eba1 +.int 0x8f1bbcdc +.int 0xca62c1d6 +sha1_nextBlock_JumpTable: +rjmp sha1_nextBlock_Ch + nop +rjmp sha1_nextBlock_Parity + nop +rjmp sha1_nextBlock_Maj + nop +rjmp sha1_nextBlock_Parity + + /* X and Y still point at a[1] aka b ; return value in tmp1 */ +sha1_nextBlock_Ch: + ld tmp1, Y+ + mov tmp2, tmp1 + com tmp2 + ldd tmp3, Y+3 /* load from c */ + and tmp1, tmp3 + ldd tmp3, Y+7 /* load from d */ + and tmp2, tmp3 + eor tmp1, tmp2 + ret + +sha1_nextBlock_Maj: + ld tmp1, Y+ + mov tmp2, tmp1 + ldd tmp3, Y+3 /* load from c */ + and tmp1, tmp3 + ldd tmp4, Y+7 /* load from d */ + and tmp2, tmp4 + eor tmp1, tmp2 + and tmp3, tmp4 + eor tmp1, tmp3 + ret + +sha1_nextBlock_Parity: + ld tmp1, Y+ + ldd tmp2, Y+3 /* load from c */ + eor tmp1, tmp2 + ldd tmp2, Y+7 /* load from d */ + eor tmp1, tmp2 + ret +/* +ch_str: .asciz "\r\nCh" +maj_str: .asciz "\r\nMaj" +parity_str: .asciz "\r\nParity" +*/ +;########################################################### + +.global sha1_init +;void sha1_init(sha1_ctx_t *state){ +; DEBUG_S("\r\nSHA1_INIT"); +; state->h[0] = 0x67452301; +; state->h[1] = 0xefcdab89; +; state->h[2] = 0x98badcfe; +; state->h[3] = 0x10325476; +; state->h[4] = 0xc3d2e1f0; +; state->length = 0; +;} +; param1: (Func3,r24) 16-bit pointer to sha1_ctx_t struct in ram +; modifys: Z(r30,r31), Func1, r22 +sha1_init: + movw r26, r24 ; (24,25) --> (26,27) load X with param1 + ldi r30, lo8((sha1_init_vector)) + ldi r31, hi8((sha1_init_vector)) + ldi r22, 5*4 /* bytes to copy */ +sha1_init_vloop: + lpm r23, Z+ + st X+, r23 + dec r22 + brne sha1_init_vloop + ldi r22, 8 +sha1_init_lloop: + st X+, r1 + dec r22 + brne sha1_init_lloop + ret + +sha1_init_vector: +.int 0x67452301; +.int 0xefcdab89; +.int 0x98badcfe; +.int 0x10325476; +.int 0xc3d2e1f0; + diff --git a/libcrypt/sha1/sha1.h b/libcrypt/sha1/sha1.h new file mode 100644 index 0000000..1966786 --- /dev/null +++ b/libcrypt/sha1/sha1.h @@ -0,0 +1,119 @@ +/* sha1.h */ +/* + This file is part of the AVR-Crypto-Lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * \file sha1.h + * \author Daniel Otte + * \email daniel.otte@rub.de + * \date 2006-10-08 + * \license GPLv3 or later + * \brief SHA-1 declaration. + * \ingroup SHA-1 + * + */ + +#ifndef SHA1_H_ +#define SHA1_H_ + +#include +/** \def SHA1_HASH_BITS + * definees the size of a SHA-1 hash in bits + */ + +/** \def SHA1_HASH_BYTES + * definees the size of a SHA-1 hash in bytes + */ + +/** \def SHA1_BLOCK_BITS + * definees the size of a SHA-1 input block in bits + */ + +/** \def SHA1_BLOCK_BYTES + * definees the size of a SHA-1 input block in bytes + */ +#define SHA1_HASH_BITS 160 +#define SHA1_HASH_BYTES (SHA1_HASH_BITS/8) +#define SHA1_BLOCK_BITS 512 +#define SHA1_BLOCK_BYTES (SHA1_BLOCK_BITS/8) + +/** \typedef sha1_ctx_t + * \brief SHA-1 context type + * + * A vatiable of this type may hold the state of a SHA-1 hashing process + */ +typedef struct { + uint32_t h[5]; + uint64_t length; +} sha1_ctx_t; + +/** \typedef sha1_hash_t + * \brief hash value type + * A variable of this type may hold a SHA-1 hash value + */ +/* +typedef uint8_t sha1_hash_t[SHA1_HASH_BITS/8]; +*/ + +/** \fn sha1_init(sha1_ctx_t *state) + * \brief initializes a SHA-1 context + * This function sets a ::sha1_ctx_t variable to the initialization vector + * for SHA-1 hashing. + * \param state pointer to the SHA-1 context variable + */ +void sha1_init(sha1_ctx_t *state); + +/** \fn sha1_nextBlock(sha1_ctx_t *state, const void* block) + * \brief process one input block + * This function processes one input block and updates the hash context + * accordingly + * \param state pointer to the state variable to update + * \param block pointer to the message block to process + */ +void sha1_nextBlock (sha1_ctx_t *state, const void* block); + +/** \fn sha1_lastBlock(sha1_ctx_t *state, const void* block, uint16_t length_b) + * \brief processes the given block and finalizes the context + * This function processes the last block in a SHA-1 hashing process. + * The block should have a maximum length of a single input block. + * \param state pointer to the state variable to update and finalize + * \param block pointer to themessage block to process + * \param length_b length of the message block in bits + */ +void sha1_lastBlock (sha1_ctx_t *state, const void* block, uint16_t length_b); + +/** \fn sha1_ctx2hash(sha1_hash_t *dest, sha1_ctx_t *state) + * \brief convert a state variable into an actual hash value + * Writes the hash value corresponding to the state to the memory pointed by dest. + * \param dest pointer to the hash value destination + * \param state pointer to the hash context + */ +void sha1_ctx2hash (void *dest, sha1_ctx_t *state); + +/** \fn sha1(sha1_hash_t *dest, const void* msg, uint32_t length_b) + * \brief hashing a message which in located entirely in RAM + * This function automatically hashes a message which is entirely in RAM with + * the SHA-1 hashing algorithm. + * \param dest pointer to the hash value destination + * \param msg pointer to the message which should be hashed + * \param length_b length of the message in bits + */ +void sha1(void *dest, const void* msg, uint32_t length_b); + + + +#endif /*SHA1_H_*/ diff --git a/libcrypt/trunc.c b/libcrypt/trunc.c new file mode 100644 index 0000000..b8a8a0f --- /dev/null +++ b/libcrypt/trunc.c @@ -0,0 +1,35 @@ + +#include "trunc.h" + +int32_t get_otp_from_cnt(uint64_t cnt, uint8_t digits, uint8_t* secret, uint8_t sec_len){ + uint8_t tmp[8]={((uint8_t*)&cnt)[7],((uint8_t*)&cnt)[6],((uint8_t*)&cnt)[5],((uint8_t*)&cnt)[4],((uint8_t*)&cnt)[3],((uint8_t*)&cnt)[2],((uint8_t*)&cnt)[1],((uint8_t*)&cnt)[0]}; + /*Step 1 generate HMAC-SHA1*/ + uint8_t hmac_result[20]; + + hmac_sha1(hmac_result, secret, sec_len*8, tmp, 64); + return get_otp(hmac_result,digits); +} + +int32_t get_otp(uint8_t* hmac, uint8_t digits){ + uint8_t n; + uint32_t dt; + + /*Step 1 generate HMAC-SHA1*/ + /*Step 2 get DT(HMAC) */ + /* get the lower 4-bits and treat them as a number n*/ + /* DT is the 31bit integer at HMAC[n]+HMAC[n+1]+HMAC[n+2]+HMAC[n+3]*/ + /* the MSB is ignored */ + n=hmac[SHA1_SIZE-1] & 0x0F; + dt= (uint32_t)(hmac[n ]&0x7F)<<(uint32_t)24 | + (uint32_t)(hmac[n+1])<<(uint32_t)16 | + (uint32_t)(hmac[n+2])<<(uint32_t)8 | + (uint32_t)(hmac[n+3]); + /*Step 3 return dt mod 10^digits*/ + switch(digits){ + case 6: return dt % 1000000; + case 7: return dt % 10000000; + default: case 8: return dt % 100000000; + } +} + + diff --git a/libcrypt/trunc.h b/libcrypt/trunc.h new file mode 100644 index 0000000..9e0b8b3 --- /dev/null +++ b/libcrypt/trunc.h @@ -0,0 +1,10 @@ +#ifndef _TRUNC_H_ +#define _TRUNC_H_ + +#include "hmac-sha1/hmac-sha1.h" +#define SHA1_SIZE 20 + +int32_t get_otp(uint8_t* hmac, uint8_t digits); +int32_t get_otp_from_cnt(uint64_t cnt, uint8_t digits, uint8_t* secret, uint8_t sec_len); + +#endif diff --git a/libcrypt/usart/usart.c b/libcrypt/usart/usart.c new file mode 100644 index 0000000..1b3168c --- /dev/null +++ b/libcrypt/usart/usart.c @@ -0,0 +1,67 @@ +#ifdef DEBUG +#include "usart.h" + +void initUSART(){ + UBRR0 = (unsigned char) MYUBRR; + + /*enable USART write and read*/ + UCSR0B |= /*(1<>4) <0x0A ){ + tx('0'+((c&0xF0)>>4) ); + }else{ + tx('A'-0x0A+((c&0xF0)>>4)); + } + + if( (c&0x0F)<0x0A ){ + tx('0'+(c&0x0F)); + }else{ + tx('A'-0x0A+(c&0x0F)); + } +} + +char rx( void ){ + while ( !(UCSR0A & (1< + +#ifdef DEBUG +#define MYUBRR 8 /*BAUD=115200*/ + +void initUSART(); +void tx( char data ); +void sendstr( char* str); +void sendunum(uint32_t num); +void tx_hex(uint8_t c); +char rx( void ); + +#endif //DEBUG + + +#endif //_USART_H + diff --git a/libcrypt/usb_callback.c b/libcrypt/usb_callback.c new file mode 100644 index 0000000..35f3d76 --- /dev/null +++ b/libcrypt/usb_callback.c @@ -0,0 +1,58 @@ + +#include +#include +#include "usbdrv.h" + +extern void buildReport(uint8_t mod,uint8_t key); +extern uint8_t reportBuffer[2]; +extern uint8_t idleRate; + +uint8_t usbFunctionSetup(uint8_t data[8]){ + usbRequest_t *rq = (void *)data; + usbMsgPtr = reportBuffer; + 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); + return sizeof(reportBuffer); + }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ + usbMsgPtr = &idleRate; + return 1; + }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ + idleRate = rq->wValue.bytes[1]; + } + }else{ + /* no vendor specific requests implemented */ + } + return 0; +} + +/* We use a simplifed keyboard report descriptor which does not support the + * boot protocol. We don't allow setting status LEDs and we only allow one + * simultaneous key press (except modifiers). We can therefore use short + * 2 byte input reports. + * The report descriptor has been created with usb.org's "HID Descriptor Tool" + * which can be downloaded from http://www.usb.org/developers/hidpage/. + * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted + * for the second INPUT item. + */ +PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; diff --git a/usbconfig.h b/libcrypt/usbconfig.h similarity index 93% rename from usbconfig.h rename to libcrypt/usbconfig.h index 0a0c06c..d63e18f 100644 --- a/usbconfig.h +++ b/libcrypt/usbconfig.h @@ -17,11 +17,11 @@ /* This is the port where the USB bus is connected. When you configure it to * "B", the registers PORTB, PINB and DDRB will be used. */ -#define USB_CFG_DMINUS_BIT 4 +#define USB_CFG_DMINUS_BIT 4 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. * This may be any bit in the port. */ -#define USB_CFG_DPLUS_BIT 3 +#define USB_CFG_DPLUS_BIT 3 /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. * This may be any bit in the port. Please note that D+ must also be connected * to interrupt pin INT0! @@ -74,7 +74,7 @@ /* Define this to 1 if the device has its own power supply. Set it to 0 if the * device is powered from the USB bus. */ -#define USB_CFG_MAX_BUS_POWER 200 +#define USB_CFG_MAX_BUS_POWER 50 /* Set this variable to the maximum USB bus power consumption of your device. * The value is in milliamperes. [It will be divided by two since USB * communicates power requirements in units of 2 mA.] @@ -103,7 +103,7 @@ #ifndef __ASSEMBLER__ extern void usbEventResetReady(void); #endif -//#define USB_RESET_HOOK(isReset) if(!isReset){usbEventResetReady();} +#define USB_RESET_HOOK(isReset) if(!isReset){usbEventResetReady();} /* This macro is a hook if you need to know when an USB RESET occurs. It has * one parameter which distinguishes between the start of RESET state and its * end. @@ -115,14 +115,14 @@ extern void usbEventResetReady(void); /* -------------------------- Device Description --------------------------- */ -#define USB_CFG_VENDOR_ID 0x81, 0x17 +#define USB_CFG_VENDOR_ID 0x42, 0x42 /* USB vendor ID for the device, low byte first. If you have registered your * own Vendor ID, define it here. Otherwise you use obdev's free shared * VID/PID pair. Be sure to read USBID-License.txt for rules! * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. * Use this VID/PID pair ONLY if you understand the implications! */ -#define USB_CFG_DEVICE_ID 0x9f, 0x0c +#define USB_CFG_DEVICE_ID 0x31, 0xe1 /* This is the ID of the product, low byte first. It is interpreted in the * scope of the vendor ID. If you have registered your own VID with usb.org * or if you have licensed a PID from somebody else, define it here. Otherwise @@ -131,13 +131,11 @@ extern void usbEventResetReady(void); * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. * Use this VID/PID pair ONLY if you understand the implications! */ -#define USB_CFG_DEVICE_VERSION 0x04, 0x01 +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 /* Version number of the device: Minor number first, then major number. */ -#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' -#define USB_CFG_VENDOR_NAME_LEN 8 -#undef USB_CFG_VENDOR_NAME -#undef USB_CFG_VENDOR_NAME_LEN +#define USB_CFG_VENDOR_NAME 'h', 'a', 'c', 'k', 'e', 'r', 's', 'p', 'a', 'c', 'e', 's', 'h', 'o', 'p','.','c','o','m' +#define USB_CFG_VENDOR_NAME_LEN 19 /* These two values define the vendor name returned by the USB device. The name * must be given as a list of characters under single quotes. The characters * are interpreted as Unicode (UTF-16) entities. @@ -146,8 +144,8 @@ extern void usbEventResetReady(void); * obdev's free shared VID/PID pair. See the file USBID-License.txt for * details. */ -#define USB_CFG_DEVICE_NAME 'U', 'S', 'B', 't', 'i', 'n', 'y', 'S', 'P', 'I' -#define USB_CFG_DEVICE_NAME_LEN 10 +#define USB_CFG_DEVICE_NAME 'T','r','u','s','t','M','e' +#define USB_CFG_DEVICE_NAME_LEN 7 /* Same as above for the device name. If you don't want a device name, undefine * the macros. See the file USBID-License.txt before you assign a name if you * use a shared VID/PID. @@ -165,13 +163,13 @@ extern void usbEventResetReady(void); #define USB_CFG_DEVICE_SUBCLASS 0 /* See USB specification if you want to conform to an existing device class. */ -#define USB_CFG_INTERFACE_CLASS 0xff /* HID */ +#define USB_CFG_INTERFACE_CLASS 3 /* HID */ #define USB_CFG_INTERFACE_SUBCLASS 0 /* no boot interface */ #define USB_CFG_INTERFACE_PROTOCOL 0 /* no protocol */ /* See USB specification if you want to conform to an existing device class or * protocol. */ -#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 /* total length of report descriptor */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 35 /* total length of report descriptor */ /* Define this to the length of the HID report descriptor, if you implement * an HID device. Otherwise don't define it or define it to 0. * Since this template defines a HID device, it must also specify a HID @@ -255,14 +253,16 @@ extern void usbEventResetReady(void); /* #define USB_INTR_ENABLE_BIT INT0 */ /* #define USB_INTR_PENDING GIFR */ /* #define USB_INTR_PENDING_BIT INTF0 */ -// use PCINT1 instead of INT0 + + +/* #define USB_INTR_CFG PCMSK #define USB_INTR_CFG_SET (1< +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define PRG_RDB(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() + +/* 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. + */ + +#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */ +#endif /* __iarcompat_h_INCLUDED__ */ diff --git a/usbdrv/oddebug.c b/libcrypt/usbdrv/oddebug.c similarity index 86% rename from usbdrv/oddebug.c rename to libcrypt/usbdrv/oddebug.c index 466e68f..bd528e2 100644 --- a/usbdrv/oddebug.c +++ b/libcrypt/usbdrv/oddebug.c @@ -4,8 +4,8 @@ * Creation Date: 2005-01-16 * Tabsize: 4 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.c 275 2007-03-20 09:58:28Z cs $ */ #include "oddebug.h" diff --git a/usbdrv/oddebug.h b/libcrypt/usbdrv/oddebug.h similarity index 92% rename from usbdrv/oddebug.h rename to libcrypt/usbdrv/oddebug.h index c56af1c..1b11ef0 100644 --- a/usbdrv/oddebug.h +++ b/libcrypt/usbdrv/oddebug.h @@ -4,8 +4,8 @@ * Creation Date: 2005-01-16 * Tabsize: 4 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.h 275 2007-03-20 09:58:28Z cs $ */ #ifndef __oddebug_h_included__ @@ -29,7 +29,10 @@ the output and a memory block to dump in hex ('data' and 'len'). #endif /* make sure we have the UART defines: */ -#include "usbportability.h" +#include "iarcompat.h" +#ifndef __IAR_SYSTEMS_ICC__ +# include +#endif #ifndef uchar # define uchar unsigned char diff --git a/usbdrv/usbconfig-prototype.h b/libcrypt/usbdrv/usbconfig-prototype.h similarity index 63% rename from usbdrv/usbconfig-prototype.h rename to libcrypt/usbdrv/usbconfig-prototype.h index 826f026..4f51809 100644 --- a/usbdrv/usbconfig-prototype.h +++ b/libcrypt/usbdrv/usbconfig-prototype.h @@ -1,11 +1,11 @@ /* Name: usbconfig.h - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2005-04-01 * Tabsize: 4 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbconfig-prototype.h 532 2008-02-28 15:35:05Z cs $ */ #ifndef __usbconfig_h_included__ @@ -14,14 +14,12 @@ /* General Description: This file is an example configuration (with inline documentation) for the USB -driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is -also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may -wire the lines to any other port, as long as D+ is also wired to INT0 (or any -other hardware interrupt, as long as it is the highest level interrupt, see -section at the end of this file). -+ To create your own usbconfig.h file, copy this file to your project's -+ firmware source directory) and rename it to "usbconfig.h". -+ Then edit it accordingly. +driver. It configures AVR-USB for an ATMega8 with USB D+ connected to Port D +bit 2 (which is also hardware interrupt 0) and USB D- to Port D bit 0. You may +wire the lines to any other port, as long as D+ is also wired to INT0. +To create your own usbconfig.h file, copy this file to the directory +containing "usbdrv" (that is your project firmware source directory) and +rename it to "usbconfig.h". Then edit it accordingly. */ /* ---------------------------- Hardware Config ---------------------------- */ @@ -30,7 +28,7 @@ section at the end of this file). /* This is the port where the USB bus is connected. When you configure it to * "B", the registers PORTB, PINB and DDRB will be used. */ -#define USB_CFG_DMINUS_BIT 4 +#define USB_CFG_DMINUS_BIT 0 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. * This may be any bit in the port. */ @@ -43,20 +41,12 @@ section at the end of this file). * interrupt, the USB interrupt will also be triggered at Start-Of-Frame * markers every millisecond.] */ -#define USB_CFG_CLOCK_KHZ (F_CPU/1000) -/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, - * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code - * require no crystal, they tolerate +/- 1% deviation from the nominal - * frequency. All other rates require a precision of 2000 ppm and thus a - * crystal! - * Since F_CPU should be defined to your actual clock rate anyway, you should - * not need to modify this setting. - */ -#define USB_CFG_CHECK_CRC 0 -/* Define this to 1 if you want that the driver checks integrity of incoming - * data packets (CRC checks). CRC checks cost quite a bit of code size and are - * currently only available for 18 MHz crystal clock. You must choose - * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. +/* #define USB_CFG_CLOCK_KHZ (F_CPU/1000) */ +/* Clock rate of the AVR in MHz. Legal values are 12000, 15000, 16000 or 16500. + * The 16.5 MHz version of the code requires no crystal, it tolerates +/- 1% + * deviation from the nominal frequency. All other rates require a precision + * of 2000 ppm and thus a crystal! + * Default if not specified: 12 MHz */ /* ----------------------- Optional Hardware Config ------------------------ */ @@ -75,7 +65,7 @@ section at the end of this file). /* --------------------------- Functional Range ---------------------------- */ -#define USB_CFG_HAVE_INTRIN_ENDPOINT 0 +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 /* Define this to 1 if you want to compile a version with two endpoints: The * default control endpoint 0 and an interrupt-in endpoint (any other endpoint * number). @@ -90,11 +80,9 @@ section at the end of this file). /* If the so-called endpoint 3 is used, it can now be configured to any other * endpoint number (except 0) with this macro. Default if undefined is 3. */ -/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ +/* #define USB_INITIAL_DATATOKEN USBPID_DATA0 */ /* The above macro defines the startup condition for data toggling on the - * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. - * Since the token is toggled BEFORE sending any data, the first packet is - * sent with the oposite value of this configuration! + * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA0. */ #define USB_CFG_IMPLEMENT_HALT 0 /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature @@ -102,15 +90,7 @@ section at the end of this file). * it is required by the standard. We have made it a config option because it * bloats the code considerably. */ -#define USB_CFG_SUPPRESS_INTR_CODE 0 -/* Define this to 1 if you want to declare interrupt-in endpoints, but don't - * want to send any data over them. If this macro is defined to 1, functions - * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if - * you need the interrupt-in endpoints in order to comply to an interface - * (e.g. HID), but never want to send any data. This option saves a couple - * of bytes in flash memory and the transmit buffers in RAM. - */ -#define USB_CFG_INTR_POLL_INTERVAL 10 +#define USB_CFG_INTR_POLL_INTERVAL 20 /* If you compile a version with endpoint 1 (interrupt-in), this is the poll * interval. The value is in milliseconds and must not be less than 10 ms for * low speed devices. @@ -146,16 +126,6 @@ section at the end of this file). * of the macros usbDisableAllRequests() and usbEnableAllRequests() in * usbdrv.h. */ -#define USB_CFG_DRIVER_FLASH_PAGE 0 -/* If the device has more than 64 kBytes of flash, define this to the 64 k page - * where the driver's constants (descriptors) are located. Or in other words: - * Define this to 1 for boot loaders on the ATMega128. - */ -#define USB_CFG_LONG_TRANSFERS 0 -/* Define this to 1 if you want to send/receive blocks of more than 254 bytes - * in a single control-in or control-out transfer. Note that the capability - * for long transfers increases the driver size. - */ /* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ /* This macro is a hook if you want to do unconventional things. If it is * defined, it's inserted at the beginning of received message processing. @@ -177,86 +147,47 @@ section at the end of this file). * counts SOF packets. This feature requires that the hardware interrupt is * connected to D- instead of D+. */ -/* #ifdef __ASSEMBLER__ - * macro myAssemblerMacro - * in YL, TCNT0 - * sts timer0Snapshot, YL - * endm - * #endif - * #define USB_SOF_HOOK myAssemblerMacro - * This macro (if defined) is executed in the assembler module when a - * Start Of Frame condition is detected. It is recommended to define it to - * the name of an assembler macro which is defined here as well so that more - * than one assembler instruction can be used. The macro may use the register - * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages - * immediately after an SOF pulse may be lost and must be retried by the host. - * What can you do with this hook? Since the SOF signal occurs exactly every - * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in - * designs running on the internal RC oscillator. - * Please note that Start Of Frame detection works only if D- is wired to the - * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! - */ -#define USB_CFG_CHECK_DATA_TOGGLING 0 -/* define this macro to 1 if you want to filter out duplicate data packets - * sent by the host. Duplicates occur only as a consequence of communication - * errors, when the host does not receive an ACK. Please note that you need to - * implement the filtering yourself in usbFunctionWriteOut() and - * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable - * for each control- and out-endpoint to check for duplicate packets. - */ #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0 /* define this macro to 1 if you want the function usbMeasureFrameLength() * compiled in. This function can be used to calibrate the AVR's RC oscillator. */ -#define USB_USE_FAST_CRC 0 -/* The assembler module has two implementations for the CRC algorithm. One is - * faster, the other is smaller. This CRC routine is only used for transmitted - * messages where timing is not critical. The faster routine needs 31 cycles - * per byte while the smaller one needs 61 to 69 cycles. The faster routine - * may be worth the 32 bytes bigger code size if you transmit lots of data and - * run the AVR close to its limit. - */ /* -------------------------- Device Description --------------------------- */ -#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* USB vendor ID for the device, low byte first. If you have registered your - * own Vendor ID, define it here. Otherwise you may use one of obdev's free - * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! - * *** IMPORTANT NOTE *** - * This template uses obdev's shared VID/PID pair for Vendor Class devices - * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand - * the implications! - */ -#define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x05dc = 1500 */ + * own Vendor ID, define it here. Otherwise you use obdev's free shared + * VID/PID pair. Be sure to read USBID-License.txt for rules! + * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. + * Use this VID/PID pair ONLY if you understand the implications! + */ +#define USB_CFG_DEVICE_ID 0xdf, 0x05 /* This is the ID of the product, low byte first. It is interpreted in the * scope of the vendor ID. If you have registered your own VID with usb.org * or if you have licensed a PID from somebody else, define it here. Otherwise - * you may use one of obdev's free shared VID/PID pairs. See the file - * USB-IDs-for-free.txt for details! - * *** IMPORTANT NOTE *** - * This template uses obdev's shared VID/PID pair for Vendor Class devices - * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand - * the implications! + * you use obdev's free shared VID/PID pair. Be sure to read the rules in + * USBID-License.txt! + * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. + * Use this VID/PID pair ONLY if you understand the implications! */ #define USB_CFG_DEVICE_VERSION 0x00, 0x01 /* Version number of the device: Minor number first, then major number. */ -#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' -#define USB_CFG_VENDOR_NAME_LEN 8 +#define USB_CFG_VENDOR_NAME 'w', 'w', 'w', '.', 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 12 /* These two values define the vendor name returned by the USB device. The name * must be given as a list of characters under single quotes. The characters * are interpreted as Unicode (UTF-16) entities. * If you don't want a vendor name string, undefine these macros. * ALWAYS define a vendor name containing your Internet domain name if you use - * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * obdev's free shared VID/PID pair. See the file USBID-License.txt for * details. */ #define USB_CFG_DEVICE_NAME 'T', 'e', 'm', 'p', 'l', 'a', 't', 'e' #define USB_CFG_DEVICE_NAME_LEN 8 /* Same as above for the device name. If you don't want a device name, undefine - * the macros. See the file USB-IDs-for-free.txt before you assign a name if - * you use a shared VID/PID. + * the macros. See the file USBID-License.txt before you assign a name if you + * use a shared VID/PID. */ /*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ /*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ @@ -267,23 +198,23 @@ section at the end of this file). * to fine tune control over USB descriptors such as the string descriptor * for the serial number. */ -#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ +#define USB_CFG_DEVICE_CLASS 0 #define USB_CFG_DEVICE_SUBCLASS 0 /* See USB specification if you want to conform to an existing device class. - * Class 0xff is "vendor specific". */ -#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ +#define USB_CFG_INTERFACE_CLASS 3 /* HID */ #define USB_CFG_INTERFACE_SUBCLASS 0 #define USB_CFG_INTERFACE_PROTOCOL 0 /* See USB specification if you want to conform to an existing device class or - * protocol. The following classes must be set at interface level: - * HID class is 3, no subclass and protocol required (but may be useful!) - * CDC class is 2, use subclass 2 and protocol 1 for ACM + * protocol. + * This template defines a HID class device. If you implement a vendor class + * device, set USB_CFG_INTERFACE_CLASS to 0 and USB_CFG_DEVICE_CLASS to 0xff. */ -/* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 /* total length of report descriptor */ /* Define this to the length of the HID report descriptor, if you implement * an HID device. Otherwise don't define it or define it to 0. - * If you use this define, you must add a PROGMEM character array named + * Since this template defines a HID device, it must also specify a HID + * report descriptor length. You must add a PROGMEM character array named * "usbHidReportDescriptor" to your code which contains the report descriptor. * Don't forget to keep the array and this define in sync! */ @@ -303,9 +234,7 @@ section at the end of this file). * no properties are defined or if they are 0, the default descriptor is used. * Possible properties are: * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched - * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is - * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if - * you want RAM pointers. + * at runtime via usbFunctionDescriptor(). * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found * in static memory is in RAM, not in flash memory. * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), @@ -337,12 +266,6 @@ section at the end of this file). * USB_CFG_DESCR_PROPS_HID_REPORT * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) * - * Note about string descriptors: String descriptors are not just strings, they - * are Unicode strings prefixed with a 2 byte header. Example: - * int serialNumberDescriptor[] = { - * USB_STRING_DESCRIPTOR_HEADER(6), - * 'S', 'e', 'r', 'i', 'a', 'l' - * }; */ #define USB_CFG_DESCR_PROPS_DEVICE 0 @@ -371,6 +294,6 @@ section at the end of this file). /* #define USB_INTR_ENABLE_BIT INT0 */ /* #define USB_INTR_PENDING GIFR */ /* #define USB_INTR_PENDING_BIT INTF0 */ -/* #define USB_INTR_VECTOR INT0_vect */ +/* #define USB_INTR_VECTOR SIG_INTERRUPT0 */ #endif /* __usbconfig_h_included__ */ diff --git a/libcrypt/usbdrv/usbdrv.c b/libcrypt/usbdrv/usbdrv.c new file mode 100644 index 0000000..1a6bdf8 --- /dev/null +++ b/libcrypt/usbdrv/usbdrv.c @@ -0,0 +1,578 @@ +/* Name: usbdrv.c + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrv.c 530 2008-02-28 15:34:04Z cs $ + */ + +#include "iarcompat.h" +#ifndef __IAR_SYSTEMS_ICC__ +# include +# include +#endif +#include "usbdrv.h" +#include "oddebug.h" + +/* +General Description: +This module implements the C-part of the USB driver. See usbdrv.h for a +documentation of the entire driver. +*/ + +/* ------------------------------------------------------------------------- */ + +/* raw USB registers / interface to assembler code: */ +uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ +uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */ +uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */ +uchar usbNewDeviceAddr; /* device ID which should be set after status phase */ +uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */ +volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ +uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */ +uchar usbRxToken; /* token for data we received; or endpont number for last OUT */ +uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */ +volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */ +uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ +#if USB_COUNT_SOF +volatile uchar usbSofCount; /* incremented by assembler module every SOF */ +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT +volatile uchar usbTxLen1 = USBPID_NAK; /* TX count for endpoint 1 */ +uchar usbTxBuf1[USB_BUFSIZE]; /* TX data for endpoint 1 */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 +volatile uchar usbTxLen3 = USBPID_NAK; /* TX count for endpoint 3 */ +uchar usbTxBuf3[USB_BUFSIZE]; /* TX data for endpoint 3 */ +# endif +#endif + +/* USB status registers / not shared with asm code */ +uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */ +static uchar usbMsgFlags; /* flag values see below */ + +#define USB_FLG_TX_PACKET (1<<0) +/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */ +#define USB_FLG_MSGPTR_IS_ROM (1<<6) +#define USB_FLG_USE_DEFAULT_RW (1<<7) + +/* +optimizing hints: +- do not post/pre inc/dec integer values in operations +- assign value of PRG_RDB() to register variables and don't use side effects in arg +- use narrow scope for variables which should be in X/Y/Z register +- assign char sized expressions to variables to force 8 bit arithmetics +*/ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_DESCR_PROPS_STRINGS == 0 + +#if USB_CFG_DESCR_PROPS_STRING_0 == 0 +#undef USB_CFG_DESCR_PROPS_STRING_0 +#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0) +PROGMEM const char usbDescriptorString0[] = { /* language descriptor */ + 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ + 3, /* descriptor type */ + 0x09, 0x04, /* language index (0x0409 = US-English) */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_VENDOR +#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor) +PROGMEM const int usbDescriptorStringVendor[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), + USB_CFG_VENDOR_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice) +PROGMEM const int usbDescriptorStringDevice[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), + USB_CFG_DEVICE_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN +#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber) +PROGMEM const int usbDescriptorStringSerialNumber[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), + USB_CFG_SERIAL_NUMBER +}; +#endif + +#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ + +#if USB_CFG_DESCR_PROPS_DEVICE == 0 +#undef USB_CFG_DESCR_PROPS_DEVICE +#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice) +PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */ + 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ + USBDESCR_DEVICE, /* descriptor type */ + 0x10, 0x01, /* USB version supported */ + USB_CFG_DEVICE_CLASS, + USB_CFG_DEVICE_SUBCLASS, + 0, /* protocol */ + 8, /* max packet size */ + /* the following two casts affect the first byte of the constant only, but + * that's sufficient to avoid a warning with the default values. + */ + (char)USB_CFG_VENDOR_ID,/* 2 bytes */ + (char)USB_CFG_DEVICE_ID,/* 2 bytes */ + USB_CFG_DEVICE_VERSION, /* 2 bytes */ + USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */ + USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */ + USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ + 1, /* number of configurations */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 +#undef USB_CFG_DESCR_PROPS_HID +#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */ +#endif + +#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 +#undef USB_CFG_DESCR_PROPS_CONFIGURATION +#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration) +PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ + 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ + USBDESCR_CONFIG, /* descriptor type */ + 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0, + /* total length of data returned (including inlined descriptors) */ + 1, /* number of interfaces in this configuration */ + 1, /* index of this configuration */ + 0, /* configuration name string index */ +#if USB_CFG_IS_SELF_POWERED + USBATTR_SELFPOWER, /* attributes */ +#else + (char)USBATTR_BUSPOWER, /* attributes */ +#endif + USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ +/* interface descriptor follows inline: */ + 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ + USBDESCR_INTERFACE, /* descriptor type */ + 0, /* index of this interface */ + 0, /* alternate setting for this interface */ + USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ + USB_CFG_INTERFACE_CLASS, + USB_CFG_INTERFACE_SUBCLASS, + USB_CFG_INTERFACE_PROTOCOL, + 0, /* string index for interface */ +#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ + 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ + USBDESCR_HID, /* descriptor type: HID */ + 0x01, 0x01, /* BCD representation of HID version */ + 0x00, /* target country code */ + 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ + 0x22, /* descriptor type: report */ + USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ + 7, /* sizeof(usbDescrEndpoint) */ + USBDESCR_ENDPOINT, /* descriptor type = endpoint */ + (char)0x81, /* IN endpoint number 1 */ + 0x03, /* attrib: Interrupt endpoint */ + 8, 0, /* maximum packet size */ + USB_CFG_INTR_POLL_INTERVAL, /* in ms */ +#endif +}; +#endif + +/* We don't use prog_int or prog_int16_t for compatibility with various libc + * versions. Here's an other compatibility hack: + */ +#ifndef PRG_RDB +#define PRG_RDB(addr) pgm_read_byte(addr) +#endif + +typedef union{ + unsigned word; + uchar *ptr; + uchar bytes[2]; +}converter_t; +/* We use this union to do type conversions. This is better optimized than + * type casts in gcc 3.4.3 and much better than using bit shifts to build + * ints from chars. Byte ordering is not a problem on an 8 bit platform. + */ + +/* ------------------------------------------------------------------------- */ + +static inline void usbResetDataToggling(void) +{ +#if USB_CFG_HAVE_INTRIN_ENDPOINT + USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# endif +#endif +} + +static inline void usbResetStall(void) +{ +#if USB_CFG_IMPLEMENT_HALT && USB_CFG_HAVE_INTRIN_ENDPOINT + usbTxLen1 = USBPID_NAK; +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 + usbTxLen3 = USBPID_NAK; +#endif +#endif +} + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_HAVE_INTRIN_ENDPOINT +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) +{ +uchar *p, i; + +#if USB_CFG_IMPLEMENT_HALT + if(usbTxLen1 == USBPID_STALL) + return; +#endif +#if 0 /* No runtime checks! Caller is responsible for valid data! */ + if(len > 8) /* interrupt transfers are limited to 8 bytes */ + len = 8; +#endif + if(usbTxLen1 & 0x10){ /* packet buffer was empty */ + usbTxBuf1[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf1 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf1[1], len); + usbTxLen1 = len + 4; /* len must be given including sync byte */ + DBG2(0x21, usbTxBuf1, len + 3); +} +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) +{ +uchar *p, i; + + if(usbTxLen3 & 0x10){ /* packet buffer was empty */ + usbTxBuf3[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen3 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf3 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf3[1], len); + usbTxLen3 = len + 4; /* len must be given including sync byte */ + DBG2(0x23, usbTxBuf3, len + 3); +} +#endif + + +static uchar usbRead(uchar *data, uchar len) +{ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){ +#endif + uchar i = len, *r = usbMsgPtr; + if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ + while(i--){ + uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */ + *data++ = c; + r++; + } + }else{ /* RAM data */ + while(i--) + *data++ = *r++; + } + usbMsgPtr = r; + return len; +#if USB_CFG_IMPLEMENT_FN_READ + }else{ + if(len != 0) /* don't bother app with 0 sized reads */ + return usbFunctionRead(data, len); + return 0; + } +#endif +} + + +#define GET_DESCRIPTOR(cfgProp, staticName) \ + if(cfgProp){ \ + if((cfgProp) & USB_PROP_IS_RAM) \ + flags &= ~USB_FLG_MSGPTR_IS_ROM; \ + if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ + replyLen = usbFunctionDescriptor(rq); \ + }else{ \ + replyData = (uchar *)(staticName); \ + SET_REPLY_LEN((cfgProp) & 0xff); \ + } \ + } +/* We use if() instead of #if in the macro above because #if can't be used + * in macros and the compiler optimizes constant conditions anyway. + */ + + +/* Don't make this function static to avoid inlining. + * The entire function would become too large and exceed the range of + * relative jumps. + * 2006-02-25: Either gcc 3.4.3 is better than the gcc used when the comment + * above was written, or other parts of the code have changed. We now get + * better results with an inlined function. Test condition: PowerSwitch code. + */ +static void usbProcessRx(uchar *data, uchar len) +{ +usbRequest_t *rq = (void *)data; +uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW; +/* We use if() cascades because the compare is done byte-wise while switch() + * is int-based. The if() cascades are therefore more efficient. + */ +/* usbRxToken can be: + * 0x2d 00101101 (USBPID_SETUP for endpoint 0) + * 0xe1 11100001 (USBPID_OUT for endpoint 0) + * 0xff 11111111 (USBPID_OUT for endpoint 1) + */ + DBG2(0x10 + ((usbRxToken >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */ +#ifdef USB_RX_USER_HOOK + USB_RX_USER_HOOK(data, len) +#endif +#if USB_CFG_IMPLEMENT_FN_WRITEOUT + if(usbRxToken < 0x10){ /* endpoint number in usbRxToken */ + usbFunctionWriteOut(data, len); + return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */ + } +#endif + if(usbRxToken == (uchar)USBPID_SETUP){ + usbTxLen = USBPID_NAK; /* abort pending transmit */ + if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */ + uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; + if(type == USBRQ_TYPE_STANDARD){ + #define SET_REPLY_LEN(len) replyLen = (len); usbMsgPtr = replyData + /* This macro ensures that replyLen and usbMsgPtr are always set in the same way. + * That allows optimization of common code in if() branches */ + uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */ + replyData[0] = 0; /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ + if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */ + uchar __attribute__((__unused__)) recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ +#if USB_CFG_IS_SELF_POWERED + if(recipient == USBRQ_RCPT_DEVICE) + replyData[0] = USB_CFG_IS_SELF_POWERED; +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT + if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */ + replyData[0] = usbTxLen1 == USBPID_STALL; +#endif + replyData[1] = 0; + SET_REPLY_LEN(2); + }else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */ + usbNewDeviceAddr = rq->wValue.bytes[0]; +#ifdef USB_SET_ADDRESS_HOOK + USB_SET_ADDRESS_HOOK(); +#endif + }else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */ + flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW; + if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) + }else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){ /* 2 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) + }else if(rq->wValue.bytes[1] == USBDESCR_STRING){ /* 3 */ +#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC + if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) + flags &= ~USB_FLG_MSGPTR_IS_ROM; + replyLen = usbFunctionDescriptor(rq); +#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + if(rq->wValue.bytes[0] == 0){ /* descriptor index */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) + }else if(rq->wValue.bytes[0] == 1){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) + }else if(rq->wValue.bytes[0] == 2){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) + }else if(rq->wValue.bytes[0] == 3){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } +#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ +#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ + }else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) + }else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) +#endif /* USB_CFG_DESCR_PROPS_HID_REPORT */ + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } + }else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */ + replyData = &usbConfiguration; /* send current configuration value */ + SET_REPLY_LEN(1); + }else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */ + usbConfiguration = rq->wValue.bytes[0]; + usbResetStall(); + }else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */ + SET_REPLY_LEN(1); +#if USB_CFG_HAVE_INTRIN_ENDPOINT + }else if(rq->bRequest == USBRQ_SET_INTERFACE){ /* 11 */ + usbResetDataToggling(); + usbResetStall(); +# if USB_CFG_IMPLEMENT_HALT + }else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){ /* 1|3 */ + if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */ + usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; + usbResetDataToggling(); + } +# endif +#endif + }else{ + /* the following requests can be ignored, send default reply */ + /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */ + /* 12: SYNCH_FRAME */ + } + #undef SET_REPLY_LEN + }else{ /* not a standard request -- must be vendor or class request */ + replyLen = usbFunctionSetup(data); + } +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + if(replyLen == 0xff){ /* use user-supplied read/write function */ + if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){ + replyLen = rq->wLength.bytes[0]; /* IN transfers only */ + } + flags &= ~USB_FLG_USE_DEFAULT_RW; /* we have no valid msg, use user supplied read/write functions */ + }else /* The 'else' prevents that we limit a replyLen of 0xff to the maximum transfer len. */ +#endif + if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + replyLen = rq->wLength.bytes[0]; + } + /* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */ + }else{ /* DATA packet from out request */ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){ + uchar rval = usbFunctionWrite(data, len); + replyLen = 0xff; + if(rval == 0xff){ /* an error occurred */ + usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */ + usbTxLen = USBPID_STALL; + }else if(rval != 0){ /* This was the final package */ + replyLen = 0; /* answer with a zero-sized data packet */ + } + flags = 0; /* start with a DATA1 package, stay with user supplied write() function */ + } +#endif + } + usbMsgFlags = flags; + usbMsgLen = replyLen; +} + +/* ------------------------------------------------------------------------- */ + +static void usbBuildTxBlock(void) +{ +uchar wantLen, len, txLen, token; + + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + token = USBPID_DATA1; + if(usbMsgFlags & USB_FLG_TX_PACKET) + token = USBPID_DATA0; + usbMsgFlags++; + len = usbRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + usbCrc16Append(&usbTxBuf[1], len); + txLen = len + 4; /* length including sync byte */ + if(len < 8) /* a partial package identifies end of message */ + usbMsgLen = 0xff; + }else{ + txLen = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = 0xff; + } + usbTxBuf[0] = token; + usbTxLen = txLen; + DBG2(0x20, usbTxBuf, txLen-1); +} + +/* ------------------------------------------------------------------------- */ + +static inline uchar isNotSE0(void) +{ +uchar rval; +/* We want to do + * return (USBIN & USBMASK); + * here, but the compiler does int-expansion acrobatics. + * We can avoid this by assigning to a char-sized variable. + */ + rval = USBIN & USBMASK; + return rval; +} + +static inline void usbHandleResetHook(uchar notResetState) +{ +#ifdef USB_RESET_HOOK +static uchar wasReset; +uchar isReset = !notResetState; + + if(wasReset != isReset){ + USB_RESET_HOOK(isReset); + wasReset = isReset; + } +#endif +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbPoll(void) +{ +schar len; +uchar i; + + if((len = usbRxLen) > 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); + */ + usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len - 3); +#if USB_CFG_HAVE_FLOWCONTROL + if(usbRxLen > 0) /* only mark as available if not inactivated */ + usbRxLen = 0; +#else + usbRxLen = 0; /* mark rx buffer as available */ +#endif + } + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != 0xff){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + for(i = 10; i > 0; i--){ + if(isNotSE0()) + break; + } + if(i == 0){ /* RESET condition, called multiple times during reset */ + usbNewDeviceAddr = 0; + usbDeviceAddr = 0; + usbResetStall(); + DBG1(0xff, 0, 0); + } + usbHandleResetHook(i); +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbInit(void) +{ +#if USB_INTR_CFG_SET != 0 + USB_INTR_CFG |= USB_INTR_CFG_SET; +#endif +#if USB_INTR_CFG_CLR != 0 + USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); +#endif + USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); + usbResetDataToggling(); +} + +/* ------------------------------------------------------------------------- */ diff --git a/usbdrv/usbdrv.h b/libcrypt/usbdrv/usbdrv.h similarity index 85% rename from usbdrv/usbdrv.h rename to libcrypt/usbdrv/usbdrv.h index cd0445c..6ecf19c 100644 --- a/usbdrv/usbdrv.h +++ b/libcrypt/usbdrv/usbdrv.h @@ -1,17 +1,17 @@ /* Name: usbdrv.h - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2004-12-29 * Tabsize: 4 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrv.h 536 2008-02-28 21:11:35Z cs $ */ #ifndef __usbdrv_h_included__ #define __usbdrv_h_included__ -#include "usbconfig.h" -#include "usbportability.h" +#include "../usbconfig.h" +#include "iarcompat.h" /* Hardware Prerequisites: @@ -34,8 +34,8 @@ usbDeviceConnect() and usbDeviceDisconnect() further down in this file. Please adapt the values in usbconfig.h according to your hardware! -The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz -or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. +The device MUST be clocked at exactly 12 MHz, 15 MHz or 16 MHz +or at 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. Limitations: @@ -105,9 +105,9 @@ interrupt routine. Interrupt latency: The application must ensure that the USB interrupt is not disabled for more than 25 cycles (this is for 12 MHz, faster clocks allow longer latency). -This implies that all interrupt routines must either have the "ISR_NOBLOCK" -attribute set (see "avr/interrupt.h") or be written in assembler with "sei" -as the first instruction. +This implies that all interrupt routines must either be declared as "INTERRUPT" +instead of "SIGNAL" (see "avr/signal.h") or that they are written in assembler +with "sei" as the first instruction. Maximum interrupt duration / CPU cycle consumption: The driver handles all USB communication during the interrupt service @@ -122,7 +122,7 @@ USB messages, even if they address another (low-speed) device on the same bus. /* --------------------------- Module Interface ---------------------------- */ /* ------------------------------------------------------------------------- */ -#define USBDRV_VERSION 20120109 +#define USBDRV_VERSION 20080228 /* This define uniquely identifies a driver version. It is a decimal number * constructed from the driver's release date in the form YYYYMMDD. If the * driver's behavior or interface changes, you can use this constant to @@ -150,26 +150,11 @@ USB messages, even if they address another (low-speed) device on the same bus. #endif /* shortcuts for well defined 8 bit integer types */ -#if USB_CFG_LONG_TRANSFERS /* if more than 254 bytes transfer size required */ -# define usbMsgLen_t unsigned -#else -# define usbMsgLen_t uchar -#endif -/* usbMsgLen_t is the data type used for transfer lengths. By default, it is - * defined to uchar, allowing a maximum of 254 bytes (255 is reserved for - * USB_NO_MSG below). If the usbconfig.h defines USB_CFG_LONG_TRANSFERS to 1, - * a 16 bit data type is used, allowing up to 16384 bytes (the rest is used - * for flags in the descriptor configuration). - */ -#define USB_NO_MSG ((usbMsgLen_t)-1) /* constant meaning "no message" */ - struct usbRequest; /* forward declaration */ USB_PUBLIC void usbInit(void); /* This function must be called before interrupts are enabled and the main - * loop is entered. We exepct that the PORT and DDR bits for D+ and D- have - * not been changed from their default status (which is 0). If you have changed - * them, set both back to 0 (configure them as input with no internal pull-up). + * loop is entered. */ USB_PUBLIC void usbPoll(void); /* This function must be called at regular intervals from the main loop. @@ -183,7 +168,7 @@ extern uchar *usbMsgPtr; * implementation of usbFunctionWrite(). It is also used internally by the * driver for standard control requests. */ -USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); +USB_PUBLIC uchar usbFunctionSetup(uchar data[8]); /* This function is called when the driver receives a SETUP transaction from * the host which is not answered by the driver itself (in practice: class and * vendor requests). All control transfers start with a SETUP transaction where @@ -196,21 +181,21 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); * requested data to the driver. There are two ways to transfer this data: * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data * block and return the length of the data in 'usbFunctionSetup()'. The driver - * will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The - * driver will then call 'usbFunctionRead()' when data is needed. See the + * will handle the rest. Or (2) return 0xff in 'usbFunctionSetup()'. The driver + * will then call 'usbFunctionRead()' when data is needed. See the * documentation for usbFunctionRead() for details. * * If the SETUP indicates a control-out transfer, the only way to receive the * data from the host is through the 'usbFunctionWrite()' call. If you - * implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()' - * to indicate that 'usbFunctionWrite()' should be used. See the documentation - * of this function for more information. If you just want to ignore the data - * sent by the host, return 0 in 'usbFunctionSetup()'. + * implement this function, you must return 0xff in 'usbFunctionSetup()' to + * indicate that 'usbFunctionWrite()' should be used. See the documentation of + * this function for more information. If you just want to ignore the data sent + * by the host, return 0 in 'usbFunctionSetup()'. * * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() * are only done if enabled by the configuration in usbconfig.h. */ -USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq); +USB_PUBLIC uchar usbFunctionDescriptor(struct usbRequest *rq); /* You need to implement this function ONLY if you provide USB descriptors at * runtime (which is an expert feature). It is very similar to * usbFunctionSetup() above, but it is called only to request USB descriptor @@ -224,6 +209,7 @@ USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len); * interrupt status to the host. * If you need to transfer more bytes, use a control read after the interrupt. */ +extern volatile uchar usbTxLen1; #define usbInterruptIsReady() (usbTxLen1 & 0x10) /* This macro indicates whether the last interrupt message has already been * sent. If you set a new interrupt message before the old was sent, the @@ -231,6 +217,7 @@ USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len); */ #if USB_CFG_HAVE_INTRIN_ENDPOINT3 USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len); +extern volatile uchar usbTxLen3; #define usbInterruptIsReady3() (usbTxLen3 & 0x10) /* Same as above for endpoint 3 */ #endif @@ -275,14 +262,11 @@ USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len); * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. */ #endif /* USB_CFG_IMPLEMENT_FN_READ */ - -extern uchar usbRxToken; /* may be used in usbFunctionWriteOut() below */ #if USB_CFG_IMPLEMENT_FN_WRITEOUT USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len); -/* This function is called by the driver when data is received on an interrupt- - * or bulk-out endpoint. The endpoint number can be found in the global - * variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in - * usbconfig.h to get this function called. +/* This function is called by the driver when data on interrupt-out or bulk- + * out endpoint 1 is received. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT + * to 1 in usbconfig.h to get this function called. */ #endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */ #ifdef USB_CFG_PULLUP_IOPORTNAME @@ -343,12 +327,6 @@ extern volatile uchar usbSofCount; * the macro USB_COUNT_SOF is defined to a value != 0. */ #endif -#if USB_CFG_CHECK_DATA_TOGGLING -extern uchar usbCurrentDataToken; -/* This variable can be checked in usbFunctionWrite() and usbFunctionWriteOut() - * to ignore duplicate packets. - */ -#endif #define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8)) /* This macro builds a descriptor header for a string descriptor given the @@ -375,9 +353,7 @@ extern volatile schar usbRxLen; #define USB_SET_DATATOKEN1(token) usbTxBuf1[0] = token #define USB_SET_DATATOKEN3(token) usbTxBuf3[0] = token /* These two macros can be used by application software to reset data toggling - * for interrupt-in endpoints 1 and 3. Since the token is toggled BEFORE - * sending data, you must set the opposite value of the token which should come - * first. + * for interrupt-in endpoints 1 and 3. */ #endif /* __ASSEMBLER__ */ @@ -390,18 +366,16 @@ extern volatile schar usbRxLen; * about the various methods to define USB descriptors. If you do nothing, * the default descriptors will be used. */ -#define USB_PROP_IS_DYNAMIC (1 << 14) +#define USB_PROP_IS_DYNAMIC (1 << 8) /* If this property is set for a descriptor, usbFunctionDescriptor() will be - * used to obtain the particular descriptor. Data directly returned via - * usbMsgPtr are FLASH data by default, combine (OR) with USB_PROP_IS_RAM to - * return RAM data. + * used to obtain the particular descriptor. */ -#define USB_PROP_IS_RAM (1 << 15) +#define USB_PROP_IS_RAM (1 << 9) /* If this property is set for a descriptor, the data is read from RAM * memory instead of Flash. The property is used for all methods to provide * external descriptors. */ -#define USB_PROP_LENGTH(len) ((len) & 0x3fff) +#define USB_PROP_LENGTH(len) ((len) & 0xff) /* If a static external descriptor is used, this is the total length of the * descriptor in bytes. */ @@ -513,22 +487,22 @@ const int usbDescriptorStringSerialNumber[]; #if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID) #warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h" /* If the user has not defined IDs, we default to obdev's free IDs. - * See USB-IDs-for-free.txt for details. + * See USBID-License.txt for details. */ #endif /* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */ #ifndef USB_CFG_VENDOR_ID -# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* 5824 in dec, stands for VOTI */ #endif #ifndef USB_CFG_DEVICE_ID # if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH -# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* = 0x5df = 1503, shared PID for HIDs */ +# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* 1503 in dec, shared PID for HIDs */ # elif USB_CFG_INTERFACE_CLASS == 2 -# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* = 0x5e1 = 1505, shared PID for CDC Modems */ +# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* 1505 in dec, shared PID for CDC Modems */ # else -# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x5dc = 1500, obdev's free PID */ +# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free PID */ # endif #endif @@ -558,10 +532,6 @@ const int usbDescriptorStringSerialNumber[]; #define USB_CFG_EP3_NUMBER 3 #endif -#ifndef USB_CFG_HAVE_INTRIN_ENDPOINT3 -#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 -#endif - #define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */ /* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */ @@ -574,14 +544,7 @@ const int usbDescriptorStringSerialNumber[]; # endif #endif #ifndef USB_INTR_CFG_SET /* allow user to override our default */ -# if defined(USB_COUNT_SOF) || defined(USB_SOF_HOOK) -# define USB_INTR_CFG_SET (1 << ISC01) /* cfg for falling edge */ - /* If any SOF logic is used, the interrupt must be wired to D- where - * we better trigger on falling edge - */ -# else -# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */ -# endif +# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */ #endif #ifndef USB_INTR_CFG_CLR /* allow user to override our default */ # define USB_INTR_CFG_CLR 0 /* no bits to clear */ @@ -639,22 +602,12 @@ at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM #define USBPID_STALL 0x1e #ifndef USB_INITIAL_DATATOKEN -#define USB_INITIAL_DATATOKEN USBPID_DATA1 +#define USB_INITIAL_DATATOKEN USBPID_DATA0 #endif #ifndef __ASSEMBLER__ -typedef struct usbTxStatus{ - volatile uchar len; - uchar buffer[USB_BUFSIZE]; -}usbTxStatus_t; - -extern usbTxStatus_t usbTxStatus1, usbTxStatus3; -#define usbTxLen1 usbTxStatus1.len -#define usbTxBuf1 usbTxStatus1.buffer -#define usbTxLen3 usbTxStatus3.len -#define usbTxBuf3 usbTxStatus3.buffer - +extern uchar usbTxBuf1[USB_BUFSIZE], usbTxBuf3[USB_BUFSIZE]; typedef union usbWord{ unsigned word; @@ -718,8 +671,7 @@ typedef struct usbRequest{ #define USBDESCR_HID_REPORT 0x22 #define USBDESCR_HID_PHYS 0x23 -//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more -#define USBATTR_BUSPOWER 0 +#define USBATTR_BUSPOWER 0x80 #define USBATTR_SELFPOWER 0x40 #define USBATTR_REMOTEWAKE 0x20 diff --git a/usbdrv/usbdrvasm.S b/libcrypt/usbdrv/usbdrvasm.S similarity index 60% rename from usbdrv/usbdrvasm.S rename to libcrypt/usbdrv/usbdrvasm.S index 4e6158c..518037e 100644 --- a/usbdrv/usbdrvasm.S +++ b/libcrypt/usbdrv/usbdrvasm.S @@ -1,10 +1,10 @@ /* Name: usbdrvasm.S - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2007-06-13 * Tabsize: 4 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) * Revision: $Id$ */ @@ -15,9 +15,16 @@ general code (preprocessor acrobatics and CRC computation) and then includes the file appropriate for the given clock rate. */ -#define __SFR_OFFSET 0 /* used by avr-libc's register definitions */ -#include "usbportability.h" -#include "usbdrv.h" /* for common defs */ +#include "iarcompat.h" +#ifndef __IAR_SYSTEMS_ASM__ + /* configs for io.h */ +# define __SFR_OFFSET 0 +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +# include /* for CPU I/O register definitions and vectors */ +# define macro .macro /* GNU Assembler macro definition */ +# define endm .endm /* End of GNU Assembler macro definition */ +#endif /* __IAR_SYSTEMS_ASM__ */ +#include "usbdrv.h" /* for common defs */ /* register names */ #define x1 r16 @@ -26,17 +33,27 @@ the file appropriate for the given clock rate. #define cnt r19 #define x3 r20 #define x4 r21 -#define x5 r22 -#define bitcnt x5 +#define bitcnt r22 #define phase x4 #define leap x4 /* Some assembler dependent definitions and declarations: */ #ifdef __IAR_SYSTEMS_ASM__ + +# 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 */ + extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen - extern usbTxBuf, usbTxStatus1, usbTxStatus3 + extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3 # if USB_COUNT_SOF extern usbSofCount # endif @@ -56,12 +73,10 @@ the file appropriate for the given clock rate. #else /* __IAR_SYSTEMS_ASM__ */ +# define nop2 rjmp .+0 /* jump to next instruction */ + # ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ -# ifdef INT0_vect -# define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector -# else -# define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector -# endif +# define USB_INTR_VECTOR SIG_INTERRUPT0 # endif .text .global USB_INTR_VECTOR @@ -79,11 +94,6 @@ the file appropriate for the given clock rate. # define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg #endif -#define usbTxLen1 usbTxStatus1 -#define usbTxBuf1 (usbTxStatus1 + 1) -#define usbTxLen3 usbTxStatus3 -#define usbTxBuf3 (usbTxStatus3 + 1) - ;---------------------------------------------------------------------------- ; Utility functions @@ -143,93 +153,16 @@ RTMODEL "__rt_version", "3" #endif -#if USB_USE_FAST_CRC - -; This implementation is faster, but has bigger code size -; Thanks to Slawomir Fras (BoskiDialer) for this code! -; It implements the following C pseudo-code: -; unsigned table(unsigned char x) -; { -; unsigned value; -; -; value = (unsigned)x << 6; -; value ^= (unsigned)x << 7; -; if(parity(x)) -; value ^= 0xc001; -; return value; -; } -; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen) -; { -; unsigned crc = 0xffff; -; -; while(argLen--) -; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc); -; return ~crc; -; } - -; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); -; argPtr r24+25 / r16+r17 -; argLen r22 / r18 +; extern unsigned usbCrc16(unsigned char *data, unsigned char len); +; data: r24/25 +; len: r22 ; temp variables: -; byte r18 / r22 -; scratch r23 -; resCrc r24+r25 / r16+r17 -; ptr X / Z -usbCrc16: - mov ptrL, argPtrL - mov ptrH, argPtrH - ldi resCrcL, 0xFF - ldi resCrcH, 0xFF - rjmp usbCrc16LoopTest -usbCrc16ByteLoop: - ld byte, ptr+ - eor resCrcL, byte ; resCrcL is now 'x' in table() - mov byte, resCrcL ; compute parity of 'x' - swap byte - eor byte, resCrcL - mov scratch, byte - lsr byte - lsr byte - eor byte, scratch - inc byte - lsr byte - andi byte, 1 ; byte is now parity(x) - mov scratch, resCrcL - mov resCrcL, resCrcH - eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001; - neg byte - andi byte, 0xc0 - mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001; - clr byte - lsr scratch - ror byte - eor resCrcH, scratch - eor resCrcL, byte - lsr scratch - ror byte - eor resCrcH, scratch - eor resCrcL, byte -usbCrc16LoopTest: - subi argLen, 1 - brsh usbCrc16ByteLoop - com resCrcL - com resCrcH - ret - -#else /* USB_USE_FAST_CRC */ - -; This implementation is slower, but has less code size -; -; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); -; argPtr r24+25 / r16+r17 -; argLen r22 / r18 -; temp variables: -; byte r18 / r22 -; bitCnt r19 -; poly r20+r21 -; scratch r23 -; resCrc r24+r25 / r16+r17 -; ptr X / Z +; r18: data byte +; r19: bit counter +; r20/21: polynomial +; r23: scratch +; r24/25: crc-sum +; r26/27=X: ptr usbCrc16: mov ptrL, argPtrL mov ptrH, argPtrH @@ -237,30 +170,27 @@ usbCrc16: ldi resCrcH, 0 ldi polyL, lo8(0xa001) ldi polyH, hi8(0xa001) - com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set - ldi bitCnt, 0 ; loop counter with starnd condition = end condition - rjmp usbCrcLoopEntry -usbCrcByteLoop: + com argLen ; argLen = -argLen - 1 +crcByteLoop: + subi argLen, -1 + brcc crcReady ; modified loop to ensure that carry is set below ld byte, ptr+ + ldi bitCnt, -8 ; strange loop counter to ensure that carry is set where we need it eor resCrcL, byte -usbCrcBitLoop: - ror resCrcH ; carry is always set here (see brcs jumps to here) +crcBitLoop: + ror resCrcH ; carry is always set here ror resCrcL - brcs usbCrcNoXor + brcs crcNoXor eor resCrcL, polyL eor resCrcH, polyH -usbCrcNoXor: - subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times - brcs usbCrcBitLoop -usbCrcLoopEntry: - subi argLen, -1 - brcs usbCrcByteLoop -usbCrcReady: +crcNoXor: + subi bitCnt, -1 + brcs crcBitLoop + rjmp crcByteLoop +crcReady: ret ; Thanks to Reimar Doeffinger for optimizing this CRC routine! -#endif /* USB_USE_FAST_CRC */ - ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len); usbCrc16Append: rcall usbCrc16 @@ -361,33 +291,17 @@ usbMFTimeout: ;---------------------------------------------------------------------------- #ifndef USB_CFG_CLOCK_KHZ -# ifdef F_CPU -# define USB_CFG_CLOCK_KHZ (F_CPU/1000) -# else -# error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" -# endif +# define USB_CFG_CLOCK_KHZ 12000 #endif -#if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */ -# if USB_CFG_CLOCK_KHZ == 18000 -# include "usbdrvasm18-crc.inc" -# else -# error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!" -# endif -#else /* USB_CFG_CHECK_CRC */ -# if USB_CFG_CLOCK_KHZ == 12000 -# include "usbdrvasm12.inc" -# elif USB_CFG_CLOCK_KHZ == 12800 -# include "usbdrvasm128.inc" -# elif USB_CFG_CLOCK_KHZ == 15000 -# include "usbdrvasm15.inc" -# elif USB_CFG_CLOCK_KHZ == 16000 -# include "usbdrvasm16.inc" -# elif USB_CFG_CLOCK_KHZ == 16500 -# include "usbdrvasm165.inc" -# elif USB_CFG_CLOCK_KHZ == 20000 -# include "usbdrvasm20.inc" -# else -# error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!" -# endif -#endif /* USB_CFG_CHECK_CRC */ +#if USB_CFG_CLOCK_KHZ == 12000 +# include "usbdrvasm12.inc" +#elif USB_CFG_CLOCK_KHZ == 15000 +# include "usbdrvasm15.inc" +#elif USB_CFG_CLOCK_KHZ == 16000 +# include "usbdrvasm16.inc" +#elif USB_CFG_CLOCK_KHZ == 16500 +# include "usbdrvasm165.inc" +#else +# error "USB_CFG_CLOCK_KHZ is not one of the supported rates!" +#endif diff --git a/usbdrv/usbdrvasm.asm b/libcrypt/usbdrv/usbdrvasm.asm similarity index 72% rename from usbdrv/usbdrvasm.asm rename to libcrypt/usbdrv/usbdrvasm.asm index 9cc4e4d..4a5486f 100644 --- a/usbdrv/usbdrvasm.asm +++ b/libcrypt/usbdrv/usbdrvasm.asm @@ -1,10 +1,10 @@ /* Name: usbdrvasm.asm - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2006-03-01 * Tabsize: 4 * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) * This Revision: $Id$ */ diff --git a/usbdrv/usbdrvasm12.inc b/libcrypt/usbdrv/usbdrvasm12.inc similarity index 64% rename from usbdrv/usbdrvasm12.inc rename to libcrypt/usbdrv/usbdrvasm12.inc index cb74ceb..23b988c 100644 --- a/usbdrv/usbdrvasm12.inc +++ b/libcrypt/usbdrv/usbdrvasm12.inc @@ -1,11 +1,11 @@ /* Name: usbdrvasm12.inc - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2004-12-29 * Tabsize: 4 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrvasm12.inc 483 2008-02-05 15:05:32Z cs $ */ /* Do not link this file! Link usbdrvasm.S instead, which includes the @@ -48,13 +48,10 @@ USB_INTR_VECTOR: ;---------------------------------------------------------------------------- ;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. +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) waitForJ: - inc YL - sbis USBIN, USBMINUS - brne waitForJ ; just make sure we have ANY timeout + sbis USBIN, USBMINUS ;1 [40] wait for D- == 1 + rjmp waitForJ ;2 waitForK: ;The following code results in a sampling window of 1/4 bit which meets the spec. sbis USBIN, USBMINUS @@ -72,9 +69,6 @@ waitForK: 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] @@ -256,12 +250,12 @@ macro POP_STANDARD ; 12 cycles pop x1 pop shift pop YH - endm +endm macro POP_RETI ; 5 cycles pop YL out SREG, YL pop YL - endm +endm #include "asmcommon.inc" @@ -269,16 +263,25 @@ macro POP_RETI ; 5 cycles ; Transmitting data ;---------------------------------------------------------------------------- -txByteLoop: -txBitloop: -stuffN1Delay: ; [03] - ror shift ;[-5] [11] [59] - brcc doExorN1 ;[-4] [60] - subi x4, 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 +bitstuff0: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff0 ;2 branch back 2 cycles earlier +bitstuff1: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff1 ;2 we know that C is clear, jump back to do OUT and ror 0 into x2 +bitstuff2: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff2 ;2 jump back 4 cycles earlier and do out and ror 0 into x2 +bitstuff3: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff3 ;2 jump back earlier and ror 0 into x2 +bitstuff4: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff4 ;2 jump back 2 cycles earlier sendNakAndReti: ;0 [-19] 19 cycles until SOP ldi x3, USBPID_NAK ;1 [-18] @@ -303,91 +306,122 @@ usbSendX3: ;0 [-16] ;usbSend: ;pointer to data in 'Y' ;number of bytes in 'cnt' -- including sync byte -;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] -;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) -usbSendAndReti: - in x2, USBDDR ;[-12] 12 cycles until SOP - ori x2, USBMASK ;[-11] - sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) - out USBDDR, x2 ;[-8] <--- acquire bus - in x1, USBOUT ;[-7] port mirror for tx loop - ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror) - ldi x2, USBMASK ;[-5] - push x4 ;[-4] -doExorN1: - eor x1, x2 ;[-2] [06] [62] - ldi x4, 6 ;[-1] [07] [63] -commonN1: -stuffN2Delay: - out USBOUT, x1 ;[00] [08] [64] <--- set bit - ror shift ;[01] - brcc doExorN2 ;[02] - subi x4, 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 x4, 6 ;[05] [13] -commonN2: - nop ;[06] [14] - subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1 - out USBOUT, x1 ;[08] [16] <--- set bit - brcs txBitloop ;[09] [25] [41] - -stuff6Delay: - ror shift ;[42] [50] - brcc doExor6 ;[43] - subi x4, 1 ;[44] - brne common6 ;[45] - lsl shift ;[46] compensate ror after rjmp stuffDelay - nop ;[47] stuffing consists of just waiting 8 cycles - rjmp stuff6Delay ;[48] after ror, C bit is reliably clear -doExor6: - eor x1, x2 ;[45] [53] - ldi x4, 6 ;[46] -common6: -stuff7Delay: - ror shift ;[47] [55] - out USBOUT, x1 ;[48] <--- set bit - brcc doExor7 ;[49] - subi x4, 1 ;[50] - brne common7 ;[51] - lsl shift ;[52] compensate ror after rjmp stuffDelay - rjmp stuff7Delay ;[53] after ror, C bit is reliably clear -doExor7: - eor x1, x2 ;[51] [59] - ldi x4, 6 ;[52] -common7: - ld shift, y+ ;[53] - tst cnt ;[55] - out USBOUT, x1 ;[56] <--- set bit - brne txByteLoop ;[57] - +;uses: x1...x4, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +usbSendAndReti: ;0 [-13] timing: 13 cycles until SOP + in x2, USBDDR ;1 [-12] + ori x2, USBMASK ;1 [-11] + sbi USBOUT, USBMINUS;2 [-9] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;1 [-8] port mirror for tx loop + out USBDDR, x2 ;1 [-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + push x4 ;2 [-5] + ldi x4, USBMASK ;1 [-4] exor mask + ldi shift, 0x80 ;1 [-3] sync byte is first byte sent +txLoop: ; [62] + sbrs shift, 0 ;1 [-2] [62] + eor x1, x4 ;1 [-1] [63] + out USBOUT, x1 ;1 [0] <-- out bit 0 + ror shift ;1 [1] + ror x2 ;1 [2] +didStuff0: + cpi x2, 0xfc ;1 [3] + brsh bitstuff0 ;1 [4] + sbrs shift, 0 ;1 [5] + eor x1, x4 ;1 [6] + ror shift ;1 [7] +didStuff1: + out USBOUT, x1 ;1 [8] <-- out bit 1 + ror x2 ;1 [9] + cpi x2, 0xfc ;1 [10] + brsh bitstuff1 ;1 [11] + sbrs shift, 0 ;1 [12] + eor x1, x4 ;1 [13] + ror shift ;1 [14] +didStuff2: + ror x2 ;1 [15] + out USBOUT, x1 ;1 [16] <-- out bit 2 + cpi x2, 0xfc ;1 [17] + brsh bitstuff2 ;1 [18] + sbrs shift, 0 ;1 [19] + eor x1, x4 ;1 [20] + ror shift ;1 [21] +didStuff3: + ror x2 ;1 [22] + cpi x2, 0xfc ;1 [23] + out USBOUT, x1 ;1 [24] <-- out bit 3 + brsh bitstuff3 ;1 [25] + nop2 ;2 [27] + ld x3, y+ ;2 [29] + sbrs shift, 0 ;1 [30] + eor x1, x4 ;1 [31] + out USBOUT, x1 ;1 [32] <-- out bit 4 + ror shift ;1 [33] + ror x2 ;1 [34] +didStuff4: + cpi x2, 0xfc ;1 [35] + brsh bitstuff4 ;1 [36] + sbrs shift, 0 ;1 [37] + eor x1, x4 ;1 [38] + ror shift ;1 [39] +didStuff5: + out USBOUT, x1 ;1 [40] <-- out bit 5 + ror x2 ;1 [41] + cpi x2, 0xfc ;1 [42] + brsh bitstuff5 ;1 [43] + sbrs shift, 0 ;1 [44] + eor x1, x4 ;1 [45] + ror shift ;1 [46] +didStuff6: + ror x2 ;1 [47] + out USBOUT, x1 ;1 [48] <-- out bit 6 + cpi x2, 0xfc ;1 [49] + brsh bitstuff6 ;1 [50] + sbrs shift, 0 ;1 [51] + eor x1, x4 ;1 [52] + ror shift ;1 [53] +didStuff7: + ror x2 ;1 [54] + cpi x2, 0xfc ;1 [55] + out USBOUT, x1 ;1 [56] <-- out bit 7 + brsh bitstuff7 ;1 [57] + mov shift, x3 ;1 [58] + dec cnt ;1 [59] + brne txLoop ;1/2 [60/61] ;make SE0: - cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] - lds x2, usbNewDeviceAddr;[59] - lsl x2 ;[61] we compare with left shifted address - subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3 - sbci YH, 0 ;[63] - out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle + cbr x1, USBMASK ;1 [61] prepare SE0 [spec says EOP may be 15 to 18 cycles] + pop x4 ;2 [63] +;brackets are cycles from start of SE0 now + out USBOUT, x1 ;1 [0] <-- 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 + lds x2, usbNewDeviceAddr;2 [2] + lsl x2; ;1 [3] we compare with left shifted address + subi YL, 20 + 2 ;1 [4] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;1 [5] + breq skipAddrAssign ;2 [7] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer skipAddrAssign: ;end of usbDeviceAddress transfer - ldi x2, 1< subtract 1/3 + subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit rjmp didUnstuff6 ;[08] unstuff7: @@ -133,7 +124,7 @@ unstuff7: in x2, USBIN ;[00] [10] re-sample bit 7 andi x2, USBMASK ;[01] andi shift, ~0x80;[02] - subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 + subi leap, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit rjmp didUnstuff7 ;[04] unstuffEven: @@ -142,8 +133,8 @@ unstuffEven: andi shift, ~0x80;[01] andi x1, USBMASK ;[02] breq se0 ;[03] - subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 - nop2 ;[05] + subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit + nop ;[05] rjmp didUnstuffE ;[06] unstuffOdd: @@ -152,8 +143,8 @@ unstuffOdd: andi shift, ~0x80;[01] andi x2, USBMASK ;[02] breq se0 ;[03] - subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 - nop2 ;[05] + subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit + nop ;[05] rjmp didUnstuffO ;[06] rxByteLoop: @@ -217,13 +208,13 @@ macro POP_STANDARD ; 14 cycles pop x1 pop shift pop bitcnt - endm +endm macro POP_RETI ; 7 cycles pop YH pop YL out SREG, YL pop YL - endm +endm #include "asmcommon.inc" diff --git a/usbdrv/usbdrvasm165.inc b/libcrypt/usbdrv/usbdrvasm165.inc similarity index 96% rename from usbdrv/usbdrvasm165.inc rename to libcrypt/usbdrv/usbdrvasm165.inc index d8a95ba..8639aa1 100644 --- a/usbdrv/usbdrvasm165.inc +++ b/libcrypt/usbdrv/usbdrvasm165.inc @@ -1,10 +1,10 @@ /* Name: usbdrvasm165.inc - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2007-04-22 * Tabsize: 4 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) * Revision: $Id$ */ @@ -46,13 +46,10 @@ USB_INTR_VECTOR: ;---------------------------------------------------------------------------- ;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. +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) waitForJ: - inc YL - sbis USBIN, USBMINUS - brne waitForJ ; just make sure we have ANY timeout + sbis USBIN, USBMINUS ;[-18] wait for D- == 1 + rjmp waitForJ waitForK: ;The following code results in a sampling window of < 1/4 bit which meets the spec. sbis USBIN, USBMINUS ;[-15] @@ -72,9 +69,6 @@ waitForK: inc YL sts usbSofCount, YL #endif /* USB_COUNT_SOF */ -#ifdef USB_SOF_HOOK - USB_SOF_HOOK -#endif rjmp sofError foundK: ;[-12] ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] @@ -340,12 +334,12 @@ macro POP_STANDARD ; 16 cycles pop shift pop YH pop r0 - endm +endm macro POP_RETI ; 5 cycles pop YL out SREG, YL pop YL - endm +endm #include "asmcommon.inc" diff --git a/usbdrv/.gitignore b/usbdrv/.gitignore deleted file mode 100644 index c41c150..0000000 --- a/usbdrv/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.hex -*.elf -*.o diff --git a/usbdrv/Readme.txt b/usbdrv/Readme.txt deleted file mode 100644 index 970dc66..0000000 --- a/usbdrv/Readme.txt +++ /dev/null @@ -1,172 +0,0 @@ -This is the Readme file to Objective Development's firmware-only USB driver -for Atmel AVR microcontrollers. For more information please visit -http://www.obdev.at/vusb/ - -This directory contains the USB firmware only. Copy it as-is to your own -project and add all .c and .S files to your project (these files are marked -with an asterisk in the list below). Then copy usbconfig-prototype.h as -usbconfig.h to your project and edit it according to your configuration. - - -TECHNICAL DOCUMENTATION -======================= -The technical documentation (API) for the firmware driver is contained in the -file "usbdrv.h". Please read all of it carefully! Configuration options are -documented in "usbconfig-prototype.h". - -The driver consists of the following files: - Readme.txt ............. The file you are currently reading. - Changelog.txt .......... Release notes for all versions of the driver. - usbdrv.h ............... Driver interface definitions and technical docs. -* usbdrv.c ............... High level language part of the driver. Link this - module to your code! -* usbdrvasm.S ............ Assembler part of the driver. This module is mostly - a stub and includes one of the usbdrvasm*.S files - depending on processor clock. Link this module to - your code! - usbdrvasm*.inc ......... Assembler routines for particular clock frequencies. - Included by usbdrvasm.S, don't link it directly! - asmcommon.inc .......... Common assembler routines. Included by - usbdrvasm*.inc, don't link it directly! - usbconfig-prototype.h .. Prototype for your own usbdrv.h file. -* oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is - defined to a value greater than 0. Link this module - to your code! - oddebug.h .............. Interface definitions of the debug module. - usbportability.h ....... Header with compiler-dependent stuff. - usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this - module instead of usbdrvasm.S when you assembler - with IAR's tools. - License.txt ............ Open Source license for this driver. - CommercialLicense.txt .. Optional commercial license for this driver. - USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs. - USB-IDs-for-free.txt ... List and terms of use for free shared PIDs. - -(*) ... These files should be linked to your project. - - -CPU CORE CLOCK FREQUENCY -======================== -We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz, -16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The -actual clock rate must be configured in usbconfig.h. - -12 MHz Clock -This is the traditional clock rate of V-USB because it's the lowest clock -rate where the timing constraints of the USB spec can be met. - -15 MHz Clock -Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock -rate allows for some loops which make the resulting code size somewhat smaller -than the 12 MHz version. - -16 MHz Clock -This clock rate has been added for users of the Arduino board and other -ready-made boards which come with a fixed 16 MHz crystal. It's also an option -if you need the slightly higher clock rate for performance reasons. Since -16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code -is somewhat tricky and has to insert a leap cycle every third byte. - -12.8 MHz and 16.5 MHz Clock -The assembler modules for these clock rates differ from the other modules -because they have been built for an RC oscillator with only 1% precision. The -receiver code inserts leap cycles to compensate for clock deviations. 1% is -also the precision which can be achieved by calibrating the internal RC -oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL -oscillator can reach 16.5 MHz with the RC oscillator. This includes the very -popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost -all AVRs can reach 12.8 MHz, although this is outside the specified range. - -See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for -code which calibrates the RC oscillator based on the USB frame clock. - -18 MHz Clock -This module is closer to the USB specification because it performs an on the -fly CRC check for incoming packets. Packets with invalid checksum are -discarded as required by the spec. If you also implement checks for data -PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING -in usbconfig.h for more info), this ensures data integrity. Due to the CRC -tables and alignment requirements, this code is bigger than modules for other -clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1 -and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h. - -20 MHz Clock -This module is for people who won't do it with less than the maximum. Since -20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code -uses similar tricks as the 16 MHz module to insert leap cycles. - - -USB IDENTIFIERS -=============== -Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs -are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you -can assign PIDs at will. - -Since an entry level cost of 1,500 USD is too high for most small companies -and hobbyists, we provide some VID/PID pairs for free. See the file -USB-IDs-for-free.txt for details. - -Objective Development also has some license offerings which include product -IDs. See http://www.obdev.at/vusb/ for details. - - -DEVELOPMENT SYSTEM -================== -This driver has been developed and optimized for the GNU compiler version 3 -and 4. We recommend that you use the GNU compiler suite because it is freely -available. V-USB has also been ported to the IAR compiler and assembler. It -has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the -"small" and "tiny" memory model. Not every release is tested with IAR CC and -the driver may therefore fail to compile with IAR. Please note that gcc is -more efficient for usbdrv.c because this module has been deliberately -optimized for gcc. - -Gcc version 3 produces smaller code than version 4 due to new optimizing -capabilities which don't always improve things on 8 bit CPUs. The code size -generated by gcc 4 can be reduced with the compiler options --fno-move-loop-invariants, -fno-tree-scev-cprop and --fno-inline-small-functions in addition to -Os. On devices with more than -8k of flash memory, we also recommend the linker option --relax (written as --Wl,--relax for gcc) to convert absolute calls into relative where possible. - -For more information about optimizing options see: - - http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html - -These optimizations are good for gcc 4.x. Version 3.x of gcc does not support -most of these options and produces good code anyway. - - -USING V-USB FOR FREE -==================== -The AVR firmware driver is published under the GNU General Public License -Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is -your choice whether you apply the terms of version 2 or version 3. - -If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the -following things IN ADDITION to the obligations from the GPL: - -(1) Publish your entire project on a web site and drop us a note with the URL. -Use the form at http://www.obdev.at/vusb/feedback.html for your submission. -If you don't have a web site, you can publish the project in obdev's -documentation wiki at -http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects. - -(2) Adhere to minimum publication standards. Please include AT LEAST: - - a circuit diagram in PDF, PNG or GIF format - - full source code for the host software - - a Readme.txt file in ASCII format which describes the purpose of the - project and what can be found in which directories and which files - - a reference to http://www.obdev.at/vusb/ - -(3) If you improve the driver firmware itself, please give us a free license -to your modifications for our commercial license offerings. - - -COMMERCIAL LICENSES FOR V-USB -============================= -If you don't want to publish your source code under the terms of the GPL, -you can simply pay money for V-USB. As an additional benefit you get -USB PIDs for free, reserved exclusively to you. See the file -"CommercialLicense.txt" for details. - diff --git a/usbdrv/USB-ID-FAQ.txt b/usbdrv/USB-ID-FAQ.txt deleted file mode 100644 index d1de8fb..0000000 --- a/usbdrv/USB-ID-FAQ.txt +++ /dev/null @@ -1,149 +0,0 @@ -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/usbdrv/USB-IDs-for-free.txt b/usbdrv/USB-IDs-for-free.txt deleted file mode 100644 index d46517d..0000000 --- a/usbdrv/USB-IDs-for-free.txt +++ /dev/null @@ -1,154 +0,0 @@ -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/usbdrv/usbdrv.c b/usbdrv/usbdrv.c deleted file mode 100644 index 5594407..0000000 --- a/usbdrv/usbdrv.c +++ /dev/null @@ -1,628 +0,0 @@ -/* Name: usbdrv.c - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers - * Author: Christian Starkjohann - * Creation Date: 2004-12-29 - * Tabsize: 4 - * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id$ - */ - -#include "usbportability.h" -#include "usbdrv.h" -#include "oddebug.h" - -/* -General Description: -This module implements the C-part of the USB driver. See usbdrv.h for a -documentation of the entire driver. -*/ - -/* ------------------------------------------------------------------------- */ - -/* raw USB registers / interface to assembler code: */ -uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ -uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */ -uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */ -uchar usbNewDeviceAddr; /* device ID which should be set after status phase */ -uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */ -volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ -uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */ -uchar usbRxToken; /* token for data we received; or endpont number for last OUT */ -volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */ -uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ -#if USB_COUNT_SOF -volatile uchar usbSofCount; /* incremented by assembler module every SOF */ -#endif -#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE -usbTxStatus_t usbTxStatus1; -# if USB_CFG_HAVE_INTRIN_ENDPOINT3 -usbTxStatus_t usbTxStatus3; -# endif -#endif -#if USB_CFG_CHECK_DATA_TOGGLING -uchar usbCurrentDataToken;/* when we check data toggling to ignore duplicate packets */ -#endif - -/* USB status registers / not shared with asm code */ -uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */ -static usbMsgLen_t usbMsgLen = USB_NO_MSG; /* remaining number of bytes */ -static uchar usbMsgFlags; /* flag values see below */ - -#define USB_FLG_MSGPTR_IS_ROM (1<<6) -#define USB_FLG_USE_USER_RW (1<<7) - -/* -optimizing hints: -- do not post/pre inc/dec integer values in operations -- assign value of USB_READ_FLASH() to register variables and don't use side effects in arg -- use narrow scope for variables which should be in X/Y/Z register -- assign char sized expressions to variables to force 8 bit arithmetics -*/ - -/* -------------------------- String Descriptors --------------------------- */ - -#if USB_CFG_DESCR_PROPS_STRINGS == 0 - -#if USB_CFG_DESCR_PROPS_STRING_0 == 0 -#undef USB_CFG_DESCR_PROPS_STRING_0 -#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0) -PROGMEM const char usbDescriptorString0[] = { /* language descriptor */ - 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ - 3, /* descriptor type */ - 0x09, 0x04, /* language index (0x0409 = US-English) */ -}; -#endif - -#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN -#undef USB_CFG_DESCR_PROPS_STRING_VENDOR -#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor) -PROGMEM const int usbDescriptorStringVendor[] = { - USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), - USB_CFG_VENDOR_NAME -}; -#endif - -#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN -#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT -#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice) -PROGMEM const int usbDescriptorStringDevice[] = { - USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), - USB_CFG_DEVICE_NAME -}; -#endif - -#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN -#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER -#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber) -PROGMEM const int usbDescriptorStringSerialNumber[] = { - USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), - USB_CFG_SERIAL_NUMBER -}; -#endif - -#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ - -/* --------------------------- Device Descriptor --------------------------- */ - -#if USB_CFG_DESCR_PROPS_DEVICE == 0 -#undef USB_CFG_DESCR_PROPS_DEVICE -#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice) -PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */ - 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ - USBDESCR_DEVICE, /* descriptor type */ - 0x10, 0x01, /* USB version supported */ - USB_CFG_DEVICE_CLASS, - USB_CFG_DEVICE_SUBCLASS, - 0, /* protocol */ - 8, /* max packet size */ - /* the following two casts affect the first byte of the constant only, but - * that's sufficient to avoid a warning with the default values. - */ - (char)USB_CFG_VENDOR_ID,/* 2 bytes */ - (char)USB_CFG_DEVICE_ID,/* 2 bytes */ - USB_CFG_DEVICE_VERSION, /* 2 bytes */ - USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */ - USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */ - USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ - 1, /* number of configurations */ -}; -#endif - -/* ----------------------- Configuration Descriptor ------------------------ */ - -#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 -#undef USB_CFG_DESCR_PROPS_HID -#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */ -#endif - -#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 -#undef USB_CFG_DESCR_PROPS_CONFIGURATION -#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration) -PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ - 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ - USBDESCR_CONFIG, /* descriptor type */ - 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + - (USB_CFG_DESCR_PROPS_HID & 0xff), 0, - /* total length of data returned (including inlined descriptors) */ - 1, /* number of interfaces in this configuration */ - 1, /* index of this configuration */ - 0, /* configuration name string index */ -#if USB_CFG_IS_SELF_POWERED - (1 << 7) | USBATTR_SELFPOWER, /* attributes */ -#else - (1 << 7), /* attributes */ -#endif - USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ -/* interface descriptor follows inline: */ - 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ - USBDESCR_INTERFACE, /* descriptor type */ - 0, /* index of this interface */ - 0, /* alternate setting for this interface */ - USB_CFG_HAVE_INTRIN_ENDPOINT + USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */ - USB_CFG_INTERFACE_CLASS, - USB_CFG_INTERFACE_SUBCLASS, - USB_CFG_INTERFACE_PROTOCOL, - 0, /* string index for interface */ -#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ - 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ - USBDESCR_HID, /* descriptor type: HID */ - 0x01, 0x01, /* BCD representation of HID version */ - 0x00, /* target country code */ - 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ - 0x22, /* descriptor type: report */ - USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ -#endif -#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ - 7, /* sizeof(usbDescrEndpoint) */ - USBDESCR_ENDPOINT, /* descriptor type = endpoint */ - (char)0x81, /* IN endpoint number 1 */ - 0x03, /* attrib: Interrupt endpoint */ - 8, 0, /* maximum packet size */ - USB_CFG_INTR_POLL_INTERVAL, /* in ms */ -#endif -#if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */ - 7, /* sizeof(usbDescrEndpoint) */ - USBDESCR_ENDPOINT, /* descriptor type = endpoint */ - (char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */ - 0x03, /* attrib: Interrupt endpoint */ - 8, 0, /* maximum packet size */ - USB_CFG_INTR_POLL_INTERVAL, /* in ms */ -#endif -}; -#endif - -/* ------------------------------------------------------------------------- */ - -static inline void usbResetDataToggling(void) -{ -#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE - USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ -# if USB_CFG_HAVE_INTRIN_ENDPOINT3 - USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ -# endif -#endif -} - -static inline void usbResetStall(void) -{ -#if USB_CFG_IMPLEMENT_HALT && USB_CFG_HAVE_INTRIN_ENDPOINT - usbTxLen1 = USBPID_NAK; -#if USB_CFG_HAVE_INTRIN_ENDPOINT3 - usbTxLen3 = USBPID_NAK; -#endif -#endif -} - -/* ------------------------------------------------------------------------- */ - -#if !USB_CFG_SUPPRESS_INTR_CODE -#if USB_CFG_HAVE_INTRIN_ENDPOINT -static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus) -{ -uchar *p; -char i; - -#if USB_CFG_IMPLEMENT_HALT - if(usbTxLen1 == USBPID_STALL) - return; -#endif - if(txStatus->len & 0x10){ /* packet buffer was empty */ - txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ - }else{ - txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ - } - p = txStatus->buffer + 1; - i = len; - do{ /* if len == 0, we still copy 1 byte, but that's no problem */ - *p++ = *data++; - }while(--i > 0); /* loop control at the end is 2 bytes shorter than at beginning */ - usbCrc16Append(&txStatus->buffer[1], len); - txStatus->len = len + 4; /* len must be given including sync byte */ - DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3); -} - -USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) -{ - usbGenericSetInterrupt(data, len, &usbTxStatus1); -} -#endif - -#if USB_CFG_HAVE_INTRIN_ENDPOINT3 -USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) -{ - usbGenericSetInterrupt(data, len, &usbTxStatus3); -} -#endif -#endif /* USB_CFG_SUPPRESS_INTR_CODE */ - -/* ------------------ utilities for code following below ------------------- */ - -/* Use defines for the switch statement so that we can choose between an - * if()else if() and a switch/case based implementation. switch() is more - * efficient for a LARGE set of sequential choices, if() is better in all other - * cases. - */ -#if USB_CFG_USE_SWITCH_STATEMENT -# define SWITCH_START(cmd) switch(cmd){{ -# define SWITCH_CASE(value) }break; case (value):{ -# define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{ -# define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{ -# define SWITCH_DEFAULT }break; default:{ -# define SWITCH_END }} -#else -# define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){ -# define SWITCH_CASE(value) }else if(_cmd == (value)){ -# define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){ -# define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){ -# define SWITCH_DEFAULT }else{ -# define SWITCH_END }} -#endif - -#ifndef USB_RX_USER_HOOK -#define USB_RX_USER_HOOK(data, len) -#endif -#ifndef USB_SET_ADDRESS_HOOK -#define USB_SET_ADDRESS_HOOK() -#endif - -/* ------------------------------------------------------------------------- */ - -/* We use if() instead of #if in the macro below because #if can't be used - * in macros and the compiler optimizes constant conditions anyway. - * This may cause problems with undefined symbols if compiled without - * optimizing! - */ -#define GET_DESCRIPTOR(cfgProp, staticName) \ - if(cfgProp){ \ - if((cfgProp) & USB_PROP_IS_RAM) \ - flags = 0; \ - if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ - len = usbFunctionDescriptor(rq); \ - }else{ \ - len = USB_PROP_LENGTH(cfgProp); \ - usbMsgPtr = (uchar *)(staticName); \ - } \ - } - -/* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used - * internally for all types of descriptors. - */ -static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq) -{ -usbMsgLen_t len = 0; -uchar flags = USB_FLG_MSGPTR_IS_ROM; - - SWITCH_START(rq->wValue.bytes[1]) - SWITCH_CASE(USBDESCR_DEVICE) /* 1 */ - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) - SWITCH_CASE(USBDESCR_CONFIG) /* 2 */ - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) - SWITCH_CASE(USBDESCR_STRING) /* 3 */ -#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC - if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) - flags = 0; - len = usbFunctionDescriptor(rq); -#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ - SWITCH_START(rq->wValue.bytes[0]) - SWITCH_CASE(0) - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) - SWITCH_CASE(1) - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) - SWITCH_CASE(2) - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) - SWITCH_CASE(3) - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) - SWITCH_DEFAULT - if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ - len = usbFunctionDescriptor(rq); - } - SWITCH_END -#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ -#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ - SWITCH_CASE(USBDESCR_HID) /* 0x21 */ - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) - SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */ - GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) -#endif - SWITCH_DEFAULT - if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ - len = usbFunctionDescriptor(rq); - } - SWITCH_END - usbMsgFlags = flags; - return len; -} - -/* ------------------------------------------------------------------------- */ - -/* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for - * standard requests instead of class and custom requests. - */ -static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq) -{ -usbMsgLen_t len = 0; -uchar *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */ -uchar value = rq->wValue.bytes[0]; -#if USB_CFG_IMPLEMENT_HALT -uchar index = rq->wIndex.bytes[0]; -#endif - - dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ - SWITCH_START(rq->bRequest) - SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */ - uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ - if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE) - dataPtr[0] = USB_CFG_IS_SELF_POWERED; -#if USB_CFG_IMPLEMENT_HALT - if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81) /* request status for endpoint 1 */ - dataPtr[0] = usbTxLen1 == USBPID_STALL; -#endif - dataPtr[1] = 0; - len = 2; -#if USB_CFG_IMPLEMENT_HALT - SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */ - if(value == 0 && index == 0x81){ /* feature 0 == HALT for endpoint == 1 */ - usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; - usbResetDataToggling(); - } -#endif - SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */ - usbNewDeviceAddr = value; - USB_SET_ADDRESS_HOOK(); - SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */ - len = usbDriverDescriptor(rq); - goto skipMsgPtrAssignment; - SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */ - dataPtr = &usbConfiguration; /* send current configuration value */ - len = 1; - SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */ - usbConfiguration = value; - usbResetStall(); - SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */ - len = 1; -#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE - SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */ - usbResetDataToggling(); - usbResetStall(); -#endif - SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */ - /* Should we add an optional hook here? */ - SWITCH_END - usbMsgPtr = dataPtr; -skipMsgPtrAssignment: - return len; -} - -/* ------------------------------------------------------------------------- */ - -/* usbProcessRx() is called for every message received by the interrupt - * routine. It distinguishes between SETUP and DATA packets and processes - * them accordingly. - */ -static inline void usbProcessRx(uchar *data, uchar len) -{ -usbRequest_t *rq = (void *)data; - -/* usbRxToken can be: - * 0x2d 00101101 (USBPID_SETUP for setup data) - * 0xe1 11100001 (USBPID_OUT: data phase of setup transfer) - * 0...0x0f for OUT on endpoint X - */ - DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ - USB_RX_USER_HOOK(data, len) -#if USB_CFG_IMPLEMENT_FN_WRITEOUT - if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */ - usbFunctionWriteOut(data, len); - return; - } -#endif - if(usbRxToken == (uchar)USBPID_SETUP){ - if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */ - return; - usbMsgLen_t replyLen; - usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */ - usbTxLen = USBPID_NAK; /* abort pending transmit */ - usbMsgFlags = 0; - uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; - if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */ - replyLen = usbFunctionSetup(data); - }else{ - replyLen = usbDriverSetup(rq); - } -#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE - if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */ - /* do some conditioning on replyLen, but on IN transfers only */ - if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){ - if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ - replyLen = rq->wLength.bytes[0]; - }else{ - replyLen = rq->wLength.word; - } - } - usbMsgFlags = USB_FLG_USE_USER_RW; - }else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */ -#endif - if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ - if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ - replyLen = rq->wLength.bytes[0]; - }else{ - if(replyLen > rq->wLength.word) /* limit length to max */ - replyLen = rq->wLength.word; - } - usbMsgLen = replyLen; - }else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */ -#if USB_CFG_IMPLEMENT_FN_WRITE - if(usbMsgFlags & USB_FLG_USE_USER_RW){ - uchar rval = usbFunctionWrite(data, len); - if(rval == 0xff){ /* an error occurred */ - usbTxLen = USBPID_STALL; - }else if(rval != 0){ /* This was the final package */ - usbMsgLen = 0; /* answer with a zero-sized data packet */ - } - } -#endif - } -} - -/* ------------------------------------------------------------------------- */ - -/* This function is similar to usbFunctionRead(), but it's also called for - * data handled automatically by the driver (e.g. descriptor reads). - */ -static uchar usbDeviceRead(uchar *data, uchar len) -{ - if(len > 0){ /* don't bother app with 0 sized reads */ -#if USB_CFG_IMPLEMENT_FN_READ - if(usbMsgFlags & USB_FLG_USE_USER_RW){ - len = usbFunctionRead(data, len); - }else -#endif - { - uchar i = len, *r = usbMsgPtr; - if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ - do{ - uchar c = USB_READ_FLASH(r); /* assign to char size variable to enforce byte ops */ - *data++ = c; - r++; - }while(--i); - }else{ /* RAM data */ - do{ - *data++ = *r++; - }while(--i); - } - usbMsgPtr = r; - } - } - return len; -} - -/* ------------------------------------------------------------------------- */ - -/* usbBuildTxBlock() is called when we have data to transmit and the - * interrupt routine's transmit buffer is empty. - */ -static inline void usbBuildTxBlock(void) -{ -usbMsgLen_t wantLen; -uchar len; - - wantLen = usbMsgLen; - if(wantLen > 8) - wantLen = 8; - usbMsgLen -= wantLen; - usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ - len = usbDeviceRead(usbTxBuf + 1, wantLen); - if(len <= 8){ /* valid data packet */ - usbCrc16Append(&usbTxBuf[1], len); - len += 4; /* length including sync byte */ - if(len < 12) /* a partial package identifies end of message */ - usbMsgLen = USB_NO_MSG; - }else{ - len = USBPID_STALL; /* stall the endpoint */ - usbMsgLen = USB_NO_MSG; - } - usbTxLen = len; - DBG2(0x20, usbTxBuf, len-1); -} - -/* ------------------------------------------------------------------------- */ - -static inline void usbHandleResetHook(uchar notResetState) -{ -#ifdef USB_RESET_HOOK -static uchar wasReset; -uchar isReset = !notResetState; - - if(wasReset != isReset){ - USB_RESET_HOOK(isReset); - wasReset = isReset; - } -#else - notResetState = notResetState; // avoid compiler warning -#endif -} - -/* ------------------------------------------------------------------------- */ - -USB_PUBLIC void usbPoll(void) -{ -schar len; -uchar i; - - len = usbRxLen - 3; - if(len >= 0){ -/* We could check CRC16 here -- but ACK has already been sent anyway. If you - * need data integrity checks with this driver, check the CRC in your app - * code and report errors back to the host. Since the ACK was already sent, - * retries must be handled on application level. - * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); - */ - usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len); -#if USB_CFG_HAVE_FLOWCONTROL - if(usbRxLen > 0) /* only mark as available if not inactivated */ - usbRxLen = 0; -#else - usbRxLen = 0; /* mark rx buffer as available */ -#endif - } - if(usbTxLen & 0x10){ /* transmit system idle */ - if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */ - usbBuildTxBlock(); - } - } - for(i = 20; i > 0; i--){ - uchar usbLineStatus = USBIN & USBMASK; - if(usbLineStatus != 0) /* SE0 has ended */ - goto isNotReset; - } - /* RESET condition, called multiple times during reset */ - usbNewDeviceAddr = 0; - usbDeviceAddr = 0; - usbResetStall(); - DBG1(0xff, 0, 0); -isNotReset: - usbHandleResetHook(i); -} - -/* ------------------------------------------------------------------------- */ - -USB_PUBLIC void usbInit(void) -{ -#if USB_INTR_CFG_SET != 0 - USB_INTR_CFG |= USB_INTR_CFG_SET; -#endif -#if USB_INTR_CFG_CLR != 0 - USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); -#endif - USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); - usbResetDataToggling(); -#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE - usbTxLen1 = USBPID_NAK; -#if USB_CFG_HAVE_INTRIN_ENDPOINT3 - usbTxLen3 = USBPID_NAK; -#endif -#endif -} - -/* ------------------------------------------------------------------------- */ diff --git a/usbdrv/usbdrvasm128.inc b/usbdrv/usbdrvasm128.inc deleted file mode 100644 index 122cc75..0000000 --- a/usbdrv/usbdrvasm128.inc +++ /dev/null @@ -1,750 +0,0 @@ -/* 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/usbdrv/usbdrvasm18-crc.inc b/usbdrv/usbdrvasm18-crc.inc deleted file mode 100644 index dde09da..0000000 --- a/usbdrv/usbdrvasm18-crc.inc +++ /dev/null @@ -1,707 +0,0 @@ -/* 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/usbdrv/usbdrvasm20.inc b/usbdrv/usbdrvasm20.inc deleted file mode 100644 index 0c74679..0000000 --- a/usbdrv/usbdrvasm20.inc +++ /dev/null @@ -1,360 +0,0 @@ -/* 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__ */