diff --git a/libcrypt/main.c b/libcrypt/main.c index cef1961..f6ea8f5 100644 --- a/libcrypt/main.c +++ b/libcrypt/main.c @@ -20,6 +20,7 @@ #include #include "usbdrv.h" +#include "usb_key_codes.h" uint8_t reportBuffer[2]; /* buffer for HID reports */ uint8_t idleRate; @@ -40,11 +41,11 @@ int main(void){ uint16_t siz; uint8_t sec[SECLEN]=SECRET; - InitializeMemory(); + /*InitializeMemory(); initUSART(); tx('+'); - sendunum( get_otp_from_cnt(777,8,sec,SECLEN) ); + sendunum( get_otp_from_cnt(777,8,sec,SECLEN) );*/ #ifdef CALIB /* oszillator calibration */ @@ -58,19 +59,24 @@ int main(void){ _delay_ms(300); /* mustn't be that exact */ usbDeviceConnect(); + uint8_t foo=0; usbInit(); sei(); for(;;){ /* main event loop */ - usbPoll(); + //usbPoll(); /* we can send another key */ if(usbInterruptIsReady()){ - buildReport(0x00, 'A'); + foo=!foo; + if(foo) + buildReport(0x00, USB_KEY_1); + else + buildReport(0x00, 0x00); usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); } - AnalyzeMemory(&p,&siz); + /*AnalyzeMemory(&p,&siz); sendunum(siz); - _delay_ms(2000); + _delay_ms(2000);*/ } return 0; } diff --git a/libcrypt/main.h b/libcrypt/main.h index 3386e5e..62d8c5c 100644 --- a/libcrypt/main.h +++ b/libcrypt/main.h @@ -15,4 +15,3 @@ #define P_BTN P_PORT_BTN_NUM_BTN #define BTN_VECT INT_NUM_BTN_vect - diff --git a/libcrypt/usbconfig.h b/libcrypt/usbconfig.h index d63e18f..37a4761 100644 --- a/libcrypt/usbconfig.h +++ b/libcrypt/usbconfig.h @@ -1,37 +1,59 @@ /* Name: usbconfig.h - * Project: AVR USB driver + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers * Author: Christian Starkjohann - * Creation Date: 2007-06-23 + * Creation Date: 2005-04-01 * Tabsize: 4 - * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbconfig.h 537 2008-02-28 21:13:01Z cs $ + * 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$ */ #ifndef __usbconfig_h_included__ #define __usbconfig_h_included__ +/* +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). +*/ + /* ---------------------------- Hardware Config ---------------------------- */ -#define USB_CFG_IOPORTNAME B +#define USB_CFG_IOPORTNAME D /* 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 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. */ -#define USB_CFG_DPLUS_BIT 3 +#define USB_CFG_DPLUS_BIT 2 /* 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! + * to interrupt pin INT0! [You can also use other interrupts, see section + * "Optional MCU Description" below, or you can connect D- to the interrupt, as + * it is required if you use the USB_COUNT_SOF feature. If you use D- for the + * 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 MHz. Legal values are 12000, 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 +/* 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. */ /* ----------------------- Optional Hardware Config ------------------------ */ @@ -52,12 +74,24 @@ #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 1. + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). */ #define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 /* Define this to 1 if you want to compile a version with three endpoints: The - * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in - * endpoint 3. You must also enable endpoint 1 above. + * default control endpoint 0, an interrupt-in endpoint 3 (or the number + * configured below) and a catch-all default interrupt-in endpoint as above. + * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. + */ +#define USB_CFG_EP3_NUMBER 3 +/* 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 */ +/* 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! */ #define USB_CFG_IMPLEMENT_HALT 0 /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature @@ -65,7 +99,15 @@ * it is required by the standard. We have made it a config option because it * bloats the code considerably. */ -#define USB_CFG_INTR_POLL_INTERVAL 10 +#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 100 /* 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. @@ -74,7 +116,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 50 +#define USB_CFG_MAX_BUS_POWER 20 /* 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.] @@ -91,64 +133,127 @@ * usbFunctionSetup(). This saves a couple of bytes. */ #define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 -/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1. +/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. * You must implement the function usbFunctionWriteOut() which receives all - * interrupt/bulk data sent to endpoint 1. + * interrupt/bulk data sent to any endpoint other than 0. The endpoint number + * can be found in 'usbRxToken'. */ #define USB_CFG_HAVE_FLOWCONTROL 0 /* Define this to 1 if you want flowcontrol over USB data. See the definition * of the macros usbDisableAllRequests() and usbEnableAllRequests() in * usbdrv.h. */ -#ifndef __ASSEMBLER__ -extern void usbEventResetReady(void); -#endif -#define USB_RESET_HOOK(isReset) if(!isReset){usbEventResetReady();} +#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. + * If you eat the received message and don't want default processing to + * proceed, do a return after doing your things. One possible application + * (besides debugging) is to flash a status LED on each packet. + */ +// #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} /* 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. */ +/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */ +/* This macro (if defined) is executed when a USB SET_ADDRESS request was + * received. + */ +#define USB_COUNT_SOF 0 +/* define this macro to 1 if you need the global variable "usbSofCount" which + * 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 1 /* 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 0x42, 0x42 +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ /* 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! + * 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 0x31, 0xe1 +#define USB_CFG_DEVICE_ID 0xdf, 0x05 /* obdev's shared PID for HIDs */ /* 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 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! + * 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! */ #define USB_CFG_DEVICE_VERSION 0x00, 0x01 /* Version number of the device: Minor number first, then major number. */ -#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 +#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 8 /* 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 USBID-License.txt for + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for * details. */ -#define USB_CFG_DEVICE_NAME 'T','r','u','s','t','M','e' -#define USB_CFG_DEVICE_NAME_LEN 7 +#define USB_CFG_DEVICE_NAME 'D', 'a', 't', 'a', 'S', 't', 'o', 'r', 'e' +#define USB_CFG_DEVICE_NAME_LEN 9 /* 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. + * the macros. See the file USB-IDs-for-free.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 */ @@ -162,18 +267,20 @@ extern void usbEventResetReady(void); #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 3 /* HID */ -#define USB_CFG_INTERFACE_SUBCLASS 0 /* no boot interface */ -#define USB_CFG_INTERFACE_PROTOCOL 0 /* no protocol */ +#define USB_CFG_INTERFACE_CLASS 3 +#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. + * 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 */ -#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 35 /* total length of report descriptor */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 35 /* 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 - * report descriptor length. You must add a PROGMEM character array named + * If you use this define, 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! */ @@ -193,7 +300,9 @@ extern void usbEventResetReady(void); * 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(). + * 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. * + 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), @@ -225,6 +334,12 @@ extern void usbEventResetReady(void); * 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 @@ -250,19 +365,9 @@ extern void usbEventResetReady(void); /* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */ /* #define USB_INTR_CFG_CLR 0 */ /* #define USB_INTR_ENABLE GIMSK */ -/* #define USB_INTR_ENABLE_BIT INT0 */ +/*#define USB_INTR_ENABLE_BIT INT2*/ /* #define USB_INTR_PENDING GIFR */ /* #define USB_INTR_PENDING_BIT INTF0 */ - - -/* -#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/libcrypt/usbdrv/oddebug.c b/libcrypt/usbdrv/oddebug.c index bd528e2..466e68f 100644 --- a/libcrypt/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) or proprietary (CommercialLicense.txt) - * This Revision: $Id: oddebug.c 275 2007-03-20 09:58:28Z cs $ + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ */ #include "oddebug.h" diff --git a/libcrypt/usbdrv/oddebug.h b/libcrypt/usbdrv/oddebug.h index 1b11ef0..c56af1c 100644 --- a/libcrypt/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) or proprietary (CommercialLicense.txt) - * This Revision: $Id: oddebug.h 275 2007-03-20 09:58:28Z cs $ + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ */ #ifndef __oddebug_h_included__ @@ -29,10 +29,7 @@ the output and a memory block to dump in hex ('data' and 'len'). #endif /* make sure we have the UART defines: */ -#include "iarcompat.h" -#ifndef __IAR_SYSTEMS_ICC__ -# include -#endif +#include "usbportability.h" #ifndef uchar # define uchar unsigned char diff --git a/libcrypt/usbdrv/usbconfig-prototype.h b/libcrypt/usbdrv/usbconfig-prototype.h index 4f51809..826f026 100644 --- a/libcrypt/usbdrv/usbconfig-prototype.h +++ b/libcrypt/usbdrv/usbconfig-prototype.h @@ -1,11 +1,11 @@ /* Name: usbconfig.h - * Project: AVR USB driver + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers * 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) or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbconfig-prototype.h 532 2008-02-28 15:35:05Z cs $ + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ */ #ifndef __usbconfig_h_included__ @@ -14,12 +14,14 @@ /* General Description: This file is an example configuration (with inline documentation) for the USB -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. +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. */ /* ---------------------------- Hardware Config ---------------------------- */ @@ -28,7 +30,7 @@ rename it to "usbconfig.h". Then edit it accordingly. /* 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 0 +#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. */ @@ -41,12 +43,20 @@ rename it to "usbconfig.h". Then edit it accordingly. * 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 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 +#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. */ /* ----------------------- Optional Hardware Config ------------------------ */ @@ -65,7 +75,7 @@ rename it to "usbconfig.h". Then edit it accordingly. /* --------------------------- Functional Range ---------------------------- */ -#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +#define USB_CFG_HAVE_INTRIN_ENDPOINT 0 /* 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). @@ -80,9 +90,11 @@ rename it to "usbconfig.h". Then edit it accordingly. /* 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_DATA0 */ +/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ /* The above macro defines the startup condition for data toggling on the - * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA0. + * 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! */ #define USB_CFG_IMPLEMENT_HALT 0 /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature @@ -90,7 +102,15 @@ rename it to "usbconfig.h". Then edit it accordingly. * it is required by the standard. We have made it a config option because it * bloats the code considerably. */ -#define USB_CFG_INTR_POLL_INTERVAL 20 +#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 /* 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. @@ -126,6 +146,16 @@ rename it to "usbconfig.h". Then edit it accordingly. * 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. @@ -147,47 +177,86 @@ rename it to "usbconfig.h". Then edit it accordingly. * 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 +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ /* 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 0xdf, 0x05 + * 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 */ /* 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 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! + * 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! */ #define USB_CFG_DEVICE_VERSION 0x00, 0x01 /* Version number of the device: Minor number first, then major number. */ -#define USB_CFG_VENDOR_NAME 'w', 'w', 'w', '.', 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' -#define USB_CFG_VENDOR_NAME_LEN 12 +#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 8 /* 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 USBID-License.txt for + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.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 USBID-License.txt before you assign a name if you - * use a shared VID/PID. + * the macros. See the file USB-IDs-for-free.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 */ @@ -198,23 +267,23 @@ rename it to "usbconfig.h". Then edit it accordingly. * to fine tune control over USB descriptors such as the string descriptor * for the serial number. */ -#define USB_CFG_DEVICE_CLASS 0 +#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ #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 3 /* HID */ +#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ #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. - * 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. + * 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 */ -#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 /* total length of report descriptor */ +/* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */ /* 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 - * report descriptor length. You must add a PROGMEM character array named + * If you use this define, 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! */ @@ -234,7 +303,9 @@ rename it to "usbconfig.h". Then edit it accordingly. * 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(). + * 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. * + 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), @@ -266,6 +337,12 @@ rename it to "usbconfig.h". Then edit it accordingly. * 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 @@ -294,6 +371,6 @@ rename it to "usbconfig.h". Then edit it accordingly. /* #define USB_INTR_ENABLE_BIT INT0 */ /* #define USB_INTR_PENDING GIFR */ /* #define USB_INTR_PENDING_BIT INTF0 */ -/* #define USB_INTR_VECTOR SIG_INTERRUPT0 */ +/* #define USB_INTR_VECTOR INT0_vect */ #endif /* __usbconfig_h_included__ */ diff --git a/libcrypt/usbdrv/usbdrv.c b/libcrypt/usbdrv/usbdrv.c index 1a6bdf8..a4d51f8 100644 --- a/libcrypt/usbdrv/usbdrv.c +++ b/libcrypt/usbdrv/usbdrv.c @@ -1,21 +1,19 @@ /* Name: usbdrv.c - * Project: AVR USB driver + * 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) or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbdrv.c 530 2008-02-28 15:34:04Z cs $ + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ */ -#include "iarcompat.h" -#ifndef __IAR_SYSTEMS_ICC__ -# include -# include -#endif +#include "usbportability.h" #include "usbdrv.h" #include "oddebug.h" +#include + /* General Description: This module implements the C-part of the USB driver. See usbdrv.h for a @@ -33,46 +31,45 @@ uchar usbConfiguration; /* currently selected configuration. Administere 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_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE +usbTxStatus_t usbTxStatus1; # 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 */ +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 uchar usbMsgFlags; /* flag values see below */ +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_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) +#define USB_FLG_USE_USER_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 +- 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 */ +const PROGMEM char usbDescriptorString0[] = { /* language descriptor */ 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ 3, /* descriptor type */ 0x09, 0x04, /* language index (0x0409 = US-English) */ @@ -82,7 +79,7 @@ PROGMEM const char usbDescriptorString0[] = { /* language descriptor */ #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[] = { +const PROGMEM int usbDescriptorStringVendor[] = { USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), USB_CFG_VENDOR_NAME }; @@ -91,7 +88,7 @@ PROGMEM const int usbDescriptorStringVendor[] = { #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[] = { +const PROGMEM int usbDescriptorStringDevice[] = { USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), USB_CFG_DEVICE_NAME }; @@ -100,7 +97,7 @@ PROGMEM const int usbDescriptorStringDevice[] = { #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[] = { +PROGMEM int usbDescriptorStringSerialNumber[] = { USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), USB_CFG_SERIAL_NUMBER }; @@ -108,10 +105,12 @@ PROGMEM const int usbDescriptorStringSerialNumber[] = { #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 */ +const PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */ 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ USBDESCR_DEVICE, /* descriptor type */ 0x10, 0x01, /* USB version supported */ @@ -132,6 +131,8 @@ PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */ }; #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 */ @@ -140,18 +141,19 @@ PROGMEM const char usbDescriptorDevice[] = { /* USB device descriptor */ #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 */ +const PROGMEM 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, + 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 - USBATTR_SELFPOWER, /* attributes */ + (1 << 7) | USBATTR_SELFPOWER, /* attributes */ #else - (char)USBATTR_BUSPOWER, /* attributes */ + (1 << 7), /* attributes */ #endif USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ /* interface descriptor follows inline: */ @@ -159,7 +161,7 @@ PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration desc 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_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, @@ -181,31 +183,22 @@ PROGMEM const char usbDescriptorConfiguration[] = { /* USB configuration desc 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 -/* 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 +#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 */ @@ -225,289 +218,338 @@ static inline void usbResetStall(void) /* ------------------------------------------------------------------------- */ +#if !USB_CFG_SUPPRESS_INTR_CODE #if USB_CFG_HAVE_INTRIN_ENDPOINT -USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) +static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus) { -uchar *p, i; +uchar *p; +char 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 */ + if(txStatus->len & 0x10){ /* packet buffer was empty */ + txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ }else{ - usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ } - p = usbTxBuf1 + 1; - for(i=len;i--;) + p = txStatus->buffer + 1; + i = len; + do{ /* if len == 0, we still copy 1 byte, but that's no problem */ *p++ = *data++; - usbCrc16Append(&usbTxBuf1[1], len); - usbTxLen1 = len + 4; /* len must be given including sync byte */ - DBG2(0x21, usbTxBuf1, len + 3); + }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) { -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); + usbGenericSetInterrupt(data, len, &usbTxStatus3); } #endif +#endif /* USB_CFG_SUPPRESS_INTR_CODE */ +/* ------------------ utilities for code following below ------------------- */ -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; - } +/* 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 &= ~USB_FLG_MSGPTR_IS_ROM; \ + flags = 0; \ if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ - replyLen = usbFunctionDescriptor(rq); \ + len = usbFunctionDescriptor(rq); \ }else{ \ - replyData = (uchar *)(staticName); \ - SET_REPLY_LEN((cfgProp) & 0xff); \ + len = USB_PROP_LENGTH(cfgProp); \ + usbMsgPtr = (uchar *)(staticName); \ } \ } -/* 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. + +/* 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; +} +/* ------------------------------------------------------------------------- */ -/* 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. +/* usbProcessRx() is called for every message received by the interrupt + * routine. It distinguishes between SETUP and DATA packets and processes + * them accordingly. */ -static void usbProcessRx(uchar *data, uchar len) +static inline 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) + * 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 >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */ -#ifdef USB_RX_USER_HOOK + DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ USB_RX_USER_HOOK(data, len) -#endif #if USB_CFG_IMPLEMENT_FN_WRITEOUT - if(usbRxToken < 0x10){ /* endpoint number in usbRxToken */ + if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */ usbFunctionWriteOut(data, len); - return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */ + return; } #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 + 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{ - /* the following requests can be ignored, send default reply */ - /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */ - /* 12: SYNCH_FRAME */ + replyLen = rq->wLength.word; } - #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. */ + 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(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + 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; } - /* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */ - }else{ /* DATA packet from out request */ + 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_DEFAULT_RW)){ + if(usbMsgFlags & USB_FLG_USE_USER_RW){ uchar rval = usbFunctionWrite(data, len); - replyLen = 0xff; - if(rval == 0xff){ /* an error occurred */ - usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */ + if(rval == 0xff){ /* an error occurred */ usbTxLen = USBPID_STALL; }else if(rval != 0){ /* This was the final package */ - replyLen = 0; /* answer with a zero-sized data packet */ + usbMsgLen = 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) +/* 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) { -uchar wantLen, len, txLen, token; + 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; - token = USBPID_DATA1; - if(usbMsgFlags & USB_FLG_TX_PACKET) - token = USBPID_DATA0; - usbMsgFlags++; - len = usbRead(usbTxBuf + 1, wantLen); + usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ + len = usbDeviceRead(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; + len += 4; /* length including sync byte */ + if(len < 12) /* a partial package identifies end of message */ + usbMsgLen = USB_NO_MSG; }else{ - txLen = USBPID_STALL; /* stall the endpoint */ - usbMsgLen = 0xff; + len = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = USB_NO_MSG; } - usbTxBuf[0] = token; - usbTxLen = txLen; - DBG2(0x20, usbTxBuf, txLen-1); + usbTxLen = len; + DBG2(0x20, usbTxBuf, len-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 @@ -518,6 +560,8 @@ uchar isReset = !notResetState; USB_RESET_HOOK(isReset); wasReset = isReset; } +#else + notResetState = notResetState; // avoid compiler warning #endif } @@ -528,14 +572,15 @@ USB_PUBLIC void usbPoll(void) schar len; uchar i; - if((len = usbRxLen) > 0){ + 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 - 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; @@ -543,21 +588,22 @@ uchar i; usbRxLen = 0; /* mark rx buffer as available */ #endif } - if(usbTxLen & 0x10){ /* transmit system idle */ - if(usbMsgLen != 0xff){ /* transmit data pending? */ + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != USB_NO_MSG){ /* 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); + 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); } @@ -573,6 +619,12 @@ USB_PUBLIC void usbInit(void) #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/libcrypt/usbdrv/usbdrv.h b/libcrypt/usbdrv/usbdrv.h index 6ecf19c..2041ea1 100644 --- a/libcrypt/usbdrv/usbdrv.h +++ b/libcrypt/usbdrv/usbdrv.h @@ -1,17 +1,17 @@ /* Name: usbdrv.h - * Project: AVR USB driver + * 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) or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbdrv.h 536 2008-02-28 21:11:35Z cs $ + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id$ */ #ifndef __usbdrv_h_included__ #define __usbdrv_h_included__ #include "../usbconfig.h" -#include "iarcompat.h" +#include "usbportability.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 or 16 MHz -or at 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. +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. 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 be declared as "INTERRUPT" -instead of "SIGNAL" (see "avr/signal.h") or that they are written in assembler -with "sei" as the first instruction. +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. 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 20080228 +#define USBDRV_VERSION 20120109 /* 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,11 +150,26 @@ 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. + * 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). */ USB_PUBLIC void usbPoll(void); /* This function must be called at regular intervals from the main loop. @@ -168,7 +183,7 @@ extern uchar *usbMsgPtr; * implementation of usbFunctionWrite(). It is also used internally by the * driver for standard control requests. */ -USB_PUBLIC uchar usbFunctionSetup(uchar data[8]); +USB_PUBLIC usbMsgLen_t 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 @@ -181,21 +196,21 @@ USB_PUBLIC uchar 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 0xff in 'usbFunctionSetup()'. The driver - * will then call 'usbFunctionRead()' when data is needed. See the + * will handle the rest. Or (2) return USB_NO_MSG 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 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()'. + * 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()'. * * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() * are only done if enabled by the configuration in usbconfig.h. */ -USB_PUBLIC uchar usbFunctionDescriptor(struct usbRequest *rq); +USB_PUBLIC usbMsgLen_t 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 @@ -209,7 +224,6 @@ 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 @@ -217,7 +231,6 @@ extern volatile uchar usbTxLen1; */ #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 @@ -262,11 +275,14 @@ 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 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. +/* 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. */ #endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */ #ifdef USB_CFG_PULLUP_IOPORTNAME @@ -327,6 +343,12 @@ 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 @@ -353,7 +375,9 @@ 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. + * 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. */ #endif /* __ASSEMBLER__ */ @@ -366,16 +390,18 @@ 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 << 8) +#define USB_PROP_IS_DYNAMIC (1 << 14) /* If this property is set for a descriptor, usbFunctionDescriptor() will be - * used to obtain the particular descriptor. + * 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. */ -#define USB_PROP_IS_RAM (1 << 9) +#define USB_PROP_IS_RAM (1 << 15) /* 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) & 0xff) +#define USB_PROP_LENGTH(len) ((len) & 0x3fff) /* If a static external descriptor is used, this is the total length of the * descriptor in bytes. */ @@ -424,45 +450,45 @@ extern volatile schar usbRxLen; #ifndef __ASSEMBLER__ extern #if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const char usbDescriptorDevice[]; +char usbDescriptorDevice[]; extern #if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const char usbDescriptorConfiguration[]; +char usbDescriptorConfiguration[]; extern #if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const char usbDescriptorHidReport[]; +char usbDescriptorHidReport[]; extern #if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const char usbDescriptorString0[]; + char usbDescriptorString0[]; extern #if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const int usbDescriptorStringVendor[]; +int usbDescriptorStringVendor[]; extern #if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const int usbDescriptorStringDevice[]; +int usbDescriptorStringDevice[]; extern #if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM) -PROGMEM +const PROGMEM #endif -const int usbDescriptorStringSerialNumber[]; +int usbDescriptorStringSerialNumber[]; #endif /* __ASSEMBLER__ */ @@ -487,22 +513,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 USBID-License.txt for details. + * See USB-IDs-for-free.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 /* 5824 in dec, stands for VOTI */ +# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ #endif #ifndef USB_CFG_DEVICE_ID # if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH -# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* 1503 in dec, shared PID for HIDs */ +# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* = 0x5df = 1503, shared PID for HIDs */ # elif USB_CFG_INTERFACE_CLASS == 2 -# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* 1505 in dec, shared PID for CDC Modems */ +# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* = 0x5e1 = 1505, shared PID for CDC Modems */ # else -# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free PID */ +# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x5dc = 1500, obdev's free PID */ # endif #endif @@ -532,6 +558,10 @@ 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 ----- */ @@ -544,7 +574,14 @@ const int usbDescriptorStringSerialNumber[]; # endif #endif #ifndef USB_INTR_CFG_SET /* allow user to override our default */ -# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */ +# 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 #endif #ifndef USB_INTR_CFG_CLR /* allow user to override our default */ # define USB_INTR_CFG_CLR 0 /* no bits to clear */ @@ -602,12 +639,22 @@ at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM #define USBPID_STALL 0x1e #ifndef USB_INITIAL_DATATOKEN -#define USB_INITIAL_DATATOKEN USBPID_DATA0 +#define USB_INITIAL_DATATOKEN USBPID_DATA1 #endif #ifndef __ASSEMBLER__ -extern uchar usbTxBuf1[USB_BUFSIZE], usbTxBuf3[USB_BUFSIZE]; +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 + typedef union usbWord{ unsigned word; @@ -671,7 +718,8 @@ typedef struct usbRequest{ #define USBDESCR_HID_REPORT 0x22 #define USBDESCR_HID_PHYS 0x23 -#define USBATTR_BUSPOWER 0x80 +//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more +#define USBATTR_BUSPOWER 0 #define USBATTR_SELFPOWER 0x40 #define USBATTR_REMOTEWAKE 0x20 diff --git a/libcrypt/usbdrv/usbdrvasm.S b/libcrypt/usbdrv/usbdrvasm.S index 518037e..4e6158c 100644 --- a/libcrypt/usbdrv/usbdrvasm.S +++ b/libcrypt/usbdrv/usbdrvasm.S @@ -1,10 +1,10 @@ /* Name: usbdrvasm.S - * Project: AVR USB driver + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers * 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) or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * Revision: $Id$ */ @@ -15,16 +15,9 @@ general code (preprocessor acrobatics and CRC computation) and then includes the file appropriate for the given clock rate. */ -#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 */ +#define __SFR_OFFSET 0 /* used by avr-libc's register definitions */ +#include "usbportability.h" +#include "usbdrv.h" /* for common defs */ /* register names */ #define x1 r16 @@ -33,27 +26,17 @@ the file appropriate for the given clock rate. #define cnt r19 #define x3 r20 #define x4 r21 -#define bitcnt r22 +#define x5 r22 +#define bitcnt x5 #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, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3 + extern usbTxBuf, usbTxStatus1, usbTxStatus3 # if USB_COUNT_SOF extern usbSofCount # endif @@ -73,10 +56,12 @@ 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 */ -# define USB_INTR_VECTOR SIG_INTERRUPT0 +# 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 # endif .text .global USB_INTR_VECTOR @@ -94,6 +79,11 @@ 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 @@ -153,16 +143,93 @@ RTMODEL "__rt_version", "3" #endif -; extern unsigned usbCrc16(unsigned char *data, unsigned char len); -; data: r24/25 -; len: r22 +#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 ; temp variables: -; r18: data byte -; r19: bit counter -; r20/21: polynomial -; r23: scratch -; r24/25: crc-sum -; r26/27=X: ptr +; 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 usbCrc16: mov ptrL, argPtrL mov ptrH, argPtrH @@ -170,27 +237,30 @@ usbCrc16: ldi resCrcH, 0 ldi polyL, lo8(0xa001) ldi polyH, hi8(0xa001) - com argLen ; argLen = -argLen - 1 -crcByteLoop: - subi argLen, -1 - brcc crcReady ; modified loop to ensure that carry is set below + 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: ld byte, ptr+ - ldi bitCnt, -8 ; strange loop counter to ensure that carry is set where we need it eor resCrcL, byte -crcBitLoop: - ror resCrcH ; carry is always set here +usbCrcBitLoop: + ror resCrcH ; carry is always set here (see brcs jumps to here) ror resCrcL - brcs crcNoXor + brcs usbCrcNoXor eor resCrcL, polyL eor resCrcH, polyH -crcNoXor: - subi bitCnt, -1 - brcs crcBitLoop - rjmp crcByteLoop -crcReady: +usbCrcNoXor: + subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times + brcs usbCrcBitLoop +usbCrcLoopEntry: + subi argLen, -1 + brcs usbCrcByteLoop +usbCrcReady: 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 @@ -291,17 +361,33 @@ usbMFTimeout: ;---------------------------------------------------------------------------- #ifndef USB_CFG_CLOCK_KHZ -# define USB_CFG_CLOCK_KHZ 12000 +# 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 #endif -#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 +#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 */ diff --git a/libcrypt/usbdrv/usbdrvasm.asm b/libcrypt/usbdrv/usbdrvasm.asm index 4a5486f..9cc4e4d 100644 --- a/libcrypt/usbdrv/usbdrvasm.asm +++ b/libcrypt/usbdrv/usbdrvasm.asm @@ -1,10 +1,10 @@ /* Name: usbdrvasm.asm - * Project: AVR USB driver + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers * 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) or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * This Revision: $Id$ */ diff --git a/libcrypt/usbdrv/usbdrvasm12.inc b/libcrypt/usbdrv/usbdrvasm12.inc index 23b988c..cb74ceb 100644 --- a/libcrypt/usbdrv/usbdrvasm12.inc +++ b/libcrypt/usbdrv/usbdrvasm12.inc @@ -1,11 +1,11 @@ /* Name: usbdrvasm12.inc - * Project: AVR USB driver + * 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) 2007 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbdrvasm12.inc 483 2008-02-05 15:05:32Z cs $ + * 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 @@ -48,10 +48,13 @@ 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 -;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +;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: - sbis USBIN, USBMINUS ;1 [40] wait for D- == 1 - rjmp waitForJ ;2 + 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 @@ -69,6 +72,9 @@ 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] @@ -250,12 +256,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" @@ -263,25 +269,16 @@ endm ; Transmitting data ;---------------------------------------------------------------------------- -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 +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 sendNakAndReti: ;0 [-19] 19 cycles until SOP ldi x3, USBPID_NAK ;1 [-18] @@ -306,122 +303,91 @@ usbSendX3: ;0 [-16] ;usbSend: ;pointer to data in 'Y' ;number of bytes in 'cnt' -- including sync byte -;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] +;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] + ;make SE0: - 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 + 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 ;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 - 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 + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer skipAddrAssign: ;end of usbDeviceAddress transfer - ldi x2, 1< subtract 1/3 rjmp didUnstuff6 ;[08] unstuff7: @@ -124,7 +133,7 @@ unstuff7: in x2, USBIN ;[00] [10] re-sample bit 7 andi x2, USBMASK ;[01] andi shift, ~0x80;[02] - subi leap, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit + subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 rjmp didUnstuff7 ;[04] unstuffEven: @@ -133,8 +142,8 @@ unstuffEven: andi shift, ~0x80;[01] andi x1, USBMASK ;[02] breq se0 ;[03] - subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit - nop ;[05] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] rjmp didUnstuffE ;[06] unstuffOdd: @@ -143,8 +152,8 @@ unstuffOdd: andi shift, ~0x80;[01] andi x2, USBMASK ;[02] breq se0 ;[03] - subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit - nop ;[05] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] rjmp didUnstuffO ;[06] rxByteLoop: @@ -208,13 +217,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/libcrypt/usbdrv/usbdrvasm165.inc b/libcrypt/usbdrv/usbdrvasm165.inc index 8639aa1..d8a95ba 100644 --- a/libcrypt/usbdrv/usbdrvasm165.inc +++ b/libcrypt/usbdrv/usbdrvasm165.inc @@ -1,10 +1,10 @@ /* Name: usbdrvasm165.inc - * Project: AVR USB driver + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers * 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) or proprietary (CommercialLicense.txt) + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * Revision: $Id$ */ @@ -46,10 +46,13 @@ 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 -;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +;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: - sbis USBIN, USBMINUS ;[-18] wait for D- == 1 - rjmp 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 ;[-15] @@ -69,6 +72,9 @@ 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] @@ -334,12 +340,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"