USBKeys haben schon mal funktioniert

master
Stefan Krulj 14 years ago
parent 35aeaaea5b
commit 9ac8624d3c
  1. 18
      libcrypt/main.c
  2. 1
      libcrypt/main.h
  3. 229
      libcrypt/usbconfig.h
  4. 102
      libcrypt/usbdrv/Changelog.txt
  5. 69
      libcrypt/usbdrv/CommercialLicense.txt
  6. 12
      libcrypt/usbdrv/License.txt
  7. 142
      libcrypt/usbdrv/Readme.txt
  8. 143
      libcrypt/usbdrv/USBID-License.txt
  9. 26
      libcrypt/usbdrv/asmcommon.inc
  10. 65
      libcrypt/usbdrv/iarcompat.h
  11. 4
      libcrypt/usbdrv/oddebug.c
  12. 9
      libcrypt/usbdrv/oddebug.h
  13. 169
      libcrypt/usbdrv/usbconfig-prototype.h
  14. 590
      libcrypt/usbdrv/usbdrv.c
  15. 152
      libcrypt/usbdrv/usbdrv.h
  16. 210
      libcrypt/usbdrv/usbdrvasm.S
  17. 4
      libcrypt/usbdrv/usbdrvasm.asm
  18. 246
      libcrypt/usbdrv/usbdrvasm12.inc
  19. 23
      libcrypt/usbdrv/usbdrvasm15.inc
  20. 35
      libcrypt/usbdrv/usbdrvasm16.inc
  21. 20
      libcrypt/usbdrv/usbdrvasm165.inc

@ -20,6 +20,7 @@
#include <stdlib.h>
#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;
}

@ -15,4 +15,3 @@
#define P_BTN P_PORT_BTN_NUM_BTN
#define BTN_VECT INT_NUM_BTN_vect

@ -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<<USB_CFG_DPLUS_BIT)
#define USB_INTR_ENABLE_BIT PCIE
#define USB_INTR_PENDING_BIT PCIF
#define USB_INTR_VECTOR SIG_PIN_CHANGE
*/
/*#define USB_INTR_VECTOR INT2_vect*/
#endif /* __usbconfig_h_included__ */

@ -214,3 +214,105 @@ Scroll down to the bottom to see the most recent changes.
* Release 2008-02-28
- USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we
start with sending USBPID_DATA0.
- Changed defaults in usbconfig-prototype.h
- Added free USB VID/PID pair for MIDI class devices
- Restructured AVR-USB as separate package, not part of PowerSwitch any more.
* Release 2008-04-18
- Restructured usbdrv.c so that it is easier to read and understand.
- Better code optimization with gcc 4.
- If a second interrupt in endpoint is enabled, also add it to config
descriptor.
- Added config option for long transfers (above 254 bytes), see
USB_CFG_LONG_TRANSFERS in usbconfig.h.
- Added 20 MHz module contributed by Jeroen Benschop.
* Release 2008-05-13
- Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length
was not incremented, pointer to length was incremented instead.
- Added code to command line tool(s) which claims an interface. This code
is disabled by default, but may be necessary on newer Linux kernels.
- Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING".
- New header "usbportability.h" prepares ports to other development
environments.
- Long transfers (above 254 bytes) did not work when usbFunctionRead() was
used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!]
- In hiddata.c (example code for sending/receiving data over HID), use
USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so
that we need not claim the interface.
- in usbPoll() loop 20 times polling for RESET state instead of 10 times.
This accounts for the higher clock rates we now support.
- Added a module for 12.8 MHz RC oscillator with PLL in receiver loop.
- Added hook to SOF code so that oscillator can be tuned to USB frame clock.
- Added timeout to waitForJ loop. Helps preventing unexpected hangs.
- Added example code for oscillator tuning to libs-device (thanks to
Henrik Haftmann for the idea to this routine).
- Implemented option USB_CFG_SUPPRESS_INTR_CODE.
* Release 2008-10-22
- Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and
similar, not offset of 0x20 needs to be added.
- Allow distribution under GPLv3 for those who have to link against other
code distributed under GPLv3.
* Release 2008-11-26
- Removed libusb-win32 dependency for hid-data example in Makefile.windows.
It was never required and confused many people.
- Added extern uchar usbRxToken to usbdrv.h.
- Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser.
* Release 2009-03-23
- Hid-mouse example used settings from hid-data example, fixed that.
- Renamed project to V-USB due to a trademark issue with Atmel(r).
- Changed CommercialLicense.txt and USBID-License.txt to make the
background of USB ID registration clearer.
* Release 2009-04-15
- Changed CommercialLicense.txt to reflect the new range of PIDs from
Jason Kotzin.
- Removed USBID-License.txt in favor of USB-IDs-for-free.txt and
USB-ID-FAQ.txt
- Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in
the center between bit 0 and 1 of each byte. This is where the data lines
are expected to change and the sampled data may therefore be nonsense.
We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-.
- Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed,
the unstuffing code in the receiver routine was 1 cycle too long. If
multiple bytes had the unstuffing in bit 6, the error summed up until the
receiver was out of sync.
- Included option for faster CRC routine.
Thanks to Slawomir Fras (BoskiDialer) for this code!
- Updated bits in Configuration Descriptor's bmAttributes according to
USB 1.1 (in particular bit 7, it is a must-be-set bit now).
* Release 2009-08-22
- Moved first DBG1() after odDebugInit() in all examples.
- Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes
V-USB compatible with the new "p" suffix devices (e.g. ATMega328p).
- USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any
more).
- New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with
more than 64 kB flash.
- Built-in configuration descriptor allows custom definition for second
endpoint now.
* Release 2010-07-15
- Fixed bug in usbDriverSetup() which prevented descriptor sizes above 255
bytes.
- Avoid a compiler warning for unused parameter in usbHandleResetHook() when
compiler option -Wextra is enabled.
- Fixed wrong hex value for some IDs in USB-IDs-for-free.txt.
- Keep a define for USBATTR_BUSPOWER, although the flag does not exist
in USB 1.1 any more. Set it to 0. This is for backward compatibility.
* Release 2012-01-09

