From 31ab89bbaedddefdaeadc14e3c4d61d1a7dc3d8a Mon Sep 17 00:00:00 2001 From: optixx Date: Tue, 9 Feb 2016 12:29:43 +0100 Subject: [PATCH] Add new vusb package --- packages/vusb-20121206/Changelog.txt | 329 ++++++++ packages/vusb-20121206/CommercialLicense.txt | 166 ++++ packages/vusb-20121206/License.txt | 361 +++++++++ packages/vusb-20121206/Makefile | 60 ++ packages/vusb-20121206/Readme.txt | 83 ++ packages/vusb-20121206/USB-ID-FAQ.txt | 149 ++++ packages/vusb-20121206/USB-IDs-for-free.txt | 154 ++++ packages/vusb-20121206/circuits/Readme.txt | 79 ++ packages/vusb-20121206/circuits/tiny45-rc.png | Bin 0 -> 7582 bytes packages/vusb-20121206/circuits/tiny45-rc.sch | Bin 0 -> 193502 bytes .../circuits/with-series-diodes.png | Bin 0 -> 12316 bytes .../circuits/with-series-diodes.sch | Bin 0 -> 213956 bytes packages/vusb-20121206/circuits/with-vreg.png | Bin 0 -> 13073 bytes packages/vusb-20121206/circuits/with-vreg.sch | Bin 0 -> 215922 bytes .../vusb-20121206/circuits/with-zener.png | Bin 0 -> 12364 bytes .../vusb-20121206/circuits/with-zener.sch | Bin 0 -> 225497 bytes packages/vusb-20121206/examples/Readme.txt | 102 +++ .../examples/custom-class/Readme.txt | 64 ++ .../custom-class/commandline/Makefile | 47 ++ .../custom-class/commandline/Makefile.windows | 17 + .../custom-class/commandline/opendevice.c | 202 +++++ .../custom-class/commandline/opendevice.h | 76 ++ .../custom-class/commandline/set-led.c | 134 ++++ .../examples/custom-class/firmware/Makefile | 163 ++++ .../examples/custom-class/firmware/main.c | 96 +++ .../examples/custom-class/firmware/requests.h | 35 + .../custom-class/firmware/usbconfig.h | 381 +++++++++ .../examples/hid-custom-rq/Readme.txt | 28 + .../hid-custom-rq/commandline/Makefile | 47 ++ .../commandline/Makefile.windows | 17 + .../hid-custom-rq/commandline/opendevice.c | 202 +++++ .../hid-custom-rq/commandline/opendevice.h | 76 ++ .../hid-custom-rq/commandline/set-led.c | 134 ++++ .../examples/hid-custom-rq/firmware/Makefile | 163 ++++ .../examples/hid-custom-rq/firmware/main.c | 119 +++ .../hid-custom-rq/firmware/requests.h | 31 + .../hid-custom-rq/firmware/usbconfig.h | 381 +++++++++ .../examples/hid-data/Readme.txt | 75 ++ .../examples/hid-data/commandline/Makefile | 41 + .../hid-data/commandline/Makefile.windows | 17 + .../examples/hid-data/commandline/hiddata.c | 323 ++++++++ .../examples/hid-data/commandline/hiddata.h | 70 ++ .../examples/hid-data/commandline/hidsdi.h | 48 ++ .../examples/hid-data/commandline/hidtool.c | 126 +++ .../examples/hid-data/firmware/Makefile | 163 ++++ .../examples/hid-data/firmware/main.c | 140 ++++ .../examples/hid-data/firmware/usbconfig.h | 381 +++++++++ .../examples/hid-mouse/Readme.txt | 48 ++ .../examples/hid-mouse/firmware/Makefile | 163 ++++ .../examples/hid-mouse/firmware/main.c | 163 ++++ .../examples/hid-mouse/firmware/usbconfig.h | 381 +++++++++ .../vusb-20121206/examples/usbtool/Makefile | 47 ++ .../examples/usbtool/Makefile.windows | 17 + .../vusb-20121206/examples/usbtool/Readme.txt | 209 +++++ .../examples/usbtool/opendevice.c | 202 +++++ .../examples/usbtool/opendevice.h | 76 ++ .../vusb-20121206/examples/usbtool/usbtool.c | 355 +++++++++ packages/vusb-20121206/libs-device/Readme.txt | 22 + packages/vusb-20121206/libs-device/osccal.c | 62 ++ packages/vusb-20121206/libs-device/osccal.h | 62 ++ packages/vusb-20121206/libs-device/osctune.h | 87 ++ packages/vusb-20121206/libs-host/Readme.txt | 26 + packages/vusb-20121206/libs-host/hiddata.c | 323 ++++++++ packages/vusb-20121206/libs-host/hiddata.h | 70 ++ packages/vusb-20121206/libs-host/hidsdi.h | 48 ++ packages/vusb-20121206/libs-host/opendevice.c | 202 +++++ packages/vusb-20121206/libs-host/opendevice.h | 76 ++ packages/vusb-20121206/tests/Makefile | 126 +++ packages/vusb-20121206/tests/Readme.txt | 13 + .../vusb-20121206/tests/compare-sizes.awk | 44 + packages/vusb-20121206/tests/main.c | 158 ++++ packages/vusb-20121206/tests/null.c | 25 + .../sizes-20080418-gcc3.4.6.txt | 13 + .../sizes-20080418-gcc4.2.2.txt | 13 + .../sizes-20080513-gcc3.4.6.txt | 15 + .../sizes-20080513-gcc4.3.0.txt | 15 + .../sizes-20081022-gcc3.4.6.txt | 16 + .../sizes-20081022-gcc4.3.0.txt | 16 + .../sizes-20081126-gcc3.4.6.txt | 16 + .../sizes-20081126-gcc4.3.0.txt | 16 + .../sizes-20090323-gcc3.4.6.txt | 17 + .../sizes-20090323-gcc4.3.2.txt | 17 + .../sizes-20090415-gcc3.4.6.txt | 17 + .../sizes-20090415-gcc4.3.2.txt | 17 + .../sizes-20100715-gcc3.4.6.txt | 17 + .../sizes-20100715-gcc4.3.3.txt | 17 + .../sizes-20120109-gcc3.4.6.txt | 17 + .../sizes-20120109-gcc4.3.3.txt | 17 + .../sizes-20121206-gcc4.6.2.txt | 17 + packages/vusb-20121206/tests/usbconfig.h | 295 +++++++ packages/vusb-20121206/usbdrv/Changelog.txt | 329 ++++++++ .../usbdrv/CommercialLicense.txt | 166 ++++ packages/vusb-20121206/usbdrv/License.txt | 361 +++++++++ packages/vusb-20121206/usbdrv/Readme.txt | 172 ++++ packages/vusb-20121206/usbdrv/USB-ID-FAQ.txt | 149 ++++ .../vusb-20121206/usbdrv/USB-IDs-for-free.txt | 154 ++++ packages/vusb-20121206/usbdrv/asmcommon.inc | 187 +++++ packages/vusb-20121206/usbdrv/oddebug.c | 49 ++ packages/vusb-20121206/usbdrv/oddebug.h | 122 +++ .../usbdrv/usbconfig-prototype.h | 384 +++++++++ packages/vusb-20121206/usbdrv/usbdrv.c | 628 +++++++++++++++ packages/vusb-20121206/usbdrv/usbdrv.h | 746 +++++++++++++++++ packages/vusb-20121206/usbdrv/usbdrvasm.S | 392 +++++++++ packages/vusb-20121206/usbdrv/usbdrvasm.asm | 20 + packages/vusb-20121206/usbdrv/usbdrvasm12.inc | 392 +++++++++ .../vusb-20121206/usbdrv/usbdrvasm128.inc | 749 ++++++++++++++++++ packages/vusb-20121206/usbdrv/usbdrvasm15.inc | 422 ++++++++++ packages/vusb-20121206/usbdrv/usbdrvasm16.inc | 345 ++++++++ .../vusb-20121206/usbdrv/usbdrvasm165.inc | 452 +++++++++++ .../vusb-20121206/usbdrv/usbdrvasm18-crc.inc | 706 +++++++++++++++++ packages/vusb-20121206/usbdrv/usbdrvasm20.inc | 359 +++++++++ .../vusb-20121206/usbdrv/usbportability.h | 143 ++++ 112 files changed, 16280 insertions(+) create mode 100644 packages/vusb-20121206/Changelog.txt create mode 100644 packages/vusb-20121206/CommercialLicense.txt create mode 100644 packages/vusb-20121206/License.txt create mode 100644 packages/vusb-20121206/Makefile create mode 100644 packages/vusb-20121206/Readme.txt create mode 100644 packages/vusb-20121206/USB-ID-FAQ.txt create mode 100644 packages/vusb-20121206/USB-IDs-for-free.txt create mode 100644 packages/vusb-20121206/circuits/Readme.txt create mode 100644 packages/vusb-20121206/circuits/tiny45-rc.png create mode 100644 packages/vusb-20121206/circuits/tiny45-rc.sch create mode 100644 packages/vusb-20121206/circuits/with-series-diodes.png create mode 100644 packages/vusb-20121206/circuits/with-series-diodes.sch create mode 100644 packages/vusb-20121206/circuits/with-vreg.png create mode 100644 packages/vusb-20121206/circuits/with-vreg.sch create mode 100644 packages/vusb-20121206/circuits/with-zener.png create mode 100644 packages/vusb-20121206/circuits/with-zener.sch create mode 100644 packages/vusb-20121206/examples/Readme.txt create mode 100644 packages/vusb-20121206/examples/custom-class/Readme.txt create mode 100644 packages/vusb-20121206/examples/custom-class/commandline/Makefile create mode 100644 packages/vusb-20121206/examples/custom-class/commandline/Makefile.windows create mode 100644 packages/vusb-20121206/examples/custom-class/commandline/opendevice.c create mode 100644 packages/vusb-20121206/examples/custom-class/commandline/opendevice.h create mode 100644 packages/vusb-20121206/examples/custom-class/commandline/set-led.c create mode 100644 packages/vusb-20121206/examples/custom-class/firmware/Makefile create mode 100644 packages/vusb-20121206/examples/custom-class/firmware/main.c create mode 100644 packages/vusb-20121206/examples/custom-class/firmware/requests.h create mode 100644 packages/vusb-20121206/examples/custom-class/firmware/usbconfig.h create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/Readme.txt create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile.windows create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.c create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.h create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/commandline/set-led.c create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/firmware/Makefile create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/firmware/main.c create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/firmware/requests.h create mode 100644 packages/vusb-20121206/examples/hid-custom-rq/firmware/usbconfig.h create mode 100644 packages/vusb-20121206/examples/hid-data/Readme.txt create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/Makefile create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/Makefile.windows create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/hiddata.c create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/hiddata.h create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/hidsdi.h create mode 100644 packages/vusb-20121206/examples/hid-data/commandline/hidtool.c create mode 100644 packages/vusb-20121206/examples/hid-data/firmware/Makefile create mode 100644 packages/vusb-20121206/examples/hid-data/firmware/main.c create mode 100644 packages/vusb-20121206/examples/hid-data/firmware/usbconfig.h create mode 100644 packages/vusb-20121206/examples/hid-mouse/Readme.txt create mode 100644 packages/vusb-20121206/examples/hid-mouse/firmware/Makefile create mode 100644 packages/vusb-20121206/examples/hid-mouse/firmware/main.c create mode 100644 packages/vusb-20121206/examples/hid-mouse/firmware/usbconfig.h create mode 100644 packages/vusb-20121206/examples/usbtool/Makefile create mode 100644 packages/vusb-20121206/examples/usbtool/Makefile.windows create mode 100644 packages/vusb-20121206/examples/usbtool/Readme.txt create mode 100644 packages/vusb-20121206/examples/usbtool/opendevice.c create mode 100644 packages/vusb-20121206/examples/usbtool/opendevice.h create mode 100644 packages/vusb-20121206/examples/usbtool/usbtool.c create mode 100644 packages/vusb-20121206/libs-device/Readme.txt create mode 100644 packages/vusb-20121206/libs-device/osccal.c create mode 100644 packages/vusb-20121206/libs-device/osccal.h create mode 100644 packages/vusb-20121206/libs-device/osctune.h create mode 100644 packages/vusb-20121206/libs-host/Readme.txt create mode 100644 packages/vusb-20121206/libs-host/hiddata.c create mode 100644 packages/vusb-20121206/libs-host/hiddata.h create mode 100644 packages/vusb-20121206/libs-host/hidsdi.h create mode 100644 packages/vusb-20121206/libs-host/opendevice.c create mode 100644 packages/vusb-20121206/libs-host/opendevice.h create mode 100644 packages/vusb-20121206/tests/Makefile create mode 100644 packages/vusb-20121206/tests/Readme.txt create mode 100755 packages/vusb-20121206/tests/compare-sizes.awk create mode 100644 packages/vusb-20121206/tests/main.c create mode 100644 packages/vusb-20121206/tests/null.c create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc4.2.2.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc4.3.0.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc4.3.0.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc4.3.0.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc4.3.2.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc4.3.2.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc4.3.3.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc3.4.6.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc4.3.3.txt create mode 100644 packages/vusb-20121206/tests/sizes-reference/sizes-20121206-gcc4.6.2.txt create mode 100644 packages/vusb-20121206/tests/usbconfig.h create mode 100644 packages/vusb-20121206/usbdrv/Changelog.txt create mode 100644 packages/vusb-20121206/usbdrv/CommercialLicense.txt create mode 100644 packages/vusb-20121206/usbdrv/License.txt create mode 100644 packages/vusb-20121206/usbdrv/Readme.txt create mode 100644 packages/vusb-20121206/usbdrv/USB-ID-FAQ.txt create mode 100644 packages/vusb-20121206/usbdrv/USB-IDs-for-free.txt create mode 100644 packages/vusb-20121206/usbdrv/asmcommon.inc create mode 100644 packages/vusb-20121206/usbdrv/oddebug.c create mode 100644 packages/vusb-20121206/usbdrv/oddebug.h create mode 100644 packages/vusb-20121206/usbdrv/usbconfig-prototype.h create mode 100644 packages/vusb-20121206/usbdrv/usbdrv.c create mode 100644 packages/vusb-20121206/usbdrv/usbdrv.h create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm.S create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm.asm create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm12.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm128.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm15.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm16.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm165.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm18-crc.inc create mode 100644 packages/vusb-20121206/usbdrv/usbdrvasm20.inc create mode 100644 packages/vusb-20121206/usbdrv/usbportability.h diff --git a/packages/vusb-20121206/Changelog.txt b/packages/vusb-20121206/Changelog.txt new file mode 100644 index 0000000..79b5215 --- /dev/null +++ b/packages/vusb-20121206/Changelog.txt @@ -0,0 +1,329 @@ +This file documents changes in the firmware-only USB driver for atmel's AVR +microcontrollers. New entries are always appended to the end of the file. +Scroll down to the bottom to see the most recent changes. + +2005-04-01: + - Implemented endpoint 1 as interrupt-in endpoint. + - Moved all configuration options to usbconfig.h which is not part of the + driver. + - Changed interface for usbVendorSetup(). + - Fixed compatibility with ATMega8 device. + - Various minor optimizations. + +2005-04-11: + - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() + and usbFunctionWrite() now. Added configuration options to choose which + of these functions to compile in. + - Assembler module delivers receive data non-inverted now. + - Made register and bit names compatible with more AVR devices. + +2005-05-03: + - Allow address of usbRxBuf on any memory page as long as the buffer does + not cross 256 byte page boundaries. + - Better device compatibility: works with Mega88 now. + - Code optimization in debugging module. + - Documentation updates. + +2006-01-02: + - Added (free) default Vendor- and Product-IDs bought from voti.nl. + - Added USBID-License.txt file which defines the rules for using the free + shared VID/PID pair. + - Added Readme.txt to the usbdrv directory which clarifies administrative + issues. + +2006-01-25: + - Added "configured state" to become more standards compliant. + - Added "HALT" state for interrupt endpoint. + - Driver passes the "USB Command Verifier" test from usb.org now. + - Made "serial number" a configuration option. + - Minor optimizations, we now recommend compiler option "-Os" for best + results. + - Added a version number to usbdrv.h + +2006-02-03: + - New configuration variable USB_BUFFER_SECTION for the memory section where + the USB rx buffer will go. This defaults to ".bss" if not defined. Since + this buffer MUST NOT cross 256 byte pages (not even touch a page at the + end), the user may want to pass a linker option similar to + "-Wl,--section-start=.mybuffer=0x800060". + - Provide structure for usbRequest_t. + - New defines for USB constants. + - Prepared for HID implementations. + - Increased data size limit for interrupt transfers to 8 bytes. + - New macro usbInterruptIsReady() to query interrupt buffer state. + +2006-02-18: + - Ensure that the data token which is sent as an ack to an OUT transfer is + always zero sized. This fixes a bug where the host reports an error after + sending an out transfer to the device, although all data arrived at the + device. + - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite(). + +* Release 2006-02-20 + + - Give a compiler warning when compiling with debugging turned on. + - Added Oleg Semyonov's changes for IAR-cc compatibility. + - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect() + (also thanks to Oleg!). + - Rearranged tests in usbPoll() to save a couple of instructions in the most + likely case that no actions are pending. + - We need a delay between the SET ADDRESS request until the new address + becomes active. This delay was handled in usbPoll() until now. Since the + spec says that the delay must not exceed 2ms, previous versions required + aggressive polling during the enumeration phase. We have now moved the + handling of the delay into the interrupt routine. + - We must not reply with NAK to a SETUP transaction. We can only achieve this + by making sure that the rx buffer is empty when SETUP tokens are expected. + We therefore don't pass zero sized data packets from the status phase of + a transfer to usbPoll(). This change MAY cause troubles if you rely on + receiving a less than 8 bytes long packet in usbFunctionWrite() to + identify the end of a transfer. usbFunctionWrite() will NEVER be called + with a zero length. + +* Release 2006-03-14 + + - Improved IAR C support: tiny memory model, more devices + - Added template usbconfig.h file under the name usbconfig-prototype.h + +* Release 2006-03-26 + + - Added provision for one more interrupt-in endpoint (endpoint 3). + - Added provision for one interrupt-out endpoint (endpoint 1). + - Added flowcontrol macros for USB. + - Added provision for custom configuration descriptor. + - Allow ANY two port bits for D+ and D-. + - Merged (optional) receive endpoint number into global usbRxToken variable. + - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the + variable name from the single port letter instead of computing the address + of related ports from the output-port address. + +* Release 2006-06-26 + + - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the + new features. + - Removed "#warning" directives because IAR does not understand them. Use + unused static variables instead to generate a warning. + - Do not include when compiling with IAR. + - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each + USB descriptor should be handled. It is now possible to provide descriptor + data in Flash, RAM or dynamically at runtime. + - STALL is now a status in usbTxLen* instead of a message. We can now conform + to the spec and leave the stall status pending until it is cleared. + - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the + application code to reset data toggling on interrupt pipes. + +* Release 2006-07-18 + + - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes + an assembler error. + - usbDeviceDisconnect() takes pull-up resistor to high impedance now. + +* Release 2007-02-01 + + - Merged in some code size improvements from usbtiny (thanks to Dick + Streefland for these optimizations!) + - Special alignment requirement for usbRxBuf not required any more. Thanks + again to Dick Streefland for this hint! + - Reverted to "#warning" instead of unused static variables -- new versions + of IAR CC should handle this directive. + - Changed Open Source license to GNU GPL v2 in order to make linking against + other free libraries easier. We no longer require publication of the + circuit diagrams, but we STRONGLY encourage it. If you improve the driver + itself, PLEASE grant us a royalty free license to your changes for our + commercial license. + +* Release 2007-03-29 + + - New configuration option "USB_PUBLIC" in usbconfig.h. + - Set USB version number to 1.10 instead of 1.01. + - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and + USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences + to USB_CFG_DESCR_PROPS_STRING_PRODUCT. + - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver + code. + - New assembler module for 16 MHz crystal. + - usbdrvasm.S contains common code only, clock-specific parts have been moved + to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. + +* Release 2007-06-25 + + - 16 MHz module: Do SE0 check in stuffed bits as well. + +* Release 2007-07-07 + + - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary + for negative values. + - Added 15 MHz module contributed by V. Bosch. + - Interrupt vector name can now be configured. This is useful if somebody + wants to use a different hardware interrupt than INT0. + +* Release 2007-08-07 + + - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is + not exceeded. + - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, + USB_COUNT_SOF + - USB_INTR_PENDING can now be a memory address, not just I/O + +* Release 2007-09-19 + + - Split out common parts of assembler modules into separate include file + - Made endpoint numbers configurable so that given interface definitions + can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. + - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() + can handle any number of endpoints. + - Define usbDeviceConnect() and usbDeviceDisconnect() even if no + USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this + case. + +* Release 2007-12-01 + + - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size + when USB_CFG_PULLUP_IOPORTNAME is not defined. + +* Release 2007-12-13 + + - Renamed all include-only assembler modules from *.S to *.inc so that + people don't add them to their project sources. + - Distribute leap bits in tx loop more evenly for 16 MHz module. + - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR + - Avoid compiler warnings for constant expr range by casting some values in + USB descriptors. + +* Release 2008-01-21 + + - Fixed bug in 15 and 16 MHz module where the new address set with + SET_ADDRESS was already accepted at the next NAK or ACK we send, not at + the next data packet we send. This caused problems when the host polled + too fast. Thanks to Alexander Neumann for his help and patience debugging + this issue! + +* Release 2008-02-05 + + - Fixed bug in 16.5 MHz module where a register was used in the interrupt + handler before it was pushed. This bug was introduced with version + 2007-09-19 when common parts were moved to a separate file. + - Optimized CRC routine (thanks to Reimar Doeffinger). + +* Release 2008-02-16 + + - Removed outdated IAR compatibility stuff (code sections). + - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). + - Added optional routine usbMeasureFrameLength() for calibration of the + internal RC oscillator. + +* 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 + + - Define a separate (defined) type for usbMsgPtr so that projects using a + tiny memory model can define it to an 8 bit type in usbconfig.h. This + change also saves a couple of bytes when using a scalar 16 bit type. + - Inserted "const" keyword for all PROGMEM declarations because new GCC + requires it. + - Fixed problem with dependence of usbportability.h on usbconfig.h. This + problem occurred with IAR CC only. + - Prepared repository for github.com. + +* Release 2012-12-06 \ No newline at end of file diff --git a/packages/vusb-20121206/CommercialLicense.txt b/packages/vusb-20121206/CommercialLicense.txt new file mode 100644 index 0000000..de1a2b0 --- /dev/null +++ b/packages/vusb-20121206/CommercialLicense.txt @@ -0,0 +1,166 @@ +V-USB Driver Software License Agreement +Version 2012-07-09 + +THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN +ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING +THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. + + +1 DEFINITIONS + +1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, +Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. + +1.2 "You" shall mean the Licensee. + +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 V-USB. + +2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the +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 +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 (now flirc.tv, Inc.). 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 + +3.1 Number of Units. Only one of the following three definitions is +applicable. Which one is determined by the amount you pay to OBJECTIVE +DEVELOPMENT, see section 4 ("Payment") below. + +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 V-USB according to section 2 above in no +more than 150 hardware units. + +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 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 +such consent is obtained, you may permanently transfer this License to +another party. The recipient of such transfer must agree to all terms and +conditions of this Agreement. + +3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not +expressly granted. + +3.5 Non-Exclusive Rights. Your license rights under this Agreement are +non-exclusive. + +3.6 Third Party Rights. This Agreement cannot grant you rights controlled +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 V-USB will not pass certification because it does not +implement checksum verification and the microcontroller ports do not meet +the electrical specifications. + + +4 PAYMENT + +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/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 + +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. + + +6 TERM AND TERMINATION + +6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE +DEVELOPMENT may terminate this Agreement and revoke the granted license and +USB-IDs if you fail to comply with any of its terms and conditions. + +6.2 Survival of Terms. All provisions regarding secrecy, confidentiality +and limitation of liability shall survive termination of this agreement. + + +7 DISCLAIMER OF WARRANTY AND LIABILITY + +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 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. + +LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, +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 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 V-USB. + + +8 MISCELLANEOUS TERMS + +8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing +purposes that you entered into this agreement. + +8.2 Entire Agreement. This document represents the entire agreement between +OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by +an authorized representative of both, OBJECTIVE DEVELOPMENT and you. + +8.3 Severability. In case a provision of these terms and conditions should +be or become partly or entirely invalid, ineffective, or not executable, +the validity of all other provisions shall not be affected. + +8.4 Applicable Law. This agreement is governed by the laws of the Republic +of Austria. + +8.5 Responsible Courts. The responsible courts in Vienna/Austria will have +exclusive jurisdiction regarding all disputes in connection with this +agreement. + diff --git a/packages/vusb-20121206/License.txt b/packages/vusb-20121206/License.txt new file mode 100644 index 0000000..4460cfb --- /dev/null +++ b/packages/vusb-20121206/License.txt @@ -0,0 +1,361 @@ +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/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/vusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/packages/vusb-20121206/Makefile b/packages/vusb-20121206/Makefile new file mode 100644 index 0000000..a6eb8a5 --- /dev/null +++ b/packages/vusb-20121206/Makefile @@ -0,0 +1,60 @@ +# Name: Makefile +# Project: v-usb +# Author: Christian Starkjohann +# Creation Date: 2012-12-05 +# Tabsize: 4 +# Copyright: (c) 2012 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# This is the main Makefile. The two primary targets are "all", to build +# everything which can be built (except tests), and "clean" to remove all +# dependent files. In a repository clone, derived source files are generated +# and deleted as well. +# +# We distinguish between repository clones and source packages by the existence +# of make-files.sh scripts in various subdirectories. + + +all: + if [ ! -f examples/hid-mouse/firmware/Makefile ]; then \ + $(MAKE) files; \ + fi + if [ -n "$(uname -s | grep -i mingw)" ]; then \ + $(MAKE) windows; \ + else \ + $(MAKE) unix; \ + fi + +clean: + $(MAKE) unixclean + if cross-make.sh --help >/dev/null 2>&1; then \ + $(MAKE) windowsclean; \ + fi + $(MAKE) filesremove + + +unix unixclean: + target=$$(echo $@ | sed -e 's/unix//g'); \ + find . -mindepth 3 -name Makefile -print | while read i; do \ + dir=$$(dirname $$i); \ + dirname=$$(basename $$dir); \ + pushd $$dir >/dev/null; \ + if [ "$$dirname" = firmware -a -z "$$target" ]; then \ + if ! $(MAKE) hex; then break; fi; \ + else \ + if ! $(MAKE) $$target; then break; fi;\ + fi; \ + popd >/dev/null; \ + done + + +windows windowsclean: + target=$$(echo $@ | sed -e 's/windows//g'); \ + find . -mindepth 3 -name Makefile.windows -execdir cross-make.sh $$target \; ; \ + if [ -z "$$target" ]; then target=hex; fi; \ + find . -mindepth 2 -name firmware -exec sh -c "cd '{}'; $(MAKE) $$target" \; + +files filesremove: + target=$$(echo $@ | sed -e 's/files//g'); \ + find . -mindepth 2 -name make-files.sh -execdir ./make-files.sh $$target \; + diff --git a/packages/vusb-20121206/Readme.txt b/packages/vusb-20121206/Readme.txt new file mode 100644 index 0000000..84d27f9 --- /dev/null +++ b/packages/vusb-20121206/Readme.txt @@ -0,0 +1,83 @@ +This is the Readme file for V-USB and related code. V-USB is Objective +Development's firmware-only USB driver for Atmel's(r) AVR(r) microcontrollers. +For more information please visit http://www.obdev.at/vusb/. + +To avoid name confusion: This project was formerly known as AVR-USB. Due to +a trademark issue, it was renamed to V-USB in April 2009. + + +WHAT IS INCLUDED IN THIS PACKAGE? +================================= +This package consists of the device side USB driver firmware, library code +for device and host and fully working examples for device and host: + + Readme.txt .............. The file you are currently reading. + usbdrv .................. V-USB firmware, to be included in your project. + examples ................ Example code for device and host side. + libs-device ............. Useful code snippets for the device firmware. + libs-host ............... Useful code snippets for host-side drivers. + circuits ................ Example circuits using this driver. + Changelog.txt ........... Documentation of changes between versions. + License.txt ............. Free Open Source license for this package (GPL). + CommercialLicense.txt ... Alternative commercial license for this package. + 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. + +Each subdirectory contains a separate Readme file which explains its +contents. We recommend that you also read the Readme.txt file in the +usbdrv subdirectory. + + +PREREQUISITES +============= +The AVR code of V-USB is written in C and assembler. You need either +avr-gcc or IAR CC to compile the project. We recommend avr-gcc because it +is free and easily available. Gcc version 3 generates slightly more +efficient code than version 4 for V-USB. Not every release is tested with +the IAR compiler. Previous versions have been tested with IAR 4.10B/W32 and +4.12A/W32 on an ATmega8 with the "small" and "tiny" memory model. + +Ready made avr-gcc tool chains are available for most operating systems: + * Windows: WinAVR http://winavr.sourceforge.net/ + * Mac: CrossPack for AVR Development http://www.obdev.at/crosspack/ + * Linux and other Unixes: Most free Unixes have optional packages for AVR + development. If not, follow the instructions at + http://www.nongnu.org/avr-libc/user-manual/install_tools.html + +Our host side examples are compiled with gcc on all platforms. Gcc is the +default C compiler on Mac, Linux and many other Unixes. On windows, we +recommend MinGW (http://www.mingw.org/). Use the automated MinGW installer +for least troubles. You also need MSYS from the same site to work with +standard Makefiles. + +Most examples also depend on libusb. Libusb is available from +http://libusb.sourceforge.net/ for Unix and +http://libusb-win32.sourceforge.net/ for Windows. + + +TECHNICAL DOCUMENTATION +======================= +The API reference of the driver firmware can be found in usbdrv/usbdrv.h. +Documentation for host and device library files are in the respective header +files. For more information, see our documentation wiki at +http://www.obdev.at/goto.php?t=vusb-wiki. + +See the file usbdrv/Readme.txt for more info about the driver itself. + + +LICENSE +======= +V-USB and related code is distributed under the terms of the GNU General +Public License (GPL) version 2 (see License.txt for details) and the GNU +General Public License (GPL) version 3. It is your choice whether you apply +the terms of version 2 or version 3. In addition to the terms of the GPL, we +strongly encourage you to publish your entire project and mail OBJECTIVE +DEVELOPMENT a link to your publication. + +Alternatively, we offer a commercial license without the restrictions of the +GPL. See CommercialLicense.txt for details. + + +---------------------------------------------------------------------------- +(c) 2010 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/USB-ID-FAQ.txt b/packages/vusb-20121206/USB-ID-FAQ.txt new file mode 100644 index 0000000..a4a6bd6 --- /dev/null +++ b/packages/vusb-20121206/USB-ID-FAQ.txt @@ -0,0 +1,149 @@ +Version 2012-07-09 + +========================== +WHY DO WE NEED THESE IDs? +========================== + +USB is more than a low level protocol for data transport. It also defines a +common set of requests which must be understood by all devices. And as part +of these common requests, the specification defines data structures, the +USB Descriptors, which are used to describe the properties of the device. + +From the perspective of an operating system, it is therefore possible to find +out basic properties of a device (such as e.g. the manufacturer and the name +of the device) without a device-specific driver. This is essential because +the operating system can choose a driver to load based on this information +(Plug-And-Play). + +Among the most important properties in the Device Descriptor are the USB +Vendor- and Product-ID. Both are 16 bit integers. The most simple form of +driver matching is based on these IDs. The driver announces the Vendor- and +Product-IDs of the devices it can handle and the operating system loads the +appropriate driver when the device is connected. + +It is obvious that this technique only works if the pair Vendor- plus +Product-ID is unique: Only devices which require the same driver can have the +same pair of IDs. + + +===================================================== +HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? +===================================================== + +Since it is so important that USB IDs are unique, the USB Implementers Forum, +Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by +law to build a device and assign it any random numbers as IDs. Usb.org +therefore needs an agreement to regulate the use of USB IDs. The agreement +binds only parties who agreed to it, of course. Everybody else is free to use +any numbers for their IDs. + +So how can usb.org ensure that every manufacturer of USB devices enters into +an agreement with them? They do it via trademark licensing. Usb.org has +registered the trademark "USB", all associated logos and related terms. If +you want to put an USB logo on your product or claim that it is USB +compliant, you must license these trademarks from usb.org. And this is where +you enter into an agreement. See the "USB-IF Trademark License Agreement and +Usage Guidelines for the USB-IF Logo" at +http://www.usb.org/developers/logo_license/. + +Licensing the USB trademarks requires that you buy a USB Vendor-ID from +usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org +(yearly fee of ca. 4,000 USD) and that you meet all the technical +specifications from the USB spec. + +This means that most hobbyists and small companies will never be able to +become USB compliant, just because membership is so expensive. And you can't +be compliant with a driver based on V-USB anyway, because the AVR's port pins +don't meet the electrical specifications for USB. So, in principle, all +hobbyists and small companies are free to choose any random numbers for their +IDs. They have nothing to lose... + +There is one exception worth noting, though: If you use a sub-component which +implements USB, the vendor of the sub-components may guarantee USB +compliance. This might apply to some or all of FTDI's solutions. + + +======================================================================= +WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? +======================================================================= + +You have learned in the previous section that you are free to choose any +numbers for your IDs anyway. So why not do exactly this? There is still the +technical issue. If you choose IDs which are already in use by somebody else, +operating systems will load the wrong drivers and your device won't work. +Even if you choose IDs which are not currently in use, they may be in use in +the next version of the operating system or even after an automatic update. + +So what you need is a pair of Vendor- and Product-IDs for which you have the +guarantee that no USB compliant product uses them. This implies that no +operating system will ever ship with drivers responsible for these IDs. + + +============================================== +HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? +============================================== + +Objective Development gives away pairs of USB-IDs with their V-USB licenses. +In order to ensure that these IDs are unique, Objective Development has an +agreement with the company/person who has bought the USB Vendor-ID from +usb.org. This agreement ensures that a range of USB Product-IDs is reserved +for assignment by Objective Development and that the owner of the Vendor-ID +won't give it to anybody else. + +This means that you have to trust three parties to ensure uniqueness of +your IDs: + + - Objective Development, that they don't give the same PID to more than + one person. + - The owner of the Vendor-ID that they don't assign PIDs from the range + assigned to Objective Development to anybody else. + - Usb.org that they don't assign the same Vendor-ID a second time. + + +================================== +WHO IS THE OWNER OF THE VENDOR-ID? +================================== + +Objective Development has obtained ranges of USB Product-IDs under two +Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen +Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason +Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID +directly from usb.org. + + +========================================================================= +CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? +========================================================================= + +The short answer is: Yes. All you get is a guarantee that the IDs are never +assigned to anybody else. What more do you need? + + +============================ +WHAT ABOUT SHARED ID PAIRS? +============================ + +Objective Development has reserved some PID/VID pairs for shared use. You +have no guarantee of uniqueness for them, except that no USB compliant device +uses them. In order to avoid technical problems, we must ensure that all +devices with the same pair of IDs use the same driver on kernel level. For +details, see the file USB-IDs-for-free.txt. + + +====================================================== +I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? +====================================================== + +A 16 bit integer number cannot be protected by copyright laws. It is not +sufficiently complex. And since none of the parties involved entered into the +USB-IF Trademark License Agreement, we are not bound by this agreement. So +there is no reason why it should be illegal to sub-license USB-IDs. + + +============================================= +WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? +============================================= + +Objective Development disclaims all liabilities which might arise from the +assignment of IDs. If you guarantee product features to your customers +without proper disclaimer, YOU are liable for that. diff --git a/packages/vusb-20121206/USB-IDs-for-free.txt b/packages/vusb-20121206/USB-IDs-for-free.txt new file mode 100644 index 0000000..d46517d --- /dev/null +++ b/packages/vusb-20121206/USB-IDs-for-free.txt @@ -0,0 +1,154 @@ +Version 2009-08-22 + +=========================== +FREE USB-IDs FOR SHARED USE +=========================== + +Objective Development has reserved a set of USB Product-IDs for use according +to the guidelines outlined below. For more information about the concept of +USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees +that the IDs listed below are not used by any USB compliant devices. + + +==================== +MECHANISM OF SHARING +==================== + +From a technical point of view, two different devices can share the same USB +Vendor- and Product-ID if they require the same driver on operating system +level. We make use of this fact by assigning separate IDs for various device +classes. On application layer, devices must be distinguished by their textual +name or serial number. We offer separate sets of IDs for discrimination by +textual name and for serial number. + +Examples for shared use of USB IDs are included with V-USB in the "examples" +subdirectory. + + +====================================== +IDs FOR DISCRIMINATION BY TEXTUAL NAME +====================================== + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the manufacturer +and product identification. The manufacturer identification MUST be available +at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail +address under your control (e.g. "myname@gmx.net"). You can embed the domain +name or e-mail address in any string you like, e.g. "Objective Development +http://www.obdev.at/vusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as long +as this string is unique within the scope of your textual manufacturer +identification. + +(5) Application side device look-up MUST be based on the textual manufacturer +and product identification in addition to VID/PID matching. The driver +matching MUST be a comparison of the entire strings, NOT a sub-string match. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +Table if IDs for discrimination by textual name: + +PID dec (hex) | VID dec (hex) | Description of use +==============+===============+============================================ +1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb +--------------+---------------+-------------------------------------------- +1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +--------------+---------------+-------------------------------------------- +1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +--------------+---------------+-------------------------------------------- +1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices +--------------+---------------+-------------------------------------------- + +Note that Windows caches the textual product- and vendor-description for +mice, keyboards and joysticks. Name-bsed discrimination is therefore not +recommended for these device classes. + + +======================================= +IDs FOR DISCRIMINATION BY SERIAL NUMBER +======================================= + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the serial +number, unless ONLY the operating system's default class driver is used. +The serial number string MUST be available at least in USB language 0x0409 +(English/US). + +(2) The serial number MUST start with either an Internet domain name (e.g. +"mycompany.com") registered and owned by you, or an e-mail address under your +control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. +You MAY append any string you like for further discrimination of your devices. + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(5) Application side device look-up MUST be based on the serial number string +in addition to VID/PID matching. The matching must start at the first +character of the serial number string and include the colon character +terminating your domain or e-mail address. It MAY stop anywhere after that. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +(7) If ONLY the operating system's default class driver is used, e.g. for +mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an +application is needed, the serial number may be omitted. + + +Table if IDs for discrimination by serial number string: + +PID dec (hex) | VID dec (hex) | Description of use +===============+===============+=========================================== +10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb +---------------+---------------+------------------------------------------- +10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +---------------+---------------+------------------------------------------- +10202 (0x27da) | 5824 (0x16c0) | For USB Mice +---------------+---------------+------------------------------------------- +10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards +---------------+---------------+------------------------------------------- +10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks +---------------+---------------+------------------------------------------- +10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +---------------+---------------+------------------------------------------- +10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices +---------------+---------------+------------------------------------------- + + +================= +ORIGIN OF USB-IDs +================= + +OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed +here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. +Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. +(see www.usb.org). The VID is registered for the company name "Van Ooijen +Technische Informatica". + + +========== +DISCLAIMER +========== + +OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. diff --git a/packages/vusb-20121206/circuits/Readme.txt b/packages/vusb-20121206/circuits/Readme.txt new file mode 100644 index 0000000..1aa5218 --- /dev/null +++ b/packages/vusb-20121206/circuits/Readme.txt @@ -0,0 +1,79 @@ +This is the Readme file for the V-USB example circuits directory. + + +CIRCUITS IN THIS DIRECTORY +========================== +Since USB requires 3.3 V levels on D+ and D- but delivers a power supply of +ca. 5 V, some kind of level conversion must be performed. There are several +ways to implement this level conversion, see the example circuits below. + +with-vreg.png and with-vreg.sch (EAGLE schematics): + This circuit uses a low drop voltage regulator to reduce the USB supply to + 3.3 V. You MUST use a low drop regulator because standard regulators such + as the LM317 require at least ca. 2 V drop. The advantage of this approach + is that it comes closest to the voltage levels required by the USB + specification and that the circuit is powered from a regulated supply. If + no USB cable is used (connector directly soldered on PCB), you can even + omit the 68 Ohm series resistors. The disadvantage is that you may want to + use other chips in your design which require 5 V. Please check that the AVR + used in your design allows the chosen clock rate at 3.3 V. + +with-zener.png and with-zener.sch (EAGLE schematics): + This circuit enforces lower voltage levels on D+ and D- with zener diodes. + The zener diodes MUST be low power / low current types to ensure that the + 1k5 pull-up resistor on D- generates a voltage of well above 2.5 V (but + below 3.6 V). The advantage of this circuit is its simplicity and that the + circuit can be powered at 5 V (usually precise enough if the cable drop is + neglected). The disadvantage is that some zener diodes have a lower voltage + than 3 V when powered through 1k5 and the choice of components becomes + relevant. In addition to that, the power consumption during USB data + transfer is increased because the current is only limited by the 68 Ohm + series resistor. The zeners may even distort the signal waveforms due to + their capacity. + +with-series-diodes.png and with-series-diodes.sch (EAGLE schematics): + This is a simplified low-cost version of the voltage regulator approach. + Instead of using a voltage regulator, we reduce the voltage by the forward + voltage of two silicon diodes (roughly 1.4 V). This gives ca. 3.6 V which + is practically inside the allowed range. The big disadvantage is that the + supply is not regulated -- it even depends strongly on the power + consumption. This cannot be tolerated for analog circuits. + +tiny45-rc.png and tiny45-rc.sch (EAGLE schematics): + This is mostly an example for connecting an 8 pin device using the internal + RC oscillator for system clock. This example uses series diodes to limit + the supply, but you may choose any other method. Please note that you must + choose a clock rate of 12.8 or 16.5 MHz because only the receiver modules + for these frequencies have a PLL to allow higher clock rate tolerances. + + +GENERAL DESIGN NOTES +==================== +All examples have D+ on hardware interrupt INT0 because this is the highest +priority interrupt on AVRs. You may use other hardware interrupts (and +configure the options at the end of usbconfig.h accordingly) if you make sure +that no higher priority interrupt is used. + +If you use USB_SOF_HOOK or USB_COUNT_SOF in usbconfig.h, you must wire D- to +the interrupt instead. This way the interrupt is triggered on USB Start Of +Frame pulses as well. + +Most examples have a 1M pull-down resistor at D+. This pull-up ensures that +in self-powered designs no interrupts occur while USB is not connected. You +may omit this resistor in bus-powered designs. Older examples had a pull-up +resistor instead. This is not compatible with the zener diode approach to +level conversion: 1M pull-up in conjunction with a 3.6 V zener diode give an +invalid logic level. + +All examples with ATMega8/88/168 have D+ at port D bit 2 (because this is +hardware interrupt 0) and D- on port D bit 4 because it is also a clock input +for timer/counter 0. This way the firmware can easily check for activity on +D- (USB frame pulses) by checking the counter value in regular intervals. If +no activity is found, the firmware should (according to the USB +specification) put the system into a low power suspend mode. + + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/circuits/tiny45-rc.png b/packages/vusb-20121206/circuits/tiny45-rc.png new file mode 100644 index 0000000000000000000000000000000000000000..ac97657a44f782a0e56088fb00e307fce6083860 GIT binary patch literal 7582 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 Qj#n8TYCqDd)Ub>BKYbiLV*mgE literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/tiny45-rc.sch b/packages/vusb-20121206/circuits/tiny45-rc.sch new file mode 100644 index 0000000000000000000000000000000000000000..349f1ad60c47e121ae2c0032259d379e03fbf397 GIT binary patch literal 193502 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 z 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 LTMN4R^~e7Q7Hst_ literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/with-series-diodes.sch b/packages/vusb-20121206/circuits/with-series-diodes.sch new file mode 100644 index 0000000000000000000000000000000000000000..d84d99e562a27e3f613511c6c9b340c9a9d59020 GIT binary patch literal 213956 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 J_OZ*^{|BitSq}gJ literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/with-vreg.png b/packages/vusb-20121206/circuits/with-vreg.png new file mode 100644 index 0000000000000000000000000000000000000000..eca79324fc1371ab2d2ed74eecac544f74b28886 GIT binary patch literal 13073 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%0AWN28f? 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 V(^t6}|7c-){7_3J`+@1F{{!z3m{$M* literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/with-vreg.sch b/packages/vusb-20121206/circuits/with-vreg.sch new file mode 100644 index 0000000000000000000000000000000000000000..1f1797bddb31bb9d52adee492dc6c75fc775c17f GIT binary patch literal 215922 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 =c(K5lb_W%CF6am+RL{;5Cs?fcR9t7lziemra4 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 literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/with-zener.png b/packages/vusb-20121206/circuits/with-zener.png new file mode 100644 index 0000000000000000000000000000000000000000..598441fb2e902efae32a47461078042437335bb4 GIT binary patch literal 12364 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 literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/circuits/with-zener.sch b/packages/vusb-20121206/circuits/with-zener.sch new file mode 100644 index 0000000000000000000000000000000000000000..624177a7d611271c2c008539e8a4022e0d94d4d1 GIT binary patch literal 225497 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 X-d^SaSSzP9!1B+ZjUVubLyi9c@AfUg literal 0 HcmV?d00001 diff --git a/packages/vusb-20121206/examples/Readme.txt b/packages/vusb-20121206/examples/Readme.txt new file mode 100644 index 0000000..82b10fe --- /dev/null +++ b/packages/vusb-20121206/examples/Readme.txt @@ -0,0 +1,102 @@ +This is the Readme file for the directory "examples" of V-USB, a firmware- +only USB driver for AVR microcontrollers. + +WHAT IS IN THIS DIRECTORY? +========================== +This directory contains examples which are mostly for educational purposes. +Examples can be device firmware only, host software only or both. Here is +a summary: + +custom-class + A custom class device with host software based on libusb. It demonstrates + the straight forward way of sending small amounts of data to a device and + receiving data from the device. It does NOT demonstrate how to send large + amounts of data to the device or how to receive data generated on the fly + by the device (how to use usbFunctionWrite() and usbFunctionRead()). See + the hid-data example for how usbFunctionWrite() and usbFunctionRead() are + used. + +hid-custom-rq + This example implements the same functionality as the custom-class example + above, but declares the device as HID. This prevents the "give me a driver + CD" dialog on Windows. The device can still be controlled with libusb as in + the previous example (on Windows, the filter version of libusb-win32 must + be installed). In addition to the features presented in custom-class, this + example demonstrates how a HID class device is defined. + +hid-mouse + This example implements a mouse device. No host driver is required since + today's operating systems have drivers for USB mice built-in. It + demonstrates how a real-world HID class device is implemented and how + interrupt-in endpoints are used. + +hid-data + This example demonstrates how the HID class can be misused to transfer + arbitrary data over HID feature reports. This technique is of great value + on Windows because no driver DLLs are needed (the hid-custom-rq example + still requires the libusb-win32 DLL, although it may be in the program's + directory). The host side application requires no installation, it can + even be started directly from a CD. This example also demonstrates how + to transfer data using usbFunctionWrite() and usbFunctionRead(). + +usbtool + This is a general purpose development and debugging tool for USB devices. + You can use it during development of your device to test various requests + without special test programs. But it is also an example how all the + libusb API functions are used. + +More information about each example can be found in the Readme file in the +respective directory. + +Hardware dependencies of AVR code has been kept at a minimum. All examples +should work on any AVR chip which has enough resources to run the driver. +Makefile and usbconfig.h have been configured for the metaboard hardware (see +http://www.obdev.at/goto.php?t=metaboard for details). Edit the target +device, fuse values, clock rate and programmer in Makefile and the I/O pins +dedicated to USB in usbconfig.h. + + +WHAT IS NOT DEMONSTRATED IN THESE EXAMPLES? +=========================================== +These examples show only the most basic functionality. More elaborate +examples and real world applications showing more features of the driver are +available at http://www.obdev.at/vusb/projects.html. Most of these +features are described in our documentation wiki at +http://www.obdev.at/goto.php?t=vusb-wiki. + +To mention just a few: + +Using RC oscillator for system clock + The 12.8 MHz and 16.5 MHz modules of V-USB have been designed to cope + with clock rate deviations up to 1%. This allows an RC oscillator to be + used. Since the AVR's RC oscillator has a factory precision of only 10%, + it must be calibrated to an external reference. The EasyLogger example + shows how this can be done. + +Dynamically generated descriptors + Sometimes you want to implement different typtes of USB device depending + on a jumper or other condition. V-USB has a very flexible interface for + providing USB descriptors. See AVR-Doper for how to provide descriptors + at runtime. + +Virtual COM port + Some people prefer a virtual serial interface to communicate with their + device. We strongly discourage this method because it does things + forbidden by the USB specification. If you still want to go this route, + see AVR-CDC. + +Implementing suspend mode + V-USB does not implement suspend mode. This means that the device does + not reduce power consumption when the host goes into sleep mode. Device + firmware is free to implement suspend mode, though. See USB2LPT for an + example. + +The projects mentioned above can best be found on + + http://www.obdev.at/vusb/prjall.html + +where all projects are listed. + +---------------------------------------------------------------------------- +(c) 2009 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/custom-class/Readme.txt b/packages/vusb-20121206/examples/custom-class/Readme.txt new file mode 100644 index 0000000..815518e --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/Readme.txt @@ -0,0 +1,64 @@ +This is the Readme file for the custom-class example. In this example, we +show how an LED can be controlled via USB. + + +WHAT IS DEMONSTRATED? +===================== +This example shows how small amounts of data (several bytes) can be +transferred between the device and the host. In addition to a very basic +USB device, it demonstrates how to build a host side driver application +using libusb or libusb-win32. It does NOT show how usbFunctionWrite() and +usbFunctionRead() are used. See the hid-data example if you want to learn +about these functions. + + +PREREQUISITES +============= +Target hardware: You need an AVR based circuit based on one of the examples +(see the "circuits" directory at the top level of this package), e.g. the +metaboard (http://www.obdev.at/goto.php?t=metaboard). + +AVR development environment: You need the gcc tool chain for the AVR, see +the Prerequisites section in the top level Readme file for how to obtain it. + +Host development environment: A C compiler and libusb. See the top level +Readme file, section Prerequisites for more information. + + +BUILDING THE FIRMWARE +===================== +Change to the "firmware" directory and modify Makefile according to your +architecture (CPU clock, target device, fuse values) and ISP programmer. Then +edit usbconfig.h according to your pin assignments for D+ and D-. The default +settings are for the metaboard hardware. You should have wired an LED with a +current limiting resistor of ca. 270 Ohm to a free I/O pin. Change the +defines in main.c to match the port and bit number. + +Type "make hex" to build main.hex, then "make flash" to upload the firmware +to the device. Don't forget to run "make fuse" once to program the fuses. If +you use a prototyping board with boot loader, follow the instructions of the +boot loader instead. + +Please note that the first "make hex" copies the driver from the top level +into the firmware directory. If you use a different build system than our +Makefile, you must copy the driver by hand. + + +BUILDING THE HOST SOFTWARE +========================== +Since the host software is based on libusb or libusb-win32, make sure that +this library is installed. On Unix, ensure that libusb-config is in your +search PATH. On Windows, edit Makefile.windows and set the library path +appropriately. Then type "make" on Unix or "make -f Makefile.windows" on +Windows to build the command line tool. + + +USING THE COMMAND LINE TOOL +=========================== +The command line tool has three valid arguments: "status" to query the +current LED status, "on" to turn on the LED and "off" to turn it off. + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/custom-class/commandline/Makefile b/packages/vusb-20121206/examples/custom-class/commandline/Makefile new file mode 100644 index 0000000..4d28373 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/commandline/Makefile @@ -0,0 +1,47 @@ +# Name: Makefile +# Project: custom-class example +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + + +# Concigure the following definitions according to your system. +# This Makefile has been tested on Mac OS X, Linux and Windows. + +# Use the following 3 lines on Unix (uncomment the framework on Mac OS X): +USBFLAGS = `libusb-config --cflags` +USBLIBS = `libusb-config --libs` +EXE_SUFFIX = + +# Use the following 3 lines on Windows and comment out the 3 above. You may +# have to change the include paths to where you installed libusb-win32 +#USBFLAGS = -I/usr/local/include +#USBLIBS = -L/usr/local/lib -lusb +#EXE_SUFFIX = .exe + +NAME = set-led + +OBJECTS = opendevice.o $(NAME).o + +CC = gcc +CFLAGS = $(CPPFLAGS) $(USBFLAGS) -O -g -Wall +LIBS = $(USBLIBS) + +PROGRAM = $(NAME)$(EXE_SUFFIX) + + +all: $(PROGRAM) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(PROGRAM): $(OBJECTS) + $(CC) -o $(PROGRAM) $(OBJECTS) $(LIBS) + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f *.o $(PROGRAM) diff --git a/packages/vusb-20121206/examples/custom-class/commandline/Makefile.windows b/packages/vusb-20121206/examples/custom-class/commandline/Makefile.windows new file mode 100644 index 0000000..c5d6a1f --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/commandline/Makefile.windows @@ -0,0 +1,17 @@ +# Name: Makefile.windows +# Project: custom-class example +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS = -I/usr/local/mingw/include +USBLIBS = -L/usr/local/mingw/lib -lusb +EXE_SUFFIX = .exe diff --git a/packages/vusb-20121206/examples/custom-class/commandline/opendevice.c b/packages/vusb-20121206/examples/custom-class/commandline/opendevice.c new file mode 100644 index 0000000..ea88e86 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/commandline/opendevice.c @@ -0,0 +1,202 @@ +/* Name: opendevice.c + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The functions in this module can be used to find and open a device based on +libusb or libusb-win32. +*/ + +#include +#include "opendevice.h" + +/* ------------------------------------------------------------------------- */ + +#define MATCH_SUCCESS 1 +#define MATCH_FAILED 0 +#define MATCH_ABORT -1 + +/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ +static int _shellStyleMatch(char *text, char *p) +{ +int last, matched, reverse; + + for(; *p; text++, p++){ + if(*text == 0 && *p != '*') + return MATCH_ABORT; + switch(*p){ + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if(*text != *p) + return MATCH_FAILED; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while(*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if(*p == 0) + /* Trailing star matches everything. */ + return MATCH_SUCCESS; + while(*text) + if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) + return matched; + return MATCH_ABORT; + case '[': + reverse = p[1] == '^'; + if(reverse) /* Inverted character class. */ + p++; + matched = MATCH_FAILED; + if(p[1] == ']' || p[1] == '-') + if(*++p == *text) + matched = MATCH_SUCCESS; + for(last = *p; *++p && *p != ']'; last = *p) + if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) + matched = MATCH_SUCCESS; + if(matched == reverse) + return MATCH_FAILED; + continue; + } + } + return *text == 0; +} + +/* public interface for shell style matching: returns 0 if fails, 1 if matches */ +static int shellStyleMatch(char *text, char *pattern) +{ + if(pattern == NULL) /* NULL pattern is synonymous to "*" */ + return 1; + return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +/* ------------------------------------------------------------------------- */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; + + usb_find_busses(); + usb_find_devices(); + for(bus = usb_get_busses(); bus; bus = bus->next){ + for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ + if((vendorID == 0 || dev->descriptor.idVendor == vendorID) + && (productID == 0 || dev->descriptor.idProduct == productID)){ + char vendor[256], product[256], serial[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + continue; + } + /* now check whether the names match: */ + len = vendor[0] = 0; + if(dev->descriptor.iManufacturer > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen device from vendor ->%s<-\n", vendor); */ + if(shellStyleMatch(vendor, vendorNamePattern)){ + len = product[0] = 0; + if(dev->descriptor.iProduct > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen product ->%s<-\n", product); */ + if(shellStyleMatch(product, productNamePattern)){ + len = serial[0] = 0; + if(dev->descriptor.iSerialNumber > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + } + if(shellStyleMatch(serial, serialNamePattern)){ + if(printMatchingDevicesFp != NULL){ + if(serial[0] == 0){ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); + }else{ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); + } + }else{ + break; + } + } + } + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) /* we have found a deice */ + break; + } + if(handle != NULL){ + errorCode = 0; + *device = handle; + } + if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ + errorCode = 0; + return errorCode; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/custom-class/commandline/opendevice.h b/packages/vusb-20121206/examples/custom-class/commandline/opendevice.h new file mode 100644 index 0000000..c925276 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/commandline/opendevice.h @@ -0,0 +1,76 @@ +/* Name: opendevice.h + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module offers additional functionality for host side drivers based on +libusb or libusb-win32. It includes a function to find and open a device +based on numeric IDs and textual description. It also includes a function to +obtain textual descriptions from a device. + +To use this functionality, simply copy opendevice.c and opendevice.h into your +project and add them to your Makefile. You may modify and redistribute these +files according to the GNU General Public License (GPL) version 2 or 3. +*/ + +#ifndef __OPENDEVICE_H_INCLUDED__ +#define __OPENDEVICE_H_INCLUDED__ + +#include /* this is libusb, see http://libusb.sourceforge.net/ */ +#include + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen); +/* This function gets a string descriptor from the device. 'index' is the + * string descriptor index. The string is returned in ISO Latin 1 encoding in + * 'buf' and it is terminated with a 0-character. The buffer size must be + * passed in 'buflen' to prevent buffer overflows. A libusb device handle + * must be given in 'dev'. + * Returns: The length of the string (excluding the terminating 0) or + * a negative number in case of an error. If there was an error, use + * usb_strerror() to obtain the error message. + */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp); +/* This function iterates over all devices on all USB busses and searches for + * a device. Matching is done first by means of Vendor- and Product-ID (passed + * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard). + * When a device matches by its IDs, matching by names is performed. Name + * matching can be done on textual vendor name ('vendorNamePattern'), product + * name ('productNamePattern') and serial number ('serialNamePattern'). A + * device matches only if all non-null pattern match. If you don't care about + * a string, pass NULL for the pattern. Patterns are Unix shell style pattern: + * '*' stands for 0 or more characters, '?' for one single character, a list + * of characters in square brackets for a single character from the list + * (dashes are allowed to specify a range) and if the lis of characters begins + * with a caret ('^'), it matches one character which is NOT in the list. + * Other parameters to the function: If 'warningsFp' is not NULL, warning + * messages are printed to this file descriptor with fprintf(). If + * 'printMatchingDevicesFp' is not NULL, no device is opened but matching + * devices are printed to the given file descriptor with fprintf(). + * If a device is opened, the resulting USB handle is stored in '*device'. A + * pointer to a "usb_dev_handle *" type variable must be passed here. + * Returns: 0 on success, an error code (see defines below) on failure. + */ + +/* usbOpenDevice() error codes: */ +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + + +/* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */ + +#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */ +#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */ +#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */ +#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */ +#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */ + +#endif /* __OPENDEVICE_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/custom-class/commandline/set-led.c b/packages/vusb-20121206/examples/custom-class/commandline/set-led.c new file mode 100644 index 0000000..fe0d75d --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/commandline/set-led.c @@ -0,0 +1,134 @@ +/* Name: set-led.c + * Project: custom-class, a basic USB example + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This is the host-side driver for the custom-class example device. It searches +the USB for the LEDControl device and sends the requests understood by this +device. +This program must be linked with libusb on Unix and libusb-win32 on Windows. +See http://libusb.sourceforge.net/ or http://libusb-win32.sourceforge.net/ +respectively. +*/ + +#include +#include +#include +#include /* this is libusb */ +#include "opendevice.h" /* common code moved to separate module */ + +#include "../firmware/requests.h" /* custom request numbers */ +#include "../firmware/usbconfig.h" /* device's VID/PID and names */ + +static void usage(char *name) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s on ....... turn on LED\n", name); + fprintf(stderr, " %s off ...... turn off LED\n", name); + fprintf(stderr, " %s status ... ask current status of LED\n", name); +#if ENABLE_TEST + fprintf(stderr, " %s test ..... run driver reliability test\n", name); +#endif /* ENABLE_TEST */ +} + +int main(int argc, char **argv) +{ +usb_dev_handle *handle = NULL; +const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID}; +char vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0}; +char buffer[4]; +int cnt, vid, pid, isOn; + + usb_init(); + if(argc < 2){ /* we need at least one argument */ + usage(argv[0]); + exit(1); + } + /* compute VID/PID from usbconfig.h so that there is a central source of information */ + vid = rawVid[1] * 256 + rawVid[0]; + pid = rawPid[1] * 256 + rawPid[0]; + /* The following function is in opendevice.c: */ + if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){ + fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid); + exit(1); + } + /* Since we use only control endpoint 0, we don't need to choose a + * configuration and interface. Reading device descriptor and setting a + * configuration and interface is done through endpoint 0 after all. + * However, newer versions of Linux require that we claim an interface + * even for endpoint 0. Enable the following code if your operating system + * needs it: */ +#if 0 + int retries = 1, usbConfiguration = 1, usbInterface = 0; + if(usb_set_configuration(handle, usbConfiguration) && showWarnings){ + fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); + } + /* now try to claim the interface and detach the kernel HID driver on + * Linux and other operating systems which support the call. */ + while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){ +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){ + fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror()); + } +#endif + } +#endif + + if(strcasecmp(argv[1], "status") == 0){ + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS, 0, 0, buffer, sizeof(buffer), 5000); + if(cnt < 1){ + if(cnt < 0){ + fprintf(stderr, "USB error: %s\n", usb_strerror()); + }else{ + fprintf(stderr, "only %d bytes received.\n", cnt); + } + }else{ + printf("LED is %s\n", buffer[0] ? "on" : "off"); + } + }else if((isOn = (strcasecmp(argv[1], "on") == 0)) || strcasecmp(argv[1], "off") == 0){ + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, isOn, 0, buffer, 0, 5000); + if(cnt < 0){ + fprintf(stderr, "USB error: %s\n", usb_strerror()); + } +#if ENABLE_TEST + }else if(strcasecmp(argv[1], "test") == 0){ + int i; + srandomdev(); + for(i = 0; i < 50000; i++){ + int value = random() & 0xffff, index = random() & 0xffff; + int rxValue, rxIndex; + if((i+1) % 100 == 0){ + fprintf(stderr, "\r%05d", i+1); + fflush(stderr); + } + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_ECHO, value, index, buffer, sizeof(buffer), 5000); + if(cnt < 0){ + fprintf(stderr, "\nUSB error in iteration %d: %s\n", i, usb_strerror()); + break; + }else if(cnt != 4){ + fprintf(stderr, "\nerror in iteration %d: %d bytes received instead of 4\n", i, cnt); + break; + } + rxValue = ((int)buffer[0] & 0xff) | (((int)buffer[1] & 0xff) << 8); + rxIndex = ((int)buffer[2] & 0xff) | (((int)buffer[3] & 0xff) << 8); + if(rxValue != value || rxIndex != index){ + fprintf(stderr, "\ndata error in iteration %d:\n", i); + fprintf(stderr, "rxValue = 0x%04x value = 0x%04x\n", rxValue, value); + fprintf(stderr, "rxIndex = 0x%04x index = 0x%04x\n", rxIndex, index); + } + } + fprintf(stderr, "\nTest completed.\n"); +#endif /* ENABLE_TEST */ + }else{ + usage(argv[0]); + exit(1); + } + usb_close(handle); + return 0; +} diff --git a/packages/vusb-20121206/examples/custom-class/firmware/Makefile b/packages/vusb-20121206/examples/custom-class/firmware/Makefile new file mode 100644 index 0000000..a653e7f --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/firmware/Makefile @@ -0,0 +1,163 @@ +# Name: Makefile +# Project: custom-class example +# Author: Christian Starkjohann +# Creation Date: 2008-04-07 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +DEVICE = atmega168 +F_CPU = 16000000 # in Hz +FUSE_L = # see below for fuse values for particular devices +FUSE_H = +AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer + +CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) + +############################################################################## +# Fuse values for particular devices +############################################################################## +# If your device is not listed here, go to +# http://palmavr.sourceforge.net/cgi-bin/fc.cgi +# and choose options for external crystal clock and no clock divider +# +################################## ATMega8 ################################## +# ATMega8 FUSE_L (Fuse low byte): +# 0x9f = 1 0 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ BODEN (BrownOut Detector enabled) +# +-------------------- BODLEVEL (2.7V) +# ATMega8 FUSE_H (Fuse high byte): +# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) +# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 +# | | | | | +-------- BOOTSZ1 +# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) +# | | | +-------------- CKOPT (full output swing) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ WDTON (WDT not always on) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATMega48/88/168 ############################## +# ATMega*8 FUSE_L (Fuse low byte): +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ CKOUT (if 0: Clock output enabled) +# +-------------------- CKDIV8 (if 0: divide by 8) +# ATMega*8 FUSE_H (Fuse high byte): +# 0xde = 1 1 0 1 1 1 1 0 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- WDTON (if 0: watchdog always on) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATTiny25/45/85 ############################### +# ATMega*5 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATMega*5 FUSE_H (Fuse high byte): +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +################################ ATTiny2313 ################################# +# ATTiny2313 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATTiny2313 FUSE_H (Fuse high byte): +# 0xdb = 1 1 0 1 1 0 1 1 +# ^ ^ ^ ^ \-+-/ ^ +# | | | | | +---- RSTDISBL (disable external reset -> enabled) +# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# +-------------------- DWEN (debug wire enable) + + +# symbolic targets: +help: + @echo "This Makefile has no default rule. Use one of the following:" + @echo "make hex ....... to build main.hex" + @echo "make program ... to flash fuses and firmware" + @echo "make fuse ...... to flash the fuses" + @echo "make flash ..... to flash the firmware (use this on metaboard)" + @echo "make clean ..... to delete objects and hex file" + +hex: main.hex + +program: flash fuse + +# rule for programming fuse bits: +fuse: + @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ + { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } + $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m + +# rule for uploading firmware: +flash: main.hex + $(AVRDUDE) -U flash:w:main.hex:i + +# rule for deleting dependent files (those which can be built by Make): +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# Generic rule for compiling C files: +.c.o: + $(COMPILE) -c $< -o $@ + +# Generic rule for assembling Assembler source files: +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +# Generic rule for compiling C to assembler, used for debugging only. +.c.s: + $(COMPILE) -S $< -o $@ + +# file targets: + +# Since we don't want to ship the driver multipe times, we copy it into this project: +usbdrv: + cp -r ../../../usbdrv . + +main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it + $(COMPILE) -o main.elf $(OBJECTS) + +main.hex: main.elf + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.elf main.hex + avr-size main.hex + +# debugging targets: + +disasm: main.elf + avr-objdump -d main.elf + +cpp: + $(COMPILE) -E main.c diff --git a/packages/vusb-20121206/examples/custom-class/firmware/main.c b/packages/vusb-20121206/examples/custom-class/firmware/main.c new file mode 100644 index 0000000..0222729 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/firmware/main.c @@ -0,0 +1,96 @@ +/* Name: main.c + * Project: custom-class, a basic USB example + * Author: Christian Starkjohann + * Creation Date: 2008-04-09 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This example should run on most AVRs with only little changes. No special +hardware resources except INT0 are used. You may have to change usbconfig.h for +different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or +at least be connected to INT0 as well. +We assume that an LED is connected to port B bit 0. If you connect it to a +different port or bit, change the macros below: +*/ +#define LED_PORT_DDR DDRB +#define LED_PORT_OUTPUT PORTB +#define LED_BIT 0 + +#include +#include +#include /* for sei() */ +#include /* for _delay_ms() */ + +#include /* required by usbdrv.h */ +#include "usbdrv.h" +#include "oddebug.h" /* This is also an example for using debug macros */ +#include "requests.h" /* The custom request numbers we use */ + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +usbMsgLen_t usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; +static uchar dataBuffer[4]; /* buffer must stay valid when usbFunctionSetup returns */ + + if(rq->bRequest == CUSTOM_RQ_ECHO){ /* echo -- used for reliability tests */ + dataBuffer[0] = rq->wValue.bytes[0]; + dataBuffer[1] = rq->wValue.bytes[1]; + dataBuffer[2] = rq->wIndex.bytes[0]; + dataBuffer[3] = rq->wIndex.bytes[1]; + usbMsgPtr = dataBuffer; /* tell the driver which data to return */ + return 4; + }else if(rq->bRequest == CUSTOM_RQ_SET_STATUS){ + if(rq->wValue.bytes[0] & 1){ /* set LED */ + LED_PORT_OUTPUT |= _BV(LED_BIT); + }else{ /* clear LED */ + LED_PORT_OUTPUT &= ~_BV(LED_BIT); + } + }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){ + dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0); + usbMsgPtr = dataBuffer; /* tell the driver which data to return */ + return 1; /* tell the driver to send 1 byte */ + } + return 0; /* default for not implemented requests: return no data back to host */ +} + +/* ------------------------------------------------------------------------- */ + +int __attribute__((noreturn)) main(void) +{ +uchar i; + + wdt_enable(WDTO_1S); + /* Even if you don't use the watchdog, turn it off here. On newer devices, + * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! + */ + /* RESET status: all port bits are inputs without pull-up. + * That's the way we need D+ and D-. Therefore we don't need any + * additional hardware initialization. + */ + odDebugInit(); + DBG1(0x00, 0, 0); /* debug output: main starts */ + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + LED_PORT_DDR |= _BV(LED_BIT); /* make the LED bit an output */ + sei(); + DBG1(0x01, 0, 0); /* debug output: main loop starts */ + for(;;){ /* main event loop */ + DBG1(0x02, 0, 0); /* debug output: main loop iterates */ + wdt_reset(); + usbPoll(); + } +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/custom-class/firmware/requests.h b/packages/vusb-20121206/examples/custom-class/firmware/requests.h new file mode 100644 index 0000000..3d09e66 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/firmware/requests.h @@ -0,0 +1,35 @@ +/* Name: requests.h + * Project: custom-class, a basic USB example + * Author: Christian Starkjohann + * Creation Date: 2008-04-09 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* This header is shared between the firmware and the host software. It + * defines the USB request numbers (and optionally data types) used to + * communicate between the host and the device. + */ + +#ifndef __REQUESTS_H_INCLUDED__ +#define __REQUESTS_H_INCLUDED__ + +#define CUSTOM_RQ_ECHO 0 +/* Request that the device sends back wValue and wIndex. This is used with + * random data to test the reliability of the communication. + */ +#define CUSTOM_RQ_SET_STATUS 1 +/* Set the LED status. Control-OUT. + * The requested status is passed in the "wValue" field of the control + * transfer. No OUT data is sent. Bit 0 of the low byte of wValue controls + * the LED. + */ + +#define CUSTOM_RQ_GET_STATUS 2 +/* Get the current LED status. Control-IN. + * This control transfer involves a 1 byte data phase where the device sends + * the current status to the host. The status is in bit 0 of the byte. + */ + +#endif /* __REQUESTS_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/custom-class/firmware/usbconfig.h b/packages/vusb-20121206/examples/custom-class/firmware/usbconfig.h new file mode 100644 index 0000000..29a5126 --- /dev/null +++ b/packages/vusb-20121206/examples/custom-class/firmware/usbconfig.h @@ -0,0 +1,381 @@ +/* Name: usbconfig.h + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#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 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 +/* 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 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! [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 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 ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#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). + */ +#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 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 + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 10 +/* 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. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* 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 40 +/* 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.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 0 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * 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) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * 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. + */ +#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 0 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x05dc = 1500 */ +/* This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you may use one of obdev's free shared VID/PID pairs. See the file + * USB-IDs-for-free.txt for details! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 8 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'L', 'E', 'D', 'C', 'o', 'n', 't', 'r', 'o', 'l' +#define USB_CFG_DEVICE_NAME_LEN 10 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * to fine tune control over USB descriptors such as the string descriptor + * for the serial number. + */ +#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + * Class 0xff is "vendor specific". + */ +#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +/* #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. + * 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! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + 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), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * 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 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + + +#define usbMsgPtr_t unsigned short +/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to + * a scalar type here because gcc generates slightly shorter code for scalar + * arithmetics than for pointer arithmetics. Remove this define for backward + * type compatibility or define it to an 8 bit type if you use data in RAM only + * and all RAM is below 256 bytes (tiny memory model in IAR CC). + */ + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #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_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/Readme.txt b/packages/vusb-20121206/examples/hid-custom-rq/Readme.txt new file mode 100644 index 0000000..6a2ab3b --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/Readme.txt @@ -0,0 +1,28 @@ +This is the Readme file for the hid-custom-rq example. This is basically the +same as the custom-class example, except that the device conforms to the USB +HID class. + + +WHAT IS DEMONSTRATED? +===================== +This example demonstrates how custom requests can be sent to devices which +are otherwise HID compliant. This mechanism can be used to prevent the +"driver CD" dialog on Windows and still control the device with libusb-win32. +It can also be used to extend the functionality of the USB class, e.g. by +setting parameters. + +Please note that you should install the filter version of libusb-win32 to +take full advantage or this mode. The device driver version only has access +to devices which have been registered for it with a *.inf file. The filter +version has access to all devices. + + +MORE INFORMATION +================ +For information about how to build this example and how to use the command +line tool see the Readme file in the custom-class example. + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile b/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile new file mode 100644 index 0000000..e43131d --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile @@ -0,0 +1,47 @@ +# Name: Makefile +# Project: hid-custom-rq example +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + + +# Concigure the following definitions according to your system. +# This Makefile has been tested on Mac OS X, Linux and Windows. + +# Use the following 3 lines on Unix (uncomment the framework on Mac OS X): +USBFLAGS = `libusb-config --cflags` +USBLIBS = `libusb-config --libs` +EXE_SUFFIX = + +# Use the following 3 lines on Windows and comment out the 3 above. You may +# have to change the include paths to where you installed libusb-win32 +#USBFLAGS = -I/usr/local/include +#USBLIBS = -L/usr/local/lib -lusb +#EXE_SUFFIX = .exe + +NAME = set-led + +OBJECTS = opendevice.o $(NAME).o + +CC = gcc +CFLAGS = $(CPPFLAGS) $(USBFLAGS) -O -g -Wall +LIBS = $(USBLIBS) + +PROGRAM = $(NAME)$(EXE_SUFFIX) + + +all: $(PROGRAM) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(PROGRAM): $(OBJECTS) + $(CC) -o $(PROGRAM) $(OBJECTS) $(LIBS) + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f *.o $(PROGRAM) diff --git a/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile.windows b/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile.windows new file mode 100644 index 0000000..70648b9 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/commandline/Makefile.windows @@ -0,0 +1,17 @@ +# Name: Makefile.windows +# Project: hid-custom-rq example +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS = -I/usr/local/mingw/include +USBLIBS = -L/usr/local/mingw/lib -lusb +EXE_SUFFIX = .exe diff --git a/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.c b/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.c new file mode 100644 index 0000000..ea88e86 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.c @@ -0,0 +1,202 @@ +/* Name: opendevice.c + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The functions in this module can be used to find and open a device based on +libusb or libusb-win32. +*/ + +#include +#include "opendevice.h" + +/* ------------------------------------------------------------------------- */ + +#define MATCH_SUCCESS 1 +#define MATCH_FAILED 0 +#define MATCH_ABORT -1 + +/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ +static int _shellStyleMatch(char *text, char *p) +{ +int last, matched, reverse; + + for(; *p; text++, p++){ + if(*text == 0 && *p != '*') + return MATCH_ABORT; + switch(*p){ + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if(*text != *p) + return MATCH_FAILED; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while(*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if(*p == 0) + /* Trailing star matches everything. */ + return MATCH_SUCCESS; + while(*text) + if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) + return matched; + return MATCH_ABORT; + case '[': + reverse = p[1] == '^'; + if(reverse) /* Inverted character class. */ + p++; + matched = MATCH_FAILED; + if(p[1] == ']' || p[1] == '-') + if(*++p == *text) + matched = MATCH_SUCCESS; + for(last = *p; *++p && *p != ']'; last = *p) + if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) + matched = MATCH_SUCCESS; + if(matched == reverse) + return MATCH_FAILED; + continue; + } + } + return *text == 0; +} + +/* public interface for shell style matching: returns 0 if fails, 1 if matches */ +static int shellStyleMatch(char *text, char *pattern) +{ + if(pattern == NULL) /* NULL pattern is synonymous to "*" */ + return 1; + return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +/* ------------------------------------------------------------------------- */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; + + usb_find_busses(); + usb_find_devices(); + for(bus = usb_get_busses(); bus; bus = bus->next){ + for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ + if((vendorID == 0 || dev->descriptor.idVendor == vendorID) + && (productID == 0 || dev->descriptor.idProduct == productID)){ + char vendor[256], product[256], serial[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + continue; + } + /* now check whether the names match: */ + len = vendor[0] = 0; + if(dev->descriptor.iManufacturer > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen device from vendor ->%s<-\n", vendor); */ + if(shellStyleMatch(vendor, vendorNamePattern)){ + len = product[0] = 0; + if(dev->descriptor.iProduct > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen product ->%s<-\n", product); */ + if(shellStyleMatch(product, productNamePattern)){ + len = serial[0] = 0; + if(dev->descriptor.iSerialNumber > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + } + if(shellStyleMatch(serial, serialNamePattern)){ + if(printMatchingDevicesFp != NULL){ + if(serial[0] == 0){ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); + }else{ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); + } + }else{ + break; + } + } + } + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) /* we have found a deice */ + break; + } + if(handle != NULL){ + errorCode = 0; + *device = handle; + } + if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ + errorCode = 0; + return errorCode; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.h b/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.h new file mode 100644 index 0000000..c925276 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/commandline/opendevice.h @@ -0,0 +1,76 @@ +/* Name: opendevice.h + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module offers additional functionality for host side drivers based on +libusb or libusb-win32. It includes a function to find and open a device +based on numeric IDs and textual description. It also includes a function to +obtain textual descriptions from a device. + +To use this functionality, simply copy opendevice.c and opendevice.h into your +project and add them to your Makefile. You may modify and redistribute these +files according to the GNU General Public License (GPL) version 2 or 3. +*/ + +#ifndef __OPENDEVICE_H_INCLUDED__ +#define __OPENDEVICE_H_INCLUDED__ + +#include /* this is libusb, see http://libusb.sourceforge.net/ */ +#include + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen); +/* This function gets a string descriptor from the device. 'index' is the + * string descriptor index. The string is returned in ISO Latin 1 encoding in + * 'buf' and it is terminated with a 0-character. The buffer size must be + * passed in 'buflen' to prevent buffer overflows. A libusb device handle + * must be given in 'dev'. + * Returns: The length of the string (excluding the terminating 0) or + * a negative number in case of an error. If there was an error, use + * usb_strerror() to obtain the error message. + */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp); +/* This function iterates over all devices on all USB busses and searches for + * a device. Matching is done first by means of Vendor- and Product-ID (passed + * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard). + * When a device matches by its IDs, matching by names is performed. Name + * matching can be done on textual vendor name ('vendorNamePattern'), product + * name ('productNamePattern') and serial number ('serialNamePattern'). A + * device matches only if all non-null pattern match. If you don't care about + * a string, pass NULL for the pattern. Patterns are Unix shell style pattern: + * '*' stands for 0 or more characters, '?' for one single character, a list + * of characters in square brackets for a single character from the list + * (dashes are allowed to specify a range) and if the lis of characters begins + * with a caret ('^'), it matches one character which is NOT in the list. + * Other parameters to the function: If 'warningsFp' is not NULL, warning + * messages are printed to this file descriptor with fprintf(). If + * 'printMatchingDevicesFp' is not NULL, no device is opened but matching + * devices are printed to the given file descriptor with fprintf(). + * If a device is opened, the resulting USB handle is stored in '*device'. A + * pointer to a "usb_dev_handle *" type variable must be passed here. + * Returns: 0 on success, an error code (see defines below) on failure. + */ + +/* usbOpenDevice() error codes: */ +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + + +/* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */ + +#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */ +#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */ +#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */ +#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */ +#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */ + +#endif /* __OPENDEVICE_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/commandline/set-led.c b/packages/vusb-20121206/examples/hid-custom-rq/commandline/set-led.c new file mode 100644 index 0000000..d27a1dd --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/commandline/set-led.c @@ -0,0 +1,134 @@ +/* Name: set-led.c + * Project: hid-custom-rq example + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This is the host-side driver for the custom-class example device. It searches +the USB for the LEDControl device and sends the requests understood by this +device. +This program must be linked with libusb on Unix and libusb-win32 on Windows. +See http://libusb.sourceforge.net/ or http://libusb-win32.sourceforge.net/ +respectively. +*/ + +#include +#include +#include +#include /* this is libusb */ +#include "opendevice.h" /* common code moved to separate module */ + +#include "../firmware/requests.h" /* custom request numbers */ +#include "../firmware/usbconfig.h" /* device's VID/PID and names */ + +static void usage(char *name) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s on ....... turn on LED\n", name); + fprintf(stderr, " %s off ...... turn off LED\n", name); + fprintf(stderr, " %s status ... ask current status of LED\n", name); +#if ENABLE_TEST + fprintf(stderr, " %s test ..... run driver reliability test\n", name); +#endif /* ENABLE_TEST */ +} + +int main(int argc, char **argv) +{ +usb_dev_handle *handle = NULL; +const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID}; +char vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0}; +char buffer[4]; +int cnt, vid, pid, isOn; + + usb_init(); + if(argc < 2){ /* we need at least one argument */ + usage(argv[0]); + exit(1); + } + /* compute VID/PID from usbconfig.h so that there is a central source of information */ + vid = rawVid[1] * 256 + rawVid[0]; + pid = rawPid[1] * 256 + rawPid[0]; + /* The following function is in opendevice.c: */ + if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){ + fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid); + exit(1); + } + /* Since we use only control endpoint 0, we don't need to choose a + * configuration and interface. Reading device descriptor and setting a + * configuration and interface is done through endpoint 0 after all. + * However, newer versions of Linux require that we claim an interface + * even for endpoint 0. Enable the following code if your operating system + * needs it: */ +#if 0 + int retries = 1, usbConfiguration = 1, usbInterface = 0; + if(usb_set_configuration(handle, usbConfiguration) && showWarnings){ + fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); + } + /* now try to claim the interface and detach the kernel HID driver on + * Linux and other operating systems which support the call. */ + while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){ +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){ + fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror()); + } +#endif + } +#endif + + if(strcasecmp(argv[1], "status") == 0){ + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS, 0, 0, buffer, sizeof(buffer), 5000); + if(cnt < 1){ + if(cnt < 0){ + fprintf(stderr, "USB error: %s\n", usb_strerror()); + }else{ + fprintf(stderr, "only %d bytes received.\n", cnt); + } + }else{ + printf("LED is %s\n", buffer[0] ? "on" : "off"); + } + }else if((isOn = (strcasecmp(argv[1], "on") == 0)) || strcasecmp(argv[1], "off") == 0){ + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, isOn, 0, buffer, 0, 5000); + if(cnt < 0){ + fprintf(stderr, "USB error: %s\n", usb_strerror()); + } +#if ENABLE_TEST + }else if(strcasecmp(argv[1], "test") == 0){ + int i; + srandomdev(); + for(i = 0; i < 50000; i++){ + int value = random() & 0xffff, index = random() & 0xffff; + int rxValue, rxIndex; + if((i+1) % 100 == 0){ + fprintf(stderr, "\r%05d", i+1); + fflush(stderr); + } + cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_ECHO, value, index, buffer, sizeof(buffer), 5000); + if(cnt < 0){ + fprintf(stderr, "\nUSB error in iteration %d: %s\n", i, usb_strerror()); + break; + }else if(cnt != 4){ + fprintf(stderr, "\nerror in iteration %d: %d bytes received instead of 4\n", i, cnt); + break; + } + rxValue = ((int)buffer[0] & 0xff) | (((int)buffer[1] & 0xff) << 8); + rxIndex = ((int)buffer[2] & 0xff) | (((int)buffer[3] & 0xff) << 8); + if(rxValue != value || rxIndex != index){ + fprintf(stderr, "\ndata error in iteration %d:\n", i); + fprintf(stderr, "rxValue = 0x%04x value = 0x%04x\n", rxValue, value); + fprintf(stderr, "rxIndex = 0x%04x index = 0x%04x\n", rxIndex, index); + } + } + fprintf(stderr, "\nTest completed.\n"); +#endif /* ENABLE_TEST */ + }else{ + usage(argv[0]); + exit(1); + } + usb_close(handle); + return 0; +} diff --git a/packages/vusb-20121206/examples/hid-custom-rq/firmware/Makefile b/packages/vusb-20121206/examples/hid-custom-rq/firmware/Makefile new file mode 100644 index 0000000..eba7c66 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/firmware/Makefile @@ -0,0 +1,163 @@ +# Name: Makefile +# Project: hid-custom-rq example +# Author: Christian Starkjohann +# Creation Date: 2008-04-07 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +DEVICE = atmega168 +F_CPU = 16000000 # in Hz +FUSE_L = # see below for fuse values for particular devices +FUSE_H = +AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer + +CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) + +############################################################################## +# Fuse values for particular devices +############################################################################## +# If your device is not listed here, go to +# http://palmavr.sourceforge.net/cgi-bin/fc.cgi +# and choose options for external crystal clock and no clock divider +# +################################## ATMega8 ################################## +# ATMega8 FUSE_L (Fuse low byte): +# 0x9f = 1 0 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ BODEN (BrownOut Detector enabled) +# +-------------------- BODLEVEL (2.7V) +# ATMega8 FUSE_H (Fuse high byte): +# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) +# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 +# | | | | | +-------- BOOTSZ1 +# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) +# | | | +-------------- CKOPT (full output swing) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ WDTON (WDT not always on) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATMega48/88/168 ############################## +# ATMega*8 FUSE_L (Fuse low byte): +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ CKOUT (if 0: Clock output enabled) +# +-------------------- CKDIV8 (if 0: divide by 8) +# ATMega*8 FUSE_H (Fuse high byte): +# 0xde = 1 1 0 1 1 1 1 0 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- WDTON (if 0: watchdog always on) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATTiny25/45/85 ############################### +# ATMega*5 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATMega*5 FUSE_H (Fuse high byte): +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +################################ ATTiny2313 ################################# +# ATTiny2313 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATTiny2313 FUSE_H (Fuse high byte): +# 0xdb = 1 1 0 1 1 0 1 1 +# ^ ^ ^ ^ \-+-/ ^ +# | | | | | +---- RSTDISBL (disable external reset -> enabled) +# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# +-------------------- DWEN (debug wire enable) + + +# symbolic targets: +help: + @echo "This Makefile has no default rule. Use one of the following:" + @echo "make hex ....... to build main.hex" + @echo "make program ... to flash fuses and firmware" + @echo "make fuse ...... to flash the fuses" + @echo "make flash ..... to flash the firmware (use this on metaboard)" + @echo "make clean ..... to delete objects and hex file" + +hex: main.hex + +program: flash fuse + +# rule for programming fuse bits: +fuse: + @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ + { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } + $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m + +# rule for uploading firmware: +flash: main.hex + $(AVRDUDE) -U flash:w:main.hex:i + +# rule for deleting dependent files (those which can be built by Make): +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# Generic rule for compiling C files: +.c.o: + $(COMPILE) -c $< -o $@ + +# Generic rule for assembling Assembler source files: +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +# Generic rule for compiling C to assembler, used for debugging only. +.c.s: + $(COMPILE) -S $< -o $@ + +# file targets: + +# Since we don't want to ship the driver multipe times, we copy it into this project: +usbdrv: + cp -r ../../../usbdrv . + +main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it + $(COMPILE) -o main.elf $(OBJECTS) + +main.hex: main.elf + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.elf main.hex + avr-size main.hex + +# debugging targets: + +disasm: main.elf + avr-objdump -d main.elf + +cpp: + $(COMPILE) -E main.c diff --git a/packages/vusb-20121206/examples/hid-custom-rq/firmware/main.c b/packages/vusb-20121206/examples/hid-custom-rq/firmware/main.c new file mode 100644 index 0000000..58d3809 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/firmware/main.c @@ -0,0 +1,119 @@ +/* Name: main.c + * Project: hid-custom-rq example + * Author: Christian Starkjohann + * Creation Date: 2008-04-07 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This example should run on most AVRs with only little changes. No special +hardware resources except INT0 are used. You may have to change usbconfig.h for +different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or +at least be connected to INT0 as well. +We assume that an LED is connected to port B bit 0. If you connect it to a +different port or bit, change the macros below: +*/ +#define LED_PORT_DDR DDRB +#define LED_PORT_OUTPUT PORTB +#define LED_BIT 0 + +#include +#include +#include /* for sei() */ +#include /* for _delay_ms() */ + +#include /* required by usbdrv.h */ +#include "usbdrv.h" +#include "oddebug.h" /* This is also an example for using debug macros */ +#include "requests.h" /* The custom request numbers we use */ + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +PROGMEM const char usbHidReportDescriptor[22] = { /* USB report descriptor */ + 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Vendor Usage 1) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x09, 0x00, // USAGE (Undefined) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0xc0 // END_COLLECTION +}; +/* The descriptor above is a dummy only, it silences the drivers. The report + * it describes consists of one byte of undefined data. + * We don't transfer our data through HID reports, we use custom requests + * instead. + */ + +/* ------------------------------------------------------------------------- */ + +usbMsgLen_t usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; + + if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){ + DBG1(0x50, &rq->bRequest, 1); /* debug output: print our request */ + if(rq->bRequest == CUSTOM_RQ_SET_STATUS){ + if(rq->wValue.bytes[0] & 1){ /* set LED */ + LED_PORT_OUTPUT |= _BV(LED_BIT); + }else{ /* clear LED */ + LED_PORT_OUTPUT &= ~_BV(LED_BIT); + } + }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){ + static uchar dataBuffer[1]; /* buffer must stay valid when usbFunctionSetup returns */ + dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0); + usbMsgPtr = dataBuffer; /* tell the driver which data to return */ + return 1; /* tell the driver to send 1 byte */ + } + }else{ + /* calss requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are + * not implemented since we never call them. The operating system + * won't call them either because our descriptor defines no meaning. + */ + } + return 0; /* default for not implemented requests: return no data back to host */ +} + +/* ------------------------------------------------------------------------- */ + +int __attribute__((noreturn)) main(void) +{ +uchar i; + + wdt_enable(WDTO_1S); + /* Even if you don't use the watchdog, turn it off here. On newer devices, + * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! + */ + /* RESET status: all port bits are inputs without pull-up. + * That's the way we need D+ and D-. Therefore we don't need any + * additional hardware initialization. + */ + odDebugInit(); + DBG1(0x00, 0, 0); /* debug output: main starts */ + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + LED_PORT_DDR |= _BV(LED_BIT); /* make the LED bit an output */ + sei(); + DBG1(0x01, 0, 0); /* debug output: main loop starts */ + for(;;){ /* main event loop */ +#if 0 /* this is a bit too aggressive for a debug output */ + DBG2(0x02, 0, 0); /* debug output: main loop iterates */ +#endif + wdt_reset(); + usbPoll(); + } +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/firmware/requests.h b/packages/vusb-20121206/examples/hid-custom-rq/firmware/requests.h new file mode 100644 index 0000000..630a685 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/firmware/requests.h @@ -0,0 +1,31 @@ +/* Name: requests.h + * Project: custom-class, a basic USB example + * Author: Christian Starkjohann + * Creation Date: 2008-04-09 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* This header is shared between the firmware and the host software. It + * defines the USB request numbers (and optionally data types) used to + * communicate between the host and the device. + */ + +#ifndef __REQUESTS_H_INCLUDED__ +#define __REQUESTS_H_INCLUDED__ + +#define CUSTOM_RQ_SET_STATUS 1 +/* Set the LED status. Control-OUT. + * The requested status is passed in the "wValue" field of the control + * transfer. No OUT data is sent. Bit 0 of the low byte of wValue controls + * the LED. + */ + +#define CUSTOM_RQ_GET_STATUS 2 +/* Get the current LED status. Control-IN. + * This control transfer involves a 1 byte data phase where the device sends + * the current status to the host. The status is in bit 0 of the byte. + */ + +#endif /* __REQUESTS_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/hid-custom-rq/firmware/usbconfig.h b/packages/vusb-20121206/examples/hid-custom-rq/firmware/usbconfig.h new file mode 100644 index 0000000..82deaa1 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-custom-rq/firmware/usbconfig.h @@ -0,0 +1,381 @@ +/* Name: usbconfig.h + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#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 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 +/* 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 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! [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 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 ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#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 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 + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 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. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* 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 40 +/* 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.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 0 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * 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) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * 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. + */ +#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 0 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID 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 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 '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 USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'L', 'E', 'D', 'C', 't', 'l', 'H', 'I', 'D' +#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 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 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * 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_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 +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 22 +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + 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), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * 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 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + + +#define usbMsgPtr_t unsigned short +/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to + * a scalar type here because gcc generates slightly shorter code for scalar + * arithmetics than for pointer arithmetics. Remove this define for backward + * type compatibility or define it to an 8 bit type if you use data in RAM only + * and all RAM is below 256 bytes (tiny memory model in IAR CC). + */ + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #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_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/packages/vusb-20121206/examples/hid-data/Readme.txt b/packages/vusb-20121206/examples/hid-data/Readme.txt new file mode 100644 index 0000000..cb17baa --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/Readme.txt @@ -0,0 +1,75 @@ +This is the Readme file for the hid-data example. In this example, we show +how blocks of data can be exchanged with the device using only functionality +compliant to the HID class. Since class drivers for HID are included with +Windows, you don't need to install drivers on Windows. + + +WHAT IS DEMONSTRATED? +===================== +This example demonstrates how the HID class can be misused to transfer fixed +size blocks of data (up to the driver's transfer size limit) over HID feature +reports. This technique is of great value on Windows because no driver DLLs +are needed (the hid-custom-rq example still requires the libusb-win32 DLL, +although it may be in the program's directory). The host side application +requires no installation, it can even be started directly from a CD. This +example also demonstrates how to transfer data using usbFunctionWrite() and +usbFunctionRead(). + + +PREREQUISITES +============= +Target hardware: You need an AVR based circuit based on one of the examples +(see the "circuits" directory at the top level of this package), e.g. the +metaboard (http://www.obdev.at/goto.php?t=metaboard). + +AVR development environment: You need the gcc tool chain for the AVR, see +the Prerequisites section in the top level Readme file for how to obtain it. + +Host development environment: A C compiler and libusb on Unix. On Windows +you need the Driver Development Kit (DDK) Instead of libusb. MinGW ships +with a free version of the DDK. + + +BUILDING THE FIRMWARE +===================== +Change to the "firmware" directory and modify Makefile according to your +architecture (CPU clock, target device, fuse values) and ISP programmer. Then +edit usbconfig.h according to your pin assignments for D+ and D-. The default +settings are for the metaboard hardware. + +Type "make hex" to build main.hex, then "make flash" to upload the firmware +to the device. Don't forget to run "make fuse" once to program the fuses. If +you use a prototyping board with boot loader, follow the instructions of the +boot loader instead. + +Please note that the first "make hex" copies the driver from the top level +into the firmware directory. If you use a different build system than our +Makefile, you must copy the driver by hand. + + +BUILDING THE HOST SOFTWARE +========================== +Make sure that you have libusb (on Unix) or the DDK (on Windows) installed. +We recommend MinGW on Windows since it includes a free version of the DDK. +Then change to directory "commandline" and run "make" on Unix or +"make -f Makefile.windows" on Windows. + + +USING THE COMMAND LINE TOOL +=========================== +The device implements a data store of 128 bytes in EEPROM. You can send a +block of 128 bytes to the device or read the block using the command line +tool. + +To send a block to the device, use e.g. + + hidtool write 0x01,0x02,0x03,0x04,... + +and to receive the block, use + + hidtool read + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/hid-data/commandline/Makefile b/packages/vusb-20121206/examples/hid-data/commandline/Makefile new file mode 100644 index 0000000..b47df47 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/Makefile @@ -0,0 +1,41 @@ +# Name: Makefile +# Project: hid-data example +# Author: Christian Starkjohann +# Creation Date: 2008-04-11 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# Please read the definitions below and edit them as appropriate for your +# system: + +# Use the following 3 lines on Unix and Mac OS X: +USBFLAGS= `libusb-config --cflags` +USBLIBS= `libusb-config --libs` +EXE_SUFFIX= + +# Use the following 3 lines on Windows and comment out the 3 above: +#USBFLAGS= +#USBLIBS= -lhid -lusb -lsetupapi +#EXE_SUFFIX= .exe + +CC= gcc +CFLAGS= -O -Wall $(USBFLAGS) +LIBS= $(USBLIBS) + +OBJ= hidtool.o hiddata.o +PROGRAM= hidtool$(EXE_SUFFIX) + +all: $(PROGRAM) + +$(PROGRAM): $(OBJ) + $(CC) -o $(PROGRAM) $(OBJ) $(LIBS) + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f $(OBJ) $(PROGRAM) + +.c.o: + $(CC) $(ARCH_COMPILE) $(CFLAGS) -c $*.c -o $*.o diff --git a/packages/vusb-20121206/examples/hid-data/commandline/Makefile.windows b/packages/vusb-20121206/examples/hid-data/commandline/Makefile.windows new file mode 100644 index 0000000..ab3f5df --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/Makefile.windows @@ -0,0 +1,17 @@ +# Name: Makefile.windows +# Project: hid-data example +# Author: Christian Starkjohann +# Creation Date: 2008-04-11 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS= +USBLIBS= -lhid -lsetupapi +EXE_SUFFIX= .exe diff --git a/packages/vusb-20121206/examples/hid-data/commandline/hiddata.c b/packages/vusb-20121206/examples/hid-data/commandline/hiddata.c new file mode 100644 index 0000000..203ed19 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/hiddata.c @@ -0,0 +1,323 @@ +/* Name: hiddata.c + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#include +#include "hiddata.h" + +/* ######################################################################## */ +#if defined(WIN32) /* ##################################################### */ +/* ######################################################################## */ + +#include +#include +#include "hidsdi.h" +#include + +#ifdef DEBUG +#define DEBUG_PRINT(arg) printf arg +#else +#define DEBUG_PRINT(arg) +#endif + +/* ------------------------------------------------------------------------ */ + +static void convertUniToAscii(char *buffer) +{ +unsigned short *uni = (void *)buffer; +char *ascii = buffer; + + while(*uni != 0){ + if(*uni >= 256){ + *ascii++ = '?'; + }else{ + *ascii++ = *uni++; + } + } + *ascii++ = 0; +} + +int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs) +{ +GUID hidGuid; /* GUID for HID driver */ +HDEVINFO deviceInfoList; +SP_DEVICE_INTERFACE_DATA deviceInfo; +SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL; +DWORD size; +int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */ +int errorCode = USBOPEN_ERR_NOTFOUND; +HANDLE handle = INVALID_HANDLE_VALUE; +HIDD_ATTRIBUTES deviceAttributes; + + HidD_GetHidGuid(&hidGuid); + deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); + deviceInfo.cbSize = sizeof(deviceInfo); + for(i=0;;i++){ + if(handle != INVALID_HANDLE_VALUE){ + CloseHandle(handle); + handle = INVALID_HANDLE_VALUE; + } + if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) + break; /* no more entries */ + /* first do a dummy call just to determine the actual size required */ + SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL); + if(deviceDetails != NULL) + free(deviceDetails); + deviceDetails = malloc(size); + deviceDetails->cbSize = sizeof(*deviceDetails); + /* this call is for real: */ + SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL); + DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath)); +#if 0 + /* If we want to access a mouse our keyboard, we can only use feature + * requests as the device is locked by Windows. It must be opened + * with ACCESS_TYPE_NONE. + */ + handle = CreateFile(deviceDetails->DevicePath, ACCESS_TYPE_NONE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); +#endif + /* attempt opening for R/W -- we don't care about devices which can't be accessed */ + handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); + if(handle == INVALID_HANDLE_VALUE){ + DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError())); + /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */ + continue; + } + deviceAttributes.Size = sizeof(deviceAttributes); + HidD_GetAttributes(handle, &deviceAttributes); + DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes.VendorID, deviceAttributes.ProductID)); + if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product) + continue; /* ignore this device */ + errorCode = USBOPEN_ERR_NOTFOUND; + if(vendorName != NULL && productName != NULL){ + char buffer[512]; + if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ + DEBUG_PRINT(("error obtaining vendor name\n")); + errorCode = USBOPEN_ERR_IO; + continue; + } + convertUniToAscii(buffer); + DEBUG_PRINT(("vendorName = \"%s\"\n", buffer)); + if(strcmp(vendorName, buffer) != 0) + continue; + if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){ + DEBUG_PRINT(("error obtaining product name\n")); + errorCode = USBOPEN_ERR_IO; + continue; + } + convertUniToAscii(buffer); + DEBUG_PRINT(("productName = \"%s\"\n", buffer)); + if(strcmp(productName, buffer) != 0) + continue; + } + break; /* we have found the device we are looking for! */ + } + SetupDiDestroyDeviceInfoList(deviceInfoList); + if(deviceDetails != NULL) + free(deviceDetails); + if(handle != INVALID_HANDLE_VALUE){ + *device = (usbDevice_t *)handle; + errorCode = 0; + } + return errorCode; +} + +/* ------------------------------------------------------------------------ */ + +void usbhidCloseDevice(usbDevice_t *device) +{ + CloseHandle((HANDLE)device); +} + +/* ------------------------------------------------------------------------ */ + +int usbhidSetReport(usbDevice_t *device, char *buffer, int len) +{ +BOOLEAN rval; + + rval = HidD_SetFeature((HANDLE)device, buffer, len); + return rval == 0 ? USBOPEN_ERR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ + +int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) +{ +BOOLEAN rval = 0; + + buffer[0] = reportNumber; + rval = HidD_GetFeature((HANDLE)device, buffer, *len); + return rval == 0 ? USBOPEN_ERR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ + +/* ######################################################################## */ +#else /* defined WIN32 #################################################### */ +/* ######################################################################## */ + +#include +#include + +#define usbDevice usb_dev_handle /* use libusb's device structure */ + +/* ------------------------------------------------------------------------- */ + +#define USBRQ_HID_GET_REPORT 0x01 +#define USBRQ_HID_SET_REPORT 0x09 + +#define USB_HID_REPORT_TYPE_FEATURE 3 + + +static int usesReportIDs; + +/* ------------------------------------------------------------------------- */ + +static int usbhidGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; +static int didUsbInit = 0; + + if(!didUsbInit){ + usb_init(); + didUsbInit = 1; + } + usb_find_busses(); + usb_find_devices(); + for(bus=usb_get_busses(); bus; bus=bus->next){ + for(dev=bus->devices; dev; dev=dev->next){ + if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){ + char string[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); + continue; + } + if(vendorName == NULL && productName == NULL){ /* name does not matter */ + break; + } + /* now check whether the names match: */ + len = usbhidGetStringAscii(handle, dev->descriptor.iManufacturer, string, sizeof(string)); + if(len < 0){ + errorCode = USBOPEN_ERR_IO; + fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ + if(strcmp(string, vendorName) == 0){ + len = usbhidGetStringAscii(handle, dev->descriptor.iProduct, string, sizeof(string)); + if(len < 0){ + errorCode = USBOPEN_ERR_IO; + fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* fprintf(stderr, "seen product ->%s<-\n", string); */ + if(strcmp(string, productName) == 0) + break; + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) + break; + } + if(handle != NULL){ + errorCode = 0; + *device = (void *)handle; + usesReportIDs = _usesReportIDs; + } + return errorCode; +} + +/* ------------------------------------------------------------------------- */ + +void usbhidCloseDevice(usbDevice_t *device) +{ + if(device != NULL) + usb_close((void *)device); +} + +/* ------------------------------------------------------------------------- */ + +int usbhidSetReport(usbDevice_t *device, char *buffer, int len) +{ +int bytesSent, reportId = buffer[0]; + + if(!usesReportIDs){ + buffer++; /* skip dummy report ID */ + len--; + } + bytesSent = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | (reportId & 0xff), 0, buffer, len, 5000); + if(bytesSent != len){ + if(bytesSent < 0) + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USBOPEN_ERR_IO; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) +{ +int bytesReceived, maxLen = *len; + + if(!usesReportIDs){ + buffer++; /* make room for dummy report ID */ + maxLen--; + } + bytesReceived = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | reportNumber, 0, buffer, maxLen, 5000); + if(bytesReceived < 0){ + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USBOPEN_ERR_IO; + } + *len = bytesReceived; + if(!usesReportIDs){ + buffer[-1] = reportNumber; /* add dummy report ID */ + (*len)++; + } + return 0; +} + +/* ######################################################################## */ +#endif /* defined WIN32 ################################################### */ +/* ######################################################################## */ diff --git a/packages/vusb-20121206/examples/hid-data/commandline/hiddata.h b/packages/vusb-20121206/examples/hid-data/commandline/hiddata.h new file mode 100644 index 0000000..245453d --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/hiddata.h @@ -0,0 +1,70 @@ +/* Name: hiddata.h + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __HIDDATA_H_INCLUDED__ +#define __HIDDATA_H_INCLUDED__ + +/* +General Description: +This module implements an abstraction layer for data transfer over HID feature +requests. The implementation uses native Windows functions on Windows so that +no driver installation is required and libusb on Unix. You must link the +appropriate libraries in either case: "-lhid -lusb -lsetupapi" on Windows and +`libusb-config --libs` on Unix. +*/ + +/* ------------------------------------------------------------------------ */ + +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + +/* ------------------------------------------------------------------------ */ + +typedef struct usbDevice usbDevice_t; +/* Opaque data type representing the USB device. This can be a Windows handle + * or a libusb handle, depending on the backend implementation. + */ + +/* ------------------------------------------------------------------------ */ + +int usbhidOpenDevice(usbDevice_t **device, int vendorID, char *vendorName, int productID, char *productName, int usesReportIDs); +/* This function opens a USB device. 'vendorID' and 'productID' are the numeric + * Vendor-ID and Product-ID of the device we want to open. If 'vendorName' and + * 'productName' are both not NULL, only devices with matching manufacturer- + * and product name strings are accepted. If the device uses report IDs, + * 'usesReportIDs' must be set to a non-zero value. + * Returns: If a matching device has been found, USBOPEN_SUCCESS is returned + * and '*device' is set to an opaque pointer representing the device. The + * device must be closed with usbhidCloseDevice(). If the device has not been + * found or opening failed, an error code is returned. + */ +void usbhidCloseDevice(usbDevice_t *device); +/* Every device opened with usbhidOpenDevice() must be closed with this function. + */ +int usbhidSetReport(usbDevice_t *device, char *buffer, int len); +/* This function sends a feature report to the device. The report ID must be + * in the first byte of buffer and the length 'len' of the report is specified + * including this report ID. If no report IDs are used, buffer[0] must be set + * to 0 (dummy report ID). + * Returns: 0 on success, an error code otherwise. + */ +int usbhidGetReport(usbDevice_t *device, int reportID, char *buffer, int *len); +/* This function obtains a feature report from the device. The requested + * report-ID is passed in 'reportID'. The caller must pass a buffer of the size + * of the expected report in 'buffer' and initialize the variable pointed to by + * 'len' to the total size of this buffer. Upon successful return, the report + * (prefixed with the report-ID) is in 'buffer' and the actual length of the + * report is returned in '*len'. + * Returns: 0 on success, an error code otherwise. + */ + +/* ------------------------------------------------------------------------ */ + +#endif /* __HIDDATA_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/hid-data/commandline/hidsdi.h b/packages/vusb-20121206/examples/hid-data/commandline/hidsdi.h new file mode 100644 index 0000000..fe6da08 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/hidsdi.h @@ -0,0 +1,48 @@ +/* Name: hidsdi.h + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006-2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description +This file is a replacement for hidsdi.h from the Windows DDK. It defines some +of the types and function prototypes of this header for our project. If you +have the Windows DDK version of this file or a version shipped with MinGW, use +that instead. +*/ + +#ifndef _HIDSDI_H +#define _HIDSDI_H + +#include + +#include +#include + +typedef struct{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; +}HIDD_ATTRIBUTES; + +void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid); + +BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes); + +BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers); +BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers); + +#include + +#endif diff --git a/packages/vusb-20121206/examples/hid-data/commandline/hidtool.c b/packages/vusb-20121206/examples/hid-data/commandline/hidtool.c new file mode 100644 index 0000000..6095312 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/commandline/hidtool.c @@ -0,0 +1,126 @@ +/* Name: hidtool.c + * Project: hid-data example + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#include +#include +#include +#include "hiddata.h" +#include "../firmware/usbconfig.h" /* for device VID, PID, vendor name and product name */ + +/* ------------------------------------------------------------------------- */ + +static char *usbErrorMessage(int errCode) +{ +static char buffer[80]; + + switch(errCode){ + case USBOPEN_ERR_ACCESS: return "Access to device denied"; + case USBOPEN_ERR_NOTFOUND: return "The specified device was not found"; + case USBOPEN_ERR_IO: return "Communication error with device"; + default: + sprintf(buffer, "Unknown USB error %d", errCode); + return buffer; + } + return NULL; /* not reached */ +} + +static usbDevice_t *openDevice(void) +{ +usbDevice_t *dev = NULL; +unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID}; +char vendorName[] = {USB_CFG_VENDOR_NAME, 0}, productName[] = {USB_CFG_DEVICE_NAME, 0}; +int vid = rawVid[0] + 256 * rawVid[1]; +int pid = rawPid[0] + 256 * rawPid[1]; +int err; + + if((err = usbhidOpenDevice(&dev, vid, vendorName, pid, productName, 0)) != 0){ + fprintf(stderr, "error finding %s: %s\n", productName, usbErrorMessage(err)); + return NULL; + } + return dev; +} + +/* ------------------------------------------------------------------------- */ + +static void hexdump(char *buffer, int len) +{ +int i; +FILE *fp = stdout; + + for(i = 0; i < len; i++){ + if(i != 0){ + if(i % 16 == 0){ + fprintf(fp, "\n"); + }else{ + fprintf(fp, " "); + } + } + fprintf(fp, "0x%02x", buffer[i] & 0xff); + } + if(i != 0) + fprintf(fp, "\n"); +} + +static int hexread(char *buffer, char *string, int buflen) +{ +char *s; +int pos = 0; + + while((s = strtok(string, ", ")) != NULL && pos < buflen){ + string = NULL; + buffer[pos++] = (char)strtol(s, NULL, 0); + } + return pos; +} + +/* ------------------------------------------------------------------------- */ + +static void usage(char *myName) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s read\n", myName); + fprintf(stderr, " %s write \n", myName); +} + +int main(int argc, char **argv) +{ +usbDevice_t *dev; +char buffer[129]; /* room for dummy report ID */ +int err; + + if(argc < 2){ + usage(argv[0]); + exit(1); + } + if((dev = openDevice()) == NULL) + exit(1); + if(strcasecmp(argv[1], "read") == 0){ + int len = sizeof(buffer); + if((err = usbhidGetReport(dev, 0, buffer, &len)) != 0){ + fprintf(stderr, "error reading data: %s\n", usbErrorMessage(err)); + }else{ + hexdump(buffer + 1, sizeof(buffer) - 1); + } + }else if(strcasecmp(argv[1], "write") == 0){ + int i, pos; + memset(buffer, 0, sizeof(buffer)); + for(pos = 1, i = 2; i < argc && pos < sizeof(buffer); i++){ + pos += hexread(buffer + pos, argv[i], sizeof(buffer) - pos); + } + if((err = usbhidSetReport(dev, buffer, sizeof(buffer))) != 0) /* add a dummy report ID */ + fprintf(stderr, "error writing data: %s\n", usbErrorMessage(err)); + }else{ + usage(argv[0]); + exit(1); + } + usbhidCloseDevice(dev); + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/hid-data/firmware/Makefile b/packages/vusb-20121206/examples/hid-data/firmware/Makefile new file mode 100644 index 0000000..6149fa4 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/firmware/Makefile @@ -0,0 +1,163 @@ +# Name: Makefile +# Project: hid-data example +# Author: Christian Starkjohann +# Creation Date: 2008-04-07 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +DEVICE = atmega168 +F_CPU = 16000000 # in Hz +FUSE_L = # see below for fuse values for particular devices +FUSE_H = +AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer + +CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) + +############################################################################## +# Fuse values for particular devices +############################################################################## +# If your device is not listed here, go to +# http://palmavr.sourceforge.net/cgi-bin/fc.cgi +# and choose options for external crystal clock and no clock divider +# +################################## ATMega8 ################################## +# ATMega8 FUSE_L (Fuse low byte): +# 0x9f = 1 0 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ BODEN (BrownOut Detector enabled) +# +-------------------- BODLEVEL (2.7V) +# ATMega8 FUSE_H (Fuse high byte): +# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) +# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 +# | | | | | +-------- BOOTSZ1 +# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) +# | | | +-------------- CKOPT (full output swing) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ WDTON (WDT not always on) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATMega48/88/168 ############################## +# ATMega*8 FUSE_L (Fuse low byte): +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ CKOUT (if 0: Clock output enabled) +# +-------------------- CKDIV8 (if 0: divide by 8) +# ATMega*8 FUSE_H (Fuse high byte): +# 0xde = 1 1 0 1 1 1 1 0 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- WDTON (if 0: watchdog always on) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATTiny25/45/85 ############################### +# ATMega*5 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATMega*5 FUSE_H (Fuse high byte): +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +################################ ATTiny2313 ################################# +# ATTiny2313 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATTiny2313 FUSE_H (Fuse high byte): +# 0xdb = 1 1 0 1 1 0 1 1 +# ^ ^ ^ ^ \-+-/ ^ +# | | | | | +---- RSTDISBL (disable external reset -> enabled) +# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# +-------------------- DWEN (debug wire enable) + + +# symbolic targets: +help: + @echo "This Makefile has no default rule. Use one of the following:" + @echo "make hex ....... to build main.hex" + @echo "make program ... to flash fuses and firmware" + @echo "make fuse ...... to flash the fuses" + @echo "make flash ..... to flash the firmware (use this on metaboard)" + @echo "make clean ..... to delete objects and hex file" + +hex: main.hex + +program: flash fuse + +# rule for programming fuse bits: +fuse: + @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ + { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } + $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m + +# rule for uploading firmware: +flash: main.hex + $(AVRDUDE) -U flash:w:main.hex:i + +# rule for deleting dependent files (those which can be built by Make): +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# Generic rule for compiling C files: +.c.o: + $(COMPILE) -c $< -o $@ + +# Generic rule for assembling Assembler source files: +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +# Generic rule for compiling C to assembler, used for debugging only. +.c.s: + $(COMPILE) -S $< -o $@ + +# file targets: + +# Since we don't want to ship the driver multipe times, we copy it into this project: +usbdrv: + cp -r ../../../usbdrv . + +main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it + $(COMPILE) -o main.elf $(OBJECTS) + +main.hex: main.elf + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.elf main.hex + avr-size main.hex + +# debugging targets: + +disasm: main.elf + avr-objdump -d main.elf + +cpp: + $(COMPILE) -E main.c diff --git a/packages/vusb-20121206/examples/hid-data/firmware/main.c b/packages/vusb-20121206/examples/hid-data/firmware/main.c new file mode 100644 index 0000000..9e4241f --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/firmware/main.c @@ -0,0 +1,140 @@ +/* Name: main.c + * Project: hid-data, example how to use HID for data transfer + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This example should run on most AVRs with only little changes. No special +hardware resources except INT0 are used. You may have to change usbconfig.h for +different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or +at least be connected to INT0 as well. +*/ + +#include +#include +#include /* for sei() */ +#include /* for _delay_ms() */ +#include + +#include /* required by usbdrv.h */ +#include "usbdrv.h" +#include "oddebug.h" /* This is also an example for using debug macros */ + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +PROGMEM const char usbHidReportDescriptor[22] = { /* USB report descriptor */ + 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Vendor Usage 1) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x80, // REPORT_COUNT (128) + 0x09, 0x00, // USAGE (Undefined) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0xc0 // END_COLLECTION +}; +/* Since we define only one feature report, we don't use report-IDs (which + * would be the first byte of the report). The entire report consists of 128 + * opaque data bytes. + */ + +/* The following variables store the status of the current data transfer */ +static uchar currentAddress; +static uchar bytesRemaining; + +/* ------------------------------------------------------------------------- */ + +/* usbFunctionRead() is called when the host requests a chunk of data from + * the device. For more information see the documentation in usbdrv/usbdrv.h. + */ +uchar usbFunctionRead(uchar *data, uchar len) +{ + if(len > bytesRemaining) + len = bytesRemaining; + eeprom_read_block(data, (uchar *)0 + currentAddress, len); + currentAddress += len; + bytesRemaining -= len; + return len; +} + +/* usbFunctionWrite() is called when the host sends a chunk of data to the + * device. For more information see the documentation in usbdrv/usbdrv.h. + */ +uchar usbFunctionWrite(uchar *data, uchar len) +{ + if(bytesRemaining == 0) + return 1; /* end of transfer */ + if(len > bytesRemaining) + len = bytesRemaining; + eeprom_write_block(data, (uchar *)0 + currentAddress, len); + currentAddress += len; + bytesRemaining -= len; + return bytesRemaining == 0; /* return 1 if this was the last chunk */ +} + +/* ------------------------------------------------------------------------- */ + +usbMsgLen_t usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; + + if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* HID class request */ + if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + /* since we have only one report type, we can ignore the report-ID */ + bytesRemaining = 128; + currentAddress = 0; + return USB_NO_MSG; /* use usbFunctionRead() to obtain data */ + }else if(rq->bRequest == USBRQ_HID_SET_REPORT){ + /* since we have only one report type, we can ignore the report-ID */ + bytesRemaining = 128; + currentAddress = 0; + return USB_NO_MSG; /* use usbFunctionWrite() to receive data from host */ + } + }else{ + /* ignore vendor type requests, we don't use any */ + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ +uchar i; + + wdt_enable(WDTO_1S); + /* Even if you don't use the watchdog, turn it off here. On newer devices, + * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! + */ + /* RESET status: all port bits are inputs without pull-up. + * That's the way we need D+ and D-. Therefore we don't need any + * additional hardware initialization. + */ + odDebugInit(); + DBG1(0x00, 0, 0); /* debug output: main starts */ + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + sei(); + DBG1(0x01, 0, 0); /* debug output: main loop starts */ + for(;;){ /* main event loop */ + DBG1(0x02, 0, 0); /* debug output: main loop iterates */ + wdt_reset(); + usbPoll(); + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/hid-data/firmware/usbconfig.h b/packages/vusb-20121206/examples/hid-data/firmware/usbconfig.h new file mode 100644 index 0000000..f59c0bd --- /dev/null +++ b/packages/vusb-20121206/examples/hid-data/firmware/usbconfig.h @@ -0,0 +1,381 @@ +/* Name: usbconfig.h + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#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 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 +/* 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 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! [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 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 ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#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 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 + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 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. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* 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 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.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 1 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 1 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * 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) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * 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. + */ +#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 0 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID 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 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 '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 USB-IDs-for-free.txt for + * details. + */ +#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 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 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * 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_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 +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 22 +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + 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), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * 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 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + + +#define usbMsgPtr_t unsigned short +/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to + * a scalar type here because gcc generates slightly shorter code for scalar + * arithmetics than for pointer arithmetics. Remove this define for backward + * type compatibility or define it to an 8 bit type if you use data in RAM only + * and all RAM is below 256 bytes (tiny memory model in IAR CC). + */ + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #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_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/packages/vusb-20121206/examples/hid-mouse/Readme.txt b/packages/vusb-20121206/examples/hid-mouse/Readme.txt new file mode 100644 index 0000000..e0c8142 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-mouse/Readme.txt @@ -0,0 +1,48 @@ +This is the Readme file for hid-mouse, an example of a USB mouse device. In +order to have as little dependencies on hardware and architecture as +possible, mouse movements are computed internally so that the mouse pointer +moves in a circle. + + +WHAT IS DEMONSTRATED? +===================== +This example demonstrates how HID class devices are implemented. The example +is kept as simple as possible, except the report descriptor which is taken +from a real-world mouse. + +It does NOT include a host side driver because all modern operating systems +include one. It does NOT implement USBRQ_HID_SET_REPORT and report-IDs. See +the "hid-data" example for this topic. It does NOT implement any special +features such as suspend mode etc. + + +PREREQUISITES +============= +Target hardware: You need an AVR based circuit based on one of the examples +(see the "circuits" directory at the top level of this package), e.g. the +metaboard (http://www.obdev.at/goto.php?t=metaboard). + +AVR development environment: You need the gcc tool chain for the AVR, see +the Prerequisites section in the top level Readme file for how to obtain it. + + +BUILDING THE FIRMWARE +===================== +Change to the "firmware" directory and modify Makefile according to your +architecture (CPU clock, target device, fuse values) and ISP programmer. Then +edit usbconfig.h according to your pin assignments for D+ and D-. The default +settings are for the metaboard hardware. + +Type "make hex" to build main.hex, then "make flash" to upload the firmware +to the device. Don't forget to run "make fuse" once to program the fuses. If +you use a prototyping board with boot loader, follow the instructions of the +boot loader instead. + +Please note that the first "make hex" copies the driver from the top level +into the firmware directory. If you use a different build system than our +Makefile, you must copy the driver by hand. + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/hid-mouse/firmware/Makefile b/packages/vusb-20121206/examples/hid-mouse/firmware/Makefile new file mode 100644 index 0000000..cac9c9d --- /dev/null +++ b/packages/vusb-20121206/examples/hid-mouse/firmware/Makefile @@ -0,0 +1,163 @@ +# Name: Makefile +# Project: hid-mouse example +# Author: Christian Starkjohann +# Creation Date: 2008-04-07 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +DEVICE = atmega168 +F_CPU = 16000000 # in Hz +FUSE_L = # see below for fuse values for particular devices +FUSE_H = +AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer + +CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) + +############################################################################## +# Fuse values for particular devices +############################################################################## +# If your device is not listed here, go to +# http://palmavr.sourceforge.net/cgi-bin/fc.cgi +# and choose options for external crystal clock and no clock divider +# +################################## ATMega8 ################################## +# ATMega8 FUSE_L (Fuse low byte): +# 0x9f = 1 0 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ BODEN (BrownOut Detector enabled) +# +-------------------- BODLEVEL (2.7V) +# ATMega8 FUSE_H (Fuse high byte): +# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) +# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 +# | | | | | +-------- BOOTSZ1 +# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) +# | | | +-------------- CKOPT (full output swing) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ WDTON (WDT not always on) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATMega48/88/168 ############################## +# ATMega*8 FUSE_L (Fuse low byte): +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ CKOUT (if 0: Clock output enabled) +# +-------------------- CKDIV8 (if 0: divide by 8) +# ATMega*8 FUSE_H (Fuse high byte): +# 0xde = 1 1 0 1 1 1 1 0 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- WDTON (if 0: watchdog always on) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (reset pin is enabled) +# +############################## ATTiny25/45/85 ############################### +# ATMega*5 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATMega*5 FUSE_H (Fuse high byte): +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +################################ ATTiny2313 ################################# +# ATTiny2313 FUSE_L (Fuse low byte): +# 0xef = 1 1 1 0 1 1 1 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) +# ATTiny2313 FUSE_H (Fuse high byte): +# 0xdb = 1 1 0 1 1 0 1 1 +# ^ ^ ^ ^ \-+-/ ^ +# | | | | | +---- RSTDISBL (disable external reset -> enabled) +# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# +-------------------- DWEN (debug wire enable) + + +# symbolic targets: +help: + @echo "This Makefile has no default rule. Use one of the following:" + @echo "make hex ....... to build main.hex" + @echo "make program ... to flash fuses and firmware" + @echo "make fuse ...... to flash the fuses" + @echo "make flash ..... to flash the firmware (use this on metaboard)" + @echo "make clean ..... to delete objects and hex file" + +hex: main.hex + +program: flash fuse + +# rule for programming fuse bits: +fuse: + @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ + { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } + $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m + +# rule for uploading firmware: +flash: main.hex + $(AVRDUDE) -U flash:w:main.hex:i + +# rule for deleting dependent files (those which can be built by Make): +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# Generic rule for compiling C files: +.c.o: + $(COMPILE) -c $< -o $@ + +# Generic rule for assembling Assembler source files: +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +# Generic rule for compiling C to assembler, used for debugging only. +.c.s: + $(COMPILE) -S $< -o $@ + +# file targets: + +# Since we don't want to ship the driver multipe times, we copy it into this project: +usbdrv: + cp -r ../../../usbdrv . + +main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it + $(COMPILE) -o main.elf $(OBJECTS) + +main.hex: main.elf + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.elf main.hex + avr-size main.hex + +# debugging targets: + +disasm: main.elf + avr-objdump -d main.elf + +cpp: + $(COMPILE) -E main.c diff --git a/packages/vusb-20121206/examples/hid-mouse/firmware/main.c b/packages/vusb-20121206/examples/hid-mouse/firmware/main.c new file mode 100644 index 0000000..f13361e --- /dev/null +++ b/packages/vusb-20121206/examples/hid-mouse/firmware/main.c @@ -0,0 +1,163 @@ +/* Name: main.c + * Project: hid-mouse, a very simple HID example + * Author: Christian Starkjohann + * Creation Date: 2008-04-07 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This example should run on most AVRs with only little changes. No special +hardware resources except INT0 are used. You may have to change usbconfig.h for +different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or +at least be connected to INT0 as well. + +We use VID/PID 0x046D/0xC00E which is taken from a Logitech mouse. Don't +publish any hardware using these IDs! This is for demonstration only! +*/ + +#include +#include +#include /* for sei() */ +#include /* for _delay_ms() */ + +#include /* required by usbdrv.h */ +#include "usbdrv.h" +#include "oddebug.h" /* This is also an example for using debug macros */ + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +PROGMEM const char usbHidReportDescriptor[52] = { /* USB report descriptor, size must match usbconfig.h */ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x02, // USAGE (Mouse) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x01, // USAGE (Pointer) + 0xA1, 0x00, // COLLECTION (Physical) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM + 0x29, 0x03, // USAGE_MAXIMUM + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x05, // REPORT_SIZE (5) + 0x81, 0x03, // INPUT (Const,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x38, // USAGE (Wheel) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7F, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x03, // REPORT_COUNT (3) + 0x81, 0x06, // INPUT (Data,Var,Rel) + 0xC0, // END_COLLECTION + 0xC0, // END COLLECTION +}; +/* This is the same report descriptor as seen in a Logitech mouse. The data + * described by this descriptor consists of 4 bytes: + * . . . . . B2 B1 B0 .... one byte with mouse button states + * X7 X6 X5 X4 X3 X2 X1 X0 .... 8 bit signed relative coordinate x + * Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 .... 8 bit signed relative coordinate y + * W7 W6 W5 W4 W3 W2 W1 W0 .... 8 bit signed relative coordinate wheel + */ +typedef struct{ + uchar buttonMask; + char dx; + char dy; + char dWheel; +}report_t; + +static report_t reportBuffer; +static int sinus = 7 << 6, cosinus = 0; +static uchar idleRate; /* repeat rate for keyboards, never used for mice */ + + +/* The following function advances sin/cos by a fixed angle + * and stores the difference to the previous coordinates in the report + * descriptor. + * The algorithm is the simulation of a second order differential equation. + */ +static void advanceCircleByFixedAngle(void) +{ +char d; + +#define DIVIDE_BY_64(val) (val + (val > 0 ? 32 : -32)) >> 6 /* rounding divide */ + reportBuffer.dx = d = DIVIDE_BY_64(cosinus); + sinus += d; + reportBuffer.dy = d = DIVIDE_BY_64(sinus); + cosinus -= d; +} + +/* ------------------------------------------------------------------------- */ + +usbMsgLen_t usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; + + /* The following requests are never used. But since they are required by + * the specification, we implement them in this example. + */ + if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ + DBG1(0x50, &rq->bRequest, 1); /* debug output: print our request */ + if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + /* we only have one report type, so don't look at wValue */ + usbMsgPtr = (void *)&reportBuffer; + return sizeof(reportBuffer); + }else if(rq->bRequest == USBRQ_HID_GET_IDLE){ + usbMsgPtr = &idleRate; + return 1; + }else if(rq->bRequest == USBRQ_HID_SET_IDLE){ + idleRate = rq->wValue.bytes[1]; + } + }else{ + /* no vendor specific requests implemented */ + } + return 0; /* default for not implemented requests: return no data back to host */ +} + +/* ------------------------------------------------------------------------- */ + +int __attribute__((noreturn)) main(void) +{ +uchar i; + + wdt_enable(WDTO_1S); + /* Even if you don't use the watchdog, turn it off here. On newer devices, + * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! + */ + /* RESET status: all port bits are inputs without pull-up. + * That's the way we need D+ and D-. Therefore we don't need any + * additional hardware initialization. + */ + odDebugInit(); + DBG1(0x00, 0, 0); /* debug output: main starts */ + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + sei(); + DBG1(0x01, 0, 0); /* debug output: main loop starts */ + for(;;){ /* main event loop */ + DBG1(0x02, 0, 0); /* debug output: main loop iterates */ + wdt_reset(); + usbPoll(); + if(usbInterruptIsReady()){ + /* called after every poll of the interrupt endpoint */ + advanceCircleByFixedAngle(); + DBG1(0x03, 0, 0); /* debug output: interrupt report prepared */ + usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer)); + } + } +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/hid-mouse/firmware/usbconfig.h b/packages/vusb-20121206/examples/hid-mouse/firmware/usbconfig.h new file mode 100644 index 0000000..0c0d7c8 --- /dev/null +++ b/packages/vusb-20121206/examples/hid-mouse/firmware/usbconfig.h @@ -0,0 +1,381 @@ +/* Name: usbconfig.h + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#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 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 +/* 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 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! [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 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 ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#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 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 + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 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. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* 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 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.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 0 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * 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) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * 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. + */ +#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 0 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID 0xe8, 0x03 /* VOTI's lab use PID */ +/* This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you may use one of obdev's free shared VID/PID pairs. See the file + * USB-IDs-for-free.txt for details! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 8 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'M', 'o', 'u', 's', 'e' +#define USB_CFG_DEVICE_NAME_LEN 5 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * 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_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 +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 52 +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + 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), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * 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 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + + +#define usbMsgPtr_t unsigned short +/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to + * a scalar type here because gcc generates slightly shorter code for scalar + * arithmetics than for pointer arithmetics. Remove this define for backward + * type compatibility or define it to an 8 bit type if you use data in RAM only + * and all RAM is below 256 bytes (tiny memory model in IAR CC). + */ + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #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_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/packages/vusb-20121206/examples/usbtool/Makefile b/packages/vusb-20121206/examples/usbtool/Makefile new file mode 100644 index 0000000..1f2a8ab --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/Makefile @@ -0,0 +1,47 @@ +# Name: Makefile +# Project: usbtool +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + + +# Concigure the following definitions according to your system. +# This Makefile has been tested on Mac OS X, Linux and Windows. + +# Use the following 3 lines on Unix (uncomment the framework on Mac OS X): +USBFLAGS = `libusb-config --cflags` +USBLIBS = `libusb-config --libs` +EXE_SUFFIX = + +# Use the following 3 lines on Windows and comment out the 3 above. You may +# have to change the include paths to where you installed libusb-win32 +#USBFLAGS = -I/usr/local/include +#USBLIBS = -L/usr/local/lib -lusb +#EXE_SUFFIX = .exe + +NAME = usbtool + +OBJECTS = opendevice.o $(NAME).o + +CC = gcc +CFLAGS = $(CPPFLAGS) $(USBFLAGS) -O -g -Wall +LIBS = $(USBLIBS) + +PROGRAM = $(NAME)$(EXE_SUFFIX) + + +all: $(PROGRAM) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(PROGRAM): $(OBJECTS) + $(CC) -o $(PROGRAM) $(OBJECTS) $(LIBS) + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f *.o $(PROGRAM) diff --git a/packages/vusb-20121206/examples/usbtool/Makefile.windows b/packages/vusb-20121206/examples/usbtool/Makefile.windows new file mode 100644 index 0000000..8298dd3 --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/Makefile.windows @@ -0,0 +1,17 @@ +# Name: Makefile.windows +# Project: usbtool +# Author: Christian Starkjohann +# Creation Date: 2008-04-06 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS = -I/usr/local/mingw/include +USBLIBS = -L/usr/local/mingw/lib -lusb +EXE_SUFFIX = .exe diff --git a/packages/vusb-20121206/examples/usbtool/Readme.txt b/packages/vusb-20121206/examples/usbtool/Readme.txt new file mode 100644 index 0000000..33f527c --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/Readme.txt @@ -0,0 +1,209 @@ +This is the Readme file for usbtool, a general purpose command line utility +which can send USB requests to arbitrary devices. Usbtool is based on libusb. + + +WHAT IS USBTOOL GOOD FOR? +========================= +When you implement a communication protocol like USB, you must usually write +two programs: one on each end of the communication. For USB, this means that +you must write a firmware for the device and driver software for the host. + +Usbtool can save you the work of writing the host software, at least during +firmware development and testing. Usbtool can send control-in and -out +requests to arbitrary devices and send and receive data on interrupt- and +bulk-endpoints. + +Usbtool is not only a useful developer tool, it's also an example for using +libusb for communication with the device. + + +SYNOPSIS +======== + usbtool [options] + + +COMMANDS +======== + list + This command prints a list of devices found on all available USB busses. + Options -v, -V, -p and -P can be used to filter the list. + + control in|out + Sends a control-in or control-out request to the device. The request + parameters are: + type ........ Type of request, can be "standard", "class", "vendor" or + "reserved". The type determines which software module in + the device is responsible for answering the request: + Standard requests are answered by the driver, class + requests by the class implementation (e.g. HID, CDC) and + vendor requests by custom code. + recipient ... Recipient of the request in the device. Can be "device", + "interface", "endpoint" or "other". For standard and + class requests, the specification defines a recipient for + each request. For vendor requests, choose whatever your + code expects. + request ..... 8 bit numeric value identifying the request. + value ....... 16 bit numeric value passed to the device. + index ....... another 16 bit numeric value passed to the device. + Use options -v, -V, -p and -P to single out a particular device. Use + options -d or -D to to send data in an OUT request. Use options -n, -O + and -b to determine what to do with data received in an IN request. + + interrupt in|out + Sends or receives data on an interrupt-out resp. -in endpoint. + Use options -v, -V, -p and -P to single out a particular device. Use + options -d or -D to to send data to an OUT endpoint. Use options -n, -O + and -b to determine what to do with data received from an IN endpoint. + Use option -e to set the endpoint number, -c to choose a configuration + -i to claim a particular interface. + + bulk in|out + Same as "interrupt in" and "interrupt out", but for bulk endpoints. + + +OPTIONS +======= +Most options have already been mentioned at the commands which use them. +here is a complete list: + + -h or -? + Prints a short help. + + -v + Numeric vendor ID, can be "*" to allow any VID. Take only devices with + matching vendor ID into account. + + -p + Numeric product ID, can be "*" to allow any PID. Take only devices with + matching product ID into account. + + -V + Shell style matching pattern for vendor name. Take only devices into + account which have a vendor name that matches this pattern. + + -P + Shell style matching pattern for product name. Take only devices into + account which have a product name that matches this pattern. + + -S + Shell style matching pattern for serial number. Take only devices into + account which have a serial number that matches this pattern. + + -d + Data bytes to send to the device, comma separated list of numeric values. + E.g.: "1,2,3,4,5". + + -D + Binary data sent to the device should be taken from this file. + + -O + Write received data bytes to the given file. Format is either hex or + binary, depending on the -b flag. By default, received data is printed + to standard output. + + -b + Request binary output format for files and standard output. Default is + a hexadecimal listing. + + -n + Numeric value: Maximum number of bytes to receive. This value is passed + directly to the libusb API functions. + + -e + Numeric value: Endpoint number for interrupt and bulk commands. + + -t + Numeric value: Timeout in milliseconds for the request. This value is + passed directly to the libusb API functions. + + -c + Numeric value: Interrupt and bulk endpoints can usually only be used if + a configuration and an interface has been chosen. Use -c and -i to + specify configuration and interface values. + + -i + Numeric value: Interrupt and bulk endpoints can usually only be used if + a configuration and an interface has been chosen. Use -c and -i to + specify configuration and interface values. + + -w + Usbtool may be too verbose with warnings for some applications. Use this + option to suppress USB warnings. + + +NUMERIC VALUES +============== +All numeric values can be given in hexadecimal, decimal or octal. Hex values +are identified by their 0x or 0X prefix, octal values by a leading "0" (the +digit zero) and decimal values because they start with a non-zero digit. An +optional sign character is allowed. The special value "*" is translated to +zero and stands for "any value" in some contexts. + + +SHELL STYLE MATCHING PATTERNS +============================= +Some options take shell style matching patterns as an argument. This refers +to Unix shells and their file wildcard operations: + + "*" (asterisk character) matches any number (0 to infinite) of any + characters. + + "?" matches exactly one arbitrary character. + + A list of characters in square brackets (e.g. "[abc]") matches any of the + characters in the list. If a dash ("-") is in the list, it must be the + first or the last character. If a caret ("^") is in the list, it must + not be the first character. A closing square bracket ("]") must be the + first character in the list. A range of characters can be specified in + the way "[a-z]". This matches all characters with numeric representation + (usually ASCII) starting with "a" and ending with "z". The entire + construct matches only one character. + + A list of characters in square brackets starting with a caret ("^"), e.g. + ("[^abc]") matches any character NOT in the list. The other rules are as + above. + + "\" (backslash) followed by any character matches that following + character. This can be used to escape "*", "?", "[" and "\". + + +BUILDING USBTOOL +================ +Usbtool uses libusb on Unix and libusb-win32 on Windows. These libraries can +be obtained from http://libusb.sourceforge.net/ and +http://libusb-win32.sourceforge.net/ respectively. On Unix, a simple "make" +should compile the sources (although you may have to edit Makefile to +include or remove additional libraries). On Windows, we recommend that you +use MinGW and MSYS. See the top level Readme file for details. Edit +Makefile.windows according to your library installation paths and build with +"make -f Makefile.windows". + + +EXAMPLES +======== +To list all devices connected to your computer, do + + usbtool -w list + +To check whether our selection options single out the desired device, use eg. + + usbtool -w -P LEDControl list + +This command shows all LEDControl devices connected or prints nothing if +none is found. LEDControl is the device from the "custom-class" example. + +You can also send commands to the LEDControl device using usbtool. From +the file requests.h in custom-class/firmware, we know that the set-status +request has numeric value 1 and the get-status request is 2. See this file +for details of the protocol used. We can therefore query the status with + + usbtool -w -P LEDControl control in vendor device 2 0 0 + +This command prints 0x00 if the LED is off or 0x01 if it is on. To turn the +LED on, use + + usbtool -w -P LEDControl control out vendor device 1 1 0 + +and to turn it off, use + + usbtool -w -P LEDControl control out vendor device 1 0 0 + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/examples/usbtool/opendevice.c b/packages/vusb-20121206/examples/usbtool/opendevice.c new file mode 100644 index 0000000..ea88e86 --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/opendevice.c @@ -0,0 +1,202 @@ +/* Name: opendevice.c + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The functions in this module can be used to find and open a device based on +libusb or libusb-win32. +*/ + +#include +#include "opendevice.h" + +/* ------------------------------------------------------------------------- */ + +#define MATCH_SUCCESS 1 +#define MATCH_FAILED 0 +#define MATCH_ABORT -1 + +/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ +static int _shellStyleMatch(char *text, char *p) +{ +int last, matched, reverse; + + for(; *p; text++, p++){ + if(*text == 0 && *p != '*') + return MATCH_ABORT; + switch(*p){ + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if(*text != *p) + return MATCH_FAILED; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while(*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if(*p == 0) + /* Trailing star matches everything. */ + return MATCH_SUCCESS; + while(*text) + if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) + return matched; + return MATCH_ABORT; + case '[': + reverse = p[1] == '^'; + if(reverse) /* Inverted character class. */ + p++; + matched = MATCH_FAILED; + if(p[1] == ']' || p[1] == '-') + if(*++p == *text) + matched = MATCH_SUCCESS; + for(last = *p; *++p && *p != ']'; last = *p) + if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) + matched = MATCH_SUCCESS; + if(matched == reverse) + return MATCH_FAILED; + continue; + } + } + return *text == 0; +} + +/* public interface for shell style matching: returns 0 if fails, 1 if matches */ +static int shellStyleMatch(char *text, char *pattern) +{ + if(pattern == NULL) /* NULL pattern is synonymous to "*" */ + return 1; + return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +/* ------------------------------------------------------------------------- */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; + + usb_find_busses(); + usb_find_devices(); + for(bus = usb_get_busses(); bus; bus = bus->next){ + for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ + if((vendorID == 0 || dev->descriptor.idVendor == vendorID) + && (productID == 0 || dev->descriptor.idProduct == productID)){ + char vendor[256], product[256], serial[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + continue; + } + /* now check whether the names match: */ + len = vendor[0] = 0; + if(dev->descriptor.iManufacturer > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen device from vendor ->%s<-\n", vendor); */ + if(shellStyleMatch(vendor, vendorNamePattern)){ + len = product[0] = 0; + if(dev->descriptor.iProduct > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen product ->%s<-\n", product); */ + if(shellStyleMatch(product, productNamePattern)){ + len = serial[0] = 0; + if(dev->descriptor.iSerialNumber > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + } + if(shellStyleMatch(serial, serialNamePattern)){ + if(printMatchingDevicesFp != NULL){ + if(serial[0] == 0){ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); + }else{ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); + } + }else{ + break; + } + } + } + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) /* we have found a deice */ + break; + } + if(handle != NULL){ + errorCode = 0; + *device = handle; + } + if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ + errorCode = 0; + return errorCode; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/examples/usbtool/opendevice.h b/packages/vusb-20121206/examples/usbtool/opendevice.h new file mode 100644 index 0000000..c925276 --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/opendevice.h @@ -0,0 +1,76 @@ +/* Name: opendevice.h + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module offers additional functionality for host side drivers based on +libusb or libusb-win32. It includes a function to find and open a device +based on numeric IDs and textual description. It also includes a function to +obtain textual descriptions from a device. + +To use this functionality, simply copy opendevice.c and opendevice.h into your +project and add them to your Makefile. You may modify and redistribute these +files according to the GNU General Public License (GPL) version 2 or 3. +*/ + +#ifndef __OPENDEVICE_H_INCLUDED__ +#define __OPENDEVICE_H_INCLUDED__ + +#include /* this is libusb, see http://libusb.sourceforge.net/ */ +#include + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen); +/* This function gets a string descriptor from the device. 'index' is the + * string descriptor index. The string is returned in ISO Latin 1 encoding in + * 'buf' and it is terminated with a 0-character. The buffer size must be + * passed in 'buflen' to prevent buffer overflows. A libusb device handle + * must be given in 'dev'. + * Returns: The length of the string (excluding the terminating 0) or + * a negative number in case of an error. If there was an error, use + * usb_strerror() to obtain the error message. + */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp); +/* This function iterates over all devices on all USB busses and searches for + * a device. Matching is done first by means of Vendor- and Product-ID (passed + * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard). + * When a device matches by its IDs, matching by names is performed. Name + * matching can be done on textual vendor name ('vendorNamePattern'), product + * name ('productNamePattern') and serial number ('serialNamePattern'). A + * device matches only if all non-null pattern match. If you don't care about + * a string, pass NULL for the pattern. Patterns are Unix shell style pattern: + * '*' stands for 0 or more characters, '?' for one single character, a list + * of characters in square brackets for a single character from the list + * (dashes are allowed to specify a range) and if the lis of characters begins + * with a caret ('^'), it matches one character which is NOT in the list. + * Other parameters to the function: If 'warningsFp' is not NULL, warning + * messages are printed to this file descriptor with fprintf(). If + * 'printMatchingDevicesFp' is not NULL, no device is opened but matching + * devices are printed to the given file descriptor with fprintf(). + * If a device is opened, the resulting USB handle is stored in '*device'. A + * pointer to a "usb_dev_handle *" type variable must be passed here. + * Returns: 0 on success, an error code (see defines below) on failure. + */ + +/* usbOpenDevice() error codes: */ +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + + +/* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */ + +#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */ +#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */ +#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */ +#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */ +#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */ + +#endif /* __OPENDEVICE_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/examples/usbtool/usbtool.c b/packages/vusb-20121206/examples/usbtool/usbtool.c new file mode 100644 index 0000000..56bdac1 --- /dev/null +++ b/packages/vusb-20121206/examples/usbtool/usbtool.c @@ -0,0 +1,355 @@ +/* Name: usbtool.c + * Project: V-USB examples, host side + * Author: Christian Starkjohann + * Creation Date: 2008-04-06 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This command line tool can perform various USB requests at arbitrary +USB devices. It is intended as universal host side tool for experimentation +and debugging purposes. It must be linked with libusb, a library for accessing +the USB bus from Linux, FreeBSD, Mac OS X and other Unix operating systems. +Libusb can be obtained from http://libusb.sourceforge.net/. +On Windows use libusb-win32 from http://libusb-win32.sourceforge.net/. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include /* this is libusb, see http://libusb.sourceforge.net/ */ +#include "opendevice.h" /* common code moved to separate module */ + +#define DEFAULT_USB_VID 0 /* any */ +#define DEFAULT_USB_PID 0 /* any */ + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [options] \n", name); + fprintf(stderr, + "Options are:\n" + " -h or -? (print this help and exit)\n" + " -v (defaults to 0x%x, can be '*' for any VID)\n" + " -p (defaults to 0x%x, can be '*' for any PID)\n" + " -V (shell style matching, defaults to '*')\n" + " -P (shell style matching, defaults to '*')\n" + " -S (shell style matching, defaults to '*')\n" + " -d (data byte for request, comma separated list)\n" + " -D (binary data for request taken from file)\n" + " -O (write received data bytes to file)\n" + " -b (binary output format, default is hex)\n" + " -n (maximum number of bytes to receive)\n" + " -e (specify endpoint for some commands)\n" + " -t (specify USB timeout in milliseconds)\n" + " -c (device configuration to choose)\n" + " -i (configuration interface to claim)\n" + " -w (suppress USB warnings, default is verbose)\n" + "\n" + "Commands are:\n" + " list (list all matching devices by name)\n" + " control in|out (send control request)\n" + " interrupt in|out (send or receive interrupt data)\n" + " bulk in|out (send or receive bulk data)\n" + "For valid enum values for and pass \"x\" for the value.\n" + "Objective Development's free VID/PID pairs are:\n" + " 5824/1500 for vendor class devices\n" + " 5824/1503 for HID class devices excluding mice and keyboards\n" + " 5824/1505 for CDC-ACM class devices\n" + " 5824/1508 for MIDI class devices\n" + , DEFAULT_USB_VID, DEFAULT_USB_PID + ); + + +} + +static int vendorID = DEFAULT_USB_VID; +static int productID = DEFAULT_USB_PID; +static char *vendorNamePattern = "*"; +static char *productNamePattern = "*"; +static char *serialPattern = "*"; +static char *sendBytes = NULL; +static int sendByteCount; +static char *outputFile = NULL; +static int endpoint = 0; +static int outputFormatIsBinary = 0; +static int showWarnings = 1; +static int usbTimeout = 5000; +static int usbCount = 128; +static int usbConfiguration = 1; +static int usbInterface = 0; + +static int usbDirection, usbType, usbRecipient, usbRequest, usbValue, usbIndex; /* arguments of control transfer */ + +/* ------------------------------------------------------------------------- */ + +/* ASCII to integer (number parsing) which allows hex (0x prefix), + * octal (0 prefix) and decimal (1-9 prefix) input. + */ +static int myAtoi(char *text) +{ +long l; +char *endPtr; + + if(strcmp(text, "*") == 0) + return 0; + l = strtol(text, &endPtr, 0); + if(endPtr == text){ + fprintf(stderr, "warning: can't parse numeric parameter ->%s<-, defaults to 0.\n", text); + l = 0; + }else if(*endPtr != 0){ + fprintf(stderr, "warning: numeric parameter ->%s<- only partially parsed.\n", text); + } + return l; +} + +static int parseEnum(char *text, ...) +{ +va_list vlist; +char *entries[64]; +int i, numEntries; + + va_start(vlist, text); + for(i = 0; i < 64; i++){ + entries[i] = va_arg(vlist, char *); + if(entries[i] == NULL) + break; + } + numEntries = i; + va_end(vlist); + for(i = 0; i < numEntries; i++){ + if(strcasecmp(text, entries[i]) == 0) + return i; + } + if(isdigit(*text)){ + return myAtoi(text); + } + fprintf(stderr, "Enum value \"%s\" not allowed. Allowed values are:\n", text); + for(i = 0; i < numEntries; i++){ + fprintf(stderr, " %s\n", entries[i]); + } + exit(1); +} + +/* ------------------------------------------------------------------------- */ + +#define ACTION_LIST 0 +#define ACTION_CONTROL 1 +#define ACTION_INTERRUPT 2 +#define ACTION_BULK 3 + +int main(int argc, char **argv) +{ +usb_dev_handle *handle = NULL; +int opt, len, action, argcnt; +char *myName = argv[0], *s, *rxBuffer = NULL; +FILE *fp; + + while((opt = getopt(argc, argv, "?hv:p:V:P:S:d:D:O:e:n:tbw")) != -1){ + switch(opt){ + case 'h': + case '?': /* -h or -? (print this help and exit) */ + usage(myName); + exit(1); + case 'v': /* -v (defaults to 0x%x, can be '*' for any VID) */ + vendorID = myAtoi(optarg); + break; + case 'p': /* -p (defaults to 0x%x, can be '*' for any PID) */ + productID = myAtoi(optarg); + break; + case 'V': /* -V (shell style matching, defaults to '*') */ + vendorNamePattern = optarg; + break; + case 'P': /* -P (shell style matching, defaults to '*') */ + productNamePattern = optarg; + break; + case 'S': /* -S (shell style matching, defaults to '*') */ + serialPattern = optarg; + break; + case 'd': /* -d (data bytes for requests given on command line) */ + while((s = strtok(optarg, ", ")) != NULL){ + optarg = NULL; + if(sendBytes != NULL){ + sendBytes = realloc(sendBytes, sendByteCount + 1); + }else{ + sendBytes = malloc(sendByteCount + 1); + } + sendBytes[sendByteCount++] = myAtoi(s); + } + break; + case 'D': /* -D (data bytes for request taken from file) */ + if((fp = fopen(optarg, "rb")) == NULL){ + fprintf(stderr, "error opening %s: %s\n", optarg, strerror(errno)); + exit(1); + } + fseek(fp, 0, SEEK_END); + len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if(sendBytes != NULL){ + sendBytes = realloc(sendBytes, sendByteCount + len); + }else{ + sendBytes = malloc(sendByteCount + len); + } + fread(sendBytes + sendByteCount, 1, len, fp); /* would need error checking */ + sendByteCount += len; + fclose(fp); + break; + case 'O': /* -O (write received data bytes to file) */ + outputFile = optarg; + break; + case 'e': /* -e (specify endpoint for some commands) */ + endpoint = myAtoi(optarg); + break; + case 't': /* -t (specify USB timeout in milliseconds) */ + usbTimeout = myAtoi(optarg); + break; + case 'b': /* -b (binary output format, default is hex) */ + outputFormatIsBinary = 1; + break; + case 'n': /* -n (maximum number of bytes to receive) */ + usbCount = myAtoi(optarg); + break; + case 'c': /* -c (device configuration to choose) */ + usbConfiguration = myAtoi(optarg); + break; + case 'i': /* -i (configuration interface to claim) */ + usbInterface = myAtoi(optarg); + break; + case 'w': /* -w (suppress USB warnings, default is verbose) */ + showWarnings = 0; + break; + default: + fprintf(stderr, "Option -%c unknown\n", opt); + exit(1); + } + } + argc -= optind; + argv += optind; + if(argc < 1){ + usage(myName); + exit(1); + } + argcnt = 2; + if(strcasecmp(argv[0], "list") == 0){ + action = ACTION_LIST; + argcnt = 1; + }else if(strcasecmp(argv[0], "control") == 0){ + action = ACTION_CONTROL; + argcnt = 7; + }else if(strcasecmp(argv[0], "interrupt") == 0){ + action = ACTION_INTERRUPT; + }else if(strcasecmp(argv[0], "bulk") == 0){ + action = ACTION_BULK; + }else{ + fprintf(stderr, "command %s not known\n", argv[0]); + usage(myName); + exit(1); + } + if(argc < argcnt){ + fprintf(stderr, "Not enough arguments.\n"); + usage(myName); + exit(1); + } + if(argc > argcnt){ + fprintf(stderr, "Warning: only %d arguments expected, rest ignored.\n", argcnt); + } + usb_init(); + if(usbOpenDevice(&handle, vendorID, vendorNamePattern, productID, productNamePattern, serialPattern, action == ACTION_LIST ? stdout : NULL, showWarnings ? stderr : NULL) != 0){ + fprintf(stderr, "Could not find USB device with VID=0x%x PID=0x%x Vname=%s Pname=%s Serial=%s\n", vendorID, productID, vendorNamePattern, productNamePattern, serialPattern); + exit(1); + } + if(action == ACTION_LIST) + exit(0); /* we've done what we were asked to do already */ + usbDirection = parseEnum(argv[1], "out", "in", NULL); + if(usbDirection){ /* IN transfer */ + rxBuffer = malloc(usbCount); + } + if(action == ACTION_CONTROL){ + int requestType; + usbType = parseEnum(argv[2], "standard", "class", "vendor", "reserved", NULL); + usbRecipient = parseEnum(argv[3], "device", "interface", "endpoint", "other", NULL); + usbRequest = myAtoi(argv[4]); + usbValue = myAtoi(argv[5]); + usbIndex = myAtoi(argv[6]); + requestType = ((usbDirection & 1) << 7) | ((usbType & 3) << 5) | (usbRecipient & 0x1f); + if(usbDirection){ /* IN transfer */ + len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, rxBuffer, usbCount, usbTimeout); + }else{ /* OUT transfer */ + len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, sendBytes, sendByteCount, usbTimeout); + } + }else{ /* must be ACTION_INTERRUPT or ACTION_BULK */ + int retries = 1; + if(usb_set_configuration(handle, usbConfiguration) && showWarnings){ + fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); + } + /* now try to claim the interface and detach the kernel HID driver on + * linux and other operating systems which support the call. + */ + while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){ +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){ + fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror()); + } +#endif + } + if(len != 0 && showWarnings) + fprintf(stderr, "Warning: could not claim interface: %s\n", usb_strerror()); + if(action == ACTION_INTERRUPT){ + if(usbDirection){ /* IN transfer */ + len = usb_interrupt_read(handle, endpoint, rxBuffer, usbCount, usbTimeout); + }else{ + len = usb_interrupt_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout); + } + }else{ + if(usbDirection){ /* IN transfer */ + len = usb_bulk_read(handle, endpoint, rxBuffer, usbCount, usbTimeout); + }else{ + len = usb_bulk_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout); + } + } + } + if(len < 0){ + fprintf(stderr, "USB error: %s\n", usb_strerror()); + exit(1); + } + if(usbDirection == 0) /* OUT */ + printf("%d bytes sent.\n", len); + if(rxBuffer != NULL){ + FILE *fp = stdout; + if(outputFile != NULL){ + fp = fopen(outputFile, outputFormatIsBinary ? "wb" : "w"); + if(fp == NULL){ + fprintf(stderr, "Error writing \"%s\": %s\n", outputFile, strerror(errno)); + exit(1); + } + } + if(outputFormatIsBinary){ + fwrite(rxBuffer, 1, len, fp); + }else{ + int i; + for(i = 0; i < len; i++){ + if(i != 0){ + if(i % 16 == 0){ + fprintf(fp, "\n"); + }else{ + fprintf(fp, " "); + } + } + fprintf(fp, "0x%02x", rxBuffer[i] & 0xff); + } + if(i != 0) + fprintf(fp, "\n"); + } + } + usb_close(handle); + if(rxBuffer != NULL) + free(rxBuffer); + return 0; +} diff --git a/packages/vusb-20121206/libs-device/Readme.txt b/packages/vusb-20121206/libs-device/Readme.txt new file mode 100644 index 0000000..76518dc --- /dev/null +++ b/packages/vusb-20121206/libs-device/Readme.txt @@ -0,0 +1,22 @@ +This is the Readme file for the libs-device directory. This directory contains +code snippets which may be useful for USB device firmware. + + +WHAT IS INCLUDED IN THIS DIRECTORY? +=================================== + +osccal.c and osccal.h + This module contains a function which calibrates the AVR's built-in RC + oscillator based on the USB frame clock. See osccal.h for a documentation + of the API. + +osctune.h + This header file contains a code snippet for usbconfig.h. With this code, + you can keep the AVR's internal RC oscillator in sync with the USB frame + clock. This is a continuous synchronization, not a single calibration at + USB reset as with osccal.c above. Please note that this code works only + if D- is wired to the interrupt, not D+. + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/libs-device/osccal.c b/packages/vusb-20121206/libs-device/osccal.c new file mode 100644 index 0000000..c1bff32 --- /dev/null +++ b/packages/vusb-20121206/libs-device/osccal.c @@ -0,0 +1,62 @@ +/* Name: osccal.c + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#include + +#ifndef uchar +#define uchar unsigned char +#endif + +/* ------------------------------------------------------------------------- */ +/* ------------------------ Oscillator Calibration ------------------------- */ +/* ------------------------------------------------------------------------- */ + +/* Calibrate the RC oscillator. Our timing reference is the Start Of Frame + * signal (a single SE0 bit) repeating every millisecond immediately after + * a USB RESET. We first do a binary search for the OSCCAL value and then + * optimize this value with a neighboorhod search. + */ +void calibrateOscillator(void) +{ +uchar step = 128; +uchar trialValue = 0, optimumValue; +int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); + + /* do a binary search: */ + do{ + OSCCAL = trialValue + step; + x = usbMeasureFrameLength(); /* proportional to current real frequency */ + if(x < targetValue) /* frequency still too low */ + trialValue += step; + step >>= 1; + }while(step > 0); + /* We have a precision of +/- 1 for optimum OSCCAL here */ + /* now do a neighborhood search for optimum value */ + optimumValue = trialValue; + optimumDev = x; /* this is certainly far away from optimum */ + for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){ + x = usbMeasureFrameLength() - targetValue; + if(x < 0) + x = -x; + if(x < optimumDev){ + optimumDev = x; + optimumValue = OSCCAL; + } + } + OSCCAL = optimumValue; +} +/* +Note: This calibration algorithm may try OSCCAL values of up to 192 even if +the optimum value is far below 192. It may therefore exceed the allowed clock +frequency of the CPU in low voltage designs! +You may replace this search algorithm with any other algorithm you like if +you have additional constraints such as a maximum CPU clock. +For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g. +ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in +both regions. +*/ diff --git a/packages/vusb-20121206/libs-device/osccal.h b/packages/vusb-20121206/libs-device/osccal.h new file mode 100644 index 0000000..1ed6006 --- /dev/null +++ b/packages/vusb-20121206/libs-device/osccal.h @@ -0,0 +1,62 @@ +/* Name: osccal.h + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module contains a function which calibrates the AVR's internal RC +oscillator so that the CPU runs at F_CPU (F_CPU is a macro which must be +defined when the module is compiled, best passed in the compiler command +line). The time reference is the USB frame clock of 1 kHz available +immediately after a USB RESET condition. Timing is done by counting CPU +cycles, so all interrupts must be disabled while the calibration runs. For +low level timing measurements, usbMeasureFrameLength() is called. This +function must be enabled in usbconfig.h by defining +USB_CFG_HAVE_MEASURE_FRAME_LENGTH to 1. It is recommended to call +calibrateOscillator() from the reset hook in usbconfig.h: + +#ifndef __ASSEMBLER__ +#include // for sei() +extern void calibrateOscillator(void); +#endif +#define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();} + +This routine is an alternative to the continuous synchronization described +in osctune.h. + +Algorithm used: +calibrateOscillator() first does a binary search in the OSCCAL register for +the best matching oscillator frequency. Then it does a next neighbor search +to find the value with the lowest clock rate deviation. It is guaranteed to +find the best match among neighboring values, but for version 5 oscillators +(which have a discontinuous relationship between OSCCAL and frequency) a +better match might be available in another OSCCAL region. + +Limitations: +This calibration algorithm may try OSCCAL values of up to 192 even if the +optimum value is far below 192. It may therefore exceed the allowed clock +frequency of the CPU in low voltage designs! +Precision depends on the OSCCAL vs. frequency dependency of the oscillator. +Typical precision for an ATMega168 (derived from the OSCCAL vs. F_RC diagram +in the data sheet) should be in the range of 0.4%. Only the 12.8 MHz and +16.5 MHz versions of V-USB (with built-in receiver PLL) can tolerate this +deviation! All other frequency modules require at least 0.2% precision. +*/ + +#ifndef __OSCCAL_H_INCLUDED__ +#define __OSCCAL_H_INCLUDED__ + +void calibrateOscillator(void); +/* This function calibrates the RC oscillator so that the CPU runs at F_CPU. + * It MUST be called immediately after the end of a USB RESET condition! + * Disable all interrupts during the call! + * It is recommended that you store the resulting value in EEPROM so that a + * good guess value is available after the next reset. + */ + + +#endif /* __OSCCAL_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/libs-device/osctune.h b/packages/vusb-20121206/libs-device/osctune.h new file mode 100644 index 0000000..12961e5 --- /dev/null +++ b/packages/vusb-20121206/libs-device/osctune.h @@ -0,0 +1,87 @@ +/* Name: osctune.h + * Author: Christian Starkjohann + * Creation Date: 2008-10-18 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This file is declared as C-header file although it is mostly documentation +how the RC oscillator can be kept in sync to the USB frame rate. The code +shown here must be added to usbconfig.h or this header file is included from +there. This code works only if D- is wired to the interrupt, not D+!!! + +This is an alternative to the osccal routine in osccal.c. It has the advantage +that the synchronization is done continuously and that it has more compact +code size. The disadvantages are slow synchronization (it may take a while +until the driver works), that messages immediately after the SOF pulse may be +lost (and need to be retried by the host) and that the interrupt is on D- +contrary to most examples. + +You may want to store a good calibration value in EEPROM for the next startup. +You know that the calibration value is good when the first USB message is +received. Do not store the value on every received message because the EEPROM +has a limited endurance. + +Notes: +(*) You must declare the global character variable "lastTimer0Value" in your +main code. + +(*) Timer 0 must be free running (not written by your code) and the prescaling +must be consistent with the TIMER0_PRESCALING define. + +(*) Good values for Timer 0 prescaling depend on how precise the clock must +be tuned and how far away from the default clock rate the target clock is. +For precise tuning, choose a low prescaler factor, for a broad range of tuning +choose a high one. A prescaler factor of 64 is good for the entire OSCCAL +range and allows a precision of better than +/-1%. A prescaler factor of 8 +allows tuning to slightly more than +/-6% of the default frequency and is +more precise than one step of OSCCAL. It is therefore not suitable to tune an +8 MHz oscillator to 12.5 MHz. + +Thanks to Henrik Haftmann for the idea to this routine! +*/ + +#define TIMER0_PRESCALING 64 /* must match the configuration for TIMER0 in main */ +#define TOLERATED_DEVIATION_PPT 5 /* max clock deviation before we tune in 1/10 % */ +/* derived constants: */ +#define EXPECTED_TIMER0_INCREMENT ((F_CPU / (1000 * TIMER0_PRESCALING)) & 0xff) +#define TOLERATED_DEVIATION (TOLERATED_DEVIATION_PPT * F_CPU / (1000000 * TIMER0_PRESCALING)) + +#ifdef __ASSEMBLER__ +macro tuneOsccal + push YH ;[0] + in YL, TCNT0 ;[2] + lds YH, lastTimer0Value ;[3] + sts lastTimer0Value, YL ;[5] + sub YL, YH ;[7] time passed since last frame + subi YL, EXPECTED_TIMER0_INCREMENT ;[8] +#if OSCCAL > 0x3f /* outside I/O addressable range */ + lds YH, OSCCAL ;[6] +#else + in YH, OSCCAL ;[6] assembler modle uses __SFR_OFFSET == 0 +#endif + cpi YL, TOLERATED_DEVIATION + 1 ;[10] + brmi notTooHigh ;[11] + subi YH, 1 ;[12] clock rate was too high +; brcs tuningOverflow ; optionally check for overflow + rjmp osctuneDone ;[13] +notTooHigh: + cpi YL, -TOLERATED_DEVIATION ;[13] + brpl osctuneDone ;[14] not too low + inc YH ;[15] clock rate was too low +; breq tuningOverflow ; optionally check for overflow +osctuneDone: +#if OSCCAL > 0x3f /* outside I/O addressable range */ + sts OSCCAL, YH ;[12-13] store tuned value +#else + out OSCCAL, YH ;[12-13] store tuned value +#endif +tuningOverflow: + pop YH ;[17] + endm ;[19] max number of cycles +#endif + +#define USB_SOF_HOOK tuneOsccal diff --git a/packages/vusb-20121206/libs-host/Readme.txt b/packages/vusb-20121206/libs-host/Readme.txt new file mode 100644 index 0000000..5117d18 --- /dev/null +++ b/packages/vusb-20121206/libs-host/Readme.txt @@ -0,0 +1,26 @@ +This is the Readme file for the libs-host directory. This directory contains +code snippets which may be useful for host side USB software. + + +WHAT IS INCLUDED IN THIS DIRECTORY? +=================================== + +opendevice.c and opendevice.h + This module contains a function to find and open a device given its + numeric IDs (VID, PID), names (vendor name and product name) and serial + number. It is based on libusb/libusb-win32 and returns a libusb device + handle. See opendevice.h for an API documentation. + +hiddata.c and hiddata.h + This module contains functions for data transfer over HID feature reports. + It is based on libusb on Unix and native Windows functions on Windows. No + driver DLL is needed on Windows. See hiddata.h for an API documentation. + +hidsdi.h + This DDK header file is missing in the free MinGW version of the Windows + DDK. Use this version if you get an "include file not found" error. + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/libs-host/hiddata.c b/packages/vusb-20121206/libs-host/hiddata.c new file mode 100644 index 0000000..203ed19 --- /dev/null +++ b/packages/vusb-20121206/libs-host/hiddata.c @@ -0,0 +1,323 @@ +/* Name: hiddata.c + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#include +#include "hiddata.h" + +/* ######################################################################## */ +#if defined(WIN32) /* ##################################################### */ +/* ######################################################################## */ + +#include +#include +#include "hidsdi.h" +#include + +#ifdef DEBUG +#define DEBUG_PRINT(arg) printf arg +#else +#define DEBUG_PRINT(arg) +#endif + +/* ------------------------------------------------------------------------ */ + +static void convertUniToAscii(char *buffer) +{ +unsigned short *uni = (void *)buffer; +char *ascii = buffer; + + while(*uni != 0){ + if(*uni >= 256){ + *ascii++ = '?'; + }else{ + *ascii++ = *uni++; + } + } + *ascii++ = 0; +} + +int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs) +{ +GUID hidGuid; /* GUID for HID driver */ +HDEVINFO deviceInfoList; +SP_DEVICE_INTERFACE_DATA deviceInfo; +SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL; +DWORD size; +int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */ +int errorCode = USBOPEN_ERR_NOTFOUND; +HANDLE handle = INVALID_HANDLE_VALUE; +HIDD_ATTRIBUTES deviceAttributes; + + HidD_GetHidGuid(&hidGuid); + deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); + deviceInfo.cbSize = sizeof(deviceInfo); + for(i=0;;i++){ + if(handle != INVALID_HANDLE_VALUE){ + CloseHandle(handle); + handle = INVALID_HANDLE_VALUE; + } + if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) + break; /* no more entries */ + /* first do a dummy call just to determine the actual size required */ + SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL); + if(deviceDetails != NULL) + free(deviceDetails); + deviceDetails = malloc(size); + deviceDetails->cbSize = sizeof(*deviceDetails); + /* this call is for real: */ + SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL); + DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath)); +#if 0 + /* If we want to access a mouse our keyboard, we can only use feature + * requests as the device is locked by Windows. It must be opened + * with ACCESS_TYPE_NONE. + */ + handle = CreateFile(deviceDetails->DevicePath, ACCESS_TYPE_NONE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); +#endif + /* attempt opening for R/W -- we don't care about devices which can't be accessed */ + handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); + if(handle == INVALID_HANDLE_VALUE){ + DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError())); + /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */ + continue; + } + deviceAttributes.Size = sizeof(deviceAttributes); + HidD_GetAttributes(handle, &deviceAttributes); + DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes.VendorID, deviceAttributes.ProductID)); + if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product) + continue; /* ignore this device */ + errorCode = USBOPEN_ERR_NOTFOUND; + if(vendorName != NULL && productName != NULL){ + char buffer[512]; + if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ + DEBUG_PRINT(("error obtaining vendor name\n")); + errorCode = USBOPEN_ERR_IO; + continue; + } + convertUniToAscii(buffer); + DEBUG_PRINT(("vendorName = \"%s\"\n", buffer)); + if(strcmp(vendorName, buffer) != 0) + continue; + if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){ + DEBUG_PRINT(("error obtaining product name\n")); + errorCode = USBOPEN_ERR_IO; + continue; + } + convertUniToAscii(buffer); + DEBUG_PRINT(("productName = \"%s\"\n", buffer)); + if(strcmp(productName, buffer) != 0) + continue; + } + break; /* we have found the device we are looking for! */ + } + SetupDiDestroyDeviceInfoList(deviceInfoList); + if(deviceDetails != NULL) + free(deviceDetails); + if(handle != INVALID_HANDLE_VALUE){ + *device = (usbDevice_t *)handle; + errorCode = 0; + } + return errorCode; +} + +/* ------------------------------------------------------------------------ */ + +void usbhidCloseDevice(usbDevice_t *device) +{ + CloseHandle((HANDLE)device); +} + +/* ------------------------------------------------------------------------ */ + +int usbhidSetReport(usbDevice_t *device, char *buffer, int len) +{ +BOOLEAN rval; + + rval = HidD_SetFeature((HANDLE)device, buffer, len); + return rval == 0 ? USBOPEN_ERR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ + +int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) +{ +BOOLEAN rval = 0; + + buffer[0] = reportNumber; + rval = HidD_GetFeature((HANDLE)device, buffer, *len); + return rval == 0 ? USBOPEN_ERR_IO : 0; +} + +/* ------------------------------------------------------------------------ */ + +/* ######################################################################## */ +#else /* defined WIN32 #################################################### */ +/* ######################################################################## */ + +#include +#include + +#define usbDevice usb_dev_handle /* use libusb's device structure */ + +/* ------------------------------------------------------------------------- */ + +#define USBRQ_HID_GET_REPORT 0x01 +#define USBRQ_HID_SET_REPORT 0x09 + +#define USB_HID_REPORT_TYPE_FEATURE 3 + + +static int usesReportIDs; + +/* ------------------------------------------------------------------------- */ + +static int usbhidGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; +static int didUsbInit = 0; + + if(!didUsbInit){ + usb_init(); + didUsbInit = 1; + } + usb_find_busses(); + usb_find_devices(); + for(bus=usb_get_busses(); bus; bus=bus->next){ + for(dev=bus->devices; dev; dev=dev->next){ + if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){ + char string[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); + continue; + } + if(vendorName == NULL && productName == NULL){ /* name does not matter */ + break; + } + /* now check whether the names match: */ + len = usbhidGetStringAscii(handle, dev->descriptor.iManufacturer, string, sizeof(string)); + if(len < 0){ + errorCode = USBOPEN_ERR_IO; + fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ + if(strcmp(string, vendorName) == 0){ + len = usbhidGetStringAscii(handle, dev->descriptor.iProduct, string, sizeof(string)); + if(len < 0){ + errorCode = USBOPEN_ERR_IO; + fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* fprintf(stderr, "seen product ->%s<-\n", string); */ + if(strcmp(string, productName) == 0) + break; + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) + break; + } + if(handle != NULL){ + errorCode = 0; + *device = (void *)handle; + usesReportIDs = _usesReportIDs; + } + return errorCode; +} + +/* ------------------------------------------------------------------------- */ + +void usbhidCloseDevice(usbDevice_t *device) +{ + if(device != NULL) + usb_close((void *)device); +} + +/* ------------------------------------------------------------------------- */ + +int usbhidSetReport(usbDevice_t *device, char *buffer, int len) +{ +int bytesSent, reportId = buffer[0]; + + if(!usesReportIDs){ + buffer++; /* skip dummy report ID */ + len--; + } + bytesSent = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | (reportId & 0xff), 0, buffer, len, 5000); + if(bytesSent != len){ + if(bytesSent < 0) + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USBOPEN_ERR_IO; + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len) +{ +int bytesReceived, maxLen = *len; + + if(!usesReportIDs){ + buffer++; /* make room for dummy report ID */ + maxLen--; + } + bytesReceived = usb_control_msg((void *)device, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | reportNumber, 0, buffer, maxLen, 5000); + if(bytesReceived < 0){ + fprintf(stderr, "Error sending message: %s\n", usb_strerror()); + return USBOPEN_ERR_IO; + } + *len = bytesReceived; + if(!usesReportIDs){ + buffer[-1] = reportNumber; /* add dummy report ID */ + (*len)++; + } + return 0; +} + +/* ######################################################################## */ +#endif /* defined WIN32 ################################################### */ +/* ######################################################################## */ diff --git a/packages/vusb-20121206/libs-host/hiddata.h b/packages/vusb-20121206/libs-host/hiddata.h new file mode 100644 index 0000000..245453d --- /dev/null +++ b/packages/vusb-20121206/libs-host/hiddata.h @@ -0,0 +1,70 @@ +/* Name: hiddata.h + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __HIDDATA_H_INCLUDED__ +#define __HIDDATA_H_INCLUDED__ + +/* +General Description: +This module implements an abstraction layer for data transfer over HID feature +requests. The implementation uses native Windows functions on Windows so that +no driver installation is required and libusb on Unix. You must link the +appropriate libraries in either case: "-lhid -lusb -lsetupapi" on Windows and +`libusb-config --libs` on Unix. +*/ + +/* ------------------------------------------------------------------------ */ + +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + +/* ------------------------------------------------------------------------ */ + +typedef struct usbDevice usbDevice_t; +/* Opaque data type representing the USB device. This can be a Windows handle + * or a libusb handle, depending on the backend implementation. + */ + +/* ------------------------------------------------------------------------ */ + +int usbhidOpenDevice(usbDevice_t **device, int vendorID, char *vendorName, int productID, char *productName, int usesReportIDs); +/* This function opens a USB device. 'vendorID' and 'productID' are the numeric + * Vendor-ID and Product-ID of the device we want to open. If 'vendorName' and + * 'productName' are both not NULL, only devices with matching manufacturer- + * and product name strings are accepted. If the device uses report IDs, + * 'usesReportIDs' must be set to a non-zero value. + * Returns: If a matching device has been found, USBOPEN_SUCCESS is returned + * and '*device' is set to an opaque pointer representing the device. The + * device must be closed with usbhidCloseDevice(). If the device has not been + * found or opening failed, an error code is returned. + */ +void usbhidCloseDevice(usbDevice_t *device); +/* Every device opened with usbhidOpenDevice() must be closed with this function. + */ +int usbhidSetReport(usbDevice_t *device, char *buffer, int len); +/* This function sends a feature report to the device. The report ID must be + * in the first byte of buffer and the length 'len' of the report is specified + * including this report ID. If no report IDs are used, buffer[0] must be set + * to 0 (dummy report ID). + * Returns: 0 on success, an error code otherwise. + */ +int usbhidGetReport(usbDevice_t *device, int reportID, char *buffer, int *len); +/* This function obtains a feature report from the device. The requested + * report-ID is passed in 'reportID'. The caller must pass a buffer of the size + * of the expected report in 'buffer' and initialize the variable pointed to by + * 'len' to the total size of this buffer. Upon successful return, the report + * (prefixed with the report-ID) is in 'buffer' and the actual length of the + * report is returned in '*len'. + * Returns: 0 on success, an error code otherwise. + */ + +/* ------------------------------------------------------------------------ */ + +#endif /* __HIDDATA_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/libs-host/hidsdi.h b/packages/vusb-20121206/libs-host/hidsdi.h new file mode 100644 index 0000000..fe6da08 --- /dev/null +++ b/packages/vusb-20121206/libs-host/hidsdi.h @@ -0,0 +1,48 @@ +/* Name: hidsdi.h + * Author: Christian Starkjohann + * Creation Date: 2006-02-02 + * Tabsize: 4 + * Copyright: (c) 2006-2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description +This file is a replacement for hidsdi.h from the Windows DDK. It defines some +of the types and function prototypes of this header for our project. If you +have the Windows DDK version of this file or a version shipped with MinGW, use +that instead. +*/ + +#ifndef _HIDSDI_H +#define _HIDSDI_H + +#include + +#include +#include + +typedef struct{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; +}HIDD_ATTRIBUTES; + +void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid); + +BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes); + +BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen); +BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen); + +BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers); +BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers); + +#include + +#endif diff --git a/packages/vusb-20121206/libs-host/opendevice.c b/packages/vusb-20121206/libs-host/opendevice.c new file mode 100644 index 0000000..ea88e86 --- /dev/null +++ b/packages/vusb-20121206/libs-host/opendevice.c @@ -0,0 +1,202 @@ +/* Name: opendevice.c + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The functions in this module can be used to find and open a device based on +libusb or libusb-win32. +*/ + +#include +#include "opendevice.h" + +/* ------------------------------------------------------------------------- */ + +#define MATCH_SUCCESS 1 +#define MATCH_FAILED 0 +#define MATCH_ABORT -1 + +/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */ +static int _shellStyleMatch(char *text, char *p) +{ +int last, matched, reverse; + + for(; *p; text++, p++){ + if(*text == 0 && *p != '*') + return MATCH_ABORT; + switch(*p){ + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if(*text != *p) + return MATCH_FAILED; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while(*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if(*p == 0) + /* Trailing star matches everything. */ + return MATCH_SUCCESS; + while(*text) + if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED) + return matched; + return MATCH_ABORT; + case '[': + reverse = p[1] == '^'; + if(reverse) /* Inverted character class. */ + p++; + matched = MATCH_FAILED; + if(p[1] == ']' || p[1] == '-') + if(*++p == *text) + matched = MATCH_SUCCESS; + for(last = *p; *++p && *p != ']'; last = *p) + if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p) + matched = MATCH_SUCCESS; + if(matched == reverse) + return MATCH_FAILED; + continue; + } + } + return *text == 0; +} + +/* public interface for shell style matching: returns 0 if fails, 1 if matches */ +static int shellStyleMatch(char *text, char *pattern) +{ + if(pattern == NULL) /* NULL pattern is synonymous to "*" */ + return 1; + return _shellStyleMatch(text, pattern) == MATCH_SUCCESS; +} + +/* ------------------------------------------------------------------------- */ + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen) +{ +char buffer[256]; +int rval, i; + + if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */ + return rval; + if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0) + return rval; + if(buffer[1] != USB_DT_STRING){ + *buf = 0; + return 0; + } + if((unsigned char)buffer[0] < rval) + rval = (unsigned char)buffer[0]; + rval /= 2; + /* lossy conversion to ISO Latin1: */ + for(i=1;i buflen) /* destination buffer overflow */ + break; + buf[i-1] = buffer[2 * i]; + if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ + buf[i-1] = '?'; + } + buf[i-1] = 0; + return i-1; +} + +/* ------------------------------------------------------------------------- */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp) +{ +struct usb_bus *bus; +struct usb_device *dev; +usb_dev_handle *handle = NULL; +int errorCode = USBOPEN_ERR_NOTFOUND; + + usb_find_busses(); + usb_find_devices(); + for(bus = usb_get_busses(); bus; bus = bus->next){ + for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */ + if((vendorID == 0 || dev->descriptor.idVendor == vendorID) + && (productID == 0 || dev->descriptor.idProduct == productID)){ + char vendor[256], product[256], serial[256]; + int len; + handle = usb_open(dev); /* we need to open the device in order to query strings */ + if(!handle){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + continue; + } + /* now check whether the names match: */ + len = vendor[0] = 0; + if(dev->descriptor.iManufacturer > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen device from vendor ->%s<-\n", vendor); */ + if(shellStyleMatch(vendor, vendorNamePattern)){ + len = product[0] = 0; + if(dev->descriptor.iProduct > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + }else{ + errorCode = USBOPEN_ERR_NOTFOUND; + /* printf("seen product ->%s<-\n", product); */ + if(shellStyleMatch(product, productNamePattern)){ + len = serial[0] = 0; + if(dev->descriptor.iSerialNumber > 0){ + len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial)); + } + if(len < 0){ + errorCode = USBOPEN_ERR_ACCESS; + if(warningsFp != NULL) + fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror()); + } + if(shellStyleMatch(serial, serialNamePattern)){ + if(printMatchingDevicesFp != NULL){ + if(serial[0] == 0){ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product); + }else{ + fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial); + } + }else{ + break; + } + } + } + } + } + } + usb_close(handle); + handle = NULL; + } + } + if(handle) /* we have found a deice */ + break; + } + if(handle != NULL){ + errorCode = 0; + *device = handle; + } + if(printMatchingDevicesFp != NULL) /* never return an error for listing only */ + errorCode = 0; + return errorCode; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/libs-host/opendevice.h b/packages/vusb-20121206/libs-host/opendevice.h new file mode 100644 index 0000000..c925276 --- /dev/null +++ b/packages/vusb-20121206/libs-host/opendevice.h @@ -0,0 +1,76 @@ +/* Name: opendevice.h + * Project: V-USB host-side library + * Author: Christian Starkjohann + * Creation Date: 2008-04-10 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module offers additional functionality for host side drivers based on +libusb or libusb-win32. It includes a function to find and open a device +based on numeric IDs and textual description. It also includes a function to +obtain textual descriptions from a device. + +To use this functionality, simply copy opendevice.c and opendevice.h into your +project and add them to your Makefile. You may modify and redistribute these +files according to the GNU General Public License (GPL) version 2 or 3. +*/ + +#ifndef __OPENDEVICE_H_INCLUDED__ +#define __OPENDEVICE_H_INCLUDED__ + +#include /* this is libusb, see http://libusb.sourceforge.net/ */ +#include + +int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen); +/* This function gets a string descriptor from the device. 'index' is the + * string descriptor index. The string is returned in ISO Latin 1 encoding in + * 'buf' and it is terminated with a 0-character. The buffer size must be + * passed in 'buflen' to prevent buffer overflows. A libusb device handle + * must be given in 'dev'. + * Returns: The length of the string (excluding the terminating 0) or + * a negative number in case of an error. If there was an error, use + * usb_strerror() to obtain the error message. + */ + +int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp); +/* This function iterates over all devices on all USB busses and searches for + * a device. Matching is done first by means of Vendor- and Product-ID (passed + * in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard). + * When a device matches by its IDs, matching by names is performed. Name + * matching can be done on textual vendor name ('vendorNamePattern'), product + * name ('productNamePattern') and serial number ('serialNamePattern'). A + * device matches only if all non-null pattern match. If you don't care about + * a string, pass NULL for the pattern. Patterns are Unix shell style pattern: + * '*' stands for 0 or more characters, '?' for one single character, a list + * of characters in square brackets for a single character from the list + * (dashes are allowed to specify a range) and if the lis of characters begins + * with a caret ('^'), it matches one character which is NOT in the list. + * Other parameters to the function: If 'warningsFp' is not NULL, warning + * messages are printed to this file descriptor with fprintf(). If + * 'printMatchingDevicesFp' is not NULL, no device is opened but matching + * devices are printed to the given file descriptor with fprintf(). + * If a device is opened, the resulting USB handle is stored in '*device'. A + * pointer to a "usb_dev_handle *" type variable must be passed here. + * Returns: 0 on success, an error code (see defines below) on failure. + */ + +/* usbOpenDevice() error codes: */ +#define USBOPEN_SUCCESS 0 /* no error */ +#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */ +#define USBOPEN_ERR_IO 2 /* I/O error */ +#define USBOPEN_ERR_NOTFOUND 3 /* device not found */ + + +/* Obdev's free USB IDs, see USB-IDs-for-free.txt for details */ + +#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */ +#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */ +#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */ +#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */ +#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */ + +#endif /* __OPENDEVICE_H_INCLUDED__ */ diff --git a/packages/vusb-20121206/tests/Makefile b/packages/vusb-20121206/tests/Makefile new file mode 100644 index 0000000..a800c2a --- /dev/null +++ b/packages/vusb-20121206/tests/Makefile @@ -0,0 +1,126 @@ +# Name: Makefile +# Project: custom-class example +# Author: Christian Starkjohann +# Creation Date: 2008-04-07 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +DEVICE = attiny2313 +F_CPU = 16000000 # in Hz +DEFINES = + +CFLAGS = $(DEFINES) -Iusbdrv -I. -DDEBUG_LEVEL=0 +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) + +SIZES_TMP = /tmp/sizetmp.txt + +# symbolic targets: +help: + @echo "This Makefile has no default rule. Use one of the following:" + @echo "make clean ..... to delete objects and hex file" + @echo "make sizes ..... compute code and RAM sizes for various options" + @echo "make test ...... test with all features whether everything compiles" + +sizes sizes.txt: + rm -f $(SIZES_TMP) sizes.txt + $(MAKE) null.elf + avr-size null.elf | tail -1 | awk '{print "null", $$1+$$2, $$3+$$2}' >$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf + avr-size main.elf | tail -1 | awk '{print "Minimum_with_16_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=12000000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_12_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=12800000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_12_8_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=15000000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_15_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=16500000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_16_5_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=18000000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_18_MHz+CRC", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf F_CPU=20000000 + avr-size main.elf | tail -1 | awk '{print "Minimum_with_20_MHz", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf DEFINES=-DUSB_CFG_IMPLEMENT_FN_WRITE=1 + avr-size main.elf | tail -1 | awk '{print "With_usbFunctionWrite", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf DEFINES=-DUSB_CFG_IMPLEMENT_FN_READ=1 + avr-size main.elf | tail -1 | awk '{print "With_usbFunctionRead", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_IMPLEMENT_FN_READ=1 -DUSB_CFG_IMPLEMENT_FN_WRITE=1" + avr-size main.elf | tail -1 | awk '{print "With_usbFunctionRead_and_Write", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_IMPLEMENT_FN_WRITEOUT=1" + avr-size main.elf | tail -1 | awk '{print "With_usbFunctionWriteOut", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_HAVE_INTRIN_ENDPOINT=1" + avr-size main.elf | tail -1 | awk '{print "With_Interrupt_In_Endpoint_1", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_IMPLEMENT_HALT=1 -DUSB_CFG_HAVE_INTRIN_ENDPOINT=1" + avr-size main.elf | tail -1 | awk '{print "With_Interrupt_In_Endpoint_1_and_Halt", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_HAVE_INTRIN_ENDPOINT3=1" + avr-size main.elf | tail -1 | awk '{print "With_Interrupt_In_Endpoint_1_and_3", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSE_DYNAMIC_DESCRIPTOR=1" + avr-size main.elf | tail -1 | awk '{print "With_Dynamic_Descriptor", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + $(MAKE) clean; $(MAKE) main.elf "DEFINES=-DUSB_CFG_LONG_TRANSFERS=1" + avr-size main.elf | tail -1 | awk '{print "With_Long_Transfers", $$1+$$2, $$3+$$2}' >>$(SIZES_TMP) + cat $(SIZES_TMP) | awk 'BEGIN{printf("%39s %5s %5s %5s %5s\n"), "Variation", "Flash", "RAM", "+F", "+RAM"}\ + /^null/{nullRom=$$2; nullRam=$$3; next} \ + {rom=$$2-nullRom; ram=$$3-nullRam; if(!refRom){refRom=rom; refRam=ram} \ + printf("%39s %5d %5d %+5d %+5d\n", $$1, rom, ram, rom-refRom, ram-refRam)}' | tee sizes.txt + rm $(SIZES_TMP) + +test: + for freq in 12000000 12800000 15000000 16000000 16500000 18000000 20000000; do \ + for opt in USB_COUNT_SOF USB_CFG_HAVE_INTRIN_ENDPOINT USB_CFG_HAVE_INTRIN_ENDPOINT3 USB_CFG_HAVE_MEASURE_FRAME_LENGTH USB_CFG_LONG_TRANSFERS; do \ + $(MAKE) clean; $(MAKE) main.elf F_CPU=$$freq "DEFINES=-D$$opt=1" || exit 1; \ + $(MAKE) clean; $(MAKE) main.elf F_CPU=$$freq "DEFINES=-D$$opt=1 -DDUSB_CFG_IMPLEMENT_FN_WRITEOUT=1" || exit 1; \ + done \ + done + +# The following rule is used to check the compiler +devices: #exclude devices without RAM for stack and atmega603 for gcc 3 + excludes="at90s1200 attiny11 attiny12 attiny15 attiny28"; \ + for gccVersion in 3 4; do \ + avr-gcc-select $$gccVersion; \ + for device in `echo | avr-gcc -xc -mmcu=x - 2>&1 | egrep '^ *at[a-zA-Z0-9_-]+$$'`; do \ + if echo "$$excludes" | grep "$$device" >/dev/null; then continue; fi; \ + if [ "$$gccVersion" = 3 -a "$$device" = atmega603 ]; then continue; fi; \ + $(MAKE) clean; $(MAKE) null.elf DEVICE=$$device || exit 1; \ + done \ + done + $(MAKE) clean + avr-gcc-select 3 + @echo "+++ Device test succeeded!" + +# rule for deleting dependent files (those which can be built by Make): +clean: + rm -f *.hex *.lst *.map *.elf *.o + rm -rf usbdrv + +# Generic rule for compiling C files: +.c.o: + $(COMPILE) -c $< -o $@ + +# Generic rule for assembling Assembler source files: +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +# Generic rule for compiling C to assembler, used for debugging only. +.c.s: + $(COMPILE) -S $< -o $@ + +# file targets: + +# Since we don't want to ship the driver multipe times, we copy it into this project: +usbdrv: + cp -r ../usbdrv . + +main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it + $(COMPILE) -o main.elf $(OBJECTS) + +main_i.elf: usbdrv main.o usbdrv/usbdrvasm.o # usbdrv dependency only needed because we copy it + $(COMPILE) -o main_i.elf main.o usbdrv/usbdrvasm.o + +null.elf: null.o + $(COMPILE) -o null.elf null.o diff --git a/packages/vusb-20121206/tests/Readme.txt b/packages/vusb-20121206/tests/Readme.txt new file mode 100644 index 0000000..3f0d36d --- /dev/null +++ b/packages/vusb-20121206/tests/Readme.txt @@ -0,0 +1,13 @@ +This is the Readme file for the directory "tests" of V-USB, a firmware-only +USB driver for AVR microcontrollers. + +WHAT IS IN THIS DIRECTORY? +========================== +This directory is for driver development only. It contains tests to check +whether all branches of #ifdef code compile as they should and whether the +code size of the driver increased. + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/packages/vusb-20121206/tests/compare-sizes.awk b/packages/vusb-20121206/tests/compare-sizes.awk new file mode 100755 index 0000000..47868c4 --- /dev/null +++ b/packages/vusb-20121206/tests/compare-sizes.awk @@ -0,0 +1,44 @@ +#!/usr/bin/awk -f +# Name: compare-sizes.awk +# Project: v-usb +# Author: Christian Starkjohann +# Creation Date: 2008-04-29 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + +BEGIN{ + opt = 0; + if(ARGC != 3){ + printf("usage: compare-sizes.awk file1 file2\n"); + printf(" computes size differences between two size lists\n"); + exit 1; + } + file1 = ARGV[1]; + file2 = ARGV[2]; +} + +{ + if(($2 + 0) != 0){ + if(!hadOption[$1]){ + hadOption[$1] = 1; + options[opt++] = $1; + } + flash[FILENAME, $1] = $2; + ram[FILENAME, $1] = $3; + } +} + +END{ + if(opt > 0){ + printf ("%39s %6s %5s\n", "Variation", "+Flash", "+RAM"); + } + for(i = 0; i < opt; i++){ + option = options[i]; + if(!flash[file2, option] || !flash[file1, option]){ + printf("%39s %6s %5s\n", option, "n/a", "n/a"); + }else{ + printf("%39s %+6d %+5d\n", option, flash[file2, option] - flash[file1, option], ram[file2, option] - ram[file1, option]); + } + } +} diff --git a/packages/vusb-20121206/tests/main.c b/packages/vusb-20121206/tests/main.c new file mode 100644 index 0000000..a6efb8c --- /dev/null +++ b/packages/vusb-20121206/tests/main.c @@ -0,0 +1,158 @@ +/* Name: main.c + * Project: Testing driver features + * Author: Christian Starkjohann + * Creation Date: 2008-04-29 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This module is a do-nothing test code linking against (or including) the USB +driver. It is used to determine the code size for various options and to +check whether the code compiles with all options. +*/ +#include +#include /* for sei() */ +#include /* required by usbdrv.h */ +#include /* for _delay_ms() */ +#include "usbdrv.h" +#if USE_INCLUDE +#include "usbdrv.c" +#endif + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_IMPLEMENT_FN_WRITE +uchar usbFunctionWrite(uchar *data, uchar len) +{ + return 1; +} +#endif + +#if USB_CFG_IMPLEMENT_FN_READ +uchar usbFunctionRead(uchar *data, uchar len) +{ + return len; +} +#endif + +#if USB_CFG_IMPLEMENT_FN_WRITEOUT +void usbFunctionWriteOut(uchar *data, uchar len) +{ +} +#endif + +#if USE_DYNAMIC_DESCRIPTOR + +static PROGMEM const char myDescriptorDevice[] = { /* USB device descriptor */ + 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ + USBDESCR_DEVICE, /* descriptor type */ + 0x10, 0x01, /* USB version supported */ + USB_CFG_DEVICE_CLASS, + USB_CFG_DEVICE_SUBCLASS, + 0, /* protocol */ + 8, /* max packet size */ + /* the following two casts affect the first byte of the constant only, but + * that's sufficient to avoid a warning with the default values. + */ + (char)USB_CFG_VENDOR_ID,/* 2 bytes */ + (char)USB_CFG_DEVICE_ID,/* 2 bytes */ + USB_CFG_DEVICE_VERSION, /* 2 bytes */ + USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */ + USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */ + USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ + 1, /* number of configurations */ +}; + +static PROGMEM const char myDescriptorConfiguration[] = { /* USB configuration descriptor */ + 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ + USBDESCR_CONFIG, /* descriptor type */ + 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0, + /* total length of data returned (including inlined descriptors) */ + 1, /* number of interfaces in this configuration */ + 1, /* index of this configuration */ + 0, /* configuration name string index */ +#if USB_CFG_IS_SELF_POWERED + USBATTR_SELFPOWER, /* attributes */ +#else + 0, /* attributes */ +#endif + USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ +/* interface descriptor follows inline: */ + 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ + USBDESCR_INTERFACE, /* descriptor type */ + 0, /* index of this interface */ + 0, /* alternate setting for this interface */ + USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ + USB_CFG_INTERFACE_CLASS, + USB_CFG_INTERFACE_SUBCLASS, + USB_CFG_INTERFACE_PROTOCOL, + 0, /* string index for interface */ +#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ + 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ + USBDESCR_HID, /* descriptor type: HID */ + 0x01, 0x01, /* BCD representation of HID version */ + 0x00, /* target country code */ + 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ + 0x22, /* descriptor type: report */ + USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ + 7, /* sizeof(usbDescrEndpoint) */ + USBDESCR_ENDPOINT, /* descriptor type = endpoint */ + (char)0x81, /* IN endpoint number 1 */ + 0x03, /* attrib: Interrupt endpoint */ + 8, 0, /* maximum packet size */ + USB_CFG_INTR_POLL_INTERVAL, /* in ms */ +#endif +}; + +USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(usbRequest_t *rq) +{ +uchar *p = 0, len = 0; + + if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ + p = (uchar *)myDescriptorDevice; + len = sizeof(myDescriptorDevice); + }else{ /* must be configuration descriptor */ + p = (uchar *)(myDescriptorConfiguration); + len = sizeof(myDescriptorConfiguration); + } + usbMsgPtr = (usbMsgPtr_t)p; + return len; +} +#endif + +USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; + + if(rq->bRequest == 0) /* request using usbFunctionRead()/usbFunctionWrite() */ + return 0xff; + return 0; /* default for not implemented requests: return no data back to host */ +} + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ +uchar i; + + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + _delay_ms(1); + } + usbDeviceConnect(); + sei(); + for(;;){ /* main event loop */ + usbPoll(); + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/tests/null.c b/packages/vusb-20121206/tests/null.c new file mode 100644 index 0000000..f668354 --- /dev/null +++ b/packages/vusb-20121206/tests/null.c @@ -0,0 +1,25 @@ +/* Name: null.c + * Project: Testing driver features + * Author: Christian Starkjohann + * Creation Date: 2008-04-29 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +This is a NULL main() function to find out the code size required by libusb's +startup code, interrupt vectors etc. +*/ +#include + + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ + for(;;); + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc3.4.6.txt new file mode 100644 index 0000000..2257e89 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc3.4.6.txt @@ -0,0 +1,13 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1154 45 +0 +0 + Minimum_with_12_MHz 1274 45 +120 +0 + Minimum_with_15_MHz 1260 45 +106 +0 + Minimum_with_16_5_MHz 1276 45 +122 +0 + With_usbFunctionWrite 1214 45 +60 +0 + With_usbFunctionRead 1200 45 +46 +0 + With_usbFunctionRead_and_Write 1246 45 +92 +0 + With_usbFunctionWriteOut 1178 45 +24 +0 + With_Interrupt_In_Endpoint_1 1284 58 +130 +13 + With_Interrupt_In_Endpoint_1_and_Halt 1372 58 +218 +13 + With_Interrupt_In_Endpoint_1_and_3 1386 69 +232 +24 + With_Dynamic_Descriptor 1186 45 +32 +0 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc4.2.2.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc4.2.2.txt new file mode 100644 index 0000000..f776893 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20080418-gcc4.2.2.txt @@ -0,0 +1,13 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1208 45 +0 +0 + Minimum_with_12_MHz 1328 45 +120 +0 + Minimum_with_15_MHz 1314 45 +106 +0 + Minimum_with_16_5_MHz 1330 45 +122 +0 + With_usbFunctionWrite 1268 45 +60 +0 + With_usbFunctionRead 1264 45 +56 +0 + With_usbFunctionRead_and_Write 1314 45 +106 +0 + With_usbFunctionWriteOut 1218 45 +10 +0 + With_Interrupt_In_Endpoint_1 1340 58 +132 +13 + With_Interrupt_In_Endpoint_1_and_Halt 1414 58 +206 +13 + With_Interrupt_In_Endpoint_1_and_3 1426 69 +218 +24 + With_Dynamic_Descriptor 1238 45 +30 +0 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc3.4.6.txt new file mode 100644 index 0000000..d292bfb --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc3.4.6.txt @@ -0,0 +1,15 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1154 45 +0 +0 + Minimum_with_12_MHz 1274 45 +120 +0 + Minimum_with_15_MHz 1260 45 +106 +0 + Minimum_with_16_5_MHz 1276 45 +122 +0 + Minimum_with_20_MHz 1136 45 -18 +0 + With_usbFunctionWrite 1214 45 +60 +0 + With_usbFunctionRead 1192 45 +38 +0 + With_usbFunctionRead_and_Write 1234 45 +80 +0 + With_usbFunctionWriteOut 1178 45 +24 +0 + With_Interrupt_In_Endpoint_1 1280 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1370 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1346 69 +192 +24 + With_Dynamic_Descriptor 1182 45 +28 +0 + With_Long_Transfers 1200 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc4.3.0.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc4.3.0.txt new file mode 100644 index 0000000..e3218b4 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20080513-gcc4.3.0.txt @@ -0,0 +1,15 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1192 45 +0 +0 + Minimum_with_12_MHz 1312 45 +120 +0 + Minimum_with_15_MHz 1298 45 +106 +0 + Minimum_with_16_5_MHz 1314 45 +122 +0 + Minimum_with_20_MHz 1174 45 -18 +0 + With_usbFunctionWrite 1246 45 +54 +0 + With_usbFunctionRead 1242 45 +50 +0 + With_usbFunctionRead_and_Write 1280 45 +88 +0 + With_usbFunctionWriteOut 1208 45 +16 +0 + With_Interrupt_In_Endpoint_1 1320 57 +128 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1410 57 +218 +12 + With_Interrupt_In_Endpoint_1_and_3 1428 69 +236 +24 + With_Dynamic_Descriptor 1212 45 +20 +0 + With_Long_Transfers 1270 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc3.4.6.txt new file mode 100644 index 0000000..0dfafa7 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc3.4.6.txt @@ -0,0 +1,16 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1522 45 +370 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1198 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc4.3.0.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc4.3.0.txt new file mode 100644 index 0000000..42e2ba9 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20081022-gcc4.3.0.txt @@ -0,0 +1,16 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1194 45 +0 +0 + Minimum_with_12_MHz 1244 45 +50 +0 + Minimum_with_12_8_MHz 1564 45 +370 +0 + Minimum_with_15_MHz 1300 45 +106 +0 + Minimum_with_16_5_MHz 1316 45 +122 +0 + Minimum_with_20_MHz 1176 45 -18 +0 + With_usbFunctionWrite 1248 45 +54 +0 + With_usbFunctionRead 1244 45 +50 +0 + With_usbFunctionRead_and_Write 1282 45 +88 +0 + With_usbFunctionWriteOut 1210 45 +16 +0 + With_Interrupt_In_Endpoint_1 1322 57 +128 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1412 57 +218 +12 + With_Interrupt_In_Endpoint_1_and_3 1430 69 +236 +24 + With_Dynamic_Descriptor 1214 45 +20 +0 + With_Long_Transfers 1272 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc3.4.6.txt new file mode 100644 index 0000000..0dfafa7 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc3.4.6.txt @@ -0,0 +1,16 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1522 45 +370 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1198 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc4.3.0.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc4.3.0.txt new file mode 100644 index 0000000..42e2ba9 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20081126-gcc4.3.0.txt @@ -0,0 +1,16 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1194 45 +0 +0 + Minimum_with_12_MHz 1244 45 +50 +0 + Minimum_with_12_8_MHz 1564 45 +370 +0 + Minimum_with_15_MHz 1300 45 +106 +0 + Minimum_with_16_5_MHz 1316 45 +122 +0 + Minimum_with_20_MHz 1176 45 -18 +0 + With_usbFunctionWrite 1248 45 +54 +0 + With_usbFunctionRead 1244 45 +50 +0 + With_usbFunctionRead_and_Write 1282 45 +88 +0 + With_usbFunctionWriteOut 1210 45 +16 +0 + With_Interrupt_In_Endpoint_1 1322 57 +128 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1412 57 +218 +12 + With_Interrupt_In_Endpoint_1_and_3 1430 69 +236 +24 + With_Dynamic_Descriptor 1214 45 +20 +0 + With_Long_Transfers 1272 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc3.4.6.txt new file mode 100644 index 0000000..18e72a6 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc3.4.6.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1522 45 +370 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_18_MHz+CRC 2268 45 +1116 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1198 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc4.3.2.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc4.3.2.txt new file mode 100644 index 0000000..9b4f4ee --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20090323-gcc4.3.2.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1224 45 +0 +0 + Minimum_with_12_MHz 1274 45 +50 +0 + Minimum_with_12_8_MHz 1594 45 +370 +0 + Minimum_with_15_MHz 1330 45 +106 +0 + Minimum_with_16_5_MHz 1346 45 +122 +0 + Minimum_with_18_MHz+CRC 2298 45 +1074 +0 + Minimum_with_20_MHz 1206 45 -18 +0 + With_usbFunctionWrite 1284 45 +60 +0 + With_usbFunctionRead 1280 45 +56 +0 + With_usbFunctionRead_and_Write 1318 45 +94 +0 + With_usbFunctionWriteOut 1246 45 +22 +0 + With_Interrupt_In_Endpoint_1 1358 57 +134 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1448 57 +224 +12 + With_Interrupt_In_Endpoint_1_and_3 1466 69 +242 +24 + With_Dynamic_Descriptor 1250 45 +26 +0 + With_Long_Transfers 1302 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc3.4.6.txt new file mode 100644 index 0000000..18e72a6 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc3.4.6.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1522 45 +370 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_18_MHz+CRC 2268 45 +1116 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1198 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc4.3.2.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc4.3.2.txt new file mode 100644 index 0000000..9b4f4ee --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20090415-gcc4.3.2.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1224 45 +0 +0 + Minimum_with_12_MHz 1274 45 +50 +0 + Minimum_with_12_8_MHz 1594 45 +370 +0 + Minimum_with_15_MHz 1330 45 +106 +0 + Minimum_with_16_5_MHz 1346 45 +122 +0 + Minimum_with_18_MHz+CRC 2298 45 +1074 +0 + Minimum_with_20_MHz 1206 45 -18 +0 + With_usbFunctionWrite 1284 45 +60 +0 + With_usbFunctionRead 1280 45 +56 +0 + With_usbFunctionRead_and_Write 1318 45 +94 +0 + With_usbFunctionWriteOut 1246 45 +22 +0 + With_Interrupt_In_Endpoint_1 1358 57 +134 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1448 57 +224 +12 + With_Interrupt_In_Endpoint_1_and_3 1466 69 +242 +24 + With_Dynamic_Descriptor 1250 45 +26 +0 + With_Long_Transfers 1302 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc3.4.6.txt new file mode 100644 index 0000000..a7550ee --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc3.4.6.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1518 45 +366 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_18_MHz+CRC 2268 45 +1116 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1198 47 +46 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc4.3.3.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc4.3.3.txt new file mode 100644 index 0000000..ce162f3 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20100715-gcc4.3.3.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1226 45 +0 +0 + Minimum_with_12_MHz 1276 45 +50 +0 + Minimum_with_12_8_MHz 1592 45 +366 +0 + Minimum_with_15_MHz 1332 45 +106 +0 + Minimum_with_16_5_MHz 1348 45 +122 +0 + Minimum_with_18_MHz+CRC 2298 45 +1072 +0 + Minimum_with_20_MHz 1208 45 -18 +0 + With_usbFunctionWrite 1286 45 +60 +0 + With_usbFunctionRead 1282 45 +56 +0 + With_usbFunctionRead_and_Write 1320 45 +94 +0 + With_usbFunctionWriteOut 1248 45 +22 +0 + With_Interrupt_In_Endpoint_1 1360 57 +134 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1450 57 +224 +12 + With_Interrupt_In_Endpoint_1_and_3 1418 69 +192 +24 + With_Dynamic_Descriptor 1252 45 +26 +0 + With_Long_Transfers 1304 47 +78 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc3.4.6.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc3.4.6.txt new file mode 100644 index 0000000..50c8f26 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc3.4.6.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1152 45 +0 +0 + Minimum_with_12_MHz 1202 45 +50 +0 + Minimum_with_12_8_MHz 1518 45 +366 +0 + Minimum_with_15_MHz 1258 45 +106 +0 + Minimum_with_16_5_MHz 1274 45 +122 +0 + Minimum_with_18_MHz+CRC 2268 45 +1116 +0 + Minimum_with_20_MHz 1134 45 -18 +0 + With_usbFunctionWrite 1212 45 +60 +0 + With_usbFunctionRead 1190 45 +38 +0 + With_usbFunctionRead_and_Write 1232 45 +80 +0 + With_usbFunctionWriteOut 1176 45 +24 +0 + With_Interrupt_In_Endpoint_1 1278 57 +126 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1368 57 +216 +12 + With_Interrupt_In_Endpoint_1_and_3 1344 69 +192 +24 + With_Dynamic_Descriptor 1180 45 +28 +0 + With_Long_Transfers 1206 47 +54 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc4.3.3.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc4.3.3.txt new file mode 100644 index 0000000..14b9ca9 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20120109-gcc4.3.3.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1226 45 +0 +0 + Minimum_with_12_MHz 1276 45 +50 +0 + Minimum_with_12_8_MHz 1592 45 +366 +0 + Minimum_with_15_MHz 1332 45 +106 +0 + Minimum_with_16_5_MHz 1348 45 +122 +0 + Minimum_with_18_MHz+CRC 2298 45 +1072 +0 + Minimum_with_20_MHz 1208 45 -18 +0 + With_usbFunctionWrite 1286 45 +60 +0 + With_usbFunctionRead 1282 45 +56 +0 + With_usbFunctionRead_and_Write 1320 45 +94 +0 + With_usbFunctionWriteOut 1248 45 +22 +0 + With_Interrupt_In_Endpoint_1 1360 57 +134 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1450 57 +224 +12 + With_Interrupt_In_Endpoint_1_and_3 1418 69 +192 +24 + With_Dynamic_Descriptor 1252 45 +26 +0 + With_Long_Transfers 1300 47 +74 +2 diff --git a/packages/vusb-20121206/tests/sizes-reference/sizes-20121206-gcc4.6.2.txt b/packages/vusb-20121206/tests/sizes-reference/sizes-20121206-gcc4.6.2.txt new file mode 100644 index 0000000..266ac68 --- /dev/null +++ b/packages/vusb-20121206/tests/sizes-reference/sizes-20121206-gcc4.6.2.txt @@ -0,0 +1,17 @@ + Variation Flash RAM +F +RAM + Minimum_with_16_MHz 1192 45 +0 +0 + Minimum_with_12_MHz 1242 45 +50 +0 + Minimum_with_12_8_MHz 1558 45 +366 +0 + Minimum_with_15_MHz 1298 45 +106 +0 + Minimum_with_16_5_MHz 1314 45 +122 +0 + Minimum_with_18_MHz+CRC 2262 45 +1070 +0 + Minimum_with_20_MHz 1174 45 -18 +0 + With_usbFunctionWrite 1252 45 +60 +0 + With_usbFunctionRead 1248 45 +56 +0 + With_usbFunctionRead_and_Write 1286 45 +94 +0 + With_usbFunctionWriteOut 1214 45 +22 +0 + With_Interrupt_In_Endpoint_1 1328 57 +136 +12 + With_Interrupt_In_Endpoint_1_and_Halt 1420 57 +228 +12 + With_Interrupt_In_Endpoint_1_and_3 1386 69 +194 +24 + With_Dynamic_Descriptor 1198 45 +6 +0 + With_Long_Transfers 1236 47 +44 +2 diff --git a/packages/vusb-20121206/tests/usbconfig.h b/packages/vusb-20121206/tests/usbconfig.h new file mode 100644 index 0000000..0061ee4 --- /dev/null +++ b/packages/vusb-20121206/tests/usbconfig.h @@ -0,0 +1,295 @@ +/* Name: usbconfig.h + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + +/* +General Description: +This is the config file for tests. It is not updated to the latest set of +features. Don't use it as a prototype, use usbconfig-prototype.h instead! +*/ + +/* ---------------------------- Hardware Config ---------------------------- */ + +#define USB_CFG_IOPORTNAME D +#define USB_CFG_DMINUS_BIT 4 +#define USB_CFG_DPLUS_BIT 2 +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +#define USB_CFG_CHECK_CRC (USB_CFG_CLOCK_KHZ == 18000) + + +/* ----------------------- Optional Hardware Config ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#ifndef USB_CFG_HAVE_INTRIN_ENDPOINT3 +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 +#endif +/* Define this to 1 if you want to compile a version with three endpoints: The + * 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. + */ +#ifndef USB_CFG_HAVE_INTRIN_ENDPOINT +#define USB_CFG_HAVE_INTRIN_ENDPOINT USB_CFG_HAVE_INTRIN_ENDPOINT3 +#endif +/* 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). + */ +#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 + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * 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 +/* 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. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* 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 40 +/* 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.] + */ +//#define USB_CFG_IMPLEMENT_FN_WRITE 0 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +//#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * 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) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * 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. + */ +//#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+. + */ +//#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. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you use one of obdev's free shared + * VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + */ +#define USB_CFG_DEVICE_ID 0x08, 0x3e /* 1000 dec, "free for lab use" */ +/* 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 + * USB-IDs-for-free.txt! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 8 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'T', 'e', 's', 't' +#define USB_CFG_DEVICE_NAME_LEN 4 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * to fine tune control over USB descriptors such as the string descriptor + * for the serial number. + */ +#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */ +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + * Class 0xff is "vendor specific". + */ +#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */ +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +/* #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. + * 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! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * 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(). + * + 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), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * USB_CFG_DESCR_PROPS_HID_REPORT + * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) + * + */ + +#if USE_DYNAMIC_DESCRIPTOR +#define USB_CFG_DESCR_PROPS_DEVICE USB_PROP_IS_DYNAMIC +#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC +#else +#define USB_CFG_DESCR_PROPS_DEVICE 0 +#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#endif +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + +#define usbMsgPtr_t unsigned short +/* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to + * a scalar type here because gcc generates slightly shorter code for scalar + * arithmetics than for pointer arithmetics. Remove this define for backward + * type compatibility or define it to an 8 bit type if you use data in RAM only + * and all RAM is below 256 bytes (tiny memory model in IAR CC). + */ + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #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_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/packages/vusb-20121206/usbdrv/Changelog.txt b/packages/vusb-20121206/usbdrv/Changelog.txt new file mode 100644 index 0000000..79b5215 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/Changelog.txt @@ -0,0 +1,329 @@ +This file documents changes in the firmware-only USB driver for atmel's AVR +microcontrollers. New entries are always appended to the end of the file. +Scroll down to the bottom to see the most recent changes. + +2005-04-01: + - Implemented endpoint 1 as interrupt-in endpoint. + - Moved all configuration options to usbconfig.h which is not part of the + driver. + - Changed interface for usbVendorSetup(). + - Fixed compatibility with ATMega8 device. + - Various minor optimizations. + +2005-04-11: + - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() + and usbFunctionWrite() now. Added configuration options to choose which + of these functions to compile in. + - Assembler module delivers receive data non-inverted now. + - Made register and bit names compatible with more AVR devices. + +2005-05-03: + - Allow address of usbRxBuf on any memory page as long as the buffer does + not cross 256 byte page boundaries. + - Better device compatibility: works with Mega88 now. + - Code optimization in debugging module. + - Documentation updates. + +2006-01-02: + - Added (free) default Vendor- and Product-IDs bought from voti.nl. + - Added USBID-License.txt file which defines the rules for using the free + shared VID/PID pair. + - Added Readme.txt to the usbdrv directory which clarifies administrative + issues. + +2006-01-25: + - Added "configured state" to become more standards compliant. + - Added "HALT" state for interrupt endpoint. + - Driver passes the "USB Command Verifier" test from usb.org now. + - Made "serial number" a configuration option. + - Minor optimizations, we now recommend compiler option "-Os" for best + results. + - Added a version number to usbdrv.h + +2006-02-03: + - New configuration variable USB_BUFFER_SECTION for the memory section where + the USB rx buffer will go. This defaults to ".bss" if not defined. Since + this buffer MUST NOT cross 256 byte pages (not even touch a page at the + end), the user may want to pass a linker option similar to + "-Wl,--section-start=.mybuffer=0x800060". + - Provide structure for usbRequest_t. + - New defines for USB constants. + - Prepared for HID implementations. + - Increased data size limit for interrupt transfers to 8 bytes. + - New macro usbInterruptIsReady() to query interrupt buffer state. + +2006-02-18: + - Ensure that the data token which is sent as an ack to an OUT transfer is + always zero sized. This fixes a bug where the host reports an error after + sending an out transfer to the device, although all data arrived at the + device. + - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite(). + +* Release 2006-02-20 + + - Give a compiler warning when compiling with debugging turned on. + - Added Oleg Semyonov's changes for IAR-cc compatibility. + - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect() + (also thanks to Oleg!). + - Rearranged tests in usbPoll() to save a couple of instructions in the most + likely case that no actions are pending. + - We need a delay between the SET ADDRESS request until the new address + becomes active. This delay was handled in usbPoll() until now. Since the + spec says that the delay must not exceed 2ms, previous versions required + aggressive polling during the enumeration phase. We have now moved the + handling of the delay into the interrupt routine. + - We must not reply with NAK to a SETUP transaction. We can only achieve this + by making sure that the rx buffer is empty when SETUP tokens are expected. + We therefore don't pass zero sized data packets from the status phase of + a transfer to usbPoll(). This change MAY cause troubles if you rely on + receiving a less than 8 bytes long packet in usbFunctionWrite() to + identify the end of a transfer. usbFunctionWrite() will NEVER be called + with a zero length. + +* Release 2006-03-14 + + - Improved IAR C support: tiny memory model, more devices + - Added template usbconfig.h file under the name usbconfig-prototype.h + +* Release 2006-03-26 + + - Added provision for one more interrupt-in endpoint (endpoint 3). + - Added provision for one interrupt-out endpoint (endpoint 1). + - Added flowcontrol macros for USB. + - Added provision for custom configuration descriptor. + - Allow ANY two port bits for D+ and D-. + - Merged (optional) receive endpoint number into global usbRxToken variable. + - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the + variable name from the single port letter instead of computing the address + of related ports from the output-port address. + +* Release 2006-06-26 + + - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the + new features. + - Removed "#warning" directives because IAR does not understand them. Use + unused static variables instead to generate a warning. + - Do not include when compiling with IAR. + - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each + USB descriptor should be handled. It is now possible to provide descriptor + data in Flash, RAM or dynamically at runtime. + - STALL is now a status in usbTxLen* instead of a message. We can now conform + to the spec and leave the stall status pending until it is cleared. + - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the + application code to reset data toggling on interrupt pipes. + +* Release 2006-07-18 + + - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes + an assembler error. + - usbDeviceDisconnect() takes pull-up resistor to high impedance now. + +* Release 2007-02-01 + + - Merged in some code size improvements from usbtiny (thanks to Dick + Streefland for these optimizations!) + - Special alignment requirement for usbRxBuf not required any more. Thanks + again to Dick Streefland for this hint! + - Reverted to "#warning" instead of unused static variables -- new versions + of IAR CC should handle this directive. + - Changed Open Source license to GNU GPL v2 in order to make linking against + other free libraries easier. We no longer require publication of the + circuit diagrams, but we STRONGLY encourage it. If you improve the driver + itself, PLEASE grant us a royalty free license to your changes for our + commercial license. + +* Release 2007-03-29 + + - New configuration option "USB_PUBLIC" in usbconfig.h. + - Set USB version number to 1.10 instead of 1.01. + - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and + USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences + to USB_CFG_DESCR_PROPS_STRING_PRODUCT. + - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver + code. + - New assembler module for 16 MHz crystal. + - usbdrvasm.S contains common code only, clock-specific parts have been moved + to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. + +* Release 2007-06-25 + + - 16 MHz module: Do SE0 check in stuffed bits as well. + +* Release 2007-07-07 + + - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary + for negative values. + - Added 15 MHz module contributed by V. Bosch. + - Interrupt vector name can now be configured. This is useful if somebody + wants to use a different hardware interrupt than INT0. + +* Release 2007-08-07 + + - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is + not exceeded. + - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, + USB_COUNT_SOF + - USB_INTR_PENDING can now be a memory address, not just I/O + +* Release 2007-09-19 + + - Split out common parts of assembler modules into separate include file + - Made endpoint numbers configurable so that given interface definitions + can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. + - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() + can handle any number of endpoints. + - Define usbDeviceConnect() and usbDeviceDisconnect() even if no + USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this + case. + +* Release 2007-12-01 + + - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size + when USB_CFG_PULLUP_IOPORTNAME is not defined. + +* Release 2007-12-13 + + - Renamed all include-only assembler modules from *.S to *.inc so that + people don't add them to their project sources. + - Distribute leap bits in tx loop more evenly for 16 MHz module. + - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR + - Avoid compiler warnings for constant expr range by casting some values in + USB descriptors. + +* Release 2008-01-21 + + - Fixed bug in 15 and 16 MHz module where the new address set with + SET_ADDRESS was already accepted at the next NAK or ACK we send, not at + the next data packet we send. This caused problems when the host polled + too fast. Thanks to Alexander Neumann for his help and patience debugging + this issue! + +* Release 2008-02-05 + + - Fixed bug in 16.5 MHz module where a register was used in the interrupt + handler before it was pushed. This bug was introduced with version + 2007-09-19 when common parts were moved to a separate file. + - Optimized CRC routine (thanks to Reimar Doeffinger). + +* Release 2008-02-16 + + - Removed outdated IAR compatibility stuff (code sections). + - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). + - Added optional routine usbMeasureFrameLength() for calibration of the + internal RC oscillator. + +* 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 + + - Define a separate (defined) type for usbMsgPtr so that projects using a + tiny memory model can define it to an 8 bit type in usbconfig.h. This + change also saves a couple of bytes when using a scalar 16 bit type. + - Inserted "const" keyword for all PROGMEM declarations because new GCC + requires it. + - Fixed problem with dependence of usbportability.h on usbconfig.h. This + problem occurred with IAR CC only. + - Prepared repository for github.com. + +* Release 2012-12-06 \ No newline at end of file diff --git a/packages/vusb-20121206/usbdrv/CommercialLicense.txt b/packages/vusb-20121206/usbdrv/CommercialLicense.txt new file mode 100644 index 0000000..de1a2b0 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/CommercialLicense.txt @@ -0,0 +1,166 @@ +V-USB Driver Software License Agreement +Version 2012-07-09 + +THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN +ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING +THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. + + +1 DEFINITIONS + +1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, +Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. + +1.2 "You" shall mean the Licensee. + +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 V-USB. + +2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the +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 +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 (now flirc.tv, Inc.). 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 + +3.1 Number of Units. Only one of the following three definitions is +applicable. Which one is determined by the amount you pay to OBJECTIVE +DEVELOPMENT, see section 4 ("Payment") below. + +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 V-USB according to section 2 above in no +more than 150 hardware units. + +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 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 +such consent is obtained, you may permanently transfer this License to +another party. The recipient of such transfer must agree to all terms and +conditions of this Agreement. + +3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not +expressly granted. + +3.5 Non-Exclusive Rights. Your license rights under this Agreement are +non-exclusive. + +3.6 Third Party Rights. This Agreement cannot grant you rights controlled +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 V-USB will not pass certification because it does not +implement checksum verification and the microcontroller ports do not meet +the electrical specifications. + + +4 PAYMENT + +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/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 + +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. + + +6 TERM AND TERMINATION + +6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE +DEVELOPMENT may terminate this Agreement and revoke the granted license and +USB-IDs if you fail to comply with any of its terms and conditions. + +6.2 Survival of Terms. All provisions regarding secrecy, confidentiality +and limitation of liability shall survive termination of this agreement. + + +7 DISCLAIMER OF WARRANTY AND LIABILITY + +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 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. + +LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, +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 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 V-USB. + + +8 MISCELLANEOUS TERMS + +8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing +purposes that you entered into this agreement. + +8.2 Entire Agreement. This document represents the entire agreement between +OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by +an authorized representative of both, OBJECTIVE DEVELOPMENT and you. + +8.3 Severability. In case a provision of these terms and conditions should +be or become partly or entirely invalid, ineffective, or not executable, +the validity of all other provisions shall not be affected. + +8.4 Applicable Law. This agreement is governed by the laws of the Republic +of Austria. + +8.5 Responsible Courts. The responsible courts in Vienna/Austria will have +exclusive jurisdiction regarding all disputes in connection with this +agreement. + diff --git a/packages/vusb-20121206/usbdrv/License.txt b/packages/vusb-20121206/usbdrv/License.txt new file mode 100644 index 0000000..4460cfb --- /dev/null +++ b/packages/vusb-20121206/usbdrv/License.txt @@ -0,0 +1,361 @@ +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/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/vusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/packages/vusb-20121206/usbdrv/Readme.txt b/packages/vusb-20121206/usbdrv/Readme.txt new file mode 100644 index 0000000..970dc66 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/Readme.txt @@ -0,0 +1,172 @@ +This is the Readme file to Objective Development's firmware-only USB driver +for Atmel AVR microcontrollers. For more information please visit +http://www.obdev.at/vusb/ + +This directory contains the USB firmware only. Copy it as-is to your own +project and add all .c and .S files to your project (these files are marked +with an asterisk in the list below). Then copy usbconfig-prototype.h as +usbconfig.h to your project and edit it according to your configuration. + + +TECHNICAL DOCUMENTATION +======================= +The technical documentation (API) for the firmware driver is contained in the +file "usbdrv.h". Please read all of it carefully! Configuration options are +documented in "usbconfig-prototype.h". + +The driver consists of the following files: + Readme.txt ............. The file you are currently reading. + Changelog.txt .......... Release notes for all versions of the driver. + usbdrv.h ............... Driver interface definitions and technical docs. +* usbdrv.c ............... High level language part of the driver. Link this + module to your code! +* usbdrvasm.S ............ Assembler part of the driver. This module is mostly + a stub and includes one of the usbdrvasm*.S files + depending on processor clock. Link this module to + your code! + usbdrvasm*.inc ......... Assembler routines for particular clock frequencies. + Included by usbdrvasm.S, don't link it directly! + asmcommon.inc .......... Common assembler routines. Included by + usbdrvasm*.inc, don't link it directly! + usbconfig-prototype.h .. Prototype for your own usbdrv.h file. +* oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is + defined to a value greater than 0. Link this module + to your code! + oddebug.h .............. Interface definitions of the debug module. + usbportability.h ....... Header with compiler-dependent stuff. + usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this + module instead of usbdrvasm.S when you assembler + with IAR's tools. + License.txt ............ Open Source license for this driver. + CommercialLicense.txt .. Optional commercial license for this driver. + USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs. + USB-IDs-for-free.txt ... List and terms of use for free shared PIDs. + +(*) ... These files should be linked to your project. + + +CPU CORE CLOCK FREQUENCY +======================== +We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz, +16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The +actual clock rate must be configured in usbconfig.h. + +12 MHz Clock +This is the traditional clock rate of V-USB because it's the lowest clock +rate where the timing constraints of the USB spec can be met. + +15 MHz Clock +Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock +rate allows for some loops which make the resulting code size somewhat smaller +than the 12 MHz version. + +16 MHz Clock +This clock rate has been added for users of the Arduino board and other +ready-made boards which come with a fixed 16 MHz crystal. It's also an option +if you need the slightly higher clock rate for performance reasons. Since +16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code +is somewhat tricky and has to insert a leap cycle every third byte. + +12.8 MHz and 16.5 MHz Clock +The assembler modules for these clock rates differ from the other modules +because they have been built for an RC oscillator with only 1% precision. The +receiver code inserts leap cycles to compensate for clock deviations. 1% is +also the precision which can be achieved by calibrating the internal RC +oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL +oscillator can reach 16.5 MHz with the RC oscillator. This includes the very +popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost +all AVRs can reach 12.8 MHz, although this is outside the specified range. + +See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for +code which calibrates the RC oscillator based on the USB frame clock. + +18 MHz Clock +This module is closer to the USB specification because it performs an on the +fly CRC check for incoming packets. Packets with invalid checksum are +discarded as required by the spec. If you also implement checks for data +PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING +in usbconfig.h for more info), this ensures data integrity. Due to the CRC +tables and alignment requirements, this code is bigger than modules for other +clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1 +and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h. + +20 MHz Clock +This module is for people who won't do it with less than the maximum. Since +20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code +uses similar tricks as the 16 MHz module to insert leap cycles. + + +USB IDENTIFIERS +=============== +Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs +are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you +can assign PIDs at will. + +Since an entry level cost of 1,500 USD is too high for most small companies +and hobbyists, we provide some VID/PID pairs for free. See the file +USB-IDs-for-free.txt for details. + +Objective Development also has some license offerings which include product +IDs. See http://www.obdev.at/vusb/ for details. + + +DEVELOPMENT SYSTEM +================== +This driver has been developed and optimized for the GNU compiler version 3 +and 4. We recommend that you use the GNU compiler suite because it is freely +available. V-USB has also been ported to the IAR compiler and assembler. It +has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the +"small" and "tiny" memory model. Not every release is tested with IAR CC and +the driver may therefore fail to compile with IAR. Please note that gcc is +more efficient for usbdrv.c because this module has been deliberately +optimized for gcc. + +Gcc version 3 produces smaller code than version 4 due to new optimizing +capabilities which don't always improve things on 8 bit CPUs. The code size +generated by gcc 4 can be reduced with the compiler options +-fno-move-loop-invariants, -fno-tree-scev-cprop and +-fno-inline-small-functions in addition to -Os. On devices with more than +8k of flash memory, we also recommend the linker option --relax (written as +-Wl,--relax for gcc) to convert absolute calls into relative where possible. + +For more information about optimizing options see: + + http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html + +These optimizations are good for gcc 4.x. Version 3.x of gcc does not support +most of these options and produces good code anyway. + + +USING V-USB FOR FREE +==================== +The AVR firmware driver is published under the GNU General Public License +Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is +your choice whether you apply the terms of version 2 or version 3. + +If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the +following things IN ADDITION to the obligations from the GPL: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/vusb/feedback.html for your submission. +If you don't have a web site, you can publish the project in obdev's +documentation wiki at +http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/vusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + +COMMERCIAL LICENSES FOR V-USB +============================= +If you don't want to publish your source code under the terms of the GPL, +you can simply pay money for V-USB. As an additional benefit you get +USB PIDs for free, reserved exclusively to you. See the file +"CommercialLicense.txt" for details. + diff --git a/packages/vusb-20121206/usbdrv/USB-ID-FAQ.txt b/packages/vusb-20121206/usbdrv/USB-ID-FAQ.txt new file mode 100644 index 0000000..a4a6bd6 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/USB-ID-FAQ.txt @@ -0,0 +1,149 @@ +Version 2012-07-09 + +========================== +WHY DO WE NEED THESE IDs? +========================== + +USB is more than a low level protocol for data transport. It also defines a +common set of requests which must be understood by all devices. And as part +of these common requests, the specification defines data structures, the +USB Descriptors, which are used to describe the properties of the device. + +From the perspective of an operating system, it is therefore possible to find +out basic properties of a device (such as e.g. the manufacturer and the name +of the device) without a device-specific driver. This is essential because +the operating system can choose a driver to load based on this information +(Plug-And-Play). + +Among the most important properties in the Device Descriptor are the USB +Vendor- and Product-ID. Both are 16 bit integers. The most simple form of +driver matching is based on these IDs. The driver announces the Vendor- and +Product-IDs of the devices it can handle and the operating system loads the +appropriate driver when the device is connected. + +It is obvious that this technique only works if the pair Vendor- plus +Product-ID is unique: Only devices which require the same driver can have the +same pair of IDs. + + +===================================================== +HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? +===================================================== + +Since it is so important that USB IDs are unique, the USB Implementers Forum, +Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by +law to build a device and assign it any random numbers as IDs. Usb.org +therefore needs an agreement to regulate the use of USB IDs. The agreement +binds only parties who agreed to it, of course. Everybody else is free to use +any numbers for their IDs. + +So how can usb.org ensure that every manufacturer of USB devices enters into +an agreement with them? They do it via trademark licensing. Usb.org has +registered the trademark "USB", all associated logos and related terms. If +you want to put an USB logo on your product or claim that it is USB +compliant, you must license these trademarks from usb.org. And this is where +you enter into an agreement. See the "USB-IF Trademark License Agreement and +Usage Guidelines for the USB-IF Logo" at +http://www.usb.org/developers/logo_license/. + +Licensing the USB trademarks requires that you buy a USB Vendor-ID from +usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org +(yearly fee of ca. 4,000 USD) and that you meet all the technical +specifications from the USB spec. + +This means that most hobbyists and small companies will never be able to +become USB compliant, just because membership is so expensive. And you can't +be compliant with a driver based on V-USB anyway, because the AVR's port pins +don't meet the electrical specifications for USB. So, in principle, all +hobbyists and small companies are free to choose any random numbers for their +IDs. They have nothing to lose... + +There is one exception worth noting, though: If you use a sub-component which +implements USB, the vendor of the sub-components may guarantee USB +compliance. This might apply to some or all of FTDI's solutions. + + +======================================================================= +WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? +======================================================================= + +You have learned in the previous section that you are free to choose any +numbers for your IDs anyway. So why not do exactly this? There is still the +technical issue. If you choose IDs which are already in use by somebody else, +operating systems will load the wrong drivers and your device won't work. +Even if you choose IDs which are not currently in use, they may be in use in +the next version of the operating system or even after an automatic update. + +So what you need is a pair of Vendor- and Product-IDs for which you have the +guarantee that no USB compliant product uses them. This implies that no +operating system will ever ship with drivers responsible for these IDs. + + +============================================== +HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? +============================================== + +Objective Development gives away pairs of USB-IDs with their V-USB licenses. +In order to ensure that these IDs are unique, Objective Development has an +agreement with the company/person who has bought the USB Vendor-ID from +usb.org. This agreement ensures that a range of USB Product-IDs is reserved +for assignment by Objective Development and that the owner of the Vendor-ID +won't give it to anybody else. + +This means that you have to trust three parties to ensure uniqueness of +your IDs: + + - Objective Development, that they don't give the same PID to more than + one person. + - The owner of the Vendor-ID that they don't assign PIDs from the range + assigned to Objective Development to anybody else. + - Usb.org that they don't assign the same Vendor-ID a second time. + + +================================== +WHO IS THE OWNER OF THE VENDOR-ID? +================================== + +Objective Development has obtained ranges of USB Product-IDs under two +Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen +Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason +Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID +directly from usb.org. + + +========================================================================= +CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? +========================================================================= + +The short answer is: Yes. All you get is a guarantee that the IDs are never +assigned to anybody else. What more do you need? + + +============================ +WHAT ABOUT SHARED ID PAIRS? +============================ + +Objective Development has reserved some PID/VID pairs for shared use. You +have no guarantee of uniqueness for them, except that no USB compliant device +uses them. In order to avoid technical problems, we must ensure that all +devices with the same pair of IDs use the same driver on kernel level. For +details, see the file USB-IDs-for-free.txt. + + +====================================================== +I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? +====================================================== + +A 16 bit integer number cannot be protected by copyright laws. It is not +sufficiently complex. And since none of the parties involved entered into the +USB-IF Trademark License Agreement, we are not bound by this agreement. So +there is no reason why it should be illegal to sub-license USB-IDs. + + +============================================= +WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? +============================================= + +Objective Development disclaims all liabilities which might arise from the +assignment of IDs. If you guarantee product features to your customers +without proper disclaimer, YOU are liable for that. diff --git a/packages/vusb-20121206/usbdrv/USB-IDs-for-free.txt b/packages/vusb-20121206/usbdrv/USB-IDs-for-free.txt new file mode 100644 index 0000000..d46517d --- /dev/null +++ b/packages/vusb-20121206/usbdrv/USB-IDs-for-free.txt @@ -0,0 +1,154 @@ +Version 2009-08-22 + +=========================== +FREE USB-IDs FOR SHARED USE +=========================== + +Objective Development has reserved a set of USB Product-IDs for use according +to the guidelines outlined below. For more information about the concept of +USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees +that the IDs listed below are not used by any USB compliant devices. + + +==================== +MECHANISM OF SHARING +==================== + +From a technical point of view, two different devices can share the same USB +Vendor- and Product-ID if they require the same driver on operating system +level. We make use of this fact by assigning separate IDs for various device +classes. On application layer, devices must be distinguished by their textual +name or serial number. We offer separate sets of IDs for discrimination by +textual name and for serial number. + +Examples for shared use of USB IDs are included with V-USB in the "examples" +subdirectory. + + +====================================== +IDs FOR DISCRIMINATION BY TEXTUAL NAME +====================================== + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the manufacturer +and product identification. The manufacturer identification MUST be available +at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail +address under your control (e.g. "myname@gmx.net"). You can embed the domain +name or e-mail address in any string you like, e.g. "Objective Development +http://www.obdev.at/vusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as long +as this string is unique within the scope of your textual manufacturer +identification. + +(5) Application side device look-up MUST be based on the textual manufacturer +and product identification in addition to VID/PID matching. The driver +matching MUST be a comparison of the entire strings, NOT a sub-string match. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +Table if IDs for discrimination by textual name: + +PID dec (hex) | VID dec (hex) | Description of use +==============+===============+============================================ +1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb +--------------+---------------+-------------------------------------------- +1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +--------------+---------------+-------------------------------------------- +1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +--------------+---------------+-------------------------------------------- +1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices +--------------+---------------+-------------------------------------------- + +Note that Windows caches the textual product- and vendor-description for +mice, keyboards and joysticks. Name-bsed discrimination is therefore not +recommended for these device classes. + + +======================================= +IDs FOR DISCRIMINATION BY SERIAL NUMBER +======================================= + +If you use one of the IDs listed below, your device and host-side software +must conform to these rules: + +(1) The USB device MUST provide a textual representation of the serial +number, unless ONLY the operating system's default class driver is used. +The serial number string MUST be available at least in USB language 0x0409 +(English/US). + +(2) The serial number MUST start with either an Internet domain name (e.g. +"mycompany.com") registered and owned by you, or an e-mail address under your +control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. +You MAY append any string you like for further discrimination of your devices. + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(5) Application side device look-up MUST be based on the serial number string +in addition to VID/PID matching. The matching must start at the first +character of the serial number string and include the colon character +terminating your domain or e-mail address. It MAY stop anywhere after that. + +(6) For devices which implement a particular USB device class (e.g. HID), the +operating system's default class driver MUST be used. If an operating system +driver for Vendor Class devices is needed, this driver must be libusb or +libusb-win32 (see http://libusb.org/ and +http://libusb-win32.sourceforge.net/). + +(7) If ONLY the operating system's default class driver is used, e.g. for +mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an +application is needed, the serial number may be omitted. + + +Table if IDs for discrimination by serial number string: + +PID dec (hex) | VID dec (hex) | Description of use +===============+===============+=========================================== +10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb +---------------+---------------+------------------------------------------- +10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are + | | NOT mice, keyboards or joysticks) +---------------+---------------+------------------------------------------- +10202 (0x27da) | 5824 (0x16c0) | For USB Mice +---------------+---------------+------------------------------------------- +10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards +---------------+---------------+------------------------------------------- +10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks +---------------+---------------+------------------------------------------- +10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) +---------------+---------------+------------------------------------------- +10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices +---------------+---------------+------------------------------------------- + + +================= +ORIGIN OF USB-IDs +================= + +OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed +here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. +Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. +(see www.usb.org). The VID is registered for the company name "Van Ooijen +Technische Informatica". + + +========== +DISCLAIMER +========== + +OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. diff --git a/packages/vusb-20121206/usbdrv/asmcommon.inc b/packages/vusb-20121206/usbdrv/asmcommon.inc new file mode 100644 index 0000000..d2a4f7c --- /dev/null +++ b/packages/vusb-20121206/usbdrv/asmcommon.inc @@ -0,0 +1,187 @@ +/* Name: asmcommon.inc + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file contains assembler code which is shared among the USB driver +implementations for different CPU cocks. Since the code must be inserted +in the middle of the module, it's split out into this file and #included. + +Jump destinations called from outside: + sofError: Called when no start sequence was found. + se0: Called when a package has been successfully received. + overflow: Called when receive buffer overflows. + doReturn: Called after sending data. + +Outside jump destinations used by this module: + waitForJ: Called to receive an already arriving packet. + sendAckAndReti: + sendNakAndReti: + sendCntAndReti: + usbSendAndReti: + +The following macros must be defined before this file is included: + .macro POP_STANDARD + .endm + .macro POP_RETI + .endm +*/ + +#define token x1 + +overflow: + ldi x2, 1< 0 + +#warning "Never compile production devices with debugging enabled" + +static void uartPutc(char c) +{ + while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ + ODDBG_UDR = c; +} + +static uchar hexAscii(uchar h) +{ + h &= 0xf; + if(h >= 10) + h += 'a' - (uchar)10 - '0'; + h += '0'; + return h; +} + +static void printHex(uchar c) +{ + uartPutc(hexAscii(c >> 4)); + uartPutc(hexAscii(c)); +} + +void odDebug(uchar prefix, uchar *data, uchar len) +{ + printHex(prefix); + uartPutc(':'); + while(len--){ + uartPutc(' '); + printHex(*data++); + } + uartPutc('\r'); + uartPutc('\n'); +} + +#endif diff --git a/packages/vusb-20121206/usbdrv/oddebug.h b/packages/vusb-20121206/usbdrv/oddebug.h new file mode 100644 index 0000000..851f84d --- /dev/null +++ b/packages/vusb-20121206/usbdrv/oddebug.h @@ -0,0 +1,122 @@ +/* Name: oddebug.h + * Project: AVR library + * Author: Christian Starkjohann + * Creation Date: 2005-01-16 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __oddebug_h_included__ +#define __oddebug_h_included__ + +/* +General Description: +This module implements a function for debug logs on the serial line of the +AVR microcontroller. Debugging can be configured with the define +'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging +calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is +2, DBG1 and DBG2 logs will be printed. + +A debug log consists of a label ('prefix') to indicate which debug log created +the output and a memory block to dump in hex ('data' and 'len'). +*/ + + +#ifndef F_CPU +# define F_CPU 12000000 /* 12 MHz */ +#endif + +/* make sure we have the UART defines: */ +#include "usbportability.h" + +#ifndef uchar +# define uchar unsigned char +#endif + +#if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ +# warning "Debugging disabled because device has no UART" +# undef DEBUG_LEVEL +#endif + +#ifndef DEBUG_LEVEL +# define DEBUG_LEVEL 0 +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +# define DBG1(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG1(prefix, data, len) +#endif + +#if DEBUG_LEVEL > 1 +# define DBG2(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG2(prefix, data, len) +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +extern void odDebug(uchar prefix, uchar *data, uchar len); + +/* Try to find our control registers; ATMEL likes to rename these */ + +#if defined UBRR +# define ODDBG_UBRR UBRR +#elif defined UBRRL +# define ODDBG_UBRR UBRRL +#elif defined UBRR0 +# define ODDBG_UBRR UBRR0 +#elif defined UBRR0L +# define ODDBG_UBRR UBRR0L +#endif + +#if defined UCR +# define ODDBG_UCR UCR +#elif defined UCSRB +# define ODDBG_UCR UCSRB +#elif defined UCSR0B +# define ODDBG_UCR UCSR0B +#endif + +#if defined TXEN +# define ODDBG_TXEN TXEN +#else +# define ODDBG_TXEN TXEN0 +#endif + +#if defined USR +# define ODDBG_USR USR +#elif defined UCSRA +# define ODDBG_USR UCSRA +#elif defined UCSR0A +# define ODDBG_USR UCSR0A +#endif + +#if defined UDRE +# define ODDBG_UDRE UDRE +#else +# define ODDBG_UDRE UDRE0 +#endif + +#if defined UDR +# define ODDBG_UDR UDR +#elif defined UDR0 +# define ODDBG_UDR UDR0 +#endif + +static inline void odDebugInit(void) +{ + ODDBG_UCR |= (1<len & 0x10){ /* packet buffer was empty */ + txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = txStatus->buffer + 1; + i = len; + do{ /* if len == 0, we still copy 1 byte, but that's no problem */ + *p++ = *data++; + }while(--i > 0); /* loop control at the end is 2 bytes shorter than at beginning */ + usbCrc16Append(&txStatus->buffer[1], len); + txStatus->len = len + 4; /* len must be given including sync byte */ + DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3); +} + +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) +{ + usbGenericSetInterrupt(data, len, &usbTxStatus1); +} +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) +{ + usbGenericSetInterrupt(data, len, &usbTxStatus3); +} +#endif +#endif /* USB_CFG_SUPPRESS_INTR_CODE */ + +/* ------------------ utilities for code following below ------------------- */ + +/* Use defines for the switch statement so that we can choose between an + * if()else if() and a switch/case based implementation. switch() is more + * efficient for a LARGE set of sequential choices, if() is better in all other + * cases. + */ +#if USB_CFG_USE_SWITCH_STATEMENT +# define SWITCH_START(cmd) switch(cmd){{ +# define SWITCH_CASE(value) }break; case (value):{ +# define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{ +# define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{ +# define SWITCH_DEFAULT }break; default:{ +# define SWITCH_END }} +#else +# define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){ +# define SWITCH_CASE(value) }else if(_cmd == (value)){ +# define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){ +# define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){ +# define SWITCH_DEFAULT }else{ +# define SWITCH_END }} +#endif + +#ifndef USB_RX_USER_HOOK +#define USB_RX_USER_HOOK(data, len) +#endif +#ifndef USB_SET_ADDRESS_HOOK +#define USB_SET_ADDRESS_HOOK() +#endif + +/* ------------------------------------------------------------------------- */ + +/* We use if() instead of #if in the macro below because #if can't be used + * in macros and the compiler optimizes constant conditions anyway. + * This may cause problems with undefined symbols if compiled without + * optimizing! + */ +#define GET_DESCRIPTOR(cfgProp, staticName) \ + if(cfgProp){ \ + if((cfgProp) & USB_PROP_IS_RAM) \ + flags = 0; \ + if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ + len = usbFunctionDescriptor(rq); \ + }else{ \ + len = USB_PROP_LENGTH(cfgProp); \ + usbMsgPtr = (usbMsgPtr_t)(staticName); \ + } \ + } + +/* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used + * internally for all types of descriptors. + */ +static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq) +{ +usbMsgLen_t len = 0; +uchar flags = USB_FLG_MSGPTR_IS_ROM; + + SWITCH_START(rq->wValue.bytes[1]) + SWITCH_CASE(USBDESCR_DEVICE) /* 1 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) + SWITCH_CASE(USBDESCR_CONFIG) /* 2 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) + SWITCH_CASE(USBDESCR_STRING) /* 3 */ +#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC + if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) + flags = 0; + len = usbFunctionDescriptor(rq); +#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + SWITCH_START(rq->wValue.bytes[0]) + SWITCH_CASE(0) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) + SWITCH_CASE(1) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) + SWITCH_CASE(2) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) + SWITCH_CASE(3) + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) + SWITCH_DEFAULT + if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + len = usbFunctionDescriptor(rq); + } + SWITCH_END +#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ +#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ + SWITCH_CASE(USBDESCR_HID) /* 0x21 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) + SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) +#endif + SWITCH_DEFAULT + if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + len = usbFunctionDescriptor(rq); + } + SWITCH_END + usbMsgFlags = flags; + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for + * standard requests instead of class and custom requests. + */ +static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq) +{ +usbMsgLen_t len = 0; +uchar *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */ +uchar value = rq->wValue.bytes[0]; +#if USB_CFG_IMPLEMENT_HALT +uchar index = rq->wIndex.bytes[0]; +#endif + + dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ + SWITCH_START(rq->bRequest) + SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */ + uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ + if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE) + dataPtr[0] = USB_CFG_IS_SELF_POWERED; +#if USB_CFG_IMPLEMENT_HALT + if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81) /* request status for endpoint 1 */ + dataPtr[0] = usbTxLen1 == USBPID_STALL; +#endif + dataPtr[1] = 0; + len = 2; +#if USB_CFG_IMPLEMENT_HALT + SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */ + if(value == 0 && index == 0x81){ /* feature 0 == HALT for endpoint == 1 */ + usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; + usbResetDataToggling(); + } +#endif + SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */ + usbNewDeviceAddr = value; + USB_SET_ADDRESS_HOOK(); + SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */ + len = usbDriverDescriptor(rq); + goto skipMsgPtrAssignment; + SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */ + dataPtr = &usbConfiguration; /* send current configuration value */ + len = 1; + SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */ + usbConfiguration = value; + usbResetStall(); + SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */ + len = 1; +#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE + SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */ + usbResetDataToggling(); + usbResetStall(); +#endif + SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */ + /* Should we add an optional hook here? */ + SWITCH_END + usbMsgPtr = (usbMsgPtr_t)dataPtr; +skipMsgPtrAssignment: + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbProcessRx() is called for every message received by the interrupt + * routine. It distinguishes between SETUP and DATA packets and processes + * them accordingly. + */ +static inline void usbProcessRx(uchar *data, uchar len) +{ +usbRequest_t *rq = (void *)data; + +/* usbRxToken can be: + * 0x2d 00101101 (USBPID_SETUP for setup data) + * 0xe1 11100001 (USBPID_OUT: data phase of setup transfer) + * 0...0x0f for OUT on endpoint X + */ + DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ + USB_RX_USER_HOOK(data, len) +#if USB_CFG_IMPLEMENT_FN_WRITEOUT + if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */ + usbFunctionWriteOut(data, len); + return; + } +#endif + if(usbRxToken == (uchar)USBPID_SETUP){ + if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */ + return; + usbMsgLen_t replyLen; + usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */ + usbTxLen = USBPID_NAK; /* abort pending transmit */ + usbMsgFlags = 0; + uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; + if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */ + replyLen = usbFunctionSetup(data); + }else{ + replyLen = usbDriverSetup(rq); + } +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */ + /* do some conditioning on replyLen, but on IN transfers only */ + if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){ + if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ + replyLen = rq->wLength.bytes[0]; + }else{ + replyLen = rq->wLength.word; + } + } + usbMsgFlags = USB_FLG_USE_USER_RW; + }else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */ +#endif + if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ + if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + replyLen = rq->wLength.bytes[0]; + }else{ + if(replyLen > rq->wLength.word) /* limit length to max */ + replyLen = rq->wLength.word; + } + usbMsgLen = replyLen; + }else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(usbMsgFlags & USB_FLG_USE_USER_RW){ + uchar rval = usbFunctionWrite(data, len); + if(rval == 0xff){ /* an error occurred */ + usbTxLen = USBPID_STALL; + }else if(rval != 0){ /* This was the final package */ + usbMsgLen = 0; /* answer with a zero-sized data packet */ + } + } +#endif + } +} + +/* ------------------------------------------------------------------------- */ + +/* This function is similar to usbFunctionRead(), but it's also called for + * data handled automatically by the driver (e.g. descriptor reads). + */ +static uchar usbDeviceRead(uchar *data, uchar len) +{ + if(len > 0){ /* don't bother app with 0 sized reads */ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_USER_RW){ + len = usbFunctionRead(data, len); + }else +#endif + { + uchar i = len; + usbMsgPtr_t 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++ = *((uchar *)r); + r++; + }while(--i); + } + usbMsgPtr = r; + } + } + return len; +} + +/* ------------------------------------------------------------------------- */ + +/* usbBuildTxBlock() is called when we have data to transmit and the + * interrupt routine's transmit buffer is empty. + */ +static inline void usbBuildTxBlock(void) +{ +usbMsgLen_t wantLen; +uchar len; + + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ + len = usbDeviceRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + usbCrc16Append(&usbTxBuf[1], len); + len += 4; /* length including sync byte */ + if(len < 12) /* a partial package identifies end of message */ + usbMsgLen = USB_NO_MSG; + }else{ + len = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = USB_NO_MSG; + } + usbTxLen = len; + DBG2(0x20, usbTxBuf, len-1); +} + +/* ------------------------------------------------------------------------- */ + +static inline void usbHandleResetHook(uchar notResetState) +{ +#ifdef USB_RESET_HOOK +static uchar wasReset; +uchar isReset = !notResetState; + + if(wasReset != isReset){ + USB_RESET_HOOK(isReset); + wasReset = isReset; + } +#else + notResetState = notResetState; // avoid compiler warning +#endif +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbPoll(void) +{ +schar len; +uchar i; + + len = usbRxLen - 3; + if(len >= 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); + */ + usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len); +#if USB_CFG_HAVE_FLOWCONTROL + if(usbRxLen > 0) /* only mark as available if not inactivated */ + usbRxLen = 0; +#else + usbRxLen = 0; /* mark rx buffer as available */ +#endif + } + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + for(i = 20; i > 0; i--){ + uchar usbLineStatus = USBIN & USBMASK; + if(usbLineStatus != 0) /* SE0 has ended */ + goto isNotReset; + } + /* RESET condition, called multiple times during reset */ + usbNewDeviceAddr = 0; + usbDeviceAddr = 0; + usbResetStall(); + DBG1(0xff, 0, 0); +isNotReset: + usbHandleResetHook(i); +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbInit(void) +{ +#if USB_INTR_CFG_SET != 0 + USB_INTR_CFG |= USB_INTR_CFG_SET; +#endif +#if USB_INTR_CFG_CLR != 0 + USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); +#endif + USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); + usbResetDataToggling(); +#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE + usbTxLen1 = USBPID_NAK; +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 + usbTxLen3 = USBPID_NAK; +#endif +#endif +} + +/* ------------------------------------------------------------------------- */ diff --git a/packages/vusb-20121206/usbdrv/usbdrv.h b/packages/vusb-20121206/usbdrv/usbdrv.h new file mode 100644 index 0000000..3fe84d5 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrv.h @@ -0,0 +1,746 @@ +/* Name: usbdrv.h + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +#ifndef __usbdrv_h_included__ +#define __usbdrv_h_included__ +#include "usbconfig.h" +#include "usbportability.h" + +/* +Hardware Prerequisites: +======================= +USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+ +triggers the interrupt (best achieved by using INT0 for D+), but it is also +possible to trigger the interrupt from D-. If D- is used, interrupts are also +triggered by SOF packets. D- requires a pull-up of 1.5k to +3.5V (and the +device must be powered at 3.5V) to identify as low-speed USB device. A +pull-down or pull-up of 1M SHOULD be connected from D+ to +3.5V to prevent +interference when no USB master is connected. If you use Zener diodes to limit +the voltage on D+ and D-, you MUST use a pull-down resistor, not a pull-up. +We use D+ as interrupt source and not D- because it does not trigger on +keep-alive and RESET states. If you want to count keep-alive events with +USB_COUNT_SOF, you MUST use D- as an interrupt source. + +As a compile time option, the 1.5k pull-up resistor on D- can be made +switchable to allow the device to disconnect at will. See the definition of +usbDeviceConnect() and usbDeviceDisconnect() further down in this file. + +Please adapt the values in usbconfig.h according to your hardware! + +The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz +or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. + + +Limitations: +============ +Robustness with respect to communication errors: +The driver assumes error-free communication. It DOES check for errors in +the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte, +token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due +to timing constraints: We must start sending a reply within 7 bit times. +Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU +performance does not permit that. The driver does not check Data0/Data1 +toggling, but application software can implement the check. + +Input characteristics: +Since no differential receiver circuit is used, electrical interference +robustness may suffer. The driver samples only one of the data lines with +an ordinary I/O pin's input characteristics. However, since this is only a +low speed USB implementation and the specification allows for 8 times the +bit rate over the same hardware, we should be on the safe side. Even the spec +requires detection of asymmetric states at high bit rate for SE0 detection. + +Number of endpoints: +The driver supports the following endpoints: + +- Endpoint 0, the default control endpoint. +- Any number of interrupt- or bulk-out endpoints. The data is sent to + usbFunctionWriteOut() and USB_CFG_IMPLEMENT_FN_WRITEOUT must be defined + to 1 to activate this feature. The endpoint number can be found in the + global variable 'usbRxToken'. +- One default interrupt- or bulk-in endpoint. This endpoint is used for + interrupt- or bulk-in transfers which are not handled by any other endpoint. + You must define USB_CFG_HAVE_INTRIN_ENDPOINT in order to activate this + feature and call usbSetInterrupt() to send interrupt/bulk data. +- One additional interrupt- or bulk-in endpoint. This was endpoint 3 in + previous versions of this driver but can now be configured to any endpoint + number. You must define USB_CFG_HAVE_INTRIN_ENDPOINT3 in order to activate + this feature and call usbSetInterrupt3() to send interrupt/bulk data. The + endpoint number can be set with USB_CFG_EP3_NUMBER. + +Please note that the USB standard forbids bulk endpoints for low speed devices! +Most operating systems allow them anyway, but the AVR will spend 90% of the CPU +time in the USB interrupt polling for bulk data. + +Maximum data payload: +Data payload of control in and out transfers may be up to 254 bytes. In order +to accept payload data of out transfers, you need to implement +'usbFunctionWrite()'. + +USB Suspend Mode supply current: +The USB standard limits power consumption to 500uA when the bus is in suspend +mode. This is not a problem for self-powered devices since they don't need +bus power anyway. Bus-powered devices can achieve this only by putting the +CPU in sleep mode. The driver does not implement suspend handling by itself. +However, the application may implement activity monitoring and wakeup from +sleep. The host sends regular SE0 states on the bus to keep it active. These +SE0 states can be detected by using D- as the interrupt source. Define +USB_COUNT_SOF to 1 and use the global variable usbSofCount to check for bus +activity. + +Operation without an USB master: +The driver behaves neutral without connection to an USB master if D- reads +as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M) +pull-down or pull-up resistor on D+ (interrupt). If Zener diodes are used, +use a pull-down. If D- becomes statically 0, the driver may block in the +interrupt routine. + +Interrupt latency: +The application must ensure that the USB interrupt is not disabled for more +than 25 cycles (this is for 12 MHz, faster clocks allow longer latency). +This implies that all interrupt routines must either have the "ISR_NOBLOCK" +attribute set (see "avr/interrupt.h") or be written in assembler with "sei" +as the first instruction. + +Maximum interrupt duration / CPU cycle consumption: +The driver handles all USB communication during the interrupt service +routine. The routine will not return before an entire USB message is received +and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if +the host conforms to the standard. The driver will consume CPU cycles for all +USB messages, even if they address another (low-speed) device on the same bus. + +*/ + +/* ------------------------------------------------------------------------- */ +/* --------------------------- Module Interface ---------------------------- */ +/* ------------------------------------------------------------------------- */ + +#define USBDRV_VERSION 20121206 +/* 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 + * distinguish versions. If it is not defined, the driver's release date is + * older than 2006-01-25. + */ + + +#ifndef USB_PUBLIC +#define USB_PUBLIC +#endif +/* USB_PUBLIC is used as declaration attribute for all functions exported by + * the USB driver. The default is no attribute (see above). You may define it + * to static either in usbconfig.h or from the command line if you include + * usbdrv.c instead of linking against it. Including the C module of the driver + * directly in your code saves a couple of bytes in flash memory. + */ + +#ifndef __ASSEMBLER__ +#ifndef uchar +#define uchar unsigned char +#endif +#ifndef schar +#define schar signed char +#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" */ + +#ifndef usbMsgPtr_t +#define usbMsgPtr_t uchar * +#endif +/* Making usbMsgPtr_t a define allows the user of this library to define it to + * an 8 bit type on tiny devices. This reduces code size, especially if the + * compiler supports a tiny memory model. + * The type can be a pointer or scalar type, casts are made where necessary. + * Although it's paradoxical, Gcc 4 generates slightly better code for scalar + * types than for pointers. + */ + +struct usbRequest; /* forward declaration */ + +USB_PUBLIC void usbInit(void); +/* This function must be called before interrupts are enabled and the main + * loop is entered. We exepct that the PORT and DDR bits for D+ and D- have + * not been changed from their default status (which is 0). If you have changed + * them, set both back to 0 (configure them as input with no internal pull-up). + */ +USB_PUBLIC void usbPoll(void); +/* This function must be called at regular intervals from the main loop. + * Maximum delay between calls is somewhat less than 50ms (USB timeout for + * accepting a Setup message). Otherwise the device will not be recognized. + * Please note that debug outputs through the UART take ~ 0.5ms per byte + * at 19200 bps. + */ +extern usbMsgPtr_t usbMsgPtr; +/* This variable may be used to pass transmit data to the driver from the + * implementation of usbFunctionWrite(). It is also used internally by the + * driver for standard control requests. + */ +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 + * the host communicates the parameters of the following (optional) data + * transfer. The SETUP data is available in the 'data' parameter which can + * (and should) be casted to 'usbRequest_t *' for a more user-friendly access + * to parameters. + * + * If the SETUP indicates a control-in transfer, you should provide the + * requested data to the driver. There are two ways to transfer this data: + * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data + * block and return the length of the data in 'usbFunctionSetup()'. The driver + * will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The + * driver will then call 'usbFunctionRead()' when data is needed. See the + * documentation for usbFunctionRead() for details. + * + * If the SETUP indicates a control-out transfer, the only way to receive the + * data from the host is through the 'usbFunctionWrite()' call. If you + * implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()' + * to indicate that 'usbFunctionWrite()' should be used. See the documentation + * of this function for more information. If you just want to ignore the data + * sent by the host, return 0 in 'usbFunctionSetup()'. + * + * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() + * are only done if enabled by the configuration in usbconfig.h. + */ +USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq); +/* 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 + * data. See the documentation of usbFunctionSetup() above for more info. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len); +/* This function sets the message which will be sent during the next interrupt + * IN transfer. The message is copied to an internal buffer and must not exceed + * a length of 8 bytes. The message may be 0 bytes long just to indicate the + * interrupt status to the host. + * If you need to transfer more bytes, use a control read after the interrupt. + */ +#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 + * message already buffered will be lost. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len); +#define usbInterruptIsReady3() (usbTxLen3 & 0x10) +/* Same as above for endpoint 3 */ +#endif +#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */ +#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */ +#define usbHidReportDescriptor usbDescriptorHidReport +/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */ +/* If you implement an HID device, you need to provide a report descriptor. + * The HID report descriptor syntax is a bit complex. If you understand how + * report descriptors are constructed, we recommend that you use the HID + * Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/. + * Otherwise you should probably start with a working example. + */ +#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */ +#if USB_CFG_IMPLEMENT_FN_WRITE +USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len); +/* This function is called by the driver to provide a control transfer's + * payload data (control-out). It is called in chunks of up to 8 bytes. The + * total count provided in the current control transfer can be obtained from + * the 'length' property in the setup data. If an error occurred during + * processing, return 0xff (== -1). The driver will answer the entire transfer + * with a STALL token in this case. If you have received the entire payload + * successfully, return 1. If you expect more data, return 0. If you don't + * know whether the host will send more data (you should know, the total is + * provided in the usbFunctionSetup() call!), return 1. + * NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called + * for the remaining data. You must continue to return 0xff for STALL in these + * calls. + * In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE + * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. + */ +#endif /* USB_CFG_IMPLEMENT_FN_WRITE */ +#if USB_CFG_IMPLEMENT_FN_READ +USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len); +/* This function is called by the driver to ask the application for a control + * transfer's payload data (control-in). It is called in chunks of up to 8 + * bytes each. You should copy the data to the location given by 'data' and + * return the actual number of bytes copied. If you return less than requested, + * the control-in transfer is terminated. If you return 0xff, the driver aborts + * the transfer with a STALL token. + * In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ + * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. + */ +#endif /* USB_CFG_IMPLEMENT_FN_READ */ + +extern uchar usbRxToken; /* may be used in usbFunctionWriteOut() below */ +#if USB_CFG_IMPLEMENT_FN_WRITEOUT +USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len); +/* This function is called by the driver when data is received on an interrupt- + * or bulk-out endpoint. The endpoint number can be found in the global + * variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in + * usbconfig.h to get this function called. + */ +#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */ +#ifdef USB_CFG_PULLUP_IOPORTNAME +#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<device, 1=device->host + * t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved + * r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other + */ + +/* USB setup recipient values */ +#define USBRQ_RCPT_MASK 0x1f +#define USBRQ_RCPT_DEVICE 0 +#define USBRQ_RCPT_INTERFACE 1 +#define USBRQ_RCPT_ENDPOINT 2 + +/* USB request type values */ +#define USBRQ_TYPE_MASK 0x60 +#define USBRQ_TYPE_STANDARD (0<<5) +#define USBRQ_TYPE_CLASS (1<<5) +#define USBRQ_TYPE_VENDOR (2<<5) + +/* USB direction values: */ +#define USBRQ_DIR_MASK 0x80 +#define USBRQ_DIR_HOST_TO_DEVICE (0<<7) +#define USBRQ_DIR_DEVICE_TO_HOST (1<<7) + +/* USB Standard Requests */ +#define USBRQ_GET_STATUS 0 +#define USBRQ_CLEAR_FEATURE 1 +#define USBRQ_SET_FEATURE 3 +#define USBRQ_SET_ADDRESS 5 +#define USBRQ_GET_DESCRIPTOR 6 +#define USBRQ_SET_DESCRIPTOR 7 +#define USBRQ_GET_CONFIGURATION 8 +#define USBRQ_SET_CONFIGURATION 9 +#define USBRQ_GET_INTERFACE 10 +#define USBRQ_SET_INTERFACE 11 +#define USBRQ_SYNCH_FRAME 12 + +/* USB descriptor constants */ +#define USBDESCR_DEVICE 1 +#define USBDESCR_CONFIG 2 +#define USBDESCR_STRING 3 +#define USBDESCR_INTERFACE 4 +#define USBDESCR_ENDPOINT 5 +#define USBDESCR_HID 0x21 +#define USBDESCR_HID_REPORT 0x22 +#define USBDESCR_HID_PHYS 0x23 + +//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more +#define USBATTR_BUSPOWER 0 +#define USBATTR_SELFPOWER 0x40 +#define USBATTR_REMOTEWAKE 0x20 + +/* USB HID Requests */ +#define USBRQ_HID_GET_REPORT 0x01 +#define USBRQ_HID_GET_IDLE 0x02 +#define USBRQ_HID_GET_PROTOCOL 0x03 +#define USBRQ_HID_SET_REPORT 0x09 +#define USBRQ_HID_SET_IDLE 0x0a +#define USBRQ_HID_SET_PROTOCOL 0x0b + +/* ------------------------------------------------------------------------- */ + +#endif /* __usbdrv_h_included__ */ diff --git a/packages/vusb-20121206/usbdrv/usbdrvasm.S b/packages/vusb-20121206/usbdrv/usbdrvasm.S new file mode 100644 index 0000000..32ce8ef --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrvasm.S @@ -0,0 +1,392 @@ +/* Name: usbdrvasm.S + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +This module is the assembler part of the USB driver. This file contains +general code (preprocessor acrobatics and CRC computation) and then includes +the file appropriate for the given clock rate. +*/ + +#define __SFR_OFFSET 0 /* used by avr-libc's register definitions */ +#include "usbportability.h" +#include "usbdrv.h" /* for common defs */ + +/* register names */ +#define x1 r16 +#define x2 r17 +#define shift r18 +#define cnt r19 +#define x3 r20 +#define x4 r21 +#define x5 r22 +#define bitcnt x5 +#define phase x4 +#define leap x4 + +/* Some assembler dependent definitions and declarations: */ + +#ifdef __IAR_SYSTEMS_ASM__ + extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset + extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen + extern usbTxBuf, usbTxStatus1, usbTxStatus3 +# if USB_COUNT_SOF + extern usbSofCount +# endif + public usbCrc16 + public usbCrc16Append + + COMMON INTVEC +# ifndef USB_INTR_VECTOR + ORG INT0_vect +# else /* USB_INTR_VECTOR */ + ORG USB_INTR_VECTOR +# undef USB_INTR_VECTOR +# endif /* USB_INTR_VECTOR */ +# define USB_INTR_VECTOR usbInterruptHandler + rjmp USB_INTR_VECTOR + RSEG CODE + +#else /* __IAR_SYSTEMS_ASM__ */ + +# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ +# ifdef INT0_vect +# define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector +# else +# define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector +# endif +# endif + .text + .global USB_INTR_VECTOR + .type USB_INTR_VECTOR, @function + .global usbCrc16 + .global usbCrc16Append +#endif /* __IAR_SYSTEMS_ASM__ */ + + +#if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */ +# define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING +# define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg +#else /* It's a memory address, use lds and sts */ +# define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING +# 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 +;---------------------------------------------------------------------------- + +#ifdef __IAR_SYSTEMS_ASM__ +/* Register assignments for usbCrc16 on IAR cc */ +/* Calling conventions on IAR: + * First parameter passed in r16/r17, second in r18/r19 and so on. + * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) + * Result is passed in r16/r17 + * In case of the "tiny" memory model, pointers are only 8 bit with no + * padding. We therefore pass argument 1 as "16 bit unsigned". + */ +RTMODEL "__rt_version", "3" +/* The line above will generate an error if cc calling conventions change. + * The value "3" above is valid for IAR 4.10B/W32 + */ +# define argLen r18 /* argument 2 */ +# define argPtrL r16 /* argument 1 */ +# define argPtrH r17 /* argument 1 */ + +# define resCrcL r16 /* result */ +# define resCrcH r17 /* result */ + +# define ptrL ZL +# define ptrH ZH +# define ptr Z +# define byte r22 +# define bitCnt r19 +# define polyL r20 +# define polyH r21 +# define scratch r23 + +#else /* __IAR_SYSTEMS_ASM__ */ +/* Register assignments for usbCrc16 on gcc */ +/* Calling conventions on gcc: + * First parameter passed in r24/r25, second in r22/23 and so on. + * Callee must preserve r1-r17, r28/r29 + * Result is passed in r24/r25 + */ +# define argLen r22 /* argument 2 */ +# define argPtrL r24 /* argument 1 */ +# define argPtrH r25 /* argument 1 */ + +# define resCrcL r24 /* result */ +# define resCrcH r25 /* result */ + +# define ptrL XL +# define ptrH XH +# define ptr x +# define byte r18 +# define bitCnt r19 +# define polyL r20 +# define polyH r21 +# define scratch r23 + +#endif + +#if USB_USE_FAST_CRC + +; This implementation is faster, but has bigger code size +; Thanks to Slawomir Fras (BoskiDialer) for this code! +; It implements the following C pseudo-code: +; unsigned table(unsigned char x) +; { +; unsigned value; +; +; value = (unsigned)x << 6; +; value ^= (unsigned)x << 7; +; if(parity(x)) +; value ^= 0xc001; +; return value; +; } +; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen) +; { +; unsigned crc = 0xffff; +; +; while(argLen--) +; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc); +; return ~crc; +; } + +; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); +; argPtr r24+25 / r16+r17 +; argLen r22 / r18 +; temp variables: +; byte r18 / r22 +; scratch r23 +; resCrc r24+r25 / r16+r17 +; ptr X / Z +usbCrc16: + mov ptrL, argPtrL + mov ptrH, argPtrH + ldi resCrcL, 0xFF + ldi resCrcH, 0xFF + rjmp usbCrc16LoopTest +usbCrc16ByteLoop: + ld byte, ptr+ + eor resCrcL, byte ; resCrcL is now 'x' in table() + mov byte, resCrcL ; compute parity of 'x' + swap byte + eor byte, resCrcL + mov scratch, byte + lsr byte + lsr byte + eor byte, scratch + inc byte + lsr byte + andi byte, 1 ; byte is now parity(x) + mov scratch, resCrcL + mov resCrcL, resCrcH + eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001; + neg byte + andi byte, 0xc0 + mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001; + clr byte + lsr scratch + ror byte + eor resCrcH, scratch + eor resCrcL, byte + lsr scratch + ror byte + eor resCrcH, scratch + eor resCrcL, byte +usbCrc16LoopTest: + subi argLen, 1 + brsh usbCrc16ByteLoop + com resCrcL + com resCrcH + ret + +#else /* USB_USE_FAST_CRC */ + +; This implementation is slower, but has less code size +; +; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen); +; argPtr r24+25 / r16+r17 +; argLen r22 / r18 +; temp variables: +; byte r18 / r22 +; bitCnt r19 +; poly r20+r21 +; scratch r23 +; resCrc r24+r25 / r16+r17 +; ptr X / Z +usbCrc16: + mov ptrL, argPtrL + mov ptrH, argPtrH + ldi resCrcL, 0 + ldi resCrcH, 0 + ldi polyL, lo8(0xa001) + ldi polyH, hi8(0xa001) + com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set + ldi bitCnt, 0 ; loop counter with starnd condition = end condition + rjmp usbCrcLoopEntry +usbCrcByteLoop: + ld byte, ptr+ + eor resCrcL, byte +usbCrcBitLoop: + ror resCrcH ; carry is always set here (see brcs jumps to here) + ror resCrcL + brcs usbCrcNoXor + eor resCrcL, polyL + eor resCrcH, polyH +usbCrcNoXor: + subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times + brcs usbCrcBitLoop +usbCrcLoopEntry: + subi argLen, -1 + brcs usbCrcByteLoop +usbCrcReady: + 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 + st ptr+, resCrcL + st ptr+, resCrcH + ret + +#undef argLen +#undef argPtrL +#undef argPtrH +#undef resCrcL +#undef resCrcH +#undef ptrL +#undef ptrH +#undef ptr +#undef byte +#undef bitCnt +#undef polyL +#undef polyH +#undef scratch + + +#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH +#ifdef __IAR_SYSTEMS_ASM__ +/* Register assignments for usbMeasureFrameLength on IAR cc */ +/* Calling conventions on IAR: + * First parameter passed in r16/r17, second in r18/r19 and so on. + * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) + * Result is passed in r16/r17 + * In case of the "tiny" memory model, pointers are only 8 bit with no + * padding. We therefore pass argument 1 as "16 bit unsigned". + */ +# define resL r16 +# define resH r17 +# define cnt16L r30 +# define cnt16H r31 +# define cntH r18 + +#else /* __IAR_SYSTEMS_ASM__ */ +/* Register assignments for usbMeasureFrameLength on gcc */ +/* Calling conventions on gcc: + * First parameter passed in r24/r25, second in r22/23 and so on. + * Callee must preserve r1-r17, r28/r29 + * Result is passed in r24/r25 + */ +# define resL r24 +# define resH r25 +# define cnt16L r24 +# define cnt16H r25 +# define cntH r26 +#endif +# define cnt16 cnt16L + +; extern unsigned usbMeasurePacketLength(void); +; returns time between two idle strobes in multiples of 7 CPU clocks +.global usbMeasureFrameLength +usbMeasureFrameLength: + ldi cntH, 6 ; wait ~ 10 ms for D- == 0 + clr cnt16L + clr cnt16H +usbMFTime16: + dec cntH + breq usbMFTimeout +usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe) + sbiw cnt16, 1 ;[0] [6] + breq usbMFTime16 ;[2] + sbic USBIN, USBMINUS ;[3] + rjmp usbMFWaitStrobe ;[4] +usbMFWaitIdle: ; then wait until idle again + sbis USBIN, USBMINUS ;1 wait for D- == 1 + rjmp usbMFWaitIdle ;2 + ldi cnt16L, 1 ;1 represents cycles so far + clr cnt16H ;1 +usbMFWaitLoop: + in cntH, USBIN ;[0] [7] + adiw cnt16, 1 ;[1] + breq usbMFTimeout ;[3] + andi cntH, USBMASK ;[4] + brne usbMFWaitLoop ;[5] +usbMFTimeout: +#if resL != cnt16L + mov resL, cnt16L + mov resH, cnt16H +#endif + ret + +#undef resL +#undef resH +#undef cnt16 +#undef cnt16L +#undef cnt16H +#undef cntH + +#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ + +;---------------------------------------------------------------------------- +; Now include the clock rate specific code +;---------------------------------------------------------------------------- + +#ifndef USB_CFG_CLOCK_KHZ +# ifdef F_CPU +# define USB_CFG_CLOCK_KHZ (F_CPU/1000) +# else +# error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" +# endif +#endif + +#if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */ +# if USB_CFG_CLOCK_KHZ == 18000 +# include "usbdrvasm18-crc.inc" +# else +# error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!" +# endif +#else /* USB_CFG_CHECK_CRC */ +# if USB_CFG_CLOCK_KHZ == 12000 +# include "usbdrvasm12.inc" +# elif USB_CFG_CLOCK_KHZ == 12800 +# include "usbdrvasm128.inc" +# elif USB_CFG_CLOCK_KHZ == 15000 +# include "usbdrvasm15.inc" +# elif USB_CFG_CLOCK_KHZ == 16000 +# include "usbdrvasm16.inc" +# elif USB_CFG_CLOCK_KHZ == 16500 +# include "usbdrvasm165.inc" +# elif USB_CFG_CLOCK_KHZ == 20000 +# include "usbdrvasm20.inc" +# else +# error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!" +# endif +#endif /* USB_CFG_CHECK_CRC */ diff --git a/packages/vusb-20121206/usbdrv/usbdrvasm.asm b/packages/vusb-20121206/usbdrv/usbdrvasm.asm new file mode 100644 index 0000000..fb66934 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrvasm.asm @@ -0,0 +1,20 @@ +/* Name: usbdrvasm.asm + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* +General Description: +The IAR compiler/assembler system prefers assembler files with file extension +".asm". We simply provide this file as an alias for usbdrvasm.S. + +Thanks to Oleg Semyonov for his help with the IAR tools port! +*/ + +#include "usbdrvasm.S" + +end diff --git a/packages/vusb-20121206/usbdrv/usbdrvasm12.inc b/packages/vusb-20121206/usbdrv/usbdrvasm12.inc new file mode 100644 index 0000000..d3bd056 --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrvasm12.inc @@ -0,0 +1,392 @@ +/* Name: usbdrvasm12.inc + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 12 MHz version of the asssembler part of the USB driver. It +requires a 12 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! + + +Timing constraints according to spec (in bit times): +timing subject min max CPUcycles +--------------------------------------------------------------------------- +EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2 16 16-128 +EOP of IN to sync pattern of DATA0 (rx, then tx) 2 7.5 16-60 +DATAx (rx) to ACK/NAK/STALL (tx) 2 7.5 16-60 +*/ + +;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! +;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled +;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable +;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes +;Numbers in brackets are maximum cycles since SOF. +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt + push YL ;2 [35] push only what is necessary to sync with edge ASAP + in YL, SREG ;1 [37] + push YL ;2 [39] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push YH ;2 [2] + lds YL, usbInputBufOffset;2 [4] + clr YH ;1 [5] + subi YL, lo8(-(usbRxBuf));1 [6] + sbci YH, hi8(-(usbRxBuf));1 [7] + + sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] + rjmp haveTwoBitsK ;2 [10] + pop YH ;2 [11] undo the push from before + rjmp waitForK ;2 [13] this was not the end of sync, retry +haveTwoBitsK: +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- + push shift ;2 [16] + push x1 ;2 [12] + push x2 ;2 [14] + + in x1, USBIN ;1 [17] <-- sample bit 0 + ldi shift, 0xff ;1 [18] + bst x1, USBMINUS ;1 [19] + bld shift, 0 ;1 [20] + push x3 ;2 [22] + push cnt ;2 [24] + + in x2, USBIN ;1 [25] <-- sample bit 1 + ser x3 ;1 [26] [inserted init instruction] + eor x1, x2 ;1 [27] + bst x1, USBMINUS ;1 [28] + bld shift, 1 ;1 [29] + ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] + rjmp rxbit2 ;2 [32] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- + +unstuff0: ;1 (branch taken) + andi x3, ~0x01 ;1 [15] + mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit + in x2, USBIN ;1 [17] <-- sample bit 1 again + ori shift, 0x01 ;1 [18] + rjmp didUnstuff0 ;2 [20] + +unstuff1: ;1 (branch taken) + mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit + andi x3, ~0x02 ;1 [22] + ori shift, 0x02 ;1 [23] + nop ;1 [24] + in x1, USBIN ;1 [25] <-- sample bit 2 again + rjmp didUnstuff1 ;2 [27] + +unstuff2: ;1 (branch taken) + andi x3, ~0x04 ;1 [29] + ori shift, 0x04 ;1 [30] + mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit + nop ;1 [32] + in x2, USBIN ;1 [33] <-- sample bit 3 + rjmp didUnstuff2 ;2 [35] + +unstuff3: ;1 (branch taken) + in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] + andi x3, ~0x08 ;1 [35] + ori shift, 0x08 ;1 [36] + rjmp didUnstuff3 ;2 [38] + +unstuff4: ;1 (branch taken) + andi x3, ~0x10 ;1 [40] + in x1, USBIN ;1 [41] <-- sample stuffed bit 4 + ori shift, 0x10 ;1 [42] + rjmp didUnstuff4 ;2 [44] + +unstuff5: ;1 (branch taken) + andi x3, ~0x20 ;1 [48] + in x2, USBIN ;1 [49] <-- sample stuffed bit 5 + ori shift, 0x20 ;1 [50] + rjmp didUnstuff5 ;2 [52] + +unstuff6: ;1 (branch taken) + andi x3, ~0x40 ;1 [56] + in x1, USBIN ;1 [57] <-- sample stuffed bit 6 + ori shift, 0x40 ;1 [58] + rjmp didUnstuff6 ;2 [60] + +; extra jobs done during bit interval: +; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] +; bit 1: se0 check +; bit 2: overflow check +; bit 3: recovery from delay [bit 0 tasks took too long] +; bit 4: none +; bit 5: none +; bit 6: none +; bit 7: jump, eor +rxLoop: + eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others + in x1, USBIN ;1 [1] <-- sample bit 0 + st y+, x3 ;2 [3] store data + ser x3 ;1 [4] + nop ;1 [5] + eor x2, x1 ;1 [6] + bst x2, USBMINUS;1 [7] + bld shift, 0 ;1 [8] + in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) + andi x2, USBMASK ;1 [10] + breq se0 ;1 [11] SE0 check for bit 1 + andi shift, 0xf9 ;1 [12] +didUnstuff0: + breq unstuff0 ;1 [13] + eor x1, x2 ;1 [14] + bst x1, USBMINUS;1 [15] + bld shift, 1 ;1 [16] +rxbit2: + in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) + andi shift, 0xf3 ;1 [18] + breq unstuff1 ;1 [19] do remaining work for bit 1 +didUnstuff1: + subi cnt, 1 ;1 [20] + brcs overflow ;1 [21] loop control + eor x2, x1 ;1 [22] + bst x2, USBMINUS;1 [23] + bld shift, 2 ;1 [24] + in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) + andi shift, 0xe7 ;1 [26] + breq unstuff2 ;1 [27] +didUnstuff2: + eor x1, x2 ;1 [28] + bst x1, USBMINUS;1 [29] + bld shift, 3 ;1 [30] +didUnstuff3: + andi shift, 0xcf ;1 [31] + breq unstuff3 ;1 [32] + in x1, USBIN ;1 [33] <-- sample bit 4 + eor x2, x1 ;1 [34] + bst x2, USBMINUS;1 [35] + bld shift, 4 ;1 [36] +didUnstuff4: + andi shift, 0x9f ;1 [37] + breq unstuff4 ;1 [38] + nop2 ;2 [40] + in x2, USBIN ;1 [41] <-- sample bit 5 + eor x1, x2 ;1 [42] + bst x1, USBMINUS;1 [43] + bld shift, 5 ;1 [44] +didUnstuff5: + andi shift, 0x3f ;1 [45] + breq unstuff5 ;1 [46] + nop2 ;2 [48] + in x1, USBIN ;1 [49] <-- sample bit 6 + eor x2, x1 ;1 [50] + bst x2, USBMINUS;1 [51] + bld shift, 6 ;1 [52] +didUnstuff6: + cpi shift, 0x02 ;1 [53] + brlo unstuff6 ;1 [54] + nop2 ;2 [56] + in x2, USBIN ;1 [57] <-- sample bit 7 + eor x1, x2 ;1 [58] + bst x1, USBMINUS;1 [59] + bld shift, 7 ;1 [60] +didUnstuff7: + cpi shift, 0x04 ;1 [61] + brsh rxLoop ;2 [63] loop control +unstuff7: + andi x3, ~0x80 ;1 [63] + ori shift, 0x80 ;1 [64] + in x2, USBIN ;1 [65] <-- sample stuffed bit 7 + nop ;1 [66] + rjmp didUnstuff7 ;2 [68] + +macro POP_STANDARD ; 12 cycles + pop cnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;---------------------------------------------------------------------------- +; Transmitting data +;---------------------------------------------------------------------------- + +txByteLoop: +txBitloop: +stuffN1Delay: ; [03] + ror shift ;[-5] [11] [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] + rjmp usbSendX3 ;2 [-16] +sendAckAndReti: ;0 [-19] 19 cycles until SOP + ldi x3, USBPID_ACK ;1 [-18] + rjmp usbSendX3 ;2 [-16] +sendCntAndReti: ;0 [-17] 17 cycles until SOP + mov x3, cnt ;1 [-16] +usbSendX3: ;0 [-16] + ldi YL, 20 ;1 [-15] 'x3' is R20 + ldi YH, 0 ;1 [-14] + ldi cnt, 2 ;1 [-13] +; rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte +;uses: x1...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 ;[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 + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 12.5625 MHz +max frequency: 69.286 cycles for 8 bit -> 12.99 MHz +nominal frequency: 12.77 MHz ( = sqrt(min * max)) + +sampling positions: (next even number in range [+/- 0.5]) +cycle index range: 0 ... 66 +bits: +.5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125 +[0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59] + +bit number: 0 1 2 3 4 5 6 7 +spare cycles 1 2 1 2 1 1 1 0 + +operations to perform: duration cycle + ---------------- + eor fix, shift 1 -> 00 + andi phase, USBMASK 1 -> 08 + breq se0 1 -> 16 (moved to 11) + st y+, data 2 -> 24, 25 + mov data, fix 1 -> 33 + ser data 1 -> 41 + subi cnt, 1 1 -> 49 + brcs overflow 1 -> 50 + +layout of samples and operations: +[##] = sample bit +<##> = sample phase +*##* = operation + +0: *00* [01] 02 03 04 <05> 06 07 +1: *08* [09] 10 11 12 <13> 14 15 *16* +2: [17] 18 19 20 <21> 22 23 +3: *24* *25* [26] 27 28 29 <30> 31 32 +4: *33* [34] 35 36 37 <38> 39 40 +5: *41* [42] 43 44 45 <46> 47 48 +6: *49* *50* [51] 52 53 54 <55> 56 57 58 +7: [59] 60 61 62 <63> 64 65 66 +*****************************************************************************/ + +/* we prefer positive expressions (do if condition) instead of negative + * (skip if condition), therefore use defines for skip instructions: + */ +#define ifioclr sbis +#define ifioset sbic +#define ifrclr sbrs +#define ifrset sbrc + +/* The registers "fix" and "data" swap their meaning during the loop. Use + * defines to keep their name constant. + */ +#define fix x2 +#define data x1 +#undef phase /* phase has a default definition to x4 */ +#define phase x3 + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0 + push YL ;2 push only what is necessary to sync with edge ASAP + in YL, SREG ;1 + push YL ;2 +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS ;[0] + rjmp foundK ;[1] +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError + +foundK: +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push YH ;[2] + lds YL, usbInputBufOffset;[4] + clr YH ;[6] + subi YL, lo8(-(usbRxBuf));[7] + sbci YH, hi8(-(usbRxBuf));[8] + + sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5] + rjmp haveTwoBitsK ;[10] + pop YH ;[11] undo the push from before + rjmp waitForK ;[13] this was not the end of sync, retry +haveTwoBitsK: +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +#define fix x2 +#define data x1 + + push shift ;[12] + push x1 ;[14] + push x2 ;[16] + ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0 + ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5] + ori shift, 1<<0 ;[02] + push x3 ;[03] + push cnt ;[05] + push r0 ;[07] + ifioset USBIN, USBMINUS ;[09] <--- bit 1 + ori shift, 1<<1 ;[10] + ser fix ;[11] + ldi cnt, USB_BUFSIZE ;[12] + mov data, shift ;[13] + lsl shift ;[14] + nop2 ;[15] + ifioset USBIN, USBMINUS ;[17] <--- bit 2 + ori data, 3<<2 ;[18] store in bit 2 AND bit 3 + eor shift, data ;[19] do nrzi decoding + andi data, 1<<3 ;[20] + in phase, USBIN ;[21] <- phase + brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1 + nop ;[23] + rjmp entryAfterClr ;[24] +jumpToEntryAfterSet: + rjmp entryAfterSet ;[24] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +#undef fix +#define fix x1 +#undef data +#define data x2 + +bit7IsSet: + ifrclr phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump +bit0AfterSet: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioclr USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsClr ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0s ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterSet ;[06] +unstuff0s: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsClr ;[02] executed if first expr false or second true +se0AndStore: ; executed only if both bits 0 + st y+, x1 ;[15/17] cycles after start of byte + rjmp se0 ;[17/19] + +bit0IsClr: + ifrset phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterClr: + andi phase, USBMASK ;[08] + ifioset USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsSet ;[10] + breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0 + andi shift, ~(7 << 1) ;[12] + in phase, USBIN ;[13] <- phase + breq unstuff1c ;[14] + rjmp bit2AfterClr ;[15] +unstuff1c: + andi fix, ~(1 << 1) ;[16] + nop2 ;[08] + nop2 ;[10] +bit1IsSet: + ifrclr phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterSet: + ifioclr USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsClr ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2s ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterSet ;[22] +unstuff2s: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsClr: + ifrset phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterClr: + st y+, data ;[24] +entryAfterClr: + ifioset USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsSet ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3c ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterClr ;[31] +unstuff3c: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsSet: + ifrclr phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterSet: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioclr USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsClr ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4s ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterSet ;[39] +unstuff4s: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsClr: + ifrset phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterClr: + ser data ;[41] + ifioset USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsSet ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5c ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterClr ;[47] +unstuff5c: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsSet: + ifrclr phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterSet: + subi cnt, 1 ;[49] + brcs jumpToOverflow ;[50] + ifioclr USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsClr ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6s ;[56] + rjmp bit7AfterSet ;[57] + +jumpToOverflow: + rjmp overflow + +unstuff6s: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsClr: + ifrset phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] + nop ;[58] +bit7AfterClr: + ifioset USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsSet ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7c ;[64] + rjmp bit0AfterClr ;[65] -> [00] == [67] +unstuff7c: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsSet ;[60] + +bit7IsClr: + ifrset phase, USBMINUS ;[62] check phase only if D- changed + lpm ;[63] + in phase, USBIN ;[64] <- phase (one cycle too late) + ori shift, 1 << 7 ;[65] + nop ;[66] +;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump +bit0AfterClr: + eor fix, shift ;[00] +#undef fix +#define fix x2 +#undef data +#define data x1 /* we now have result in data, fix is reset to 0xff */ + ifioset USBIN, USBMINUS ;[01] <--- sample 0 + rjmp bit0IsSet ;[02] + andi shift, ~(7 << 0) ;[03] + breq unstuff0c ;[04] + in phase, USBIN ;[05] <- phase + rjmp bit1AfterClr ;[06] +unstuff0c: + in phase, USBIN ;[06] <- phase (one cycle too late) + andi fix, ~(1 << 0) ;[07] + ifioclr USBIN, USBMINUS ;[00] + ifioset USBIN, USBPLUS ;[01] + rjmp bit0IsSet ;[02] executed if first expr false or second true + rjmp se0AndStore ;[03] executed only if both bits 0 +bit0IsSet: + ifrclr phase, USBMINUS ;[04] check phase only if D- changed + lpm ;[05] + in phase, USBIN ;[06] <- phase (one cycle too late) + ori shift, 1 << 0 ;[07] +bit1AfterSet: + andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr + ifioclr USBIN, USBMINUS ;[09] <--- sample 1 + rjmp bit1IsClr ;[10] + breq unstuff1s ;[11] + nop2 ;[12] do not check for SE0 if bit 0 was 1 + in phase, USBIN ;[14] <- phase (one cycle too late) + rjmp bit2AfterSet ;[15] +unstuff1s: + in phase, USBIN ;[13] <- phase + andi fix, ~(1 << 1) ;[14] + lpm ;[07] + nop2 ;[10] +bit1IsClr: + ifrset phase, USBMINUS ;[12] check phase only if D- changed + lpm ;[13] + in phase, USBIN ;[14] <- phase (one cycle too late) + ori shift, 1 << 1 ;[15] + nop ;[16] +bit2AfterClr: + ifioset USBIN, USBMINUS ;[17] <--- sample 2 + rjmp bit2IsSet ;[18] + andi shift, ~(7 << 2) ;[19] + breq unstuff2c ;[20] + in phase, USBIN ;[21] <- phase + rjmp bit3AfterClr ;[22] +unstuff2c: + in phase, USBIN ;[22] <- phase (one cycle too late) + andi fix, ~(1 << 2) ;[23] + nop2 ;[16] + nop2 ;[18] +bit2IsSet: + ifrclr phase, USBMINUS ;[20] check phase only if D- changed + lpm ;[21] + in phase, USBIN ;[22] <- phase (one cycle too late) + ori shift, 1 << 2 ;[23] +bit3AfterSet: + st y+, data ;[24] +entryAfterSet: + ifioclr USBIN, USBMINUS ;[26] <--- sample 3 + rjmp bit3IsClr ;[27] + andi shift, ~(7 << 3) ;[28] + breq unstuff3s ;[29] + in phase, USBIN ;[30] <- phase + rjmp bit4AfterSet ;[31] +unstuff3s: + in phase, USBIN ;[31] <- phase (one cycle too late) + andi fix, ~(1 << 3) ;[32] + nop2 ;[25] + nop2 ;[27] +bit3IsClr: + ifrset phase, USBMINUS ;[29] check phase only if D- changed + lpm ;[30] + in phase, USBIN ;[31] <- phase (one cycle too late) + ori shift, 1 << 3 ;[32] +bit4AfterClr: + mov data, fix ;[33] undo this move by swapping defines +#undef fix +#define fix x1 +#undef data +#define data x2 + ifioset USBIN, USBMINUS ;[34] <--- sample 4 + rjmp bit4IsSet ;[35] + andi shift, ~(7 << 4) ;[36] + breq unstuff4c ;[37] + in phase, USBIN ;[38] <- phase + rjmp bit5AfterClr ;[39] +unstuff4c: + in phase, USBIN ;[39] <- phase (one cycle too late) + andi fix, ~(1 << 4) ;[40] + nop2 ;[33] + nop2 ;[35] +bit4IsSet: + ifrclr phase, USBMINUS ;[37] check phase only if D- changed + lpm ;[38] + in phase, USBIN ;[39] <- phase (one cycle too late) + ori shift, 1 << 4 ;[40] +bit5AfterSet: + ser data ;[41] + ifioclr USBIN, USBMINUS ;[42] <--- sample 5 + rjmp bit5IsClr ;[43] + andi shift, ~(7 << 5) ;[44] + breq unstuff5s ;[45] + in phase, USBIN ;[46] <- phase + rjmp bit6AfterSet ;[47] +unstuff5s: + in phase, USBIN ;[47] <- phase (one cycle too late) + andi fix, ~(1 << 5) ;[48] + nop2 ;[41] + nop2 ;[43] +bit5IsClr: + ifrset phase, USBMINUS ;[45] check phase only if D- changed + lpm ;[46] + in phase, USBIN ;[47] <- phase (one cycle too late) + ori shift, 1 << 5 ;[48] +bit6AfterClr: + subi cnt, 1 ;[49] + brcs overflow ;[50] + ifioset USBIN, USBMINUS ;[51] <--- sample 6 + rjmp bit6IsSet ;[52] + andi shift, ~(3 << 6) ;[53] + cpi shift, 2 ;[54] + in phase, USBIN ;[55] <- phase + brlt unstuff6c ;[56] + rjmp bit7AfterClr ;[57] +unstuff6c: + andi fix, ~(1 << 6) ;[50] + lpm ;[51] +bit6IsSet: + ifrclr phase, USBMINUS ;[54] check phase only if D- changed + lpm ;[55] + in phase, USBIN ;[56] <- phase (one cycle too late) + ori shift, 1 << 6 ;[57] +bit7AfterSet: + ifioclr USBIN, USBMINUS ;[59] <--- sample 7 + rjmp bit7IsClr ;[60] + andi shift, ~(1 << 7) ;[61] + cpi shift, 4 ;[62] + in phase, USBIN ;[63] <- phase + brlt unstuff7s ;[64] + rjmp bit0AfterSet ;[65] -> [00] == [67] +unstuff7s: + andi fix, ~(1 << 7) ;[58] + nop ;[59] + rjmp bit7IsClr ;[60] + +macro POP_STANDARD ; 14 cycles + pop r0 + pop cnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;---------------------------------------------------------------------------- +; Transmitting data +;---------------------------------------------------------------------------- + +txByteLoop: +txBitloop: +stuffN1Delay: ; [03] + ror shift ;[-5] [11] [63] + brcc doExorN1 ;[-4] [64] + subi x3, 1 ;[-3] + brne commonN1 ;[-2] + lsl shift ;[-1] compensate ror after rjmp stuffDelay + nop ;[00] stuffing consists of just waiting 8 cycles + rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear + +sendNakAndReti: + ldi cnt, USBPID_NAK ;[-19] + rjmp sendCntAndReti ;[-18] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov r0, cnt ;[-16] + ldi YL, 0 ;[-15] R0 address is 0 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte +;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt] +;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) +usbSendAndReti: + in x2, USBDDR ;[-10] 10 cycles until SOP + ori x2, USBMASK ;[-9] + sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups) + out USBDDR, x2 ;[-6] <--- acquire bus + in x1, USBOUT ;[-5] port mirror for tx loop + ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror) + ldi x2, USBMASK ;[-3] +doExorN1: + eor x1, x2 ;[-2] [06] [62] + ldi x3, 6 ;[-1] [07] [63] +commonN1: +stuffN2Delay: + out USBOUT, x1 ;[00] [08] [64] <--- set bit + ror shift ;[01] + brcc doExorN2 ;[02] + subi x3, 1 ;[03] + brne commonN2 ;[04] + lsl shift ;[05] compensate ror after rjmp stuffDelay + rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear +doExorN2: + eor x1, x2 ;[04] [12] + ldi x3, 6 ;[05] [13] +commonN2: + nop2 ;[06] [14] + subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1 + out USBOUT, x1 ;[09] [17] <--- set bit + brcs txBitloop ;[10] [27] [44] + +stuff6Delay: + ror shift ;[45] [53] + brcc doExor6 ;[46] + subi x3, 1 ;[47] + brne common6 ;[48] + lsl shift ;[49] compensate ror after rjmp stuffDelay + nop ;[50] stuffing consists of just waiting 8 cycles + rjmp stuff6Delay ;[51] after ror, C bit is reliably clear +doExor6: + eor x1, x2 ;[48] [56] + ldi x3, 6 ;[49] +common6: +stuff7Delay: + ror shift ;[50] [58] + out USBOUT, x1 ;[51] <--- set bit + brcc doExor7 ;[52] + subi x3, 1 ;[53] + brne common7 ;[54] + lsl shift ;[55] compensate ror after rjmp stuffDelay + rjmp stuff7Delay ;[56] after ror, C bit is reliably clear +doExor7: + eor x1, x2 ;[54] [62] + ldi x3, 6 ;[55] +common7: + ld shift, y+ ;[56] + nop ;[58] + tst cnt ;[59] + out USBOUT, x1 ;[60] [00]<--- set bit + brne txByteLoop ;[61] [01] +;make SE0: + cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles] + lds x2, usbNewDeviceAddr;[03] + lsl x2 ;[05] we compare with left shifted address + subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0 + sbci YH, 0 ;[07] + out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[01] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 0) + echo "$s\n"; + } +} + +function printBit($isAfterSet, $bitNum) +{ + ob_start(); + if($isAfterSet){ +?> + ifioclr USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsClr ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#s ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterSet ;[05] +unstuff#s: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsClr: + ifrset phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + + ifioset USBIN, USBMINUS ;[00] <--- sample + rjmp bit#IsSet ;[01] + andi shift, ~(7 << #) ;[02] + breq unstuff#c ;[03] + in phase, USBIN ;[04] <- phase + rjmp bit@AfterClr ;[05] +unstuff#c: + in phase, USBIN ;[05] <- phase (one cycle too late) + andi fix, ~(1 << #) ;[06] + nop2 ;[-1] + nop2 ;[01] +bit#IsSet: + ifrclr phase, USBMINUS ;[03] check phase only if D- changed + lpm ;[04] + in phase, USBIN ;[05] <- phase (one cycle too late) + ori shift, 1 << # ;[06] + +*****************************************************************************/ diff --git a/packages/vusb-20121206/usbdrv/usbdrvasm15.inc b/packages/vusb-20121206/usbdrv/usbdrvasm15.inc new file mode 100644 index 0000000..33bcf0e --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrvasm15.inc @@ -0,0 +1,422 @@ +/* Name: usbdrvasm15.inc + * 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), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 15 MHz version of the asssembler part of the USB driver. It +requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + +;---------------------------------------------------------------------------- +; order of registers pushed: +; YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4 +;---------------------------------------------------------------------------- +USB_INTR_VECTOR: + push YL ;2 push only what is necessary to sync with edge ASAP + in YL, SREG ;1 + push YL ;2 +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +; +; sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +; sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +;------------------------------------------------------------------------------- +; The following code results in a sampling window of < 1/4 bit +; which meets the spec. +;------------------------------------------------------------------------------- +waitForK: ;- + sbis USBIN, USBMINUS ;1 [00] <-- sample + rjmp foundK ;2 [01] + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK + sbis USBIN, USBMINUS ; <-- sample + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +;------------------------------------------------------------------------------ +; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for +; center sampling] +; we have 1 bit time for setup purposes, then sample again. +; Numbers in brackets are cycles from center of first sync (double K) +; bit after the instruction +;------------------------------------------------------------------------------ +foundK: ;- [02] + lds YL, usbInputBufOffset;2 [03+04] tx loop + push YH ;2 [05+06] + clr YH ;1 [07] + subi YL, lo8(-(usbRxBuf)) ;1 [08] [rx loop init] + sbci YH, hi8(-(usbRxBuf)) ;1 [09] [rx loop init] + push shift ;2 [10+11] + ser shift ;1 [12] + sbis USBIN, USBMINUS ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early) + rjmp haveTwoBitsK ;2 [00] [14] + pop shift ;2 [15+16] undo the push from before + pop YH ;2 [17+18] undo the push from before + rjmp waitForK ;2 [19+20] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 20 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: ;- [01] + push x1 ;2 [02+03] + push x2 ;2 [04+05] + push x3 ;2 [06+07] + push bitcnt ;2 [08+09] + in x1, USBIN ;1 [00] [10] <-- sample bit 0 + bst x1, USBMINUS ;1 [01] + bld shift, 0 ;1 [02] + push cnt ;2 [03+04] + ldi cnt, USB_BUFSIZE ;1 [05] + push x4 ;2 [06+07] tx loop + rjmp rxLoop ;2 [08] +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +unstuff0: ;- [07] (branch taken) + andi x3, ~0x01 ;1 [08] + mov x1, x2 ;1 [09] x2 contains last sampled (stuffed) bit + in x2, USBIN ;1 [00] [10] <-- sample bit 1 again + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 1 + ori shift, 0x01 ;1 [03] 0b00000001 + nop ;1 [04] + rjmp didUnstuff0 ;2 [05] +;----------------------------------------------------- +unstuff1: ;- [05] (branch taken) + mov x2, x1 ;1 [06] x1 contains last sampled (stuffed) bit + andi x3, ~0x02 ;1 [07] + ori shift, 0x02 ;1 [08] 0b00000010 + nop ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 2 again + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 2 + rjmp didUnstuff1 ;2 [03] +;----------------------------------------------------- +unstuff2: ;- [05] (branch taken) + andi x3, ~0x04 ;1 [06] + ori shift, 0x04 ;1 [07] 0b00000100 + mov x1, x2 ;1 [08] x2 contains last sampled (stuffed) bit + nop ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample bit 3 + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 3 + rjmp didUnstuff2 ;2 [03] +;----------------------------------------------------- +unstuff3: ;- [00] [10] (branch taken) + in x2, USBIN ;1 [01] [11] <-- sample stuffed bit 3 one cycle too late + andi x2, USBMASK ;1 [02] + breq se0Hop ;1 [03] SE0 check for stuffed bit 3 + andi x3, ~0x08 ;1 [04] + ori shift, 0x08 ;1 [05] 0b00001000 + rjmp didUnstuff3 ;2 [06] +;---------------------------------------------------------------------------- +; extra jobs done during bit interval: +; +; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs], +; overflow check, jump to the head of rxLoop +; bit 1: SE0 check +; bit 2: SE0 check, recovery from delay [bit 0 tasks took too long] +; bit 3: SE0 check, recovery from delay [bit 0 tasks took too long] +; bit 4: SE0 check, none +; bit 5: SE0 check, none +; bit 6: SE0 check, none +; bit 7: SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others +;---------------------------------------------------------------------------- +rxLoop: ;- [09] + in x2, USBIN ;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed) + andi x2, USBMASK ;1 [01] + brne SkipSe0Hop ;1 [02] +se0Hop: ;- [02] + rjmp se0 ;2 [03] SE0 check for bit 1 +SkipSe0Hop: ;- [03] + ser x3 ;1 [04] + andi shift, 0xf9 ;1 [05] 0b11111001 + breq unstuff0 ;1 [06] +didUnstuff0: ;- [06] + eor x1, x2 ;1 [07] + bst x1, USBMINUS ;1 [08] + bld shift, 1 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed) + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 2 + andi shift, 0xf3 ;1 [03] 0b11110011 + breq unstuff1 ;1 [04] do remaining work for bit 1 +didUnstuff1: ;- [04] + eor x2, x1 ;1 [05] + bst x2, USBMINUS ;1 [06] + bld shift, 2 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed) + andi x2, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 3 + andi shift, 0xe7 ;1 [03] 0b11100111 + breq unstuff2 ;1 [04] +didUnstuff2: ;- [04] + eor x1, x2 ;1 [05] + bst x1, USBMINUS ;1 [06] + bld shift, 3 ;1 [07] +didUnstuff3: ;- [07] + andi shift, 0xcf ;1 [08] 0b11001111 + breq unstuff3 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 4 + andi x1, USBMASK ;1 [01] + breq se0Hop ;1 [02] SE0 check for bit 4 + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 4 ;1 [05] +didUnstuff4: ;- [05] + andi shift, 0x9f ;1 [06] 0b10011111 + breq unstuff4 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 5 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 5 + eor x1, x2 ;1 [03] + bst x1, USBMINUS ;1 [04] + bld shift, 5 ;1 [05] +didUnstuff5: ;- [05] + andi shift, 0x3f ;1 [06] 0b00111111 + breq unstuff5 ;1 [07] + nop2 ;2 [08+09] + in x1, USBIN ;1 [00] [10] <-- sample bit 6 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 6 + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 6 ;1 [05] +didUnstuff6: ;- [05] + cpi shift, 0x02 ;1 [06] 0b00000010 + brlo unstuff6 ;1 [07] + nop2 ;2 [08+09] + in x2, USBIN ;1 [00] [10] <-- sample bit 7 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for bit 7 + eor x1, x2 ;1 [03] + bst x1, USBMINUS ;1 [04] + bld shift, 7 ;1 [05] +didUnstuff7: ;- [05] + cpi shift, 0x04 ;1 [06] 0b00000100 + brlo unstuff7 ;1 [07] + eor x3, shift ;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others + nop ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample bit 0 + st y+, x3 ;2 [01+02] store data + eor x2, x1 ;1 [03] + bst x2, USBMINUS ;1 [04] + bld shift, 0 ;1 [05] + subi cnt, 1 ;1 [06] + brcs overflow ;1 [07] + rjmp rxLoop ;2 [08] +;----------------------------------------------------- +unstuff4: ;- [08] + andi x3, ~0x10 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 4 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 4 + ori shift, 0x10 ;1 [03] + rjmp didUnstuff4 ;2 [04] +;----------------------------------------------------- +unstuff5: ;- [08] + ori shift, 0x20 ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 5 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 5 + andi x3, ~0x20 ;1 [03] + rjmp didUnstuff5 ;2 [04] +;----------------------------------------------------- +unstuff6: ;- [08] + andi x3, ~0x40 ;1 [09] + in x1, USBIN ;1 [00] [10] <-- sample stuffed bit 6 + andi x1, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 6 + ori shift, 0x40 ;1 [03] + rjmp didUnstuff6 ;2 [04] +;----------------------------------------------------- +unstuff7: ;- [08] + andi x3, ~0x80 ;1 [09] + in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7 + andi x2, USBMASK ;1 [01] + breq se0 ;1 [02] SE0 check for stuffed bit 7 + ori shift, 0x80 ;1 [03] + rjmp didUnstuff7 ;2 [04] + +macro POP_STANDARD ; 16 cycles + pop x4 + pop cnt + pop bitcnt + pop x3 + pop x2 + pop x1 + pop shift + pop YH + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +;--------------------------------------------------------------------------- +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies +;--------------------------------------------------------------------------- +bitstuffN: ;- [04] + eor x1, x4 ;1 [05] + clr x2 ;1 [06] + nop ;1 [07] + rjmp didStuffN ;1 [08] +;--------------------------------------------------------------------------- +bitstuff6: ;- [04] + eor x1, x4 ;1 [05] + clr x2 ;1 [06] + rjmp didStuff6 ;1 [07] +;--------------------------------------------------------------------------- +bitstuff7: ;- [02] + eor x1, x4 ;1 [03] + clr x2 ;1 [06] + nop ;1 [05] + rjmp didStuff7 ;1 [06] +;--------------------------------------------------------------------------- +sendNakAndReti: ;- [-19] + ldi x3, USBPID_NAK ;1 [-18] + rjmp sendX3AndReti ;1 [-17] +;--------------------------------------------------------------------------- +sendAckAndReti: ;- [-17] + ldi cnt, USBPID_ACK ;1 [-16] +sendCntAndReti: ;- [-16] + mov x3, cnt ;1 [-15] +sendX3AndReti: ;- [-15] + ldi YL, 20 ;1 [-14] x3==r20 address is 20 + ldi YH, 0 ;1 [-13] + ldi cnt, 2 ;1 [-12] +; rjmp usbSendAndReti fallthrough +;--------------------------------------------------------------------------- +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +;We need not to match the transfer rate exactly because the spec demands +;only 1.5% precision anyway. +usbSendAndReti: ;- [-13] 13 cycles until SOP + in x2, USBDDR ;1 [-12] + ori x2, USBMASK ;1 [-11] + sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;1 [-08] port mirror for tx loop + out USBDDR, x2 ;1 [-07] <- acquire bus + ; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;1 [-06] exor mask + ldi shift, 0x80 ;1 [-05] sync byte is first byte sent + ldi bitcnt, 6 ;1 [-04] +txBitLoop: ;- [-04] [06] + sbrs shift, 0 ;1 [-03] [07] + eor x1, x4 ;1 [-02] [08] + ror shift ;1 [-01] [09] +didStuffN: ;- [09] + out USBOUT, x1 ;1 [00] [10] <-- out N + ror x2 ;1 [01] + cpi x2, 0xfc ;1 [02] + brcc bitstuffN ;1 [03] + dec bitcnt ;1 [04] + brne txBitLoop ;1 [05] + sbrs shift, 0 ;1 [06] + eor x1, x4 ;1 [07] + ror shift ;1 [08] +didStuff6: ;- [08] + nop ;1 [09] + out USBOUT, x1 ;1 [00] [10] <-- out 6 + ror x2 ;1 [01] + cpi x2, 0xfc ;1 [02] + brcc bitstuff6 ;1 [03] + sbrs shift, 0 ;1 [04] + eor x1, x4 ;1 [05] + ror shift ;1 [06] + ror x2 ;1 [07] +didStuff7: ;- [07] + ldi bitcnt, 6 ;1 [08] + cpi x2, 0xfc ;1 [09] + out USBOUT, x1 ;1 [00] [10] <-- out 7 + brcc bitstuff7 ;1 [01] + ld shift, y+ ;2 [02+03] + dec cnt ;1 [04] + brne txBitLoop ;1 [05] +makeSE0: + cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles] + lds x2, usbNewDeviceAddr;2 [07+08] + lsl x2 ;1 [09] we compare with left shifted address +;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 + out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle + subi YL, 20 + 2 ;1 [01] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;1 [02] + breq skipAddrAssign ;1 [03] + sts usbDeviceAddr, x2 ;2 [04+05] if not skipped: SE0 is one cycle longer +;---------------------------------------------------------------------------- +;end of usbDeviceAddress transfer +skipAddrAssign: ;- [03/04] + ldi x2, 1< 10.6666666 cycles per bit, 85.333333333 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt + push YL ;[-25] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-23] + push YL ;[-22] + push YH ;[-20] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + rjmp foundK ;[-14] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-12] +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push bitcnt ;[-12] +; [---] ;[-11] + lds YL, usbInputBufOffset;[-10] +; [---] ;[-9] + clr YH ;[-8] + subi YL, lo8(-(usbRxBuf));[-7] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init] + push shift ;[-5] +; [---] ;[-4] + ldi bitcnt, 0x55 ;[-3] [rx loop init] + sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) + rjmp haveTwoBitsK ;[-1] + pop shift ;[0] undo the push from before + pop bitcnt ;[2] undo the push from before + rjmp waitForK ;[4] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 21 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[1] + push x2 ;[3] + push x3 ;[5] + ldi shift, 0 ;[7] + ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that + push x4 ;[9] == leap + + in x1, USBIN ;[11] <-- sample bit 0 + andi x1, USBMASK ;[12] + bst x1, USBMINUS ;[13] + bld shift, 7 ;[14] + push cnt ;[15] + ldi leap, 0 ;[17] [rx loop init] + ldi cnt, USB_BUFSIZE;[18] [rx loop init] + rjmp rxbit1 ;[19] arrives at [21] + +;---------------------------------------------------------------------------- +; 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, -1 ;[07] total duration = 11 bits -> subtract 1/3 + rjmp didUnstuff6 ;[08] + +unstuff7: + ori x3, 1<<7 ;[09] will not be shifted any more + in x2, USBIN ;[00] [10] re-sample bit 7 + andi x2, USBMASK ;[01] + andi shift, ~0x80;[02] + subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 + rjmp didUnstuff7 ;[04] + +unstuffEven: + ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0 + in x1, USBIN ;[00] [10] + andi shift, ~0x80;[01] + andi x1, USBMASK ;[02] + breq se0 ;[03] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] + rjmp didUnstuffE ;[06] + +unstuffOdd: + ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1 + in x2, USBIN ;[00] [10] + andi shift, ~0x80;[01] + andi x2, USBMASK ;[02] + breq se0 ;[03] + subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 + nop2 ;[05] + rjmp didUnstuffO ;[06] + +rxByteLoop: + andi x1, USBMASK ;[03] + eor x2, x1 ;[04] + subi leap, 1 ;[05] + brpl skipLeap ;[06] + subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte + nop ;1 +skipLeap: + subi x2, 1 ;[08] + ror shift ;[09] +didUnstuff6: + cpi shift, 0xfc ;[10] + in x2, USBIN ;[00] [11] <-- sample bit 7 + brcc unstuff6 ;[01] + andi x2, USBMASK ;[02] + eor x1, x2 ;[03] + subi x1, 1 ;[04] + ror shift ;[05] +didUnstuff7: + cpi shift, 0xfc ;[06] + brcc unstuff7 ;[07] + eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others + st y+, x3 ;[09] store data +rxBitLoop: + in x1, USBIN ;[00] [11] <-- sample bit 0/2/4 + andi x1, USBMASK ;[01] + eor x2, x1 ;[02] + andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7 + subi x2, 1 ;[04] + ror shift ;[05] + cpi shift, 0xfc ;[06] + brcc unstuffEven ;[07] +didUnstuffE: + lsr x3 ;[08] + lsr x3 ;[09] +rxbit1: + in x2, USBIN ;[00] [10] <-- sample bit 1/3/5 + andi x2, USBMASK ;[01] + breq se0 ;[02] + eor x1, x2 ;[03] + subi x1, 1 ;[04] + ror shift ;[05] + cpi shift, 0xfc ;[06] + brcc unstuffOdd ;[07] +didUnstuffO: + subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 + brcs rxBitLoop ;[09] + + subi cnt, 1 ;[10] + in x1, USBIN ;[00] [11] <-- sample bit 6 + brcc rxByteLoop ;[01] + rjmp overflow + +macro POP_STANDARD ; 14 cycles + pop cnt + pop x4 + pop x3 + pop x2 + pop x1 + pop shift + pop bitcnt + endm +macro POP_RETI ; 7 cycles + pop YH + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies + +bitstuffN: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] + nop2 ;[7] + nop ;[9] + out USBOUT, x1 ;[10] <-- out + rjmp didStuffN ;[0] + +bitstuff6: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] Carry is zero due to brcc + rol shift ;[7] compensate for ror shift at branch destination + rjmp didStuff6 ;[8] + +bitstuff7: + ldi x2, 0 ;[2] Carry is zero due to brcc + rjmp didStuff7 ;[3] + + +sendNakAndReti: + ldi x3, USBPID_NAK ;[-18] + rjmp sendX3AndReti ;[-17] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov x3, cnt ;[-16] +sendX3AndReti: + ldi YL, 20 ;[-15] x3==r20 address is 20 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +;We don't match the transfer rate exactly (don't insert leap cycles every third +;byte) because the spec demands only 1.5% precision anyway. +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-6] exor mask + ldi shift, 0x80 ;[-5] sync byte is first byte sent +txByteLoop: + ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101 +txBitLoop: + sbrs shift, 0 ;[-3] [7] + eor x1, x4 ;[-2] [8] + out USBOUT, x1 ;[-1] [9] <-- out N + ror shift ;[0] [10] + ror x2 ;[1] +didStuffN: + cpi x2, 0xfc ;[2] + brcc bitstuffN ;[3] + lsr bitcnt ;[4] + brcc txBitLoop ;[5] + brne txBitLoop ;[6] + + sbrs shift, 0 ;[7] + eor x1, x4 ;[8] +didStuff6: + out USBOUT, x1 ;[-1] [9] <-- out 6 + ror shift ;[0] [10] + ror x2 ;[1] + cpi x2, 0xfc ;[2] + brcc bitstuff6 ;[3] + ror shift ;[4] +didStuff7: + ror x2 ;[5] + sbrs x2, 7 ;[6] + eor x1, x4 ;[7] + nop ;[8] + cpi x2, 0xfc ;[9] + out USBOUT, x1 ;[-1][10] <-- out 7 + brcc bitstuff7 ;[0] [11] + ld shift, y+ ;[1] + dec cnt ;[3] + brne txByteLoop ;[4] +;make SE0: + cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] + lds x2, usbNewDeviceAddr;[6] + lsl x2 ;[8] we compare with left shifted address + subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[10] + out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[0] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< max 52 cycles interrupt disable +;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 16.5 MHz -> 11 cycles per bit +; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%) +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt + push YL ;[-23] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-21] + push YL ;[-20] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + rjmp foundK ;[-14] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-12] +;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] +;we have 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push r0 ;[-12] +; [---] ;[-11] + push YH ;[-10] +; [---] ;[-9] + lds YL, usbInputBufOffset;[-8] +; [---] ;[-7] + clr YH ;[-6] + subi YL, lo8(-(usbRxBuf));[-5] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init] + mov r0, x2 ;[-3] [rx loop init] + sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) + rjmp haveTwoBitsK ;[-1] + pop YH ;[0] undo the pushes from before + pop r0 ;[2] + rjmp waitForK ;[4] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 22 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: ;[1] + push shift ;[1] + push x1 ;[3] + push x2 ;[5] + push x3 ;[7] + ldi shift, 0xff ;[9] [rx loop init] + ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag + + in x1, USBIN ;[11] <-- sample bit 0 + bst x1, USBMINUS ;[12] + bld shift, 0 ;[13] + push x4 ;[14] == phase +; [---] ;[15] + push cnt ;[16] +; [---] ;[17] + ldi phase, 0 ;[18] [rx loop init] + ldi cnt, USB_BUFSIZE;[19] [rx loop init] + rjmp rxbit1 ;[20] +; [---] ;[21] + +;---------------------------------------------------------------------------- +; Receiver loop (numbers in brackets are cycles within byte after instr) +;---------------------------------------------------------------------------- +/* +byte oriented operations done during loop: +bit 0: store data +bit 1: SE0 check +bit 2: overflow check +bit 3: catch up +bit 4: rjmp to achieve conditional jump range +bit 5: PLL +bit 6: catch up +bit 7: jump, fixup bitstuff +; 87 [+ 2] cycles +------------------------------------------------------------------ +*/ +continueWithBit5: + in x2, USBIN ;[055] <-- bit 5 + eor r0, x2 ;[056] + or phase, r0 ;[057] + sbrc phase, USBMINUS ;[058] + lpm ;[059] optional nop3; modifies r0 + in phase, USBIN ;[060] <-- phase + eor x1, x2 ;[061] + bst x1, USBMINUS ;[062] + bld shift, 5 ;[063] + andi shift, 0x3f ;[064] + in x1, USBIN ;[065] <-- bit 6 + breq unstuff5 ;[066] *** unstuff escape + eor phase, x1 ;[067] + eor x2, x1 ;[068] + bst x2, USBMINUS ;[069] + bld shift, 6 ;[070] +didUnstuff6: ;[ ] + in r0, USBIN ;[071] <-- phase + cpi shift, 0x02 ;[072] + brlo unstuff6 ;[073] *** unstuff escape +didUnstuff5: ;[ ] + nop2 ;[074] +; [---] ;[075] + in x2, USBIN ;[076] <-- bit 7 + eor x1, x2 ;[077] + bst x1, USBMINUS ;[078] + bld shift, 7 ;[079] +didUnstuff7: ;[ ] + eor r0, x2 ;[080] + or phase, r0 ;[081] + in r0, USBIN ;[082] <-- phase + cpi shift, 0x04 ;[083] + brsh rxLoop ;[084] +; [---] ;[085] +unstuff7: ;[ ] + andi x3, ~0x80 ;[085] + ori shift, 0x80 ;[086] + in x2, USBIN ;[087] <-- sample stuffed bit 7 + nop ;[088] + rjmp didUnstuff7 ;[089] +; [---] ;[090] + ;[080] + +unstuff5: ;[067] + eor phase, x1 ;[068] + andi x3, ~0x20 ;[069] + ori shift, 0x20 ;[070] + in r0, USBIN ;[071] <-- phase + mov x2, x1 ;[072] + nop ;[073] + nop2 ;[074] +; [---] ;[075] + in x1, USBIN ;[076] <-- bit 6 + eor r0, x1 ;[077] + or phase, r0 ;[078] + eor x2, x1 ;[079] + bst x2, USBMINUS ;[080] + bld shift, 6 ;[081] no need to check bitstuffing, we just had one + in r0, USBIN ;[082] <-- phase + rjmp didUnstuff5 ;[083] +; [---] ;[084] + ;[074] + +unstuff6: ;[074] + andi x3, ~0x40 ;[075] + in x1, USBIN ;[076] <-- bit 6 again + ori shift, 0x40 ;[077] + nop2 ;[078] +; [---] ;[079] + rjmp didUnstuff6 ;[080] +; [---] ;[081] + ;[071] + +unstuff0: ;[013] + eor r0, x2 ;[014] + or phase, r0 ;[015] + andi x2, USBMASK ;[016] check for SE0 + in r0, USBIN ;[017] <-- phase + breq didUnstuff0 ;[018] direct jump to se0 would be too long + andi x3, ~0x01 ;[019] + ori shift, 0x01 ;[020] + mov x1, x2 ;[021] mov existing sample + in x2, USBIN ;[022] <-- bit 1 again + rjmp didUnstuff0 ;[023] +; [---] ;[024] + ;[014] + +unstuff1: ;[024] + eor r0, x1 ;[025] + or phase, r0 ;[026] + andi x3, ~0x02 ;[027] + in r0, USBIN ;[028] <-- phase + ori shift, 0x02 ;[029] + mov x2, x1 ;[030] + rjmp didUnstuff1 ;[031] +; [---] ;[032] + ;[022] + +unstuff2: ;[035] + eor r0, x2 ;[036] + or phase, r0 ;[037] + andi x3, ~0x04 ;[038] + in r0, USBIN ;[039] <-- phase + ori shift, 0x04 ;[040] + mov x1, x2 ;[041] + rjmp didUnstuff2 ;[042] +; [---] ;[043] + ;[033] + +unstuff3: ;[043] + in x2, USBIN ;[044] <-- bit 3 again + eor r0, x2 ;[045] + or phase, r0 ;[046] + andi x3, ~0x08 ;[047] + ori shift, 0x08 ;[048] + nop ;[049] + in r0, USBIN ;[050] <-- phase + rjmp didUnstuff3 ;[051] +; [---] ;[052] + ;[042] + +unstuff4: ;[053] + andi x3, ~0x10 ;[054] + in x1, USBIN ;[055] <-- bit 4 again + ori shift, 0x10 ;[056] + rjmp didUnstuff4 ;[057] +; [---] ;[058] + ;[048] + +rxLoop: ;[085] + eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others + in x1, USBIN ;[000] <-- bit 0 + st y+, x3 ;[001] +; [---] ;[002] + eor r0, x1 ;[003] + or phase, r0 ;[004] + eor x2, x1 ;[005] + in r0, USBIN ;[006] <-- phase + ser x3 ;[007] + bst x2, USBMINUS ;[008] + bld shift, 0 ;[009] + andi shift, 0xf9 ;[010] +rxbit1: ;[ ] + in x2, USBIN ;[011] <-- bit 1 + breq unstuff0 ;[012] *** unstuff escape + andi x2, USBMASK ;[013] SE0 check for bit 1 +didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff + breq se0 ;[014] + eor r0, x2 ;[015] + or phase, r0 ;[016] + in r0, USBIN ;[017] <-- phase + eor x1, x2 ;[018] + bst x1, USBMINUS ;[019] + bld shift, 1 ;[020] + andi shift, 0xf3 ;[021] +didUnstuff1: ;[ ] + in x1, USBIN ;[022] <-- bit 2 + breq unstuff1 ;[023] *** unstuff escape + eor r0, x1 ;[024] + or phase, r0 ;[025] + subi cnt, 1 ;[026] overflow check + brcs overflow ;[027] + in r0, USBIN ;[028] <-- phase + eor x2, x1 ;[029] + bst x2, USBMINUS ;[030] + bld shift, 2 ;[031] + andi shift, 0xe7 ;[032] +didUnstuff2: ;[ ] + in x2, USBIN ;[033] <-- bit 3 + breq unstuff2 ;[034] *** unstuff escape + eor r0, x2 ;[035] + or phase, r0 ;[036] + eor x1, x2 ;[037] + bst x1, USBMINUS ;[038] + in r0, USBIN ;[039] <-- phase + bld shift, 3 ;[040] + andi shift, 0xcf ;[041] +didUnstuff3: ;[ ] + breq unstuff3 ;[042] *** unstuff escape + nop ;[043] + in x1, USBIN ;[044] <-- bit 4 + eor x2, x1 ;[045] + bst x2, USBMINUS ;[046] + bld shift, 4 ;[047] +didUnstuff4: ;[ ] + eor r0, x1 ;[048] + or phase, r0 ;[049] + in r0, USBIN ;[050] <-- phase + andi shift, 0x9f ;[051] + breq unstuff4 ;[052] *** unstuff escape + rjmp continueWithBit5;[053] +; [---] ;[054] + +macro POP_STANDARD ; 16 cycles + pop cnt + pop x4 + pop x3 + pop x2 + pop x1 + pop shift + pop YH + pop r0 + endm +macro POP_RETI ; 5 cycles + pop YL + out SREG, YL + pop YL + endm + +#include "asmcommon.inc" + + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies + +bitstuff7: + eor x1, x4 ;[4] + ldi x2, 0 ;[5] + nop2 ;[6] C is zero (brcc) + rjmp didStuff7 ;[8] + +bitstuffN: + eor x1, x4 ;[5] + ldi x2, 0 ;[6] + lpm ;[7] 3 cycle NOP, modifies r0 + out USBOUT, x1 ;[10] <-- out + rjmp didStuffN ;[0] + +#define bitStatus x3 + +sendNakAndReti: + ldi cnt, USBPID_NAK ;[-19] + rjmp sendCntAndReti ;[-18] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov r0, cnt ;[-16] + ldi YL, 0 ;[-15] R0 address is 0 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-6] exor mask + ldi shift, 0x80 ;[-5] sync byte is first byte sent + ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes +byteloop: +bitloop: + sbrs shift, 0 ;[8] [-3] + eor x1, x4 ;[9] [-2] + out USBOUT, x1 ;[10] [-1] <-- out + ror shift ;[0] + ror x2 ;[1] +didStuffN: + cpi x2, 0xfc ;[2] + brcc bitstuffN ;[3] + nop ;[4] + subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37 + brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value + sbrs shift, 0 ;[7] + eor x1, x4 ;[8] + ror shift ;[9] +didStuff7: + out USBOUT, x1 ;[10] <-- out + ror x2 ;[0] + cpi x2, 0xfc ;[1] + brcc bitstuff7 ;[2] + ld shift, y+ ;[3] + dec cnt ;[5] + brne byteloop ;[6] +;make SE0: + cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] + lds x2, usbNewDeviceAddr;[8] + lsl x2 ;[10] we compare with left shifted address + out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 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 + subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0 + sbci YH, 0 ;[1] + breq skipAddrAssign ;[2] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 12 cycles per bit +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop to receive the data bytes: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; cnt holds the number of bytes left in the receive buffer +; x3 holds the higher crc byte (see algorithm below) +; x4 is used as temporary register for the crc algorithm +; x5 is used for unstuffing: when unstuffing the last received bit is inverted in shift (to prevent further +; unstuffing calls. In the same time the corresponding bit in x5 is cleared to mark the bit as beening iverted +; zl lower crc value and crc table index +; zh used for crc table accesses + +;-------------------------------------------------------------------------------------------------------------- +; CRC mods: +; table driven crc checker, Z points to table in prog space +; ZL is the lower crc byte, x3 is the higher crc byte +; x4 is used as temp register to store different results +; the initialization of the crc register is not 0xFFFF but 0xFE54. This is because during the receipt of the +; first data byte an virtual zero data byte is added to the crc register, this results in the correct initial +; value of 0xFFFF at beginning of the second data byte before the first data byte is added to the crc. +; The magic number 0xFE54 results form the crc table: At tabH[0x54] = 0xFF = crcH (required) and +; tabL[0x54] = 0x01 -> crcL = 0x01 xor 0xFE = 0xFF +; bitcnt is renamed to x5 and is used for unstuffing purposes, the unstuffing works like in the 12MHz version +;-------------------------------------------------------------------------------------------------------------- +; CRC algorithm: +; The crc register is formed by x3 (higher byte) and ZL (lower byte). The algorithm uses a 'reversed' form +; i.e. that it takes the least significant bit first and shifts to the right. So in fact the highest order +; bit seen from the polynomial devision point of view is the lsb of ZL. (If this sounds strange to you i +; propose a research on CRC :-) ) +; Each data byte received is xored to ZL, the lower crc byte. This byte now builds the crc +; table index. Next the new high byte is loaded from the table and stored in x4 until we have space in x3 +; (its destination). +; Afterwards the lower table is loaded from the table and stored in ZL (the old index is overwritten as +; we don't need it anymore. In fact this is a right shift by 8 bits.) Now the old crc high value is xored +; to ZL, this is the second shift of the old crc value. Now x4 (the temp reg) is moved to x3 and the crc +; calculation is done. +; Prior to the first byte the two CRC register have to be initialized to 0xFFFF (as defined in usb spec) +; however the crc engine also runs during the receipt of the first byte, therefore x3 and zl are initialized +; to a magic number which results in a crc value of 0xFFFF after the first complete byte. +; +; This algorithm is split into the extra cycles of the different bits: +; bit7: XOR the received byte to ZL +; bit5: load the new high byte to x4 +; bit6: load the lower xor byte from the table, xor zl and x3, store result in zl (=the new crc low value) +; move x4 (the new high byte) to x3, the crc value is ready +; + + +macro POP_STANDARD ; 18 cycles + pop ZH + pop ZL + pop cnt + pop x5 + pop x3 + pop x2 + pop x1 + pop shift + pop x4 + endm +macro POP_RETI ; 7 cycles + pop YH + pop YL + out SREG, YL + pop YL + endm + +macro CRC_CLEANUP_AND_CHECK + ; the last byte has already been xored with the lower crc byte, we have to do the table lookup and xor + ; x3 is the higher crc byte, zl the lower one + ldi ZH, hi8(usbCrcTableHigh);[+1] get the new high byte from the table + lpm x2, Z ;[+2][+3][+4] + ldi ZH, hi8(usbCrcTableLow);[+5] get the new low xor byte from the table + lpm ZL, Z ;[+6][+7][+8] + eor ZL, x3 ;[+7] xor the old high byte with the value from the table, x2:ZL now holds the crc value + cpi ZL, 0x01 ;[+8] if the crc is ok we have a fixed remainder value of 0xb001 in x2:ZL (see usb spec) + brne ignorePacket ;[+9] detected a crc fault -> paket is ignored and retransmitted by the host + cpi x2, 0xb0 ;[+10] + brne ignorePacket ;[+11] detected a crc fault -> paket is ignored and retransmitted by the host + endm + + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG, YH, [sofError], x4, shift, x1, x2, x3, x5, cnt, ZL, ZH + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-17] + rjmp foundK ;[-16] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-15] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 30 (2.5 bits) for center sampling. Currently at 4 so 26 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push x4 ;[-14] +; [---] ;[-13] + lds YL, usbInputBufOffset;[-12] used to toggle the two usb receive buffers +; [---] ;[-11] + clr YH ;[-10] + subi YL, lo8(-(usbRxBuf));[-9] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-8] [rx loop init] + push shift ;[-7] +; [---] ;[-6] + ldi shift, 0x80 ;[-5] the last bit is the end of byte marker for the pid receiver loop + clc ;[-4] the carry has to be clear for receipt of pid bit 0 + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop x4 ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 24 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] crc high byte + ldi x2, 1< jump back and store the byte + ori shift, 0x01 ;[11] invert the last received bit to prevent furhter unstuffing + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + andi x5, 0xFE ;[1] mark this bit as inverted (will be corrected before storing shift) + eor x1, x2 ;[2] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[3] mask the interesting bits + breq stuffErr ;[4] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[5] the next bit expects the last state to be in x1 + rjmp didunstuff0 ;[6] + ;[7] jump delay of rjmp didunstuffX + +unstuff1: ;[11] this is the jump delay of breq unstuffX + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + ori shift, 0x02 ;[1] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFD ;[2] mark this bit as inverted (will be corrected before storing shift) + eor x2, x1 ;[3] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[4] mask the interesting bits + breq stuffErr ;[5] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[6] the next bit expects the last state to be in x2 + nop2 ;[7] + ;[8] + rjmp didunstuff1 ;[9] + ;[10] jump delay of rjmp didunstuffX + +unstuff2: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x04 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xFB ;[11] mark this bit as inverted (will be corrected before storing shift) + in x2, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x1, x2 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x1, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x1, x2 ;[4] the next bit expects the last state to be in x1 + nop2 ;[5] + ;[6] + rjmp didunstuff2 ;[7] + ;[8] jump delay of rjmp didunstuffX + +unstuff3: ;[9] this is the jump delay of breq unstuffX + ori shift, 0x08 ;[10] invert the last received bit to prevent furhter unstuffing + andi x5, 0xF7 ;[11] mark this bit as inverted (will be corrected before storing shift) + in x1, USBIN ;[0] we have some free cycles so we could check for bit stuffing errors + eor x2, x1 ;[1] x1 and x2 have to be different because the stuff bit is always a zero + andi x2, USBMASK ;[2] mask the interesting bits + breq stuffErr ;[3] if the stuff bit is a 1-bit something went wrong + mov x2, x1 ;[4] the next bit expects the last state to be in x2 + nop2 ;[5] + ;[6] + rjmp didunstuff3 ;[7] + ;[8] jump delay of rjmp didunstuffX + + + +; the include has to be here due to branch distance restirctions +#define __USE_CRC__ +#include "asmcommon.inc" + + + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) +; K = (D+ = 1), (D- = 0) +; Spec allows 7.5 bit times from EOP to SOP for replies +; 7.5 bit times is 90 cycles. ...there is plenty of time + + +sendNakAndReti: + ldi x3, USBPID_NAK ;[-18] + rjmp sendX3AndReti ;[-17] +sendAckAndReti: + ldi cnt, USBPID_ACK ;[-17] +sendCntAndReti: + mov x3, cnt ;[-16] +sendX3AndReti: + ldi YL, 20 ;[-15] x3==r20 address is 20 + ldi YH, 0 ;[-14] + ldi cnt, 2 ;[-13] +; rjmp usbSendAndReti fallthrough + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] +;uses: x1...x4, btcnt, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent + +usbSendAndReti: ; 12 cycles until SOP + in x2, USBDDR ;[-12] + ori x2, USBMASK ;[-11] + sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;[-8] port mirror for tx loop + out USBDDR, x2 ;[-6] <- acquire bus + ldi x2, 0 ;[-6] init x2 (bitstuff history) because sync starts with 0 + ldi x4, USBMASK ;[-5] exor mask + ldi shift, 0x80 ;[-4] sync byte is first byte sent +txByteLoop: + ldi bitcnt, 0x40 ;[-3]=[9] binary 01000000 +txBitLoop: ; the loop sends the first 7 bits of the byte + sbrs shift, 0 ;[-2]=[10] if we have to send a 1 don't change the line state + eor x1, x4 ;[-1]=[11] + out USBOUT, x1 ;[0] + ror shift ;[1] + ror x2 ;[2] transfers the last sent bit to the stuffing history +didStuffN: + nop ;[3] + nop ;[4] + cpi x2, 0xfc ;[5] if we sent six consecutive ones + brcc bitstuffN ;[6] + lsr bitcnt ;[7] + brne txBitLoop ;[8] restart the loop while the 1 is still in the bitcount + +; transmit bit 7 + sbrs shift, 0 ;[9] + eor x1, x4 ;[10] +didStuff7: + ror shift ;[11] + out USBOUT, x1 ;[0] transfer bit 7 to the pins + ror x2 ;[1] move the bit into the stuffing history + cpi x2, 0xfc ;[2] + brcc bitstuff7 ;[3] + ld shift, y+ ;[4] get next byte to transmit + dec cnt ;[5] decrement byte counter + brne txByteLoop ;[7] if we have more bytes start next one + ;[8] branch delay + +;make SE0: + cbr x1, USBMASK ;[8] prepare SE0 [spec says EOP may be 25 to 30 cycles] + lds x2, usbNewDeviceAddr;[9] + lsl x2 ;[11] we compare with left shifted address + out USBOUT, x1 ;[0] <-- out SE0 -- from now 2 bits = 24 cycles until bus idle + subi YL, 20 + 2 ;[1] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;[2] +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + breq skipAddrAssign ;[3] + sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< +int main (int argc, char **argv) +{ + int i, j; + for (i=0; i<512; i++){ + unsigned short crc = i & 0xff; + for(j=0; j<8; j++) crc = (crc >> 1) ^ ((crc & 1) ? 0xa001 : 0); + if((i & 7) == 0) printf("\n.byte "); + printf("0x%02x, ", (i > 0xff ? (crc >> 8) : crc) & 0xff); + if(i == 255) printf("\n"); + } + return 0; +} + +// Use the following algorithm to compute CRC values: +ushort computeCrc(uchar *msg, uchar msgLen) +{ + uchar i; + ushort crc = 0xffff; + for(i = 0; i < msgLen; i++) + crc = usbCrcTable16[lo8(crc) ^ msg[i]] ^ hi8(crc); + return crc; +} +*/ + +.balign 256 +usbCrcTableLow: +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 +.byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 + +; .balign 256 +usbCrcTableHigh: +.byte 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2 +.byte 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04 +.byte 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E +.byte 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8 +.byte 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A +.byte 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC +.byte 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6 +.byte 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10 +.byte 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32 +.byte 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4 +.byte 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE +.byte 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38 +.byte 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA +.byte 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C +.byte 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26 +.byte 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0 +.byte 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62 +.byte 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4 +.byte 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE +.byte 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68 +.byte 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA +.byte 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C +.byte 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76 +.byte 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0 +.byte 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92 +.byte 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54 +.byte 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E +.byte 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98 +.byte 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A +.byte 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C +.byte 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86 +.byte 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 + diff --git a/packages/vusb-20121206/usbdrv/usbdrvasm20.inc b/packages/vusb-20121206/usbdrv/usbdrvasm20.inc new file mode 100644 index 0000000..5027edd --- /dev/null +++ b/packages/vusb-20121206/usbdrv/usbdrvasm20.inc @@ -0,0 +1,359 @@ +/* Name: usbdrvasm20.inc + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Jeroen Benschop + * Based on usbdrvasm16.inc from Christian Starkjohann + * Creation Date: 2008-03-05 + * Tabsize: 4 + * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + */ + +/* Do not link this file! Link usbdrvasm.S instead, which includes the + * appropriate implementation! + */ + +/* +General Description: +This file is the 20 MHz version of the asssembler part of the USB driver. It +requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC +oscillator). + +See usbdrv.h for a description of the entire driver. + +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +#define leap2 x3 +#ifdef __IAR_SYSTEMS_ASM__ +#define nextInst $+2 +#else +#define nextInst .+0 +#endif + +;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes +;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte +; Numbers in brackets are clocks counted from center of last sync bit +; when instruction starts +;register use in receive loop: +; shift assembles the byte currently being received +; x1 holds the D+ and D- line state +; x2 holds the previous line state +; x4 (leap) is used to add a leap cycle once every three bytes received +; X3 (leap2) is used to add a leap cycle once every three stuff bits received +; bitcnt is used to determine when a stuff bit is due +; cnt holds the number of bytes left in the receive buffer + +USB_INTR_VECTOR: +;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt + push YL ;[-28] push only what is necessary to sync with edge ASAP + in YL, SREG ;[-26] + push YL ;[-25] + push YH ;[-23] +;---------------------------------------------------------------------------- +; Synchronize with sync pattern: +;---------------------------------------------------------------------------- +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;The first part waits at most 1 bit long since we must be in sync pattern. +;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to +;waitForJ, ensure that this prerequisite is met. +waitForJ: + inc YL + sbis USBIN, USBMINUS + brne waitForJ ; just make sure we have ANY timeout +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-19] + rjmp foundK ;[-18] + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK +#if USB_COUNT_SOF + lds YL, usbSofCount + inc YL + sts usbSofCount, YL +#endif /* USB_COUNT_SOF */ +#ifdef USB_SOF_HOOK + USB_SOF_HOOK +#endif + rjmp sofError +foundK: ;[-16] +;{3, 5} after falling D- edge, average delay: 4 cycles +;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample +;use 1 bit time for setup purposes, then sample again. Numbers in brackets +;are cycles from center of first sync (double K) bit after the instruction + push bitcnt ;[-16] +; [---] ;[-15] + lds YL, usbInputBufOffset;[-14] +; [---] ;[-13] + clr YH ;[-12] + subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] + sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] + push shift ;[-9] +; [---] ;[-8] + ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected + nop2 ;[-6] +; [---] ;[-5] + ldi bitcnt, 5 ;[-4] [rx loop init] + sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) + rjmp haveTwoBitsK ;[-2] + pop shift ;[-1] undo the push from before + pop bitcnt ;[1] + rjmp waitForK ;[3] this was not the end of sync, retry +; The entire loop from waitForK until rjmp waitForK above must not exceed two +; bit times (= 27 cycles). + +;---------------------------------------------------------------------------- +; push more registers and initialize values while we sample the first bits: +;---------------------------------------------------------------------------- +haveTwoBitsK: + push x1 ;[0] + push x2 ;[2] + push x3 ;[4] (leap2) + ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit + push x4 ;[7] == leap + ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received + push cnt ;[10] + ldi cnt, USB_BUFSIZE ;[12] [rx loop init] + ldi x2, 1< +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) /* not supported on IAR */ + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ /* IAR does not define standard macro for asm */ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +/* The following definitions are not needed by the driver, but may be of some + * help if you port a gcc based project to IAR. + */ +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() +#define _BV(x) (1 << (x)) + +/* assembler compatibility macros */ +#define nop2 rjmp $+2 /* jump to next instruction */ +#define XL r26 +#define XH r27 +#define YL r28 +#define YH r29 +#define ZL r30 +#define ZH r31 +#define lo8(x) LOW(x) +#define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ + +/* Depending on the device you use, you may get problems with the way usbdrv.h + * handles the differences between devices. Since IAR does not use #defines + * for MCU registers, we can't check for the existence of a particular + * register with an #ifdef. If the autodetection mechanism fails, include + * definitions for the required USB_INTR_* macros in your usbconfig.h. See + * usbconfig-prototype.h and usbdrv.h for details. + */ + +/* ------------------------------------------------------------------------- */ +#elif __CODEVISIONAVR__ /* check for CodeVision AVR */ +/* ------------------------------------------------------------------------- */ +/* This port is not working (yet) */ + +/* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ + +#include +#include + +#define __attribute__(arg) /* not supported on IAR */ + +#define PROGMEM __flash +#define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) + +#ifndef __ASSEMBLER__ +static inline void cli(void) +{ + #asm("cli"); +} +static inline void sei(void) +{ + #asm("sei"); +} +#endif +#define _delay_ms(t) delay_ms(t) +#define _BV(x) (1 << (x)) +#define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ + +#define macro .macro +#define endm .endmacro +#define nop2 rjmp .+0 /* jump to next instruction */ + +/* ------------------------------------------------------------------------- */ +#else /* default development environment is avr-gcc/avr-libc */ +/* ------------------------------------------------------------------------- */ + +#include +#ifdef __ASSEMBLER__ +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +#else +# include +#endif + +#if USB_CFG_DRIVER_FLASH_PAGE +# define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) +#else +# define USB_READ_FLASH(addr) pgm_read_byte(addr) +#endif + +#define macro .macro +#define endm .endm +#define nop2 rjmp .+0 /* jump to next instruction */ + +#endif /* development environment */ + +/* for conveniecne, ensure that PRG_RDB exists */ +#ifndef PRG_RDB +# define PRG_RDB(addr) USB_READ_FLASH(addr) +#endif +#endif /* __usbportability_h_INCLUDED__ */