@ -1,5 +1,5 @@
AVR-USB Driver Software License Agreement
Version 2006-07-24
V-USB Driver Software License Agreement
Version 2009-08-03
THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN
ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING
@ -13,30 +13,41 @@ Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA.
1.2 "You" shall mean the Licensee.
1.3 "AVR-USB" shall mean the firmware-only USB device implementation for
Atmel AVR microcontrollers distributed by OBJECTIVE DEVELOPMENT and
consisting of the files usbdrv.c, usbdrv.h, usbdrvasm.S, oddebug.c,
oddebug.h, usbdrvasm.asm, iarcompat.h and usbconfig-prototype.h.
1.3 "V-USB" shall mean all files included in the package distributed under
the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/)
unless otherwise noted. This includes the firmware-only USB device
implementation for Atmel AVR microcontrollers, some simple device examples
and host side software examples and libraries.
2 LICENSE GRANTS
2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source
code of AVR-USB.
code of V-USB.
2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the
non-exclusive right to use and distribute AVR-USB with your hardware
non-exclusive right to use, copy and distribute V-USB with your hardware
product(s), restricted by the limitations in section 3 below.
2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify
your copy of AVR-USB according to your needs.
2.4 USB IDs. OBJECTIVE DEVELOPMENT grants you the exclusive rights to use
USB Product ID(s) sent to you in e-mail after receiving your payment in
conjunction with USB Vendor ID 5824. OBJECTIVE DEVELOPMENT has acquired an
exclusive license for this pair of USB identifiers from Wouter van Ooijen
(www.voti.nl), who has licensed the VID from the USB Implementers Forum,
Inc. (www.usb.org).
the source code and your copy of V-USB according to your needs.
2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB
Product ID(s), sent to you in e-mail. These Product IDs are reserved
exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID
ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen
Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from
Jason Kotzin (Clay Logic, www.claylogic.com). Both owners of the Vendor IDs
have obtained these IDs from the USB Implementers Forum, Inc.
(www.usb.org). OBJECTIVE DEVELOPMENT disclaims all liability which might
arise from the assignment of USB IDs.
2.5 USB Certification. Although not part of this agreement, we want to make
it clear that you cannot become USB certified when you use V-USB or a USB
Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't
meet the electrical specifications required by the USB specification and
the USB Implementers Forum certifies only members who bought a Vendor ID of
their own.
3 LICENSE RESTRICTIONS
@ -45,21 +56,21 @@ Inc. (www.usb.org).
applicable. Which one is determined by the amount you pay to OBJECTIVE
DEVELOPMENT, see section 4 ("Payment") below.
Hobby License: You may use AVR-USB according to section 2 above in no more
Hobby License: You may use V-USB according to section 2 above in no more
than 5 hardware units. These units must not be sold for profit.
Entry Level License: You may use AVR-USB according to section 2 above in no
Entry Level License: You may use V-USB according to section 2 above in no
more than 150 hardware units.
Professional License: You may use AVR-USB according to section 2 above in
Professional License: You may use V-USB according to section 2 above in
any number of hardware units, except for large scale production ("unlimited
fair use"). Quantities below 10,000 units are not considered large scale
production. If your reach quantities which are obviously large scale
production, you must pay a license fee of 0.10 EUR per unit for all units
above 10,000.
3.2 Rental. You may not rent, lease, or lend AVR-USB or otherwise encumber
any copy of AVR-USB, or any of the rights granted herein.
3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber
any copy of V-USB, or any of the rights granted herein.
3.3 Transfer. You may not transfer your rights under this Agreement to
another party without OBJECTIVE DEVELOPMENT's prior written consent. If
@ -77,7 +88,7 @@ non-exclusive.
by third parties. In particular, you are not allowed to use the USB logo or
other trademarks owned by the USB Implementers Forum, Inc. without their
consent. Since such consent depends on USB certification, it should be
noted that AVR-USB will not pass certification because it does not
noted that V-USB will not pass certification because it does not
implement checksum verification and the microcontroller ports do not meet
the electrical specifications.
@ -87,15 +98,15 @@ the electrical specifications.
The payment amount depends on the variation of this agreement (according to
section 3.1) into which you want to enter. Concrete prices are listed on
OBJECTIVE DEVELOPMENT's web site, usually at
http://www.obdev.at/avrusb/license.html. You agree to pay the amount listed
http://www.obdev.at/vusb/license.html. You agree to pay the amount listed
there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor
or reseller.
5 COPYRIGHT AND OWNERSHIP
AVR-USB is protected by copyright laws and international copyright
treaties, as well as other intellectual property laws and treaties. AVR-USB
V-USB is protected by copyright laws and international copyright
treaties, as well as other intellectual property laws and treaties. V-USB
is licensed, not sold.
@ -111,12 +122,12 @@ and limitation of liability shall survive termination of this agreement.
7 DISCLAIMER OF WARRANTY AND LIABILITY
LIMITED WARRANTY. AVR-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE
DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
NON-INFRINGEMENT, WITH REGARD TO AVR-USB, AND THE PROVISION OF OR FAILURE
NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE
TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO
STATE/JURISDICTION.
@ -126,11 +137,11 @@ IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY
SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER
(INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY
LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE AVR-USB OR THE
LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE
PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE
DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY
CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS
AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR AVR-USB.
AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB.
8 MISCELLANEOUS TERMS

@ -1,16 +1,18 @@
OBJECTIVE DEVELOPMENT GmbH's AVR-USB driver software is distributed under the
terms and conditions of the GNU GPL version 2, see the text below. In addition
to the requirements in the GPL, we STRONGLY ENCOURAGE you to do the following:
OBJECTIVE DEVELOPMENT GmbH's V-USB driver software is distributed under the
terms and conditions of the GNU GPL version 2 or the GNU GPL version 3. It is
your choice whether you apply the terms of version 2 or version 3. The full
text of GPLv2 is included below. In addition to the requirements in the GPL,
we STRONGLY ENCOURAGE you to do the following:
(1) Publish your entire project on a web site and drop us a note with the URL.
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
Use the form at http://www.obdev.at/vusb/feedback.html for your submission.
(2) Adhere to minimum publication standards. Please include AT LEAST:
- a circuit diagram in PDF, PNG or GIF format
- full source code for the host software
- a Readme.txt file in ASCII format which describes the purpose of the
project and what can be found in which directories and which files
- a reference to http://www.obdev.at/avrusb/
- a reference to http://www.obdev.at/vusb/
(3) If you improve the driver firmware itself, please give us a free license
to your modifications for our commercial license offerings.

@ -1,10 +1,11 @@
This is the Readme file to Objective Development's firmware-only USB driver
for Atmel AVR microcontrollers. For more information please visit
http://www.obdev.at/avrusb/
http://www.obdev.at/vusb/
This directory contains the USB firmware only. Copy it as-is to your own
project and add your own version of "usbconfig.h". A template for your own
"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory.
project and add all .c and .S files to your project (these files are marked
with an asterisk in the list below). Then copy usbconfig-prototype.h as
usbconfig.h to your project and edit it according to your configuration.
TECHNICAL DOCUMENTATION
@ -32,26 +33,26 @@ The driver consists of the following files:
defined to a value greater than 0. Link this module
to your code!
oddebug.h .............. Interface definitions of the debug module.
iarcompat.h ............ Compatibility definitions for IAR C-compiler.
usbportability.h ....... Header with compiler-dependent stuff.
usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this
module instead of usbdrvasm.S when you assembler
with IAR's tools.
License.txt ............ Open Source license for this driver.
CommercialLicense.txt .. Optional commercial license for this driver.
USBID-License.txt ...... Terms and conditions for using particular USB ID
values for particular purposes.
USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs.
USB-IDs-for-free.txt ... List and terms of use for free shared PIDs.
(*) ... These files should be linked to your project.
CPU CORE CLOCK FREQUENCY
========================
We supply assembler modules for clock frequencies of 12 MHz, 15 MHz, 16 MHz and
16.5 MHz. Other clock rates are not supported. The actual clock rate must be
configured in usbdrv.h unless you use the default 12 MHz.
We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz,
16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The
actual clock rate must be configured in usbconfig.h.
12 MHz Clock
This is the traditional clock rate of AVR-USB because it's the lowest clock
This is the traditional clock rate of V-USB because it's the lowest clock
rate where the timing constraints of the USB spec can be met.
15 MHz Clock
@ -66,21 +67,33 @@ if you need the slightly higher clock rate for performance reasons. Since
16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code
is somewhat tricky and has to insert a leap cycle every third byte.
16.5 MHz Clock
The assembler module for this clock rate differs from the other modules because
it has been built for an RC oscillator with only 1% precision. The receiver
code inserts leap cycles to compensate for clock deviations. 1% is also the
precision which can be achieved by calibrating the internal RC oscillator of
the AVR. Please note that only AVRs with internal 64 MHz PLL oscillator can be
used since the 8 MHz RC oscillator cannot be trimmed up to 16.5 MHz. This
includes the very popular ATTiny25, ATTiny45, ATTiny85 series as well as the
ATTiny26.
We recommend that you obtain appropriate calibration values for 16.5 MHz core
clock at programming time and store it in flash or EEPROM or compute the value
from a reference clock at run time. Atmel's 8 MHz calibration is much more
precise than the guaranteed 10% and it's therefore often possible to work with
a fixed offset from this value, but it may be out of range.
12.8 MHz and 16.5 MHz Clock
The assembler modules for these clock rates differ from the other modules
because they have been built for an RC oscillator with only 1% precision. The
receiver code inserts leap cycles to compensate for clock deviations. 1% is
also the precision which can be achieved by calibrating the internal RC
oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL
oscillator can reach 16.5 MHz with the RC oscillator. This includes the very
popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost
all AVRs can reach 12.8 MHz, although this is outside the specified range.
See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for
code which calibrates the RC oscillator based on the USB frame clock.
18 MHz Clock
This module is closer to the USB specification because it performs an on the
fly CRC check for incoming packets. Packets with invalid checksum are
discarded as required by the spec. If you also implement checks for data
PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING
in usbconfig.h for more info), this ensures data integrity. Due to the CRC
tables and alignment requirements, this code is bigger than modules for other
clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1
and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h.
20 MHz Clock
This module is for people who won't do it with less than the maximum. Since
20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code
uses similar tricks as the 16 MHz module to insert leap cycles.
USB IDENTIFIERS
@ -90,65 +103,70 @@ are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you
can assign PIDs at will.
Since an entry level cost of 1,500 USD is too high for most small companies
and hobbyists, we provide a single VID/PID pair for free. If you want to use
your own VID and PID instead of our's, define the macros "USB_CFG_VENDOR_ID"
and "USB_CFG_DEVICE_ID" accordingly in "usbconfig.h".
To use our predefined VID/PID pair, you MUST conform to a couple of
requirements. See the file "USBID-License.txt" for details.
Objective Development also has some offerings which include product IDs. See
http://www.obdev.at/avrusb/ for details.
and hobbyists, we provide some VID/PID pairs for free. See the file
USB-IDs-for-free.txt for details.
HOST DRIVER
===========
You have received this driver together with an example device implementation
and an example host driver. The host driver is based on libusb and compiles
on various Unix flavors (Linux, BSD, Mac OS X). It also compiles natively on
Windows using MinGW (see www.mingw.org) and libusb-win32 (see
libusb-win32.sourceforge.net). The "Automator" project contains a native
Windows host driver (not based on libusb) for Human Interface Devices.
Objective Development also has some license offerings which include product
IDs. See http://www.obdev.at/vusb/ for details.
DEVELOPMENT SYSTEM
==================
This driver has been developed and optimized for the GNU compiler version 3
(gcc 3). It does work well with gcc 4, but with bigger code size. We recommend
that you use the GNU compiler suite because it is freely available. AVR-USB
has also been ported to the IAR compiler and assembler. It has been tested
with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the "small" and "tiny"
memory model. Not every release is tested with IAR CC and the driver may
therefore fail to compile with IAR. Please note that gcc is more efficient for
usbdrv.c because this module has been deliberately optimized for gcc.
and 4. We recommend that you use the GNU compiler suite because it is freely
available. V-USB has also been ported to the IAR compiler and assembler. It
has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the
"small" and "tiny" memory model. Not every release is tested with IAR CC and
the driver may therefore fail to compile with IAR. Please note that gcc is
more efficient for usbdrv.c because this module has been deliberately
optimized for gcc.
Gcc version 3 produces smaller code than version 4 due to new optimizing
capabilities which don't always improve things on 8 bit CPUs. The code size
generated by gcc 4 can be reduced with the compiler options
-fno-move-loop-invariants, -fno-tree-scev-cprop and
-fno-inline-small-functions in addition to -Os. On devices with more than
8k of flash memory, we also recommend the linker option --relax (written as
-Wl,--relax for gcc) to convert absolute calls into relative where possible.
For more information about optimizing options see:
http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html
These optimizations are good for gcc 4.x. Version 3.x of gcc does not support
most of these options and produces good code anyway.
USING AVR-USB FOR FREE
======================
USING V-USB FOR FREE
====================
The AVR firmware driver is published under the GNU General Public License
Version 2 (GPL2). See the file "License.txt" for details.
Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is
your choice whether you apply the terms of version 2 or version 3.
If you decide for the free GPL2, we STRONGLY ENCOURAGE you to do the following
things IN ADDITION to the obligations from the GPL2:
If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the
following things IN ADDITION to the obligations from the GPL:
(1) Publish your entire project on a web site and drop us a note with the URL.
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
Use the form at http://www.obdev.at/vusb/feedback.html for your submission.
If you don't have a web site, you can publish the project in obdev's
documentation wiki at
http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects.
(2) Adhere to minimum publication standards. Please include AT LEAST:
- a circuit diagram in PDF, PNG or GIF format
- full source code for the host software
- a Readme.txt file in ASCII format which describes the purpose of the
project and what can be found in which directories and which files
- a reference to http://www.obdev.at/avrusb/
- a reference to http://www.obdev.at/vusb/
(3) If you improve the driver firmware itself, please give us a free license
to your modifications for our commercial license offerings.
COMMERCIAL LICENSES FOR AVR-USB
===============================
If you don't want to publish your source code under the terms of the GPL2,
you can simply pay money for AVR-USB. As an additional benefit you get
USB PIDs for free, licensed exclusively to you. See the file
COMMERCIAL LICENSES FOR V-USB
=============================
If you don't want to publish your source code under the terms of the GPL,
you can simply pay money for V-USB. As an additional benefit you get
USB PIDs for free, reserved exclusively to you. See the file
"CommercialLicense.txt" for details.

@ -1,143 +0,0 @@
Royalty-Free Non-Exclusive License USB Product-ID
=================================================
Version 2006-06-19
OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive
right to use three USB.org vendor-ID (VID) / product-ID (PID) pairs with
products based on Objective Development's firmware-only USB driver for
Atmel AVR microcontrollers:
* VID = 5824 (=0x16c0) / PID = 1500 (=0x5dc) for devices implementing no
USB device class (vendor-class devices with USB class = 0xff). Devices
using this pair will be referred to as "VENDOR CLASS" devices.
* VID = 5824 (=0x16c0) / PID = 1503 (=0x5df) for HID class devices
(excluding mice and keyboards). Devices using this pair will be referred
to as "HID CLASS" devices.
* VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices
Devices using this pair will be referred to as "CDC-ACM CLASS" devices.
Since the granted right is non-exclusive, the same VID/PID pairs may be
used by many companies and individuals for different products. To avoid
conflicts, your device and host driver software MUST adhere to the rules
outlined below.
OBJECTIVE DEVELOPMENT Software GmbH has licensed these VID/PID pairs from
Wouter van Ooijen (see www.voti.nl), who has licensed the VID from the USB
Implementers Forum, Inc. (see www.usb.org). The VID is registered for the
company name "Van Ooijen Technische Informatica".
RULES AND RESTRICTIONS
======================
(1) The USB device MUST provide a textual representation of the
manufacturer and product identification. The manufacturer identification
MUST be available at least in USB language 0x0409 (English/US).
(2) The textual manufacturer identification MUST contain either an Internet
domain name (e.g. "mycompany.com") registered and owned by you, or an
e-mail address under your control (e.g. "myname@gmx.net"). You can embed
the domain name or e-mail address in any string you like, e.g. "Objective
Development http://www.obdev.at/avrusb/".
(3) You are responsible for retaining ownership of the domain or e-mail
address for as long as any of your products are in use.
(4) You may choose any string for the textual product identification, as
long as this string is unique within the scope of your textual manufacturer
identification.
(5) Matching of device-specific drivers MUST be based on the textual
manufacturer and product identification in addition to the usual VID/PID
matching. This means that operating system features which are based on
VID/PID matching only (e.g. Windows kernel level drivers, automatic actions
when the device is plugged in etc) MUST NOT be used. The driver matching
MUST be a comparison of the entire strings, NOT a sub-string match. For
CDC-ACM CLASS devices, a generic class driver should be used and the
matching is based on the USB device class.
(6) The extent to which VID/PID matching is allowed for non device-specific
drivers or features depends on the operating system and particular VID/PID
pair used:
* Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is
required and hence no VID/PID-only matching is allowed at all.
* Windows: The operating system performs VID/PID matching for the kernel
level driver. You are REQUIRED to use libusb-win32 (see
http://libusb-win32.sourceforge.net/) as the kernel level driver for
VENDOR CLASS devices. HID CLASS devices all use the generic HID class
driver shipped with Windows, except mice and keyboards. You therefore
MUST NOT use any of the shared VID/PID pairs for mice or keyboards.
CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID
pair. This ".inf" file MUST load the "usbser" driver to configure the
device as modem (COM-port).
(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any
problems which are caused by the shared use of these VID/PID pairs. You
have been warned that the sharing of VID/PID pairs may cause problems. If
you want to avoid them, get your own VID/PID pair for exclusive use.
HOW TO IMPLEMENT THESE RULES
============================
The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM
CLASS devices use the operating system's class driver and don't need a
custom driver.
The host driver MUST iterate over all devices with the given VID/PID
numbers in their device descriptors and query the string representation for
the manufacturer name in USB language 0x0409 (English/US). It MUST compare
the ENTIRE string with your textual manufacturer identification chosen in
(2) above. A substring search for your domain or e-mail address is NOT
acceptable. The driver MUST NOT touch the device (other than querying the
descriptors) unless the strings match.
For all USB devices with matching VID/PID and textual manufacturer
identification, the host driver must query the textual product
identification and string-compare it with the name of the product it can
control. It may only initialize the device if the product matches exactly.
Objective Development provides examples for these matching rules with the
"PowerSwitch" project (using libusb) and with the "Automator" project
(using Windows calls on Windows and libusb on Unix).
Technical Notes:
================
Sharing the same VID/PID pair among devices is possible as long as ALL
drivers which match the VID/PID also perform matching on the textual
identification strings. This is easy on all operating systems except
Windows, since Windows establishes a static connection between the VID/PID
pair and a kernel level driver. All devices with the same VID/PID pair must
therefore use THE SAME kernel level driver.
We therefore demand that you use libusb-win32 for VENDOR CLASS devices.
This is a generic kernel level driver which allows all types of USB access
for user space applications. This is only a partial solution of the
problem, though, because different device drivers may come with different
versions of libusb-win32 and they may not work with the libusb version of
the respective other driver. You are therefore encouraged to test your
driver against a broad range of libusb-win32 versions. Do not use new
features in new versions, or check for their existence before you use them.
When a new libusb-win32 becomes available, make sure that your driver is
compatible with it.
For HID CLASS devices it is necessary that all those devices bind to the
same kernel driver: Microsoft's generic USB HID driver. This is true for
all HID devices except those with a specialized driver. Currently, the only
HIDs with specialized drivers are mice and keyboards. You therefore MUST
NOT use a shared VID/PID with mouse and keyboard devices.
Sharing the same VID/PID among different products is unusual and probably
violates the USB specification. If you do it, you do it at your own risk.
To avoid possible incompatibilities, we highly recommend that you get your
own VID/PID pair if you intend to sell your product. Objective
Development's commercial licenses for AVR-USB include a PID for
unrestricted exclusive use.

@ -1,10 +1,10 @@
/* Name: asmcommon.inc
* Project: AVR USB driver
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2007-11-05
* 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$
*/
@ -103,8 +103,11 @@ sofError:
reti
handleData:
lds token, usbCurrentTok;[18]
tst token ;[20]
#if USB_CFG_CHECK_CRC
CRC_CLEANUP_AND_CHECK ; jumps to ignorePacket if CRC error
#endif
lds shift, usbCurrentTok;[18]
tst shift ;[20]
breq doReturn ;[21]
lds x2, usbRxLen ;[22]
tst x2 ;[24]
@ -113,8 +116,11 @@ handleData:
; recognized if usbPoll() was called less frequently than once every 4 ms.
cpi cnt, 4 ;[26] zero sized data packets are status phase only -- ignore and ack
brmi sendAckAndReti ;[27] keep rx buffer clean -- we must not NAK next SETUP
#if USB_CFG_CHECK_DATA_TOGGLING
sts usbCurrentDataToken, token ; store for checking by C code
#endif
sts usbRxLen, cnt ;[28] store received data, swap buffers
sts usbRxToken, token ;[30]
sts usbRxToken, shift ;[30]
lds x2, usbInputBufOffset;[32] swap buffers
ldi cnt, USB_BUFSIZE ;[34]
sub cnt, x2 ;[35]
@ -131,7 +137,11 @@ handleIn:
ldi x1, USBPID_NAK ;[34] prepare value for usbTxLen
#if USB_CFG_HAVE_INTRIN_ENDPOINT
andi x3, 0xf ;[35] x3 contains endpoint
#if USB_CFG_SUPPRESS_INTR_CODE
brne sendNakAndReti ;[36]
#else
brne handleIn1 ;[36]
#endif
#endif
lds cnt, usbTxLen ;[37]
sbrc cnt, 4 ;[39] all handshake tokens have bit 4 set
@ -150,7 +160,7 @@ handleIn:
; RAM this way and avoid potential problems with endless retries. The rest of
; the driver assumes error-free transfers anyway.
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
#if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
handleIn1: ;[38]
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
@ -164,9 +174,8 @@ handleIn1: ;[38]
ldi YL, lo8(usbTxBuf1) ;[46]
ldi YH, hi8(usbTxBuf1) ;[47]
rjmp usbSendAndReti ;[48] 50 + 12 = 62 until SOP
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
handleIn3:
lds cnt, usbTxLen3 ;[41]
sbrc cnt, 4 ;[43]
@ -176,3 +185,4 @@ handleIn3:
ldi YH, hi8(usbTxBuf3) ;[48]
rjmp usbSendAndReti ;[49] 51 + 12 = 63 until SOP
#endif
#endif

@ -1,65 +0,0 @@
/* Name: iarcompat.h
* Project: AVR USB driver
* Author: Christian Starkjohann
* Creation Date: 2006-03-01
* Tabsize: 4
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
* This Revision: $Id: iarcompat.h 533 2008-02-28 15:35:25Z cs $
*/
/*
General Description:
This header is included when we compile with the IAR C-compiler and assembler.
It defines macros for cross compatibility between gcc and IAR-cc.
Thanks to Oleg Semyonov for his help with the IAR tools port!
*/
#ifndef __iarcompat_h_INCLUDED__
#define __iarcompat_h_INCLUDED__
#if defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__
/* Enable bit definitions */
#ifndef ENABLE_BIT_DEFINITIONS
# define ENABLE_BIT_DEFINITIONS 1
#endif
/* Include IAR headers */
#include <ioavr.h>
#ifndef __IAR_SYSTEMS_ASM__
# include <inavr.h>
#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__ */

@ -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"

@ -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 <avr/io.h>
#endif
#include "usbportability.h"
#ifndef uchar
# define uchar unsigned char

@ -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__ */

@ -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 <avr/io.h>
# include <avr/pgmspace.h>
#endif
#include "usbportability.h"
#include "usbdrv.h"
#include "oddebug.h"
#include <avr/interrupt.h>
/*
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
}
/* ------------------------------------------------------------------------- */

@ -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

@ -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 <avr/io.h> /* 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 */

@ -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$
*/

@ -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<<USB_INTR_PENDING_BIT;1 [8] int0 occurred during TX -- clear pending flag
USB_STORE_PENDING(x2) ;1 [9]
ori x1, USBIDLE ;1 [10]
in x2, USBDDR ;1 [11]
cbr x2, USBMASK ;1 [12] set both pins to input
mov x3, x1 ;1 [13]
cbr x3, USBMASK ;1 [14] configure no pullup on both pins
out USBOUT, x1 ;1 [15] <-- out J (idle) -- end of SE0 (EOP signal)
out USBDDR, x2 ;1 [16] <-- release bus now
out USBOUT, x3 ;1 [17] <-- ensure no pull-up resistors are active
ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
USB_STORE_PENDING(x2) ;[04]
ori x1, USBIDLE ;[05]
in x2, USBDDR ;[06]
cbr x2, USBMASK ;[07] set both pins to input
mov x3, x1 ;[08]
cbr x3, USBMASK ;[09] configure no pullup on both pins
pop x4 ;[10]
nop2 ;[12]
nop2 ;[14]
out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
out USBDDR, x2 ;[17] <-- release bus now
out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active
rjmp doReturn
bitstuff5: ;1 (for branch taken)
eor x1, x4 ;1
rjmp didStuff5 ;2 same trick as in bitstuff1...
bitstuff6: ;1 (for branch taken)
eor x1, x4 ;1
rjmp didStuff6 ;2 same trick as above...
bitstuff7: ;1 (for branch taken)
eor x1, x4 ;1
rjmp didStuff7 ;2 same trick as above...

@ -1,10 +1,10 @@
/* Name: usbdrvasm15.inc
* Project: AVR USB driver
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: contributed by V. Bosch
* Creation Date: 2007-08-06
* 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$
*/
@ -43,11 +43,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)
;-------------------------------------------------------------------------------
waitForJ: ;-
sbis USBIN, USBMINUS ;1 <-- sample: wait for D- == 1
rjmp waitForJ ;2
;The first part waits at most 1 bit long since we must be in sync pattern.
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
;waitForJ, ensure that this prerequisite is met.
waitForJ:
inc YL
sbis USBIN, USBMINUS
brne waitForJ ; just make sure we have ANY timeout
;-------------------------------------------------------------------------------
; The following code results in a sampling window of < 1/4 bit
; which meets the spec.
@ -70,6 +72,9 @@ waitForK: ;-
inc YL
sts usbSofCount, YL
#endif /* USB_COUNT_SOF */
#ifdef USB_SOF_HOOK
USB_SOF_HOOK
#endif
rjmp sofError
;------------------------------------------------------------------------------
; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for
@ -289,12 +294,12 @@ macro POP_STANDARD ; 16 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"

@ -1,10 +1,10 @@
/* Name: usbdrvasm16.inc
* Project: AVR USB driver
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2007-06-15
* 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$
*/
@ -41,10 +41,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]
@ -64,6 +67,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]
@ -111,12 +117,15 @@ haveTwoBitsK:
; Receiver loop (numbers in brackets are cycles within byte after instr)
;----------------------------------------------------------------------------
; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap"
; accordingly to approximate this value in the long run.
unstuff6:
andi x2, USBMASK ;[03]
ori x3, 1<<6 ;[04] will not be shifted any more
andi shift, ~0x80;[05]
mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit
subi leap, -1 ;[07] total duration = 11 bits -> 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"

@ -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"

Loading…
Cancel
Save