diff --git a/Changelog.txt b/Changelog.txt new file mode 100644 index 0000000..cb74b1a --- /dev/null +++ b/Changelog.txt @@ -0,0 +1,5 @@ +$Id: Changelog.txt,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + +* Release 080709 + +- initial release diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..9ba8721 --- /dev/null +++ b/License.txt @@ -0,0 +1,346 @@ +The following license applies to all but the firmware/usbdrv directories. For +that directory, please refer to the firmware/usbdrv/License.txt file for +additional license restrictions. + +------------------------------------------------------------------------------- + + 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/Makefile b/Makefile new file mode 100644 index 0000000..b439c30 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +# $Id: Makefile,v 1.1 2008/07/09 20:47:11 rschaten Exp $ +# +# Creates documentation and tarball for shipping. + +TODAY=`date "+%y%m%d"` +DIR=`basename \`pwd\`` +PACKETNAME=$(DIR)_$(TODAY) + +all: usage + +usage: + @echo "Usage of this makefile:" + @echo "make docs create documentation" + @echo "make tarball packs a tarball for shipping" + @echo + @echo "For further information, consult the documentation in Readme.txt." + +# doc generation +docs: readme pdf + @echo "documentation created" + +readme: doxygen + echo "This file is auto-generated from the content of firmware/main.c" > Readme.txt + echo "You'll have more fun if you read the HTML-content in htmldoc or the PDF." >> Readme.txt + echo >> Readme.txt + lynx -dump htmldoc/main.html >> Readme.txt + +pdf: doxygen + make -C latexdoc + mv latexdoc/refman.pdf . + rm -rf latexdoc + +doxygen: + doxygen firmware/project.doxygen + +clean: + rm -rf htmldoc latexdoc Readme.txt refman.pdf + rm -f $(PACKETNAME).tar.gz + make -C firmware clean + make -C bootloader clean + +fw: + make -C firmware + mv -v firmware/main.hex firmware/main_$(TODAY).hex + +tarball: fw clean docs + @echo + @echo + @echo "I assume you updated the Changelog...? Press Enter to continue..." + @read + [ -e "firmware/main_$(TODAY).hex" ] || exit + rm --force $(PACKETNAME).tar.gz; \ + tar --directory=.. \ + --exclude=$(DIR)/Makefile \ + --exclude=CVS \ + --exclude=*.ps \ + --create \ + --gzip \ + --verbose \ + --file ../$(PACKETNAME).tar.gz $(DIR) + diff --git a/USBaspLoader.2008-02-05.tar.gz b/USBaspLoader.2008-02-05.tar.gz new file mode 100644 index 0000000..1651a9b Binary files /dev/null and b/USBaspLoader.2008-02-05.tar.gz differ diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000..04fd23c --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,78 @@ +# Configure the following variables according to your AVR. +# Program the device with +# make fuse # to set the clock generator, boot section size etc. +# make flash # to load the boot loader into flash +# make lock # to protect the boot loader from overwriting + +F_CPU = 12000000 +DEVICE = atmega32 +BOOTLOADER_ADDRESS = 0x7000 +FUSEOPT = -U lfuse:w:0xCF:m -U hfuse:w:0xD8:m +LOCKOPT = -U lock:w:0x2f:m + +# reminder, if something gets broken: default lock-byte for a mega32 is 0x3f + +PROGRAMMER = -c avrispv2 -P usb -B 10 +# PROGRAMMER contains AVRDUDE options to address your programmer + +############################################################################### + +# Tools: +AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) +CC = avr-gcc + +# Options: +DEFINES = #-DDEBUG_LEVEL=2 +CFLAGS = -Wall -Os -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES) +LDFLAGS = -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS) + +OBJECTS = usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + +# symbolic targets: +all: main.hex + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +.S.o: + $(CC) $(CFLAGS) -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. + +.c.s: + $(CC) $(CFLAGS) -S $< -o $@ + +flash: all + $(AVRDUDE) -U flash:w:main.hex:i + +readflash: + $(AVRDUDE) -U flash:r:read.hex:i + +fuse: + $(AVRDUDE) $(FUSEOPT) + +lock: + $(AVRDUDE) $(LOCKOPT) + +read_fuses: + $(UISP) --rd_fuses + +clean: + rm -f main.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# file targets: +main.bin: $(OBJECTS) + $(CC) $(CFLAGS) -o main.bin $(OBJECTS) $(LDFLAGS) + +main.hex: main.bin + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.bin main.hex + avr-size main.hex + +disasm: main.bin + avr-objdump -d main.bin + +cpp: + $(CC) $(CFLAGS) -E main.c diff --git a/bootloader/bootloaderconfig.h b/bootloader/bootloaderconfig.h new file mode 100644 index 0000000..ec0618e --- /dev/null +++ b/bootloader/bootloaderconfig.h @@ -0,0 +1,190 @@ +/** + * \file bootloader/bootloaderconfig.h + * \brief This file (together with some settings in Makefile) configures the + * boot loader according to the hardware. + * + * This file contains (besides the hardware configuration normally found in + * usbconfig.h) two functions or macros: bootLoaderInit() and + * bootLoaderCondition(). Whether you implement them as macros or as static + * inline functions is up to you, decide based on code size and convenience. + * + * bootLoaderInit() is called as one of the first actions after reset. It should + * be a minimum initialization of the hardware so that the boot loader condition + * can be read. This will usually consist of activating a pull-up resistor for an + * external jumper which selects boot loader mode. + * + * bootLoaderCondition() is called immediately after initialization and in each + * main loop iteration. If it returns TRUE, the boot loader will be active. If it + * returns FALSE, the boot loader jumps to address 0 (the loaded application) + * immediately. + * + * For compatibility with Thomas Fischl's avrusbboot, we also support the macro + * names BOOTLOADER_INIT and BOOTLOADER_CONDITION for this functionality. If + * these macros are defined, the boot loader usees them. + * + * \author Ronald Schaten + * \version $Id: bootloaderconfig.h,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + * + * License: GNU GPL v2 (see License.txt) + */ + +#ifndef __bootloaderconfig_h_included__ +#define __bootloaderconfig_h_included__ + +/* ---------------------------- Hardware Config ---------------------------- */ + +/** 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_IOPORTNAME D +/** 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_DMINUS_BIT 0 +/** This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port. Please note that D+ must also be connected + * to interrupt pin INT0! + */ +#define USB_CFG_DPLUS_BIT 2 +/** Clock rate of the AVR in MHz. Legal values are 12000, 16000 or 16500. + * The 16.5 MHz version of the code requires no crystal, it tolerates +/- 1% + * deviation from the nominal frequency. All other rates require a precision + * of 2000 ppm and thus a crystal! + * Default if not specified: 12 MHz + */ +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) + +/* ----------------------- Optional Hardware Config ------------------------ */ + +/* 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_IOPORTNAME D */ +/* 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. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ + +/* ------------------------------------------------------------------------- */ +/* ---------------------- feature / code size options ---------------------- */ +/* ------------------------------------------------------------------------- */ + +/** If HAVE_EEPROM_PAGED_ACCESS is defined to 1, page mode access to EEPROM is + * compiled in. Whether page mode or byte mode access is used by AVRDUDE + * depends on the target device. Page mode is only used if the device supports + * it, e.g. for the ATMega88, 168 etc. You can save quite a bit of memory by + * disabling page mode EEPROM access. Costs ~ 138 bytes. + */ +#define HAVE_EEPROM_PAGED_ACCESS 1 +/** If HAVE_EEPROM_BYTE_ACCESS is defined to 1, byte mode access to EEPROM is + * compiled in. Byte mode is only used if the device (as identified by its + * signature) does not support page mode for EEPROM. It is required for + * accessing the EEPROM on the ATMega8. Costs ~54 bytes. + */ +#define HAVE_EEPROM_BYTE_ACCESS 1 +/** If this macro is defined to 1, the boot loader will exit shortly after the + * programmer closes the connection to the device. Costs ~36 bytes. + */ +#define BOOTLOADER_CAN_EXIT 1 +/** This macro defines the signature bytes returned by the emulated USBasp to + * the programmer software. They should match the actual device at least in + * memory size and features. If you don't define this, values for ATMega8, + * ATMega88, ATMega168 and ATMega328 are guessed correctly. + */ +#define SIGNATURE_BYTES 0x1e, 0x95, 0x02, 0 /* ATMega32 */ + +/* The following block guesses feature options so that the resulting code + * should fit into 2k bytes boot block with the given device and clock rate. + * Activate by passing "-DUSE_AUTOCONFIG=1" to the compiler. + * This requires gcc 3.4.6 for small enough code size! + */ +#if USE_AUTOCONFIG +# undef HAVE_EEPROM_PAGED_ACCESS +# define HAVE_EEPROM_PAGED_ACCESS (USB_CFG_CLOCK_KHZ >= 16000) +# undef HAVE_EEPROM_BYTE_ACCESS +# define HAVE_EEPROM_BYTE_ACCESS 1 +# undef BOOTLOADER_CAN_EXIT +# define BOOTLOADER_CAN_EXIT 1 +# undef SIGNATURE_BYTES +#endif /* USE_AUTOCONFIG */ + +/* ------------------------------------------------------------------------- */ + +#ifndef __ASSEMBLER__ /* assembler cannot parse function definitions */ + +uint8_t ledcounter = 0; ///< counter used to set the speed of the running light +uint8_t ledstate = 0; ///< state of the running light + +/** + * Prepare IO-ports for detection of bootloader-condition, which happens in + * bootLoaderCondition(). + */ +static inline void bootLoaderInit(void) { + // switch on leds + DDRD |= (1 << PIND4) | (1 << PIND5) | (1 << PIND6); + PORTD &= ~((1 << PIND4) | (1 << PIND5) | (1 << PIND6)); + // choose matrix position for hotkey. we use KEY_KPminus, so we set row 13 + // and later look for pin 7 + DDRA = 0x00; + PORTA = 0xff; + DDRC = (1 << DDC2); + PORTC = ~(1 << PINC2); +} + +/** + * Clean up after boot loader action. In this case: switch off all LEDs. + */ +static inline void bootLoaderExit(void) { + // switch off leds + PORTD |= (1 << PIND4) | (1 << PIND5) | (1 << PIND6); +} + +/** + * Check if conditions for boot loader are met. This function is called in an + * endless loop, so we use our spare time to display a nice running light on + * the LEDs. + * \return 1 if bootloader should be active, 0 otherwise + */ +static inline uint8_t bootLoaderCondition() { + // look for pin 7 + if (!(PINB & (1 << PINB7))) { + // boot loader active, blink leds + _delay_ms(1); + ledcounter++; + if (ledcounter == 127) { + switch (ledstate) { + case 0: + PORTD &= ~(1 << PIND6); + PORTD |= (1 << PIND4) | (1 << PIND5); + ledstate = 1; + break; + case 1: + PORTD &= ~(1 << PIND5); + PORTD |= (1 << PIND4) | (1 << PIND6); + ledstate = 2; + break; + case 2: + PORTD &= ~(1 << PIND4); + PORTD |= (1 << PIND5) | (1 << PIND6); + ledstate = 0; + break; + default: + ledstate = 0; + } + ledcounter = 0; + } + return 1; + } else { + // no boot loader + return 0; + } +} + +#endif /* __ASSEMBLER__ */ + +/* ------------------------------------------------------------------------- */ + +#endif /* __bootloader_h_included__ */ diff --git a/bootloader/main.c b/bootloader/main.c new file mode 100644 index 0000000..669448b --- /dev/null +++ b/bootloader/main.c @@ -0,0 +1,299 @@ +/* Name: main.c + * Project: USBaspLoader + * Author: Christian Starkjohann + * Creation Date: 2007-12-08 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) + * This Revision: $Id: main.c,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void leaveBootloader() __attribute__((__noreturn__)); + +#include "bootloaderconfig.h" +#include "usbdrv/usbdrv.c" + +/* ------------------------------------------------------------------------ */ + +/* Request constants used by USBasp */ +#define USBASP_FUNC_CONNECT 1 +#define USBASP_FUNC_DISCONNECT 2 +#define USBASP_FUNC_TRANSMIT 3 +#define USBASP_FUNC_READFLASH 4 +#define USBASP_FUNC_ENABLEPROG 5 +#define USBASP_FUNC_WRITEFLASH 6 +#define USBASP_FUNC_READEEPROM 7 +#define USBASP_FUNC_WRITEEEPROM 8 +#define USBASP_FUNC_SETLONGADDRESS 9 + +/* ------------------------------------------------------------------------ */ + +#ifndef ulong +# define ulong unsigned long +#endif +#ifndef uint +# define uint unsigned int +#endif + +/* defaults if not in config file: */ +#ifndef HAVE_EEPROM_PAGED_ACCESS +# define HAVE_EEPROM_PAGED_ACCESS 0 +#endif +#ifndef HAVE_EEPROM_BYTE_ACCESS +# define HAVE_EEPROM_BYTE_ACCESS 0 +#endif +#ifndef BOOTLOADER_CAN_EXIT +# define BOOTLOADER_CAN_EXIT 0 +#endif + +/* allow compatibility with avrusbboot's bootloaderconfig.h: */ +#ifdef BOOTLOADER_INIT +# define bootLoaderInit() BOOTLOADER_INIT +# define bootLoaderExit() +#endif +#ifdef BOOTLOADER_CONDITION +# define bootLoaderCondition() BOOTLOADER_CONDITION +#endif + +/* device compatibility: */ +#ifndef GICR /* ATMega*8 don't have GICR, use MCUCR instead */ +# define GICR MCUCR +#endif + +/* ------------------------------------------------------------------------ */ + +typedef union longConverter{ + ulong l; + uint w[2]; + uchar b[4]; +}longConverter_t; + +static uchar requestBootLoaderExit; +static longConverter_t currentAddress; /* in bytes */ +static uchar bytesRemaining; +static uchar isLastPage; +#if HAVE_EEPROM_PAGED_ACCESS +static uchar currentRequest; +#else +static const uchar currentRequest = 0; +#endif + +static const uchar signatureBytes[4] = { +#ifdef SIGNATURE_BYTES + SIGNATURE_BYTES +#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8HVA__) + 0x1e, 0x93, 0x07, 0 +#elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__) + 0x1e, 0x92, 0x05, 0 +#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) + 0x1e, 0x93, 0x0a, 0 +#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) + 0x1e, 0x94, 0x06, 0 +#elif defined (__AVR_ATmega328P__) + 0x1e, 0x95, 0x0f, 0 +#elif defined (__AVR_ATmega32__) + 0x1e, 0x95, 0x02, 0 +#else +# error "Device signature is not known, please edit main.c!" +#endif +}; + +#if (FLASHEND) > 0xffff /* we need long addressing */ +# define CURRENT_ADDRESS currentAddress.l +#else +# define CURRENT_ADDRESS currentAddress.w[0] +#endif + +/* ------------------------------------------------------------------------ */ + +static void (*nullVector)(void) __attribute__((__noreturn__)); + +static void leaveBootloader() +{ + DBG1(0x01, 0, 0); + bootLoaderExit(); + cli(); + GICR = (1 << IVCE); /* enable change of interrupt vectors */ + GICR = (0 << IVSEL); /* move interrupts to application flash section */ +/* We must go through a global function pointer variable instead of writing + * ((void (*)(void))0)(); + * because the compiler optimizes a constant 0 to "rcall 0" which is not + * handled correctly by the assembler. + */ + nullVector(); +} + +/* ------------------------------------------------------------------------ */ + +uchar usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; +uchar len = 0; +static uchar replyBuffer[4]; + + usbMsgPtr = replyBuffer; + if(rq->bRequest == USBASP_FUNC_TRANSMIT){ /* emulate parts of ISP protocol */ + uchar rval = 0; + usbWord_t address; + address.bytes[1] = rq->wValue.bytes[1]; + address.bytes[0] = rq->wIndex.bytes[0]; + if(rq->wValue.bytes[0] == 0x30){ /* read signature */ + rval = rq->wIndex.bytes[0] & 3; + rval = signatureBytes[rval]; +#if HAVE_EEPROM_BYTE_ACCESS + }else if(rq->wValue.bytes[0] == 0xa0){ /* read EEPROM byte */ + rval = eeprom_read_byte((void *)address.word); + }else if(rq->wValue.bytes[0] == 0xc0){ /* write EEPROM byte */ + eeprom_write_byte((void *)address.word, rq->wIndex.bytes[1]); +#endif + }else{ + /* ignore all others, return default value == 0 */ + } + replyBuffer[3] = rval; + len = 4; + }else if(rq->bRequest == USBASP_FUNC_ENABLEPROG){ + /* replyBuffer[0] = 0; is never touched and thus always 0 which means success */ + len = 1; + }else if(rq->bRequest >= USBASP_FUNC_READFLASH && rq->bRequest <= USBASP_FUNC_SETLONGADDRESS){ + currentAddress.w[0] = rq->wValue.word; + if(rq->bRequest == USBASP_FUNC_SETLONGADDRESS){ +#if (FLASHEND) > 0xffff + currentAddress.w[1] = rq->wIndex.word; +#endif + }else{ + bytesRemaining = rq->wLength.bytes[0]; + /* if(rq->bRequest == USBASP_FUNC_WRITEFLASH) only evaluated during writeFlash anyway */ + isLastPage = rq->wIndex.bytes[1] & 0x02; +#if HAVE_EEPROM_PAGED_ACCESS + currentRequest = rq->bRequest; +#endif + len = 0xff; /* hand over to usbFunctionRead() / usbFunctionWrite() */ + } +#if BOOTLOADER_CAN_EXIT + }else if(rq->bRequest == USBASP_FUNC_DISCONNECT){ + requestBootLoaderExit = 1; /* allow proper shutdown/close of connection */ +#endif + }else{ + /* ignore: USBASP_FUNC_CONNECT */ + } + return len; +} + +uchar usbFunctionWrite(uchar *data, uchar len) +{ +uchar isLastWrite; + + DBG1(0x31, (void *)¤tAddress.l, 4); + if(len > bytesRemaining) + len = bytesRemaining; + bytesRemaining -= len; + isLastWrite = bytesRemaining == 0; + if(currentRequest >= USBASP_FUNC_READEEPROM){ + eeprom_write_block(data, (void *)currentAddress.w[0], len); + currentAddress.w[0] += len; + }else{ + char i = len; + while(i > 0){ + i -= 2; + if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0){ /* if page start: erase */ + DBG1(0x33, 0, 0); +#ifndef NO_FLASH_WRITE + cli(); + boot_page_erase(CURRENT_ADDRESS); /* erase page */ + sei(); + boot_spm_busy_wait(); /* wait until page is erased */ +#endif + } + DBG1(0x32, 0, 0); + cli(); + boot_page_fill(CURRENT_ADDRESS, *(short *)data); + sei(); + CURRENT_ADDRESS += 2; + data += 2; + /* write page when we cross page boundary or we have the last partial page */ + if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0 || (i <= 0 && isLastWrite && isLastPage)){ + DBG1(0x34, 0, 0); +#ifndef NO_FLASH_WRITE + cli(); + boot_page_write(CURRENT_ADDRESS - 2); + sei(); + boot_spm_busy_wait(); + cli(); + boot_rww_enable(); + sei(); +#endif + } + } + DBG1(0x35, (void *)¤tAddress.l, 4); + } + return isLastWrite; +} + +uchar usbFunctionRead(uchar *data, uchar len) +{ + if(len > bytesRemaining) + len = bytesRemaining; + bytesRemaining -= len; + if(currentRequest >= USBASP_FUNC_READEEPROM){ + eeprom_read_block(data, (void *)currentAddress.w[0], len); + }else{ + memcpy_P(data, (PGM_VOID_P)CURRENT_ADDRESS, len); + } + CURRENT_ADDRESS += len; + return len; +} + +/* ------------------------------------------------------------------------ */ + +static void initForUsbConnectivity(void) +{ +uchar i = 0; + + usbInit(); + /* enforce USB re-enumerate: */ + usbDeviceDisconnect(); /* do this while interrupts are disabled */ + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + sei(); +} + +int main(void) +{ + /* initialize */ + bootLoaderInit(); + odDebugInit(); + DBG1(0x00, 0, 0); +#ifndef NO_FLASH_WRITE + GICR = (1 << IVCE); /* enable change of interrupt vectors */ + GICR = (1 << IVSEL); /* move interrupts to boot flash section */ +#endif + if(bootLoaderCondition()){ + uint i = 0; + initForUsbConnectivity(); + do{ + usbPoll(); +#if BOOTLOADER_CAN_EXIT + if(requestBootLoaderExit){ + if(--i == 0) + break; + } +#endif + }while(bootLoaderCondition()); /* main event loop */ + } + leaveBootloader(); + return 0; +} + +/* ------------------------------------------------------------------------ */ diff --git a/bootloader/usbconfig.h b/bootloader/usbconfig.h new file mode 100644 index 0000000..5d98d6d --- /dev/null +++ b/bootloader/usbconfig.h @@ -0,0 +1,214 @@ +/* Name: usbconfig.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2007-12-08 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) + * This Revision: $Id: usbconfig.h,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + +/* +General Description: +This file contains the configuration options for the USB driver. + +Please note that the usbdrv contains a usbconfig-prototype.h file now. We +recommend that you use that file as a template because it will always list +the newest features and options. +*/ + +/* Fetch the hardware configuration from bootloaderconfig.h so that we have a + * single file where hardware settings are stored. + * Do not edit the functional settings below. + */ +#include "bootloaderconfig.h" + +#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. + */ + +/* --------------------------- 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 1. + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 +/* Define this to 1 if you want to compile a version with three endpoints: The + * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in + * endpoint 3. You must also enable endpoint 1 above. + */ +#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 200 +/* 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 100 +/* 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) endpoint 1. + * You must implement the function usbFunctionWriteOut() which receives all + * interrupt/bulk data sent to endpoint 1. + */ +#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. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* 5824 in dec, stands for VOTI */ +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you use obdev's free shared + * VID/PID pair. Be sure to read USBID-License.txt for rules! + */ +#define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free 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 use obdev's free shared VID/PID pair. Be sure to read the rules in + * USBID-License.txt! + */ +#define USB_CFG_DEVICE_VERSION 0x02, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 'w', 'w', 'w', '.', 'f', 'i', 's', 'c', 'h', 'l', '.', 'd', 'e' +#define USB_CFG_VENDOR_NAME_LEN 13 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USBID-License.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'U', 'S', 'B', 'a', 's', 'p' +#define USB_CFG_DEVICE_NAME_LEN 6 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USBID-License.txt before you assign a name. + */ +/*#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 +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + */ +#define USB_CFG_INTERFACE_CLASS 0 +#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. + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 /* total length of report descriptor */ +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + */ + +/* ------------------- 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) + * + */ + +#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 + +/* ----------------------- 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 */ + +#endif /* __usbconfig_h_included__ */ diff --git a/bootloader/usbdrv/Changelog.txt b/bootloader/usbdrv/Changelog.txt new file mode 100644 index 0000000..f04d08e --- /dev/null +++ b/bootloader/usbdrv/Changelog.txt @@ -0,0 +1,200 @@ +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. + +* Release 2008-02-05 diff --git a/bootloader/usbdrv/CommercialLicense.txt b/bootloader/usbdrv/CommercialLicense.txt new file mode 100644 index 0000000..240e45f --- /dev/null +++ b/bootloader/usbdrv/CommercialLicense.txt @@ -0,0 +1,155 @@ +AVR-USB Driver Software License Agreement +Version 2006-07-24 + +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 "AVR-USB" shall mean the firmware-only USB device implementation for +Atmel AVR microcontrollers distributed by OBJECTIVE DEVELOPMENT and +consisting of the files usbdrv.c, usbdrv.h, usbdrvasm.S, oddebug.c, +oddebug.h, usbdrvasm.asm, iarcompat.h and usbconfig-prototype.h. + + +2 LICENSE GRANTS + +2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source +code of AVR-USB. + +2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the +non-exclusive right to use and distribute AVR-USB with your hardware +product(s), restricted by the limitations in section 3 below. + +2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify +your copy of AVR-USB according to your needs. + +2.4 USB IDs. OBJECTIVE DEVELOPMENT grants you the exclusive rights to use +USB Product ID(s) sent to you in e-mail after receiving your payment in +conjunction with USB Vendor ID 5824. OBJECTIVE DEVELOPMENT has acquired an +exclusive license for this pair of USB identifiers from Wouter van Ooijen +(www.voti.nl), who has licensed the VID from the USB Implementers Forum, +Inc. (www.usb.org). + + +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 AVR-USB according to section 2 above in no more +than 5 hardware units. These units must not be sold for profit. + +Entry Level License: You may use AVR-USB according to section 2 above in no +more than 150 hardware units. + +Professional License: You may use AVR-USB according to section 2 above in +any number of hardware units, except for large scale production ("unlimited +fair use"). Quantities below 10,000 units are not considered large scale +production. If your reach quantities which are obviously large scale +production, you must pay a license fee of 0.10 EUR per unit for all units +above 10,000. + +3.2 Rental. You may not rent, lease, or lend AVR-USB or otherwise encumber +any copy of AVR-USB, or any of the rights granted herein. + +3.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 AVR-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/avrusb/license.html. You agree to pay the amount listed +there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor +or reseller. + + +5 COPYRIGHT AND OWNERSHIP + +AVR-USB is protected by copyright laws and international copyright +treaties, as well as other intellectual property laws and treaties. AVR-USB +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. AVR-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE +DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND +NON-INFRINGEMENT, WITH REGARD TO AVR-USB, AND THE PROVISION OF OR FAILURE +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 AVR-USB OR THE +PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE +DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY +CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS +AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR AVR-USB. + + +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/bootloader/usbdrv/License.txt b/bootloader/usbdrv/License.txt new file mode 100644 index 0000000..f6a232e --- /dev/null +++ b/bootloader/usbdrv/License.txt @@ -0,0 +1,359 @@ +OBJECTIVE DEVELOPMENT GmbH's AVR-USB driver software is distributed under the +terms and conditions of the GNU GPL version 2, see the text below. In addition +to the requirements in the GPL, we STRONGLY ENCOURAGE you to do the following: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/avrusb/feedback.html for your submission. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/avrusb/ + +(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/bootloader/usbdrv/Readme.txt b/bootloader/usbdrv/Readme.txt new file mode 100644 index 0000000..6fb9902 --- /dev/null +++ b/bootloader/usbdrv/Readme.txt @@ -0,0 +1,154 @@ +This is the Readme file to Objective Development's firmware-only USB driver +for Atmel AVR microcontrollers. For more information please visit +http://www.obdev.at/avrusb/ + +This directory contains the USB firmware only. Copy it as-is to your own +project and add your own version of "usbconfig.h". A template for your own +"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory. + + +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. + iarcompat.h ............ Compatibility definitions for IAR C-compiler. + usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this + module instead of usbdrvasm.S when you assembler + with IAR's tools. + License.txt ............ Open Source license for this driver. + CommercialLicense.txt .. Optional commercial license for this driver. + USBID-License.txt ...... Terms and conditions for using particular USB ID + values for particular purposes. + +(*) ... These files should be linked to your project. + + +CPU CORE CLOCK FREQUENCY +======================== +We supply assembler modules for clock frequencies of 12 MHz, 15 MHz, 16 MHz and +16.5 MHz. Other clock rates are not supported. The actual clock rate must be +configured in usbdrv.h unless you use the default 12 MHz. + +12 MHz Clock +This is the traditional clock rate of AVR-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. + +16.5 MHz Clock +The assembler module for this clock rate differs from the other modules because +it has been built for an RC oscillator with only 1% precision. The receiver +code inserts leap cycles to compensate for clock deviations. 1% is also the +precision which can be achieved by calibrating the internal RC oscillator of +the AVR. Please note that only AVRs with internal 64 MHz PLL oscillator can be +used since the 8 MHz RC oscillator cannot be trimmed up to 16.5 MHz. This +includes the very popular ATTiny25, ATTiny45, ATTiny85 series as well as the +ATTiny26. + +We recommend that you obtain appropriate calibration values for 16.5 MHz core +clock at programming time and store it in flash or EEPROM or compute the value +from a reference clock at run time. Atmel's 8 MHz calibration is much more +precise than the guaranteed 10% and it's therefore often possible to work with +a fixed offset from this value, but it may be out of range. + + +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 a single VID/PID pair for free. If you want to use +your own VID and PID instead of our's, define the macros "USB_CFG_VENDOR_ID" +and "USB_CFG_DEVICE_ID" accordingly in "usbconfig.h". + +To use our predefined VID/PID pair, you MUST conform to a couple of +requirements. See the file "USBID-License.txt" for details. + +Objective Development also has some offerings which include product IDs. See +http://www.obdev.at/avrusb/ for details. + + +HOST DRIVER +=========== +You have received this driver together with an example device implementation +and an example host driver. The host driver is based on libusb and compiles +on various Unix flavors (Linux, BSD, Mac OS X). It also compiles natively on +Windows using MinGW (see www.mingw.org) and libusb-win32 (see +libusb-win32.sourceforge.net). The "Automator" project contains a native +Windows host driver (not based on libusb) for Human Interface Devices. + + +DEVELOPMENT SYSTEM +================== +This driver has been developed and optimized for the GNU compiler version 3 +(gcc 3). It does work well with gcc 4, but with bigger code size. We recommend +that you use the GNU compiler suite because it is freely available. AVR-USB +has also been ported to the IAR compiler and assembler. It has been tested +with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the "small" and "tiny" +memory model. Not every release is tested with IAR CC and the driver may +therefore fail to compile with IAR. Please note that gcc is more efficient for +usbdrv.c because this module has been deliberately optimized for gcc. + + +USING AVR-USB FOR FREE +====================== +The AVR firmware driver is published under the GNU General Public License +Version 2 (GPL2). See the file "License.txt" for details. + +If you decide for the free GPL2, we STRONGLY ENCOURAGE you to do the following +things IN ADDITION to the obligations from the GPL2: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/avrusb/feedback.html for your submission. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/avrusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + +COMMERCIAL LICENSES FOR AVR-USB +=============================== +If you don't want to publish your source code under the terms of the GPL2, +you can simply pay money for AVR-USB. As an additional benefit you get +USB PIDs for free, licensed exclusively to you. See the file +"CommercialLicense.txt" for details. + diff --git a/bootloader/usbdrv/USBID-License.txt b/bootloader/usbdrv/USBID-License.txt new file mode 100644 index 0000000..4739a57 --- /dev/null +++ b/bootloader/usbdrv/USBID-License.txt @@ -0,0 +1,143 @@ +Royalty-Free Non-Exclusive License USB Product-ID +================================================= + +Version 2006-06-19 + +OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive +right to use three USB.org vendor-ID (VID) / product-ID (PID) pairs with +products based on Objective Development's firmware-only USB driver for +Atmel AVR microcontrollers: + + * VID = 5824 (=0x16c0) / PID = 1500 (=0x5dc) for devices implementing no + USB device class (vendor-class devices with USB class = 0xff). Devices + using this pair will be referred to as "VENDOR CLASS" devices. + + * VID = 5824 (=0x16c0) / PID = 1503 (=0x5df) for HID class devices + (excluding mice and keyboards). Devices using this pair will be referred + to as "HID CLASS" devices. + + * VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices + Devices using this pair will be referred to as "CDC-ACM CLASS" devices. + +Since the granted right is non-exclusive, the same VID/PID pairs may be +used by many companies and individuals for different products. To avoid +conflicts, your device and host driver software MUST adhere to the rules +outlined below. + +OBJECTIVE DEVELOPMENT Software GmbH has licensed these VID/PID pairs from +Wouter van Ooijen (see www.voti.nl), who has licensed the VID from the USB +Implementers Forum, Inc. (see www.usb.org). The VID is registered for the +company name "Van Ooijen Technische Informatica". + + +RULES AND RESTRICTIONS +====================== + +(1) The USB device MUST provide a textual representation of the +manufacturer and product identification. The manufacturer identification +MUST be available at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an +e-mail address under your control (e.g. "myname@gmx.net"). You can embed +the domain name or e-mail address in any string you like, e.g. "Objective +Development http://www.obdev.at/avrusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as +long as this string is unique within the scope of your textual manufacturer +identification. + +(5) Matching of device-specific drivers MUST be based on the textual +manufacturer and product identification in addition to the usual VID/PID +matching. This means that operating system features which are based on +VID/PID matching only (e.g. Windows kernel level drivers, automatic actions +when the device is plugged in etc) MUST NOT be used. The driver matching +MUST be a comparison of the entire strings, NOT a sub-string match. For +CDC-ACM CLASS devices, a generic class driver should be used and the +matching is based on the USB device class. + +(6) The extent to which VID/PID matching is allowed for non device-specific +drivers or features depends on the operating system and particular VID/PID +pair used: + + * Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is + required and hence no VID/PID-only matching is allowed at all. + + * Windows: The operating system performs VID/PID matching for the kernel + level driver. You are REQUIRED to use libusb-win32 (see + http://libusb-win32.sourceforge.net/) as the kernel level driver for + VENDOR CLASS devices. HID CLASS devices all use the generic HID class + driver shipped with Windows, except mice and keyboards. You therefore + MUST NOT use any of the shared VID/PID pairs for mice or keyboards. + CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID + pair. This ".inf" file MUST load the "usbser" driver to configure the + device as modem (COM-port). + +(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. You +have been warned that the sharing of VID/PID pairs may cause problems. If +you want to avoid them, get your own VID/PID pair for exclusive use. + + +HOW TO IMPLEMENT THESE RULES +============================ + +The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM +CLASS devices use the operating system's class driver and don't need a +custom driver. + +The host driver MUST iterate over all devices with the given VID/PID +numbers in their device descriptors and query the string representation for +the manufacturer name in USB language 0x0409 (English/US). It MUST compare +the ENTIRE string with your textual manufacturer identification chosen in +(2) above. A substring search for your domain or e-mail address is NOT +acceptable. The driver MUST NOT touch the device (other than querying the +descriptors) unless the strings match. + +For all USB devices with matching VID/PID and textual manufacturer +identification, the host driver must query the textual product +identification and string-compare it with the name of the product it can +control. It may only initialize the device if the product matches exactly. + +Objective Development provides examples for these matching rules with the +"PowerSwitch" project (using libusb) and with the "Automator" project +(using Windows calls on Windows and libusb on Unix). + + +Technical Notes: +================ + +Sharing the same VID/PID pair among devices is possible as long as ALL +drivers which match the VID/PID also perform matching on the textual +identification strings. This is easy on all operating systems except +Windows, since Windows establishes a static connection between the VID/PID +pair and a kernel level driver. All devices with the same VID/PID pair must +therefore use THE SAME kernel level driver. + +We therefore demand that you use libusb-win32 for VENDOR CLASS devices. +This is a generic kernel level driver which allows all types of USB access +for user space applications. This is only a partial solution of the +problem, though, because different device drivers may come with different +versions of libusb-win32 and they may not work with the libusb version of +the respective other driver. You are therefore encouraged to test your +driver against a broad range of libusb-win32 versions. Do not use new +features in new versions, or check for their existence before you use them. +When a new libusb-win32 becomes available, make sure that your driver is +compatible with it. + +For HID CLASS devices it is necessary that all those devices bind to the +same kernel driver: Microsoft's generic USB HID driver. This is true for +all HID devices except those with a specialized driver. Currently, the only +HIDs with specialized drivers are mice and keyboards. You therefore MUST +NOT use a shared VID/PID with mouse and keyboard devices. + +Sharing the same VID/PID among different products is unusual and probably +violates the USB specification. If you do it, you do it at your own risk. + +To avoid possible incompatibilities, we highly recommend that you get your +own VID/PID pair if you intend to sell your product. Objective +Development's commercial licenses for AVR-USB include a PID for +unrestricted exclusive use. diff --git a/bootloader/usbdrv/asmcommon.inc b/bootloader/usbdrv/asmcommon.inc new file mode 100644 index 0000000..a61e157 --- /dev/null +++ b/bootloader/usbdrv/asmcommon.inc @@ -0,0 +1,178 @@ +/* Name: asmcommon.inc + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2007-11-05 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * Revision: $Id: asmcommon.inc,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +/* 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< +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) +#define IAR_SECTION(section) @ section + +#ifndef USB_BUFFER_SECTION +# define USB_BUFFER_SECTION "TINY_Z" /* if user has not selected a named section */ +#endif + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define PRG_RDB(addr) (*(PROGMEM char *)(addr)) + +/* The following definitions are not needed by the driver, but may be of some + * help if you port a gcc based project to IAR. + */ +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() + +/* Depending on the device you use, you may get problems with the way usbdrv.h + * handles the differences between devices. Since IAR does not use #defines + * for MCU registers, we can't check for the existence of a particular + * register with an #ifdef. If the autodetection mechanism fails, include + * definitions for the required USB_INTR_* macros in your usbconfig.h. See + * usbconfig-prototype.h and usbdrv.h for details. + */ + +#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */ +#endif /* __iarcompat_h_INCLUDED__ */ diff --git a/bootloader/usbdrv/oddebug.c b/bootloader/usbdrv/oddebug.c new file mode 100644 index 0000000..85c2d7a --- /dev/null +++ b/bootloader/usbdrv/oddebug.c @@ -0,0 +1,50 @@ +/* Name: oddebug.c + * 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) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.c,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +#include "oddebug.h" + +#if DEBUG_LEVEL > 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/bootloader/usbdrv/oddebug.h b/bootloader/usbdrv/oddebug.h new file mode 100644 index 0000000..8c87dd2 --- /dev/null +++ b/bootloader/usbdrv/oddebug.h @@ -0,0 +1,126 @@ +/* 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) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.h,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +#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 "iarcompat.h" +#ifndef __IAR_SYSTEMS_ICC__ +# include +#endif + +#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< +# include +#endif +#include "usbdrv.h" +#include "oddebug.h" + +/* +General Description: +This module implements the C-part of the USB driver. See usbdrv.h for a +documentation of the entire driver. +*/ + +#ifndef IAR_SECTION +#define IAR_SECTION(arg) +#define __no_init +#endif +/* The macro IAR_SECTION is a hack to allow IAR-cc compatibility. On gcc, it + * is defined to nothing. __no_init is required on IAR. + */ + +/* ------------------------------------------------------------------------- */ + +/* raw USB registers / interface to assembler code: */ +uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ +uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */ +uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */ +uchar usbNewDeviceAddr; /* device ID which should be set after status phase */ +uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */ +volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ +uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */ +uchar usbRxToken; /* token for data we received; or endpont number for last OUT */ +uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */ +volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */ +uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ +# if USB_COUNT_SOF +volatile uchar usbSofCount; /* incremented by assembler module every SOF */ +# endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT +volatile uchar usbTxLen1 = USBPID_NAK; /* TX count for endpoint 1 */ +uchar usbTxBuf1[USB_BUFSIZE]; /* TX data for endpoint 1 */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +volatile uchar usbTxLen3 = USBPID_NAK; /* TX count for endpoint 3 */ +uchar usbTxBuf3[USB_BUFSIZE]; /* TX data for endpoint 3 */ +#endif +#endif + +/* USB status registers / not shared with asm code */ +uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */ +static uchar usbMsgFlags; /* flag values see below */ + +#define USB_FLG_TX_PACKET (1<<0) +/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */ +#define USB_FLG_MSGPTR_IS_ROM (1<<6) +#define USB_FLG_USE_DEFAULT_RW (1<<7) + +/* +optimizing hints: +- do not post/pre inc/dec integer values in operations +- assign value of PRG_RDB() to register variables and don't use side effects in arg +- use narrow scope for variables which should be in X/Y/Z register +- assign char sized expressions to variables to force 8 bit arithmetics +*/ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_DESCR_PROPS_STRINGS == 0 + +#if USB_CFG_DESCR_PROPS_STRING_0 == 0 +#undef USB_CFG_DESCR_PROPS_STRING_0 +#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0) +PROGMEM char usbDescriptorString0[] = { /* language descriptor */ + 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ + 3, /* descriptor type */ + 0x09, 0x04, /* language index (0x0409 = US-English) */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_VENDOR +#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor) +PROGMEM int usbDescriptorStringVendor[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), + USB_CFG_VENDOR_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice) +PROGMEM int usbDescriptorStringDevice[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), + USB_CFG_DEVICE_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN +#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber) +PROGMEM int usbDescriptorStringSerialNumber[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), + USB_CFG_SERIAL_NUMBER +}; +#endif + +#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ + +#if USB_CFG_DESCR_PROPS_DEVICE == 0 +#undef USB_CFG_DESCR_PROPS_DEVICE +#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice) +PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */ + 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ + USBDESCR_DEVICE, /* descriptor type */ + 0x10, 0x01, /* USB version supported */ + USB_CFG_DEVICE_CLASS, + USB_CFG_DEVICE_SUBCLASS, + 0, /* protocol */ + 8, /* max packet size */ + /* the following two casts affect the first byte of the constant only, but + * that's sufficient to avoid a warning with the default values. + */ + (char)USB_CFG_VENDOR_ID,/* 2 bytes */ + (char)USB_CFG_DEVICE_ID,/* 2 bytes */ + USB_CFG_DEVICE_VERSION, /* 2 bytes */ + USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */ + USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */ + USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ + 1, /* number of configurations */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 +#undef USB_CFG_DESCR_PROPS_HID +#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */ +#endif + +#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 +#undef USB_CFG_DESCR_PROPS_CONFIGURATION +#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration) +PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ + 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ + USBDESCR_CONFIG, /* descriptor type */ + 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0, + /* total length of data returned (including inlined descriptors) */ + 1, /* number of interfaces in this configuration */ + 1, /* index of this configuration */ + 0, /* configuration name string index */ +#if USB_CFG_IS_SELF_POWERED + USBATTR_SELFPOWER, /* attributes */ +#else + (char)USBATTR_BUSPOWER, /* attributes */ +#endif + USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ +/* interface descriptor follows inline: */ + 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ + USBDESCR_INTERFACE, /* descriptor type */ + 0, /* index of this interface */ + 0, /* alternate setting for this interface */ + USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ + USB_CFG_INTERFACE_CLASS, + USB_CFG_INTERFACE_SUBCLASS, + USB_CFG_INTERFACE_PROTOCOL, + 0, /* string index for interface */ +#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ + 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ + USBDESCR_HID, /* descriptor type: HID */ + 0x01, 0x01, /* BCD representation of HID version */ + 0x00, /* target country code */ + 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ + 0x22, /* descriptor type: report */ + USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ + 7, /* sizeof(usbDescrEndpoint) */ + USBDESCR_ENDPOINT, /* descriptor type = endpoint */ + (char)0x81, /* IN endpoint number 1 */ + 0x03, /* attrib: Interrupt endpoint */ + 8, 0, /* maximum packet size */ + USB_CFG_INTR_POLL_INTERVAL, /* in ms */ +#endif +}; +#endif + +/* We don't use prog_int or prog_int16_t for compatibility with various libc + * versions. Here's an other compatibility hack: + */ +#ifndef PRG_RDB +#define PRG_RDB(addr) pgm_read_byte(addr) +#endif + +typedef union{ + unsigned word; + uchar *ptr; + uchar bytes[2]; +}converter_t; +/* We use this union to do type conversions. This is better optimized than + * type casts in gcc 3.4.3 and much better than using bit shifts to build + * ints from chars. Byte ordering is not a problem on an 8 bit platform. + */ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_HAVE_INTRIN_ENDPOINT +USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) +{ +uchar *p, i; + +#if USB_CFG_IMPLEMENT_HALT + if(usbTxLen1 == USBPID_STALL) + return; +#endif +#if 0 /* No runtime checks! Caller is responsible for valid data! */ + if(len > 8) /* interrupt transfers are limited to 8 bytes */ + len = 8; +#endif + if(usbTxLen1 & 0x10){ /* packet buffer was empty */ + usbTxBuf1[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf1 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf1[1], len); + usbTxLen1 = len + 4; /* len must be given including sync byte */ + DBG2(0x21, usbTxBuf1, len + 3); +} +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) +{ +uchar *p, i; + + if(usbTxLen3 & 0x10){ /* packet buffer was empty */ + usbTxBuf3[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen3 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf3 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf3[1], len); + usbTxLen3 = len + 4; /* len must be given including sync byte */ + DBG2(0x23, usbTxBuf3, len + 3); +} +#endif + + +static uchar usbRead(uchar *data, uchar len) +{ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){ +#endif + uchar i = len, *r = usbMsgPtr; + if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ + while(i--){ + uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */ + *data++ = c; + r++; + } + }else{ /* RAM data */ + while(i--) + *data++ = *r++; + } + usbMsgPtr = r; + return len; +#if USB_CFG_IMPLEMENT_FN_READ + }else{ + if(len != 0) /* don't bother app with 0 sized reads */ + return usbFunctionRead(data, len); + return 0; + } +#endif +} + + +#define GET_DESCRIPTOR(cfgProp, staticName) \ + if(cfgProp){ \ + if((cfgProp) & USB_PROP_IS_RAM) \ + flags &= ~USB_FLG_MSGPTR_IS_ROM; \ + if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ + replyLen = usbFunctionDescriptor(rq); \ + }else{ \ + replyData = (uchar *)(staticName); \ + SET_REPLY_LEN((cfgProp) & 0xff); \ + } \ + } +/* We use if() instead of #if in the macro above because #if can't be used + * in macros and the compiler optimizes constant conditions anyway. + */ + + +/* Don't make this function static to avoid inlining. + * The entire function would become too large and exceed the range of + * relative jumps. + * 2006-02-25: Either gcc 3.4.3 is better than the gcc used when the comment + * above was written, or other parts of the code have changed. We now get + * better results with an inlined function. Test condition: PowerSwitch code. + */ +static void usbProcessRx(uchar *data, uchar len) +{ +usbRequest_t *rq = (void *)data; +uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW; +/* We use if() cascades because the compare is done byte-wise while switch() + * is int-based. The if() cascades are therefore more efficient. + */ +/* usbRxToken can be: + * 0x2d 00101101 (USBPID_SETUP for endpoint 0) + * 0xe1 11100001 (USBPID_OUT for endpoint 0) + * 0xff 11111111 (USBPID_OUT for endpoint 1) + */ + DBG2(0x10 + ((usbRxToken >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */ +#ifdef USB_RX_USER_HOOK + USB_RX_USER_HOOK(data, len) +#endif +#if USB_CFG_IMPLEMENT_FN_WRITEOUT + if(usbRxToken < 0x10){ /* endpoint number in usbRxToken */ + usbFunctionWriteOut(data, len); + return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */ + } +#endif + if(usbRxToken == (uchar)USBPID_SETUP){ + usbTxLen = USBPID_NAK; /* abort pending transmit */ + if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */ + uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; + if(type == USBRQ_TYPE_STANDARD){ + #define SET_REPLY_LEN(len) replyLen = (len); usbMsgPtr = replyData + /* This macro ensures that replyLen and usbMsgPtr are always set in the same way. + * That allows optimization of common code in if() branches */ + uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */ + replyData[0] = 0; /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ + if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */ + uchar __attribute__((__unused__)) recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ +#if USB_CFG_IS_SELF_POWERED + if(recipient == USBRQ_RCPT_DEVICE) + replyData[0] = USB_CFG_IS_SELF_POWERED; +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT + if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */ + replyData[0] = usbTxLen1 == USBPID_STALL; +#endif + replyData[1] = 0; + SET_REPLY_LEN(2); + }else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */ + usbNewDeviceAddr = rq->wValue.bytes[0]; + }else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */ + flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW; + if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) + }else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){ /* 2 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) + }else if(rq->wValue.bytes[1] == USBDESCR_STRING){ /* 3 */ +#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC + if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) + flags &= ~USB_FLG_MSGPTR_IS_ROM; + replyLen = usbFunctionDescriptor(rq); +#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + if(rq->wValue.bytes[0] == 0){ /* descriptor index */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) + }else if(rq->wValue.bytes[0] == 1){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) + }else if(rq->wValue.bytes[0] == 2){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) + }else if(rq->wValue.bytes[0] == 3){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } +#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ +#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */ + }else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) + }else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) +#endif /* USB_CFG_DESCR_PROPS_HID_REPORT */ + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } + }else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */ + replyData = &usbConfiguration; /* send current configuration value */ + SET_REPLY_LEN(1); + }else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */ + usbConfiguration = rq->wValue.bytes[0]; +#if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; +#endif + }else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */ + SET_REPLY_LEN(1); +#if USB_CFG_HAVE_INTRIN_ENDPOINT + }else if(rq->bRequest == USBRQ_SET_INTERFACE){ /* 11 */ + USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# endif +# if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; + }else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){ /* 1|3 */ + if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */ + usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; + USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# endif + } +# endif +#endif + }else{ + /* the following requests can be ignored, send default reply */ + /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */ + /* 12: SYNCH_FRAME */ + } + #undef SET_REPLY_LEN + }else{ /* not a standard request -- must be vendor or class request */ + replyLen = usbFunctionSetup(data); + } +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + if(replyLen == 0xff){ /* use user-supplied read/write function */ + if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){ + replyLen = rq->wLength.bytes[0]; /* IN transfers only */ + } + flags &= ~USB_FLG_USE_DEFAULT_RW; /* we have no valid msg, use user supplied read/write functions */ + }else /* The 'else' prevents that we limit a replyLen of 0xff to the maximum transfer len. */ +#endif + if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + replyLen = rq->wLength.bytes[0]; + } + /* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */ + }else{ /* DATA packet from out request */ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){ + uchar rval = usbFunctionWrite(data, len); + replyLen = 0xff; + if(rval == 0xff){ /* an error occurred */ + usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */ + usbTxLen = USBPID_STALL; + }else if(rval != 0){ /* This was the final package */ + replyLen = 0; /* answer with a zero-sized data packet */ + } + flags = 0; /* start with a DATA1 package, stay with user supplied write() function */ + } +#endif + } + usbMsgFlags = flags; + usbMsgLen = replyLen; +} + +/* ------------------------------------------------------------------------- */ + +static void usbBuildTxBlock(void) +{ +uchar wantLen, len, txLen, token; + + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + token = USBPID_DATA1; + if(usbMsgFlags & USB_FLG_TX_PACKET) + token = USBPID_DATA0; + usbMsgFlags++; + len = usbRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + usbCrc16Append(&usbTxBuf[1], len); + txLen = len + 4; /* length including sync byte */ + if(len < 8) /* a partial package identifies end of message */ + usbMsgLen = 0xff; + }else{ + txLen = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = 0xff; + } + usbTxBuf[0] = token; + usbTxLen = txLen; + DBG2(0x20, usbTxBuf, txLen-1); +} + +static inline uchar isNotSE0(void) +{ +uchar rval; +/* We want to do + * return (USBIN & USBMASK); + * here, but the compiler does int-expansion acrobatics. + * We can avoid this by assigning to a char-sized variable. + */ + rval = USBIN & USBMASK; + return rval; +} + +/* ------------------------------------------------------------------------- */ + +USB_PUBLIC void usbPoll(void) +{ +schar len; +uchar i; + + if((len = usbRxLen) > 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); + */ + usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len - 3); +#if USB_CFG_HAVE_FLOWCONTROL + if(usbRxLen > 0) /* only mark as available if not inactivated */ + usbRxLen = 0; +#else + usbRxLen = 0; /* mark rx buffer as available */ +#endif + } + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != 0xff){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + for(i = 10; i > 0; i--){ + if(isNotSE0()) + break; + } + if(i == 0){ /* RESET condition, called multiple times during reset */ + usbNewDeviceAddr = 0; + usbDeviceAddr = 0; +#if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 + usbTxLen3 = USBPID_NAK; +#endif +#endif + DBG1(0xff, 0, 0); + } +} + +/* ------------------------------------------------------------------------- */ + +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); +#if USB_CFG_HAVE_INTRIN_ENDPOINT + USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */ +# endif +#endif +} + +/* ------------------------------------------------------------------------- */ diff --git a/bootloader/usbdrv/usbdrv.h b/bootloader/usbdrv/usbdrv.h new file mode 100644 index 0000000..261281d --- /dev/null +++ b/bootloader/usbdrv/usbdrv.h @@ -0,0 +1,678 @@ +/* Name: usbdrv.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrv.h,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +#ifndef __usbdrv_h_included__ +#define __usbdrv_h_included__ +#include "usbconfig.h" +#include "iarcompat.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 or 16 MHz +or at 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 be declared as "INTERRUPT" +instead of "SIGNAL" (see "avr/signal.h") or that they are written in assembler +with "sei" as the first instruction. + +Maximum interrupt duration / CPU cycle consumption: +The driver handles all USB communication during the interrupt service +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 20080205 +/* 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 */ + +struct usbRequest; /* forward declaration */ + +USB_PUBLIC void usbInit(void); +/* This function must be called before interrupts are enabled and the main + * loop is entered. + */ +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 uchar *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 uchar usbFunctionSetup(uchar data[8]); +/* This function is called when the driver receives a SETUP transaction from + * the host which is not answered by the driver itself (in practice: class and + * vendor requests). All control transfers start with a SETUP transaction where + * 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 0xff in 'usbFunctionSetup()'. The driver + * will then call 'usbFunctionRead()' when data is needed. See the + * documentation for usbFunctionRead() for details. + * + * If the SETUP indicates a control-out transfer, the only way to receive the + * data from the host is through the 'usbFunctionWrite()' call. If you + * implement this function, you must return 0xff in 'usbFunctionSetup()' to + * indicate that 'usbFunctionWrite()' should be used. See the documentation of + * this function for more information. If you just want to ignore the data sent + * by the host, return 0 in 'usbFunctionSetup()'. + * + * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() + * are only done if enabled by the configuration in usbconfig.h. + */ +USB_PUBLIC uchar usbFunctionDescriptor(struct usbRequest *rq); +/* You need to implement this function ONLY if you provide USB descriptors at + * runtime (which is an expert feature). It is very similar to + * usbFunctionSetup() above, but it is called only to request USB descriptor + * 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. + */ +extern volatile uchar usbTxLen1; +#define usbInterruptIsReady() (usbTxLen1 & 0x10) +/* This macro indicates whether the last interrupt message has already been + * sent. If you set a new interrupt message before the old was sent, the + * message already buffered will be lost. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len); +extern volatile uchar usbTxLen3; +#define usbInterruptIsReady3() (usbTxLen3 & 0x10) +/* Same as above for endpoint 3 */ +#endif +#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 */ +#if USB_CFG_IMPLEMENT_FN_WRITEOUT +USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len); +/* This function is called by the driver when data on interrupt-out or bulk- + * out endpoint 1 is received. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT + * to 1 in usbconfig.h to get this function called. + */ +#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 +#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/bootloader/usbdrv/usbdrvasm.S b/bootloader/usbdrv/usbdrvasm.S new file mode 100644 index 0000000..d9d637e --- /dev/null +++ b/bootloader/usbdrv/usbdrvasm.S @@ -0,0 +1,223 @@ +/* Name: usbdrvasm.S + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2007-06-13 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * Revision: $Id: usbdrvasm.S,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +/* +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. +*/ + +#include "iarcompat.h" +#ifndef __IAR_SYSTEMS_ASM__ + /* configs for io.h */ +# define __SFR_OFFSET 0 +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +# include /* for CPU I/O register definitions and vectors */ +# define macro .macro /* GNU Assembler macro definition */ +# define endm .endm /* End of GNU Assembler macro definition */ +#endif /* __IAR_SYSTEMS_ASM__ */ +#include "usbdrv.h" /* for common defs */ + +/* register names */ +#define x1 r16 +#define x2 r17 +#define shift r18 +#define cnt r19 +#define x3 r20 +#define x4 r21 +#define bitcnt r22 +#define phase x4 +#define leap x4 + +/* Some assembler dependent definitions and declarations: */ + +#ifdef __IAR_SYSTEMS_ASM__ + +# define nop2 rjmp $+2 /* jump to next instruction */ +# define XL r26 +# define XH r27 +# define YL r28 +# define YH r29 +# define ZL r30 +# define ZH r31 +# define lo8(x) LOW(x) +# define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ + + extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset + extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen + extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3 +# 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__ */ + +# define nop2 rjmp .+0 /* jump to next instruction */ + +# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ +# define USB_INTR_VECTOR SIG_INTERRUPT0 +# 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 + + +;---------------------------------------------------------------------------- +; 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 + +; extern unsigned usbCrc16(unsigned char *data, unsigned char len); +; data: r24/25 +; len: r22 +; temp variables: +; r18: data byte +; r19: bit counter +; r20/21: polynomial +; r23: scratch +; r24/25: crc-sum +; r26/27=X: ptr +usbCrc16: + mov ptrL, argPtrL + mov ptrH, argPtrH + ldi resCrcL, 0xff + ldi resCrcH, 0xff + ldi polyL, lo8(0xa001) + ldi polyH, hi8(0xa001) +crcByteLoop: + subi argLen, 1 + brcs crcReady + ld byte, ptr+ + ldi bitCnt, 8 +crcBitLoop: + mov scratch, byte + eor scratch, resCrcL + lsr resCrcH + ror resCrcL + lsr byte + sbrs scratch, 0 + rjmp crcNoXor + eor resCrcL, polyL + eor resCrcH, polyH +crcNoXor: + dec bitCnt + brne crcBitLoop + rjmp crcByteLoop +crcReady: + com resCrcL + com resCrcH + ret + +; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len); +usbCrc16Append: + rcall usbCrc16 + st ptr+, resCrcL + st ptr+, resCrcH + ret + + +;---------------------------------------------------------------------------- +; Now include the clock rate specific code +;---------------------------------------------------------------------------- + +#ifndef USB_CFG_CLOCK_KHZ +# define USB_CFG_CLOCK_KHZ 12000 +#endif + +#if USB_CFG_CLOCK_KHZ == 12000 +# include "usbdrvasm12.inc" +#elif USB_CFG_CLOCK_KHZ == 15000 +# include "usbdrvasm15.inc" +#elif USB_CFG_CLOCK_KHZ == 16000 +# include "usbdrvasm16.inc" +#elif USB_CFG_CLOCK_KHZ == 16500 +# include "usbdrvasm165.inc" +#else +# error "USB_CFG_CLOCK_KHZ is not one of the supported rates!" +#endif diff --git a/bootloader/usbdrv/usbdrvasm.asm b/bootloader/usbdrv/usbdrvasm.asm new file mode 100644 index 0000000..c675f7e --- /dev/null +++ b/bootloader/usbdrv/usbdrvasm.asm @@ -0,0 +1,21 @@ +/* Name: usbdrvasm.asm + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2006-03-01 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrvasm.asm,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +/* +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/bootloader/usbdrv/usbdrvasm12.inc b/bootloader/usbdrv/usbdrvasm12.inc new file mode 100644 index 0000000..e48f353 --- /dev/null +++ b/bootloader/usbdrv/usbdrvasm12.inc @@ -0,0 +1,427 @@ +/* Name: usbdrvasm12.inc + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrvasm12.inc,v 1.1 2008/07/09 20:47:11 rschaten Exp $ + */ + +/* 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 +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +waitForJ: + sbis USBIN, USBMINUS ;1 [40] wait for D- == 1 + rjmp waitForJ ;2 +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + 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 */ + 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 +;---------------------------------------------------------------------------- + +bitstuff0: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff0 ;2 branch back 2 cycles earlier +bitstuff1: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff1 ;2 we know that C is clear, jump back to do OUT and ror 0 into x2 +bitstuff2: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff2 ;2 jump back 4 cycles earlier and do out and ror 0 into x2 +bitstuff3: ;1 (for branch taken) + eor x1, x4 ;1 + rjmp didStuff3 ;2 jump back earlier and ror 0 into x2 +bitstuff4: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff4 ;2 jump back 2 cycles earlier + +sendNakAndReti: ;0 [-19] 19 cycles until SOP + ldi x3, USBPID_NAK ;1 [-18] + 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...x4, shift, cnt, Y +;Numbers in brackets are time since first bit of sync pattern is sent +usbSendAndReti: ;0 [-13] timing: 13 cycles until SOP + in x2, USBDDR ;1 [-12] + ori x2, USBMASK ;1 [-11] + sbi USBOUT, USBMINUS;2 [-9] prepare idle state; D+ and D- must have been 0 (no pullups) + in x1, USBOUT ;1 [-8] port mirror for tx loop + out USBDDR, x2 ;1 [-7] <- acquire bus +; need not init x2 (bitstuff history) because sync starts with 0 + push x4 ;2 [-5] + ldi x4, USBMASK ;1 [-4] exor mask + ldi shift, 0x80 ;1 [-3] sync byte is first byte sent +txLoop: ; [62] + sbrs shift, 0 ;1 [-2] [62] + eor x1, x4 ;1 [-1] [63] + out USBOUT, x1 ;1 [0] <-- out bit 0 + ror shift ;1 [1] + ror x2 ;1 [2] +didStuff0: + cpi x2, 0xfc ;1 [3] + brsh bitstuff0 ;1 [4] + sbrs shift, 0 ;1 [5] + eor x1, x4 ;1 [6] + ror shift ;1 [7] +didStuff1: + out USBOUT, x1 ;1 [8] <-- out bit 1 + ror x2 ;1 [9] + cpi x2, 0xfc ;1 [10] + brsh bitstuff1 ;1 [11] + sbrs shift, 0 ;1 [12] + eor x1, x4 ;1 [13] + ror shift ;1 [14] +didStuff2: + ror x2 ;1 [15] + out USBOUT, x1 ;1 [16] <-- out bit 2 + cpi x2, 0xfc ;1 [17] + brsh bitstuff2 ;1 [18] + sbrs shift, 0 ;1 [19] + eor x1, x4 ;1 [20] + ror shift ;1 [21] +didStuff3: + ror x2 ;1 [22] + cpi x2, 0xfc ;1 [23] + out USBOUT, x1 ;1 [24] <-- out bit 3 + brsh bitstuff3 ;1 [25] + nop2 ;2 [27] + ld x3, y+ ;2 [29] + sbrs shift, 0 ;1 [30] + eor x1, x4 ;1 [31] + out USBOUT, x1 ;1 [32] <-- out bit 4 + ror shift ;1 [33] + ror x2 ;1 [34] +didStuff4: + cpi x2, 0xfc ;1 [35] + brsh bitstuff4 ;1 [36] + sbrs shift, 0 ;1 [37] + eor x1, x4 ;1 [38] + ror shift ;1 [39] +didStuff5: + out USBOUT, x1 ;1 [40] <-- out bit 5 + ror x2 ;1 [41] + cpi x2, 0xfc ;1 [42] + brsh bitstuff5 ;1 [43] + sbrs shift, 0 ;1 [44] + eor x1, x4 ;1 [45] + ror shift ;1 [46] +didStuff6: + ror x2 ;1 [47] + out USBOUT, x1 ;1 [48] <-- out bit 6 + cpi x2, 0xfc ;1 [49] + brsh bitstuff6 ;1 [50] + sbrs shift, 0 ;1 [51] + eor x1, x4 ;1 [52] + ror shift ;1 [53] +didStuff7: + ror x2 ;1 [54] + cpi x2, 0xfc ;1 [55] + out USBOUT, x1 ;1 [56] <-- out bit 7 + brsh bitstuff7 ;1 [57] + mov shift, x3 ;1 [58] + dec cnt ;1 [59] + brne txLoop ;1/2 [60/61] +;make SE0: + cbr x1, USBMASK ;1 [61] prepare SE0 [spec says EOP may be 15 to 18 cycles] + pop x4 ;2 [63] +;brackets are cycles from start of SE0 now + out USBOUT, x1 ;1 [0] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle +;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: +;set address only after data packet was sent, not after handshake + lds x2, usbNewDeviceAddr;2 [2] + lsl x2; ;1 [3] we compare with left shifted address + subi YL, 20 + 2 ;1 [4] Only assign address on data packets, not ACK/NAK in x3 + sbci YH, 0 ;1 [5] + breq skipAddrAssign ;2 [7] + sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer +skipAddrAssign: +;end of usbDeviceAddress transfer + ldi x2, 1< 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 +; first part has no timeout because it waits for IDLE or SE1 (== disconnected) +;------------------------------------------------------------------------------- +waitForJ: ;- + sbis USBIN, USBMINUS ;1 <-- sample: wait for D- == 1 + rjmp waitForJ ;2 +;------------------------------------------------------------------------------- +; The 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 */ + 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 +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +waitForJ: + sbis USBIN, USBMINUS ;[-18] wait for D- == 1 + rjmp waitForJ +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + 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 */ + 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) +;---------------------------------------------------------------------------- + +unstuff6: + andi x2, USBMASK ;[03] + ori x3, 1<<6 ;[04] will not be shifted any more + andi shift, ~0x80;[05] + mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6 + subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit + 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, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit + 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, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit + nop ;[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, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit + nop ;[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: r0, SREG [sofError], YL, YH, shift, x1, x2, x3, x4, cnt + push r0 ;[-23] push only what is necessary to sync with edge ASAP + in r0, SREG ;[-21] + push r0 ;[-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 +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +waitForJ: + sbis USBIN, USBMINUS ;[-18] wait for D- == 1 + rjmp waitForJ +waitForK: +;The following code results in a sampling window of < 1/4 bit which meets the spec. + sbis USBIN, USBMINUS ;[-15] + 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 */ + 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 YL ;[-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 YL ;[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 YL +endm +macro POP_RETI ; 5 cycles + pop r0 + out SREG, r0 + pop r0 +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<> Errors ERC: 0 diff --git a/circuit/dulcimer.lst b/circuit/dulcimer.lst new file mode 100644 index 0000000..8f6bc7f --- /dev/null +++ b/circuit/dulcimer.lst @@ -0,0 +1,67 @@ +EESchema (20080320-r918) >> Creation date: 18/4/2008-19:05:17 + +#Cmp ( order = Reference ) +| C1 100n +| C2 10u +| C3 22p +| C4 22p +| D1 3.6V +| D2 3.6V +| IC1 MEGA32-P +| J1 USB +| JP1 PINHD-1X16M +| JP10 PINHD-1X4 +| JP11 PINHD-1X3 +| JP12 PINHD-1X3 +| JP13 PINHD-1X4 +| JP2 PINHD-1X8M +| JP3 PINHD-1X4M +| JP4 JUMPER +| JP5 JUMPER +| JP6 JUMPER +| JP7 PINHD-2X5M +| P1 CONN_2 +| R1 10k +| R2 2k2 +| R3 470 +| R4 470 +| R5 470 +| R6 4k7 +| R7 68 +| R8 68 +| X1 12MHz +#End Cmp + +#Cmp ( order = Value ) +| 100n C1 +| 10k R1 +| 10u C2 +| 12MHz X1 +| 22p C3 +| 22p C4 +| 2k2 R2 +| 3.6V D1 +| 3.6V D2 +| 470 R3 +| 470 R4 +| 470 R5 +| 4k7 R6 +| 68 R7 +| 68 R8 +| CONN_2 P1 +| JUMPER JP4 +| JUMPER JP5 +| JUMPER JP6 +| MEGA32-P IC1 +| PINHD-1X16M JP1 +| PINHD-1X3 JP11 +| PINHD-1X3 JP12 +| PINHD-1X4 JP10 +| PINHD-1X4 JP13 +| PINHD-1X4M JP3 +| PINHD-1X8M JP2 +| PINHD-2X5M JP7 +| USB J1 +#End Cmp + +#End List diff --git a/circuit/dulcimer.net b/circuit/dulcimer.net new file mode 100644 index 0000000..0b94da2 --- /dev/null +++ b/circuit/dulcimer.net @@ -0,0 +1,270 @@ +# EESchema Netlist Version 1.1 created 18/4/2008-19:20:15 +( + ( /48044756 C1 C1 100n + ( 1 GND ) + ( 2 VCC ) + ) + ( /48044769 C1V7 C2 10u + ( 1 GND ) + ( 2 VCC ) + ) + ( /48044750 C1 C3 22p + ( 1 N-000050 ) + ( 2 GND ) + ) + ( /48044754 C1 C4 22p + ( 1 N-000049 ) + ( 2 GND ) + ) + ( /48044791 D3 D1 3.6V + ( 1 GND ) + ( 2 N-000020 ) + ) + ( /48044798 D3 D2 3.6V + ( 1 GND ) + ( 2 N-000018 ) + ) + ( /480447FC atmel-DIL40 IC1 MEGA32-P + ( 1 /C0 ) + ( 2 /C1 ) + ( 3 /C2 ) + ( 4 /C3 ) + ( 5 /C4 ) + ( 6 /MOSI ) + ( 7 /MISO ) + ( 8 /SCK ) + ( 9 /Reset ) + ( 10 VCC ) + ( 11 GND ) + ( 12 N-000050 ) + ( 13 N-000049 ) + ( 14 N-000005 ) + ( 15 N-000007 ) + ( 16 N-000004 ) + ( 17 N-000016 ) + ( 18 N-000013 ) + ( 19 N-000011 ) + ( 20 N-000012 ) + ( 21 N-000006 ) + ( 22 /R15 ) + ( 23 /R14 ) + ( 24 /R13 ) + ( 25 /R12 ) + ( 26 /R11 ) + ( 27 /R10 ) + ( 28 /R9 ) + ( 29 /R8 ) + ( 30 ? ) + ( 31 ? ) + ( 32 ? ) + ( 33 /R7 ) + ( 34 /R6 ) + ( 35 /R5 ) + ( 36 /R4 ) + ( 37 /R3 ) + ( 38 /R2 ) + ( 39 /R1 ) + ( 40 /R0 ) + ) + ( /480446AA CONN_USB-B J1 USB + ( 1 VCC ) + ( 2 N-000003 ) + ( 3 N-000017 ) + ( 4 GND ) + ( 5 GND ) + ( 6 GND ) + ) + ( /48044A02 pinhead-1X16 JP1 PINHD-1X16M + ( 1 /R0 ) + ( 2 /R1 ) + ( 3 /R2 ) + ( 4 /R3 ) + ( 5 /R4 ) + ( 6 /R5 ) + ( 7 /R6 ) + ( 8 /R7 ) + ( 9 /R8 ) + ( 10 /R9 ) + ( 11 /R10 ) + ( 12 /R11 ) + ( 13 /R12 ) + ( 14 /R13 ) + ( 15 /R14 ) + ( 16 /R15 ) + ) + ( /48044A0E pinhead-1X08 JP2 PINHD-1X8M + ( 1 /C0 ) + ( 2 /C1 ) + ( 3 /C2 ) + ( 4 /C3 ) + ( 5 /C4 ) + ( 6 /MOSI ) + ( 7 /MISO ) + ( 8 /SCK ) + ) + ( /48044A1E pinhead-1X04 JP3 PINHD-1X4M + ( 1 N-000010 ) + ( 2 GND ) + ( 3 N-000014 ) + ( 4 N-000009 ) + ) + ( /480486B7 pinhead-1X02 JP4 JUMPER + ( 1 N-000007 ) + ( 2 GND ) + ) + ( /480486CC pinhead-1X02 JP5 JUMPER + ( 1 N-000016 ) + ( 2 GND ) + ) + ( /480486D0 pinhead-1X02 JP6 JUMPER + ( 1 N-000006 ) + ( 2 GND ) + ) + ( /48044A4D atmel-AVR-ISP-10 JP7 PINHD-2X5M + ( 1 /MOSI ) + ( 2 VCC ) + ( 3 ? ) + ( 4 GND ) + ( 5 /Reset ) + ( 6 GND ) + ( 7 /SCK ) + ( 8 GND ) + ( 9 /MISO ) + ( 10 GND ) + ) + ( /4808C81B pinhead-1X04 JP10 PINHD-1X4 + ( 1 VCC ) + ( 2 N-000002 ) + ( 3 N-000019 ) + ( 4 GND ) + ) + ( /4808E9AB pinhead-1X03 JP11 PINHD-1X3 + ( 1 N-000019 ) + ( 2 N-000017 ) + ( 3 N-000018 ) + ) + ( /4808E9BA pinhead-1X03 JP12 PINHD-1X3 + ( 1 N-000002 ) + ( 2 N-000003 ) + ( 3 N-000020 ) + ) + ( /4808E9EA pinhead-1X04 JP13 PINHD-1X4 + ( 1 VCC ) + ( 2 N-000020 ) + ( 3 N-000018 ) + ( 4 GND ) + ) + ( /48061210 connect-CLAMP-02 P1 CONN_2 + ( 1 GND ) + ( 2 GND ) + ) + ( /4804473F R3 R1 10k + ( 1 /Reset ) + ( 2 VCC ) + ) + ( /4804473B R3 R2 2k2 + ( 1 VCC ) + ( 2 N-000020 ) + ) + ( /48044733 R3 R3 470 + ( 1 N-000010 ) + ( 2 N-000012 ) + ) + ( /48044731 R3 R4 470 + ( 1 N-000014 ) + ( 2 N-000011 ) + ) + ( /4804472B R3 R5 470 + ( 1 N-000009 ) + ( 2 N-000013 ) + ) + ( /48044739 R3 R6 4k7 + ( 1 N-000020 ) + ( 2 GND ) + ) + ( /48044741 R3 R7 68 + ( 1 N-000018 ) + ( 2 N-000004 ) + ) + ( /48044743 R3 R8 68 + ( 1 N-000020 ) + ( 2 N-000005 ) + ) + ( /4804477C HC-18UV X1 12MHz + ( 1 N-000050 ) + ( 2 N-000049 ) + ) +) +* +{ Allowed footprints by component: +$component C1 + SM* + C? + C1-1 +$endlist +$component C2 + CP* + SM* +$endlist +$component C3 + SM* + C? + C1-1 +$endlist +$component C4 + SM* + C? + C1-1 +$endlist +$component D1 + D? + SO* + SM* +$endlist +$component D2 + D? + SO* + SM* +$endlist +$component R1 + R? + SM0603 + SM0805 +$endlist +$component R2 + R? + SM0603 + SM0805 +$endlist +$component R3 + R? + SM0603 + SM0805 +$endlist +$component R4 + R? + SM0603 + SM0805 +$endlist +$component R5 + R? + SM0603 + SM0805 +$endlist +$component R6 + R? + SM0603 + SM0805 +$endlist +$component R7 + R? + SM0603 + SM0805 +$endlist +$component R8 + R? + SM0603 + SM0805 +$endlist +$endfootprintlist +} diff --git a/circuit/dulcimer.pro b/circuit/dulcimer.pro new file mode 100644 index 0000000..4b8987d --- /dev/null +++ b/circuit/dulcimer.pro @@ -0,0 +1,147 @@ +update=16/4/2008-14:31:58 +last_client=pcbnew +[general] +version=1 +RootSch=dulcimer.sch +BoardNm=dulcimer.brd +[common] +NetDir= +[eeschema] +version=1 +LibDir= +NetFmt=1 +HPGLSpd=20 +HPGLDm=15 +HPGLNum=1 +offX_A4=0 +offY_A4=0 +offX_A3=0 +offY_A3=0 +offX_A2=0 +offY_A2=0 +offX_A1=0 +offY_A1=0 +offX_A0=0 +offY_A0=0 +offX_A=0 +offY_A=0 +offX_B=0 +offY_B=0 +offX_C=0 +offY_C=0 +offX_D=0 +offY_D=0 +offX_E=0 +offY_E=0 +RptD_X=0 +RptD_Y=100 +RptLab=1 +SimCmd= +UseNetN=0 +LabSize=60 +[eeschema/libraries] +LibName1=power +LibName2=pinhead +LibName3=device +LibName4=conn +LibName5=linear +LibName6=regul +LibName7=74xx +LibName8=cmos4000 +LibName9=adc-dac +LibName10=memory +LibName11=xilinx +LibName12=special +LibName13=microcontrollers +LibName14=dsp +LibName15=microchip +LibName16=analog_switches +LibName17=motorola +LibName18=texas +LibName19=intel +LibName20=audio +LibName21=interface +LibName22=digital-audio +LibName23=philips +LibName24=display +LibName25=cypress +LibName26=siliconi +LibName27=contrib +LibName28=valves +[cvpcb] +version=1 +NetITyp=0 +NetIExt=.net +PkgIExt=.pkg +NetType=0 +[cvpcb/libraries] +EquName1=devcms +[pcbnew] +version=1 +PadDrlX=320 +PadDimH=600 +PadDimV=600 +PadForm=1 +PadMask=14745599 +ViaDiam=450 +ViaDril=250 +MViaDia=200 +MViaDrl=80 +Isol=60 +Countlayer=2 +Lpiste=170 +RouteTo=15 +RouteBo=0 +TypeVia=3 +Segm45=1 +Racc45=1 +Unite=0 +SegFill=1 +SegAffG=0 +NewAffG=1 +PadFill=1 +PadAffG=1 +PadSNum=1 +ModAffC=0 +ModAffT=0 +PcbAffT=0 +SgPcb45=1 +TxtPcbV=800 +TxtPcbH=600 +TxtModV=600 +TxtModH=600 +TxtModW=120 +HPGLnum=1 +HPGdiam=15 +HPGLSpd=20 +HPGLrec=2 +HPGLorg=0 +GERBmin=15 +VEgarde=100 +DrawLar=150 +EdgeLar=150 +TxtLar=120 +MSegLar=150 +ForPlot=1 +WpenSer=10 +UserGrX=1 +UserGrY=1 +UserGrU=1 +DivGrPc=1 +TimeOut=600 +MaxLnkS=3 +ShowRat=0 +ShowMRa=1 +[pcbnew/libraries] +LibDir= +LibName1=supports +LibName2=pl_empreinte +LibName3=pinhead +LibName4=atmel +LibName5=connect +LibName6=discret +LibName7=pin_array +LibName8=divers +LibName9=libcms +LibName10=display +LibName11=valves diff --git a/circuit/dulcimer.sch b/circuit/dulcimer.sch new file mode 100644 index 0000000..4991f70 --- /dev/null +++ b/circuit/dulcimer.sch @@ -0,0 +1,1139 @@ +EESchema Schematic File Version 2 +LIBS:power,pinhead,device,conn,linear,regul,74xx,cmos4000,adc-dac,memory,xilinx,special,microcontrollers,dsp,microchip,analog_switches,motorola,texas,intel,audio,interface,digital-audio,philips,display,cypress,siliconi,contrib,valves,./dulcimer.cache +EELAYER 24 0 +EELAYER END +$Descr A4 11700 8267 +Sheet 1 1 +Title "Dulcimer - USB Keyboard Controller" +Date "18 apr 2008" +Rev "1" +Comp "Ronald Schaten" +Comment1 "" +Comment2 "" +Comment3 "" +Comment4 "" +$EndDescr +Wire Wire Line + 3850 5650 3850 5900 +Wire Wire Line + 2750 5650 2750 5900 +Connection ~ 3750 6600 +Wire Wire Line + 3750 5650 3750 6600 +Wire Wire Line + 2550 5650 2550 6050 +Wire Wire Line + 2550 6050 2850 6050 +Wire Wire Line + 2850 6050 2850 6300 +Wire Wire Line + 3050 6750 5450 6750 +Wire Wire Line + 3050 6750 3050 6300 +Wire Wire Line + 2950 6300 2950 6750 +Wire Wire Line + 2950 6750 1750 6750 +Wire Wire Line + 5250 5900 5250 4500 +Wire Wire Line + 5250 4500 4400 4500 +Wire Wire Line + 5450 5900 5450 4700 +Wire Wire Line + 5450 4700 4400 4700 +Wire Wire Line + 2050 4200 2050 4450 +Wire Wire Line + 1000 6850 1000 7100 +Wire Wire Line + 6100 5500 6100 5750 +Wire Wire Line + 6450 4900 6450 4000 +Wire Wire Line + 6450 4000 4400 4000 +Wire Wire Line + 5750 4900 5750 4600 +Wire Wire Line + 5750 4600 4400 4600 +Wire Wire Line + 9450 5950 8900 5950 +Wire Wire Line + 4400 1300 5350 1300 +Wire Wire Line + 9250 1300 9950 1300 +Wire Wire Line + 9950 3950 8850 3950 +Wire Wire Line + 9950 3750 8850 3750 +Wire Wire Line + 9950 3550 8850 3550 +Wire Wire Line + 9950 3350 8850 3350 +Wire Wire Line + 9950 2800 9250 2800 +Wire Wire Line + 9950 2600 9250 2600 +Wire Wire Line + 9950 2400 9250 2400 +Wire Wire Line + 9950 2200 9250 2200 +Wire Wire Line + 9950 2000 9250 2000 +Wire Wire Line + 9950 1800 9250 1800 +Wire Wire Line + 9950 1600 9250 1600 +Wire Wire Line + 9950 1400 9250 1400 +Wire Wire Line + 5700 2900 4400 2900 +Wire Wire Line + 5700 2700 4400 2700 +Wire Wire Line + 5700 2500 4400 2500 +Wire Wire Line + 4400 2300 5700 2300 +Wire Wire Line + 5350 3800 4400 3800 +Wire Wire Line + 5350 3600 4400 3600 +Wire Wire Line + 5350 3400 4400 3400 +Wire Wire Line + 5350 3200 4400 3200 +Wire Wire Line + 5350 2000 4400 2000 +Wire Wire Line + 5350 1800 4400 1800 +Wire Wire Line + 5350 1600 4400 1600 +Wire Wire Line + 5350 1400 4400 1400 +Wire Bus Line + 8750 3850 8750 1750 +Wire Bus Line + 8750 1750 5800 1750 +Wire Bus Line + 5800 1750 5800 2800 +Connection ~ 10150 6350 +Wire Wire Line + 10150 6350 9750 6350 +Connection ~ 10150 6150 +Wire Wire Line + 9750 6150 10150 6150 +Wire Wire Line + 10150 5800 10150 5950 +Wire Wire Line + 10150 5950 9750 5950 +Wire Wire Line + 9950 4700 9450 4700 +Wire Wire Line + 9450 4700 9450 4800 +Wire Wire Line + 9450 4800 9050 4800 +Wire Wire Line + 9050 4400 9950 4400 +Wire Wire Line + 8550 4600 8150 4600 +Wire Wire Line + 8150 4600 8150 4200 +Wire Wire Line + 8150 4200 4400 4200 +Connection ~ 5000 6600 +Wire Wire Line + 5000 6600 5000 7000 +Wire Wire Line + 4300 5950 4300 5850 +Connection ~ 4300 6750 +Wire Wire Line + 4650 7400 4650 7550 +Wire Wire Line + 1000 6750 800 6750 +Wire Wire Line + 800 6750 800 7100 +Wire Wire Line + 3300 5000 3300 5150 +Wire Wire Line + 1550 3600 1550 3800 +Wire Wire Line + 1000 3600 1000 3800 +Wire Wire Line + 1550 2300 2200 2300 +Wire Wire Line + 1550 1700 2400 1700 +Wire Wire Line + 850 1700 1150 1700 +Wire Wire Line + 1900 1300 2400 1300 +Wire Wire Line + 1150 1100 1150 1300 +Wire Wire Line + 1150 1300 1400 1300 +Wire Wire Line + 3300 1000 3300 800 +Wire Wire Line + 2400 2100 2200 2100 +Wire Wire Line + 2200 2100 2200 2300 +Wire Wire Line + 1150 2300 850 2300 +Wire Wire Line + 1000 4200 1000 4450 +Wire Wire Line + 1550 4200 1550 4450 +Wire Wire Line + 800 6350 800 6600 +Wire Wire Line + 800 6600 1000 6600 +Wire Wire Line + 4300 7550 4300 7400 +Wire Wire Line + 5000 7550 5000 7400 +Wire Wire Line + 4300 6900 4300 6450 +Wire Wire Line + 4650 7000 4650 6750 +Connection ~ 4650 6750 +Wire Wire Line + 4400 4100 8250 4100 +Wire Wire Line + 8250 4100 8250 4400 +Wire Wire Line + 8250 4400 8550 4400 +Wire Wire Line + 4400 4300 8050 4300 +Wire Wire Line + 8050 4300 8050 4800 +Wire Wire Line + 8050 4800 8550 4800 +Wire Wire Line + 9050 4600 9950 4600 +Wire Wire Line + 9450 4500 9950 4500 +Connection ~ 1900 1700 +Connection ~ 1900 2300 +Wire Wire Line + 9750 6050 10150 6050 +Wire Wire Line + 10150 6050 10150 6550 +Wire Wire Line + 10150 6250 9750 6250 +Connection ~ 10150 6250 +Wire Bus Line + 5450 3700 5450 850 +Wire Bus Line + 5450 850 9150 850 +Wire Bus Line + 9150 850 9150 2700 +Wire Wire Line + 4400 1500 5350 1500 +Wire Wire Line + 4400 1700 5350 1700 +Wire Wire Line + 4400 1900 5350 1900 +Wire Wire Line + 4400 3100 5350 3100 +Wire Wire Line + 4400 3300 5350 3300 +Wire Wire Line + 4400 3500 5350 3500 +Wire Wire Line + 4400 3700 5350 3700 +Wire Wire Line + 5700 2200 4400 2200 +Wire Wire Line + 5700 2400 4400 2400 +Wire Wire Line + 4400 2600 5700 2600 +Wire Wire Line + 4400 2800 5700 2800 +Wire Wire Line + 9250 1500 9950 1500 +Wire Wire Line + 9250 1700 9950 1700 +Wire Wire Line + 9250 1900 9950 1900 +Wire Wire Line + 9250 2100 9950 2100 +Wire Wire Line + 9250 2300 9950 2300 +Wire Wire Line + 9250 2500 9950 2500 +Wire Wire Line + 9250 2700 9950 2700 +Wire Wire Line + 8850 3250 9950 3250 +Wire Wire Line + 8850 3450 9950 3450 +Wire Wire Line + 8850 3650 9950 3650 +Wire Wire Line + 8850 3850 9950 3850 +Wire Wire Line + 9450 6150 8900 6150 +Wire Wire Line + 9450 6250 8900 6250 +Wire Wire Line + 9450 6350 8900 6350 +Wire Wire Line + 4400 4400 6100 4400 +Wire Wire Line + 6100 4400 6100 4900 +Wire Wire Line + 5750 5500 5750 5750 +Wire Wire Line + 6450 5500 6450 5750 +Wire Wire Line + 1750 6850 1750 7100 +Wire Wire Line + 2250 4200 2250 4450 +Wire Wire Line + 5450 6750 5450 6400 +Wire Wire Line + 5250 6400 5250 6600 +Wire Wire Line + 1750 6600 2300 6600 +Wire Wire Line + 2300 6600 2300 6300 +Wire Wire Line + 2400 6300 2400 6600 +Wire Wire Line + 2400 6600 5250 6600 +Wire Wire Line + 2200 6300 2200 5950 +Wire Wire Line + 2200 5950 2650 5950 +Wire Wire Line + 2650 5950 2650 5650 +Wire Wire Line + 3650 5650 3650 6750 +Connection ~ 3650 6750 +Wire Wire Line + 2200 5650 2200 5850 +Wire Wire Line + 2200 5850 2450 5850 +Wire Wire Line + 2450 5850 2450 5650 +Wire Wire Line + 3300 5650 3300 5850 +Wire Wire Line + 3300 5850 3550 5850 +Wire Wire Line + 3550 5850 3550 5650 +$Comp +L GND #PWR01 +U 1 1 4808EF19 +P 3850 5900 +AR Path="/4808EF19" Ref="#PWR01" +F 0 "#PWR01" H 3850 5900 30 0001 C C +F 1 "GND" H 3850 5830 30 0001 C C + 1 3850 5900 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR02 +U 1 1 4808EF14 +P 2750 5900 +AR Path="/4808EF14" Ref="#PWR02" +F 0 "#PWR02" H 2750 5900 30 0001 C C +F 1 "GND" H 2750 5830 30 0001 C C + 1 2750 5900 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR03 +U 1 1 4808EF05 +P 3300 5650 +AR Path="/4808EF05" Ref="#PWR03" +F 0 "#PWR03" H 3300 5750 30 0001 C C +F 1 "VCC" H 3300 5750 30 0000 C C + 1 3300 5650 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR04 +U 1 1 4808EF01 +P 2200 5650 +AR Path="/4808EF01" Ref="#PWR04" +F 0 "#PWR04" H 2200 5750 30 0001 C C +F 1 "VCC" H 2200 5750 30 0000 C C + 1 2200 5650 + 1 0 0 -1 +$EndComp +Text Notes 3300 5450 0 60 ~ +USB AUX IN +$Comp +L PINHD-1X4 JP13 +U 1 1 4808E9EA +P 3750 5550 +AR Path="/4808E9EA" Ref="JP13" +F 0 "JP13" H 3500 5875 50 0000 L B +F 1 "PINHD-1X4" H 3500 5250 50 0000 L B +F 2 "pinhead-1X04" H 3750 5700 50 0001 C C + 1 3750 5550 + 0 -1 -1 0 +$EndComp +$Comp +L PINHD-1X3 JP12 +U 1 1 4808E9BA +P 2950 6200 +AR Path="/4808E9BA" Ref="JP12" +F 0 "JP12" H 2700 6425 50 0000 L B +F 1 "PINHD-1X3" H 2700 5900 50 0000 L B +F 2 "pinhead-1X03" H 2950 6350 50 0001 C C + 1 2950 6200 + 0 -1 -1 0 +$EndComp +$Comp +L PINHD-1X3 JP11 +U 1 1 4808E9AB +P 2300 6200 +AR Path="/4808E9AB" Ref="JP11" +F 0 "JP11" H 2050 6425 50 0000 L B +F 1 "PINHD-1X3" H 2050 5900 50 0000 L B +F 2 "pinhead-1X03" H 2300 6350 50 0001 C C + 1 2300 6200 + 0 -1 -1 0 +$EndComp +Text Notes 2150 5450 0 60 ~ +USB AUX OUT +$Comp +L PINHD-1X4 JP10 +U 1 1 4808C81B +P 2650 5550 +AR Path="/4808C81B" Ref="JP10" +F 0 "JP10" H 2400 5875 50 0000 L B +F 1 "PINHD-1X4" H 2400 5250 50 0000 L B +F 2 "pinhead-1X04" H 2650 5700 50 0001 C C + 1 2650 5550 + 0 -1 -1 0 +$EndComp +Text Notes 2050 3700 0 60 ~ +GND +$Comp +L CONN_2 P1 +U 1 1 48061210 +P 2150 3850 +AR Path="/48061210" Ref="P1" +F 0 "P1" V 2100 3850 40 0000 C C +F 1 "CONN_2" V 2200 3850 40 0000 C C + 1 2150 3850 + 0 -1 -1 0 +$EndComp +$Comp +L GND #PWR05 +U 1 1 480611EF +P 2050 4450 +AR Path="/480611EF" Ref="#PWR05" +F 0 "#PWR05" H 2050 4450 30 0001 C C +F 1 "GND" H 2050 4380 30 0001 C C + 1 2050 4450 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR06 +U 1 1 480611ED +P 2250 4450 +AR Path="/480611ED" Ref="#PWR06" +F 0 "#PWR06" H 2250 4450 30 0001 C C +F 1 "GND" H 2250 4380 30 0001 C C + 1 2250 4450 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR07 +U 1 1 480611E8 +P 1750 7100 +AR Path="/480611E8" Ref="#PWR07" +F 0 "#PWR07" H 1750 7100 30 0001 C C +F 1 "GND" H 1750 7030 30 0001 C C + 1 1750 7100 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR08 +U 1 1 480611E3 +P 1000 7100 +AR Path="/480611E3" Ref="#PWR08" +F 0 "#PWR08" H 1000 7100 30 0001 C C +F 1 "GND" H 1000 7030 30 0001 C C + 1 1000 7100 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR09 +U 1 1 48048721 +P 6450 5750 +AR Path="/48048721" Ref="#PWR09" +F 0 "#PWR09" H 6450 5750 30 0001 C C +F 1 "GND" H 6450 5680 30 0001 C C + 1 6450 5750 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR010 +U 1 1 4804871F +P 6100 5750 +AR Path="/4804871F" Ref="#PWR010" +F 0 "#PWR010" H 6100 5750 30 0001 C C +F 1 "GND" H 6100 5680 30 0001 C C + 1 6100 5750 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR011 +U 1 1 48048718 +P 5750 5750 +AR Path="/48048718" Ref="#PWR011" +F 0 "#PWR011" H 5750 5750 30 0001 C C +F 1 "GND" H 5750 5680 30 0001 C C + 1 5750 5750 + 1 0 0 -1 +$EndComp +$Comp +L JUMPER JP6 +U 1 1 480486D0 +P 6450 5200 +AR Path="/480486D0" Ref="JP6" +F 0 "JP6" H 6450 5350 60 0000 C C +F 1 "JUMPER" H 6450 5120 40 0000 C C + 1 6450 5200 + 0 1 1 0 +$EndComp +$Comp +L JUMPER JP5 +U 1 1 480486CC +P 6100 5200 +AR Path="/480486CC" Ref="JP5" +F 0 "JP5" H 6100 5350 60 0000 C C +F 1 "JUMPER" H 6100 5120 40 0000 C C + 1 6100 5200 + 0 1 1 0 +$EndComp +$Comp +L JUMPER JP4 +U 1 1 480486B7 +P 5750 5200 +AR Path="/480486B7" Ref="JP4" +F 0 "JP4" H 5750 5350 60 0000 C C +F 1 "JUMPER" H 5750 5120 40 0000 C C + 1 5750 5200 + 0 1 1 0 +$EndComp +Text Notes 10600 2450 1 60 ~ +Keyboard Rows +Text Notes 10600 4150 1 60 ~ +Keyboard Columns +Text Notes 10600 4700 1 60 ~ +LEDs +Text Notes 9500 5700 0 60 ~ +ISP +Text Label 4900 2300 0 60 ~ +MISO +Text Label 8900 6350 0 60 ~ +MISO +Text Label 4900 2200 0 60 ~ +SCK +Text Label 8900 6250 0 60 ~ +SCK +Text Label 8900 5950 0 60 ~ +MOSI +Text Label 4900 2400 0 60 ~ +MOSI +Text Label 8900 6150 0 60 ~ +Reset +Text Label 2000 1300 0 60 ~ +Reset +Text Label 9450 2800 0 60 ~ +R15 +Text Label 9450 2700 0 60 ~ +R14 +Text Label 9450 2600 0 60 ~ +R13 +Text Label 9450 2500 0 60 ~ +R12 +Text Label 9450 2400 0 60 ~ +R11 +Text Label 9450 2300 0 60 ~ +R10 +Text Label 9450 2200 0 60 ~ +R9 +Text Label 9450 2100 0 60 ~ +R8 +Text Label 9450 2000 0 60 ~ +R7 +Text Label 9450 1900 0 60 ~ +R6 +Text Label 9450 1800 0 60 ~ +R5 +Text Label 9450 1700 0 60 ~ +R4 +Text Label 9450 1600 0 60 ~ +R3 +Text Label 9450 1500 0 60 ~ +R2 +Text Label 9450 1400 0 60 ~ +R1 +Text Label 9450 1300 0 60 ~ +R0 +Text Label 4600 3800 0 60 ~ +R15 +Text Label 4600 3700 0 60 ~ +R14 +Text Label 4600 3600 0 60 ~ +R13 +Text Label 4600 3500 0 60 ~ +R12 +Text Label 4600 3400 0 60 ~ +R11 +Text Label 4600 3300 0 60 ~ +R10 +Text Label 4600 3200 0 60 ~ +R9 +Text Label 4600 3100 0 60 ~ +R8 +Text Label 4600 1300 0 60 ~ +R7 +Text Label 4600 1400 0 60 ~ +R6 +Text Label 4600 1500 0 60 ~ +R5 +Text Label 4600 1600 0 60 ~ +R4 +Text Label 4600 1700 0 60 ~ +R3 +Text Label 4600 1800 0 60 ~ +R2 +Text Label 4600 1900 0 60 ~ +R1 +Text Label 4600 2000 0 60 ~ +R0 +Text Label 4600 2200 0 60 ~ +C7 +Text Label 4600 2300 0 60 ~ +C6 +Text Label 4600 2400 0 60 ~ +C5 +Text Label 4600 2500 0 60 ~ +C4 +Text Label 4600 2600 0 60 ~ +C3 +Text Label 4600 2700 0 60 ~ +C2 +Text Label 4600 2800 0 60 ~ +C1 +Text Label 4600 2900 0 60 ~ +C0 +Text Label 9450 3950 0 60 ~ +C7 +Text Label 9450 3850 0 60 ~ +C6 +Text Label 9450 3750 0 60 ~ +C5 +Text Label 9450 3650 0 60 ~ +C4 +Text Label 9450 3550 0 60 ~ +C3 +Text Label 9450 3450 0 60 ~ +C2 +Text Label 9450 3350 0 60 ~ +C1 +Text Label 9450 3250 0 60 ~ +C0 +Entry Wire Line + 9150 1200 9250 1300 +Entry Wire Line + 9150 1300 9250 1400 +Entry Wire Line + 9150 1400 9250 1500 +Entry Wire Line + 9150 1500 9250 1600 +Entry Wire Line + 9150 1600 9250 1700 +Entry Wire Line + 9150 1700 9250 1800 +Entry Wire Line + 9150 1800 9250 1900 +Entry Wire Line + 9150 1900 9250 2000 +Entry Wire Line + 9150 2000 9250 2100 +Entry Wire Line + 9150 2100 9250 2200 +Entry Wire Line + 9150 2200 9250 2300 +Entry Wire Line + 9150 2300 9250 2400 +Entry Wire Line + 9150 2400 9250 2500 +Entry Wire Line + 9150 2500 9250 2600 +Entry Wire Line + 9150 2600 9250 2700 +Entry Wire Line + 9150 2700 9250 2800 +Entry Wire Line + 8750 3150 8850 3250 +Entry Wire Line + 8750 3250 8850 3350 +Entry Wire Line + 8750 3350 8850 3450 +Entry Wire Line + 8750 3450 8850 3550 +Entry Wire Line + 8750 3550 8850 3650 +Entry Wire Line + 8750 3650 8850 3750 +Entry Wire Line + 8750 3750 8850 3850 +Entry Wire Line + 8750 3850 8850 3950 +Entry Wire Line + 5700 2900 5800 2800 +Entry Wire Line + 5700 2800 5800 2700 +Entry Wire Line + 5700 2700 5800 2600 +Entry Wire Line + 5700 2600 5800 2500 +Entry Wire Line + 5700 2500 5800 2400 +Entry Wire Line + 5700 2400 5800 2300 +Entry Wire Line + 5700 2300 5800 2200 +Entry Wire Line + 5700 2200 5800 2100 +Entry Wire Line + 5350 3800 5450 3700 +Entry Wire Line + 5350 3700 5450 3600 +Entry Wire Line + 5350 3600 5450 3500 +Entry Wire Line + 5350 3500 5450 3400 +Entry Wire Line + 5350 3400 5450 3300 +Entry Wire Line + 5350 3300 5450 3200 +Entry Wire Line + 5350 3200 5450 3100 +Entry Wire Line + 5350 3100 5450 3000 +Entry Wire Line + 5350 2000 5450 1900 +Entry Wire Line + 5350 1900 5450 1800 +Entry Wire Line + 5350 1800 5450 1700 +Entry Wire Line + 5350 1700 5450 1600 +Entry Wire Line + 5350 1600 5450 1500 +Entry Wire Line + 5350 1500 5450 1400 +Entry Wire Line + 5350 1400 5450 1300 +Entry Wire Line + 5350 1300 5450 1200 +$Comp +L GND #PWR012 +U 1 1 4804562B +P 10150 6550 +AR Path="/4804562B" Ref="#PWR012" +F 0 "#PWR012" H 10150 6550 30 0001 C C +F 1 "GND" H 10150 6480 30 0001 C C + 1 10150 6550 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR013 +U 1 1 4804561C +P 10150 5800 +AR Path="/4804561C" Ref="#PWR013" +F 0 "#PWR013" H 10150 5900 30 0001 C C +F 1 "VCC" H 10150 5900 30 0000 C C + 1 10150 5800 + 1 0 0 -1 +$EndComp +NoConn ~ 9450 6050 +NoConn ~ 3400 5000 +NoConn ~ 2400 2500 +NoConn ~ 3400 1000 +$Comp +L VCC #PWR014 +U 1 1 480450B7 +P 4300 5850 +AR Path="/480450B7" Ref="#PWR014" +F 0 "#PWR014" H 4300 5950 30 0001 C C +F 1 "VCC" H 4300 5950 30 0000 C C + 1 4300 5850 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR015 +U 1 1 4804509C +P 9450 4500 +AR Path="/4804509C" Ref="#PWR015" +F 0 "#PWR015" H 9450 4500 30 0001 C C +F 1 "GND" H 9450 4430 30 0001 C C + 1 9450 4500 + 0 1 1 0 +$EndComp +$Comp +L VCC #PWR016 +U 1 1 48044F99 +P 1150 1100 +AR Path="/48044F99" Ref="#PWR016" +F 0 "#PWR016" H 1150 1200 30 0001 C C +F 1 "VCC" H 1150 1200 30 0000 C C + 1 1150 1100 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR017 +U 1 1 48044DD0 +P 800 7100 +AR Path="/48044DD0" Ref="#PWR017" +F 0 "#PWR017" H 800 7100 30 0001 C C +F 1 "GND" H 800 7030 30 0001 C C + 1 800 7100 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR018 +U 1 1 48044DC6 +P 800 6350 +AR Path="/48044DC6" Ref="#PWR018" +F 0 "#PWR018" H 800 6450 30 0001 C C +F 1 "VCC" H 800 6450 30 0000 C C + 1 800 6350 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR019 +U 1 1 48044DB8 +P 1550 3600 +AR Path="/48044DB8" Ref="#PWR019" +F 0 "#PWR019" H 1550 3700 30 0001 C C +F 1 "VCC" H 1550 3700 30 0000 C C + 1 1550 3600 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR020 +U 1 1 48044DB5 +P 1000 3600 +AR Path="/48044DB5" Ref="#PWR020" +F 0 "#PWR020" H 1000 3700 30 0001 C C +F 1 "VCC" H 1000 3700 30 0000 C C + 1 1000 3600 + 1 0 0 -1 +$EndComp +$Comp +L VCC #PWR021 +U 1 1 48044D21 +P 3300 800 +AR Path="/48044D21" Ref="#PWR021" +F 0 "#PWR021" H 3300 900 30 0001 C C +F 1 "VCC" H 3300 900 30 0000 C C + 1 3300 800 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR022 +U 1 1 48044A9D +P 5000 7550 +AR Path="/48044A9D" Ref="#PWR022" +F 0 "#PWR022" H 5000 7550 30 0001 C C +F 1 "GND" H 5000 7480 30 0001 C C + 1 5000 7550 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR023 +U 1 1 48044A97 +P 4650 7550 +AR Path="/48044A97" Ref="#PWR023" +F 0 "#PWR023" H 4650 7550 30 0001 C C +F 1 "GND" H 4650 7480 30 0001 C C + 1 4650 7550 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR024 +U 1 1 48044A95 +P 4300 7550 +AR Path="/48044A95" Ref="#PWR024" +F 0 "#PWR024" H 4300 7550 30 0001 C C +F 1 "GND" H 4300 7480 30 0001 C C + 1 4300 7550 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR025 +U 1 1 48044A93 +P 1550 4450 +AR Path="/48044A93" Ref="#PWR025" +F 0 "#PWR025" H 1550 4450 30 0001 C C +F 1 "GND" H 1550 4380 30 0001 C C + 1 1550 4450 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR026 +U 1 1 48044A8D +P 1000 4450 +AR Path="/48044A8D" Ref="#PWR026" +F 0 "#PWR026" H 1000 4450 30 0001 C C +F 1 "GND" H 1000 4380 30 0001 C C + 1 1000 4450 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR027 +U 1 1 48044A8A +P 3300 5150 +AR Path="/48044A8A" Ref="#PWR027" +F 0 "#PWR027" H 3300 5150 30 0001 C C +F 1 "GND" H 3300 5080 30 0001 C C + 1 3300 5150 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR028 +U 1 1 48044A88 +P 850 1700 +AR Path="/48044A88" Ref="#PWR028" +F 0 "#PWR028" H 850 1700 30 0001 C C +F 1 "GND" H 850 1630 30 0001 C C + 1 850 1700 + 0 1 1 0 +$EndComp +$Comp +L GND #PWR029 +U 1 1 48044A82 +P 850 2300 +AR Path="/48044A82" Ref="#PWR029" +F 0 "#PWR029" H 850 2300 30 0001 C C +F 1 "GND" H 850 2230 30 0001 C C + 1 850 2300 + 0 1 1 0 +$EndComp +$Comp +L PINHD-2X5M JP7 +U 1 1 48044A4D +P 9550 6150 +AR Path="/48044A4D" Ref="JP7" +F 0 "JP7" H 9300 6475 50 0000 L B +F 1 "PINHD-2X5M" H 9300 5750 50 0000 L B +F 2 "pinhead-2X05M" H 9550 6300 50 0001 C C + 1 9550 6150 + 1 0 0 -1 +$EndComp +$Comp +L PINHD-1X4M JP3 +U 1 1 48044A1E +P 10050 4600 +AR Path="/48044A1E" Ref="JP3" +F 0 "JP3" H 9800 4925 50 0000 L B +F 1 "PINHD-1X4M" H 9800 4300 50 0000 L B +F 2 "pinhead-1X04M" H 10050 4750 50 0001 C C + 1 10050 4600 + 1 0 0 -1 +$EndComp +$Comp +L PINHD-1X8M JP2 +U 1 1 48044A0E +P 10050 3650 +AR Path="/48044A0E" Ref="JP2" +F 0 "JP2" H 9800 4175 50 0000 L B +F 1 "PINHD-1X8M" H 9800 3150 50 0000 L B +F 2 "pinhead-1X08M" H 10050 3800 50 0001 C C + 1 10050 3650 + 1 0 0 -1 +$EndComp +$Comp +L PINHD-1X16M JP1 +U 1 1 48044A02 +P 10050 2000 +AR Path="/48044A02" Ref="JP1" +F 0 "JP1" H 10100 2050 50 0000 L B +F 1 "PINHD-1X16M" H 9800 1000 50 0000 L B +F 2 "pinhead-1X16M" H 10050 2150 50 0001 C C + 1 10050 2000 + 1 0 0 -1 +$EndComp +$Comp +L MEGA32-P IC1 +U 1 1 480447FC +P 3400 3000 +AR Path="/480447FC" Ref="IC1" +F 0 "IC1" H 3450 3050 50 0000 L B +F 1 "MEGA32-P" H 3600 1000 50 0000 L B +F 2 "atmel-DIL40" H 3400 3150 50 0001 C C + 1 3400 3000 + 1 0 0 -1 +$EndComp +$Comp +L ZENER D2 +U 1 1 48044798 +P 5000 7200 +AR Path="/48044798" Ref="D2" +F 0 "D2" H 5000 7300 50 0000 C C +F 1 "3.6V" H 5000 7100 40 0000 C C + 1 5000 7200 + 0 -1 -1 0 +$EndComp +$Comp +L ZENER D1 +U 1 1 48044791 +P 4650 7200 +AR Path="/48044791" Ref="D1" +F 0 "D1" H 4650 7300 50 0000 C C +F 1 "3.6V" H 4650 7100 40 0000 C C + 1 4650 7200 + 0 -1 -1 0 +$EndComp +$Comp +L CRYSTAL X1 +U 1 1 4804477C +P 1900 2000 +AR Path="/4804477C" Ref="X1" +F 0 "X1" H 1900 2150 60 0000 C C +F 1 "12MHz" H 1900 1850 60 0000 C C + 1 1900 2000 + 0 1 1 0 +$EndComp +$Comp +L CP C2 +U 1 1 48044769 +P 1550 4000 +AR Path="/48044769" Ref="C2" +F 0 "C2" H 1600 4100 50 0000 L C +F 1 "10u" H 1600 3900 50 0000 L C + 1 1550 4000 + 1 0 0 1 +$EndComp +$Comp +L C C1 +U 1 1 48044756 +P 1000 4000 +AR Path="/48044756" Ref="C1" +F 0 "C1" H 1050 4100 50 0000 L C +F 1 "100n" H 1050 3900 50 0000 L C + 1 1000 4000 + 1 0 0 1 +$EndComp +$Comp +L C C4 +U 1 1 48044754 +P 1350 2300 +AR Path="/48044754" Ref="C4" +F 0 "C4" H 1400 2400 50 0000 L C +F 1 "22p" H 1400 2200 50 0000 L C + 1 1350 2300 + 0 1 1 0 +$EndComp +$Comp +L C C3 +U 1 1 48044750 +P 1350 1700 +AR Path="/48044750" Ref="C3" +F 0 "C3" H 1400 1800 50 0000 L C +F 1 "22p" H 1400 1600 50 0000 L C + 1 1350 1700 + 0 1 1 0 +$EndComp +$Comp +L R R8 +U 1 1 48044743 +P 5450 6150 +AR Path="/48044743" Ref="R8" +F 0 "R8" V 5530 6150 50 0000 C C +F 1 "68" V 5450 6150 50 0000 C C + 1 5450 6150 + -1 0 0 1 +$EndComp +$Comp +L R R7 +U 1 1 48044741 +P 5250 6150 +AR Path="/48044741" Ref="R7" +F 0 "R7" V 5330 6150 50 0000 C C +F 1 "68" V 5250 6150 50 0000 C C + 1 5250 6150 + -1 0 0 1 +$EndComp +$Comp +L R R1 +U 1 1 4804473F +P 1650 1300 +AR Path="/4804473F" Ref="R1" +F 0 "R1" V 1730 1300 50 0000 C C +F 1 "10k" V 1650 1300 50 0000 C C + 1 1650 1300 + 0 1 1 0 +$EndComp +$Comp +L R R2 +U 1 1 4804473B +P 4300 6200 +AR Path="/4804473B" Ref="R2" +F 0 "R2" V 4380 6200 50 0000 C C +F 1 "2k2" V 4300 6200 50 0000 C C + 1 4300 6200 + 1 0 0 -1 +$EndComp +$Comp +L R R6 +U 1 1 48044739 +P 4300 7150 +AR Path="/48044739" Ref="R6" +F 0 "R6" V 4380 7150 50 0000 C C +F 1 "4k7" V 4300 7150 50 0000 C C + 1 4300 7150 + 1 0 0 -1 +$EndComp +$Comp +L R R3 +U 1 1 48044733 +P 8800 4400 +AR Path="/48044733" Ref="R3" +F 0 "R3" V 8880 4400 50 0000 C C +F 1 "470" V 8800 4400 50 0000 C C + 1 8800 4400 + 0 1 1 0 +$EndComp +$Comp +L R R4 +U 1 1 48044731 +P 8800 4600 +AR Path="/48044731" Ref="R4" +F 0 "R4" V 8880 4600 50 0000 C C +F 1 "470" V 8800 4600 50 0000 C C + 1 8800 4600 + 0 1 1 0 +$EndComp +$Comp +L R R5 +U 1 1 4804472B +P 8800 4800 +AR Path="/4804472B" Ref="R5" +F 0 "R5" V 8880 4800 50 0000 C C +F 1 "470" V 8800 4800 50 0000 C C + 1 8800 4800 + 0 1 1 0 +$EndComp +$Comp +L USB J1 +U 1 1 480446AA +P 1400 6400 +AR Path="/480446AA" Ref="J1" +F 0 "J1" H 1350 6800 60 0000 C C +F 1 "USB" V 1150 6550 60 0000 C C + 1 1400 6400 + 1 0 0 -1 +$EndComp +$EndSCHEMATC diff --git a/circuit/dulcimer.stf b/circuit/dulcimer.stf new file mode 100644 index 0000000..113f9ea --- /dev/null +++ b/circuit/dulcimer.stf @@ -0,0 +1,24 @@ +comp = "C1" module = "C1" +comp = "C2" module = "CP36V" +comp = "C3" module = "C1" +comp = "C4" module = "C1" +comp = "D1" module = "D3" +comp = "D2" module = "D3" +comp = "IC1" module = "atmel-DIL40" +comp = "J1" module = "PIN_ARRAY_2X2" +comp = "JP1" module = "pinhead-1X16M" +comp = "JP2" module = "pinhead-1X08M" +comp = "JP3" module = "pinhead-1X04M" +comp = "JP4" module = "PIN_ARRAY_2X1" +comp = "JP5" module = "PIN_ARRAY_2X1" +comp = "JP6" module = "PIN_ARRAY_2X1" +comp = "JP7" module = "pinhead-2X05M" +comp = "R1" module = "R3" +comp = "R2" module = "R3" +comp = "R3" module = "R3" +comp = "R4" module = "R3" +comp = "R5" module = "R3" +comp = "R6" module = "R3" +comp = "R7" module = "R3" +comp = "R8" module = "R3" +comp = "X1" module = "2PIN_6mm" diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..85049b4 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,59 @@ +# Name: Makefile +# Project: HIDKeys +# Author: Christian Starkjohann +# Creation Date: 2006-02-02 +# Tabsize: 4 +# Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) +# This Revision: $Id: Makefile,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + +AVRDUDE = avrdude -p atmega32 -c usbasp + +COMPILE = avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega32 #-DDEBUG_LEVEL=1 + +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o + + +# symbolic targets: +all: main.hex + +.c.o: + $(COMPILE) -std=c99 -c $< -o $@ + +.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. + +.c.s: + $(COMPILE) -S $< -o $@ + +program: all + $(AVRDUDE) -U flash:w:main.hex + +fuses: + # - enable crystal + # - disable JTAG, so we can fully use PORTC + $(AVRDUDE) -U lfuse:w:0xCF:m -U hfuse:w:0xD9:m + +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s + +# file targets: +main.bin: $(OBJECTS) + $(COMPILE) -o main.bin $(OBJECTS) + +main.hex: main.bin + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.bin main.hex + ./checksize main.bin +# do the checksize script as our last action to allow successful compilation +# on Windows with WinAVR where the Unix commands will fail. + +disasm: main.bin + avr-objdump -d main.bin + +cpp: + $(COMPILE) -E main.c diff --git a/firmware/checksize b/firmware/checksize new file mode 100644 index 0000000..ffaafc2 --- /dev/null +++ b/firmware/checksize @@ -0,0 +1,35 @@ +#!/bin/sh +# Name: checksize +# Project: AVR-USB +# Author: Christian Starkjohann +# Creation Date: 2004-12-29 +# Tabsize: 4 +# Copyright: (c) 2005 OBJECTIVE DEVELOPMENT Software GmbH. +# Revision: $Id: checksize,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + +error=0 +codelimit=32768 +datalimit=1920 # leave 128 bytes for stack + +if [ $# -gt 1 ]; then + codelimit="$2" +fi +if [ $# -gt 2 ]; then + datalimit="$3" +fi + +set -- `avr-size -d "$1" | awk '/[0-9]/ {print $1 + $2, $2 + $3, $2}'` +if [ $1 -gt $codelimit ]; then + echo "*** code size $1 exceeds limit of $codelimit" + error=1 +else + echo "ROM: $1 bytes (data=$3)" +fi +if [ $2 -gt $datalimit ]; then + echo "*** data size $2 exceeds limit of $datalimit" + error=1 +else + echo "RAM: $2 bytes" +fi + +exit $error diff --git a/firmware/keycodes.h b/firmware/keycodes.h new file mode 100644 index 0000000..288d830 --- /dev/null +++ b/firmware/keycodes.h @@ -0,0 +1,137 @@ +/** + * \file firmware/keycodes.h + * \brief This file contains modifier- and keycode definitions according to the + * USB-specifications for human interface devices. + * + * See usb.org's HID-usage-tables document, chapter 10 Keyboard/Keypad Page for + * more codes: http://www.usb.org/developers/devclass_docs/Hut1_12.pdf + * \author Ronald Schaten + * \version $Id: keycodes.h,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + * + * License: GNU GPL v2 (see License.txt) + */ + +#ifndef __keycodes_h_included__ +#define __keycodes_h_included__ + +/// Codes for modifier-keys. +enum modifiers { + MOD_NONE = 0, + MOD_CONTROL_LEFT = (1 << 0), + MOD_SHIFT_LEFT = (1 << 1), + MOD_ALT_LEFT = (1 << 2), + MOD_GUI_LEFT = (1 << 3), + MOD_CONTROL_RIGHT = (1 << 4), + MOD_SHIFT_RIGHT = (1 << 5), + MOD_ALT_RIGHT = (1 << 6), + MOD_GUI_RIGHT = (1 << 7), +}; + +/// Codes for non-modifier-keys. +enum keycodes { + KEY_Reserved = 0, // unused + KEY_ErrorRollOver, + KEY_POSTFail, + KEY_ErrorUndefined, + KEY_A, // 0x04 + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, // 0x10 + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_1, // 1 and ! + KEY_2, // 2 and @ + KEY_3, // 0x20 3 and # + KEY_4, // 4 and $ + KEY_5, // 5 and % + KEY_6, // 6 and ^ + KEY_7, // 7 and & + KEY_8, // 8 and * + KEY_9, // 9 and ( + KEY_0, // 0x27 0 and ) + KEY_Return, // 0x28 enter + KEY_ESCAPE, // 0x29 + KEY_DELETE, // 0x2A backspace + KEY_Tab, // 0x2B + KEY_Spacebar, // 0x2C + KEY_minus, // 0x2D - and _ + KEY_equals, // 0x2E = and + + KEY_lbracket, // 0x2F [ and { + KEY_rbracket, // 0x30 ] and } + KEY_backslash, // 0x31 \ and | + KEY_hash, // 0x32 non-US # and ~ + KEY_semicolon, // 0x33 ; and : + KEY_apostroph, // 0x34 ' and " + KEY_grave, // 0x35 grave accent and tilde + KEY_comma, // 0x36 , and < + KEY_dot, // 0x37 . and > + KEY_slash, // 0x38 / and ? + KEY_capslock, // 0x39 + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, // 0x40 + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_PrintScreen, + KEY_ScrollLock, + KEY_Pause, // Break + KEY_Insert, + KEY_Home, + KEY_PageUp, + KEY_DeleteForward, + KEY_End, + KEY_PageDown, + KEY_RightArrow, + KEY_LeftArrow, // 0x50 + KEY_DownArrow, + KEY_UpArrow, + KEY_NumLock, // Clear + KEY_KPslash, + KEY_KPasterisk, + KEY_KPminus, + KEY_KPplus, + KEY_KPenter, + KEY_KP1, // End + KEY_KP2, // Down Arrow + KEY_KP3, // Page Down + KEY_KP4, // Left Arrow + KEY_KP5, + KEY_KP6, // Right Arrow + KEY_KP7, // Home + KEY_KP8, // 0x60 Up Arrow + KEY_KP9, // Page Up + KEY_KP0, // Insert + KEY_KPcomma, // Delete + KEY_Euro, // non-US \ and | + KEY_Application, +}; + +#endif /* __keycodes_h_included__ */ + diff --git a/firmware/main.c b/firmware/main.c new file mode 100644 index 0000000..e27639c --- /dev/null +++ b/firmware/main.c @@ -0,0 +1,785 @@ +/** + * \file firmware/main.c + * \brief Main functions for USB-keyboard + * \author Ronald Schaten + * \version $Id: main.c,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + * + * License: GNU GPL v2 (see License.txt) + */ + +/** + * \mainpage Dulcimer + * + * \section sec_intro Introduction + * + * A computer keyboard can be a very personal utensil. Especially if it is an + * extraordinary well built one, like for example the IBM Model M. The Model M + * design dates back to 1984, but it still has many fans even nowadays. It came + * with the usual keyboard connectors. First the old 5-pin one, later a PS/2 + * plug. Unfortunately is that, at least to my knowledge, they never released a + * version with USB. + * + * A friend of mine knew that I already had built other USB-devices, and one of + * them even acted as a keyboard (it isn't really a keyboard, but that's a + * different story... ;-) ). He is a big fan of the Model M, so he asked if I + * could put new life in one of his old keyboards, which had a broken circuit + * inside. And this is the result... + * + * \subsection sec_technique Hard- and Software + * + * The main part of a computer keyboard circuit is the key matrix. You can + * imagine it as a number of keys, placed on a raster of horizontal (rows) and + * vertical (columns) wires. In the case of a Model M keyboard, we have a + * matrix of 8x16 lines. Eight columns in 16 rows, or the other way around, + * depending on how you look at it. Each key is connected to one column and one + * row. If you press the key, it will connect the column and the row on it's + * crossing of the lines. + * + * Connected to this matrix is a keyboard controller. That's a chip with a + * number of I/O-lines to detect the state of the matrix, and on the other side + * an interface that enables it to talk to the computer. Oh, and not to forget: + * it also has three output lines to drive the LEDs for Num-, Caps- and + * Scroll-lock. + * + * What I did in this project is, that I dumped the keyboard controller chip + * and its circuit, and replaced it by an ATmega32 and my own circuit. The + * ATmega scans the matrix for keyboard activity, controls the LEDs and talks + * to the computer. + * + * For further convenience, I added a boot-loader. With that, it is possible to + * update the keyboard's firmware without disassembling it, and without the + * need for a dedicated programmer. + * + * \subsection sec_hardware Other hardware? + * + * As mentioned, the controller in this project is just connected to an + * ordinary keyboard matrix. You can find this kind of matrix in all kinds of + * keyboards, from key-telephones over good old hardware like the Commodore + * C=64 or the Schneider CPC, keyboards with non-PC-connectors like those made + * by Sun, to modern hardware that could need a few more features. + * + * Till now, I just made a PCB layout for the IBM Model M, but I intend to + * modify at least a Sun keyboard. In order to do that, I expect having to + * refactor the key-scanning, since the key-matrix is not 16x8. The positions + * of the keys on the matrix will be different, I'll have to re-engineer that. + * And of course, I'll have to make another PCB. + * + * \subsection sec_features Features + * + * At the moment, the keyboard should be able to do everything that the average + * off-the-shelf-keyboard can do. But there are many features that are + * possible, regarding the fact that the ATmega32 is absolutely bored till now. + * You can think of 'magic keystrokes' that turn some hidden features on or + * off, like for example: + * - send complete phrases on one keystroke + * - 'autofire' feature on keys that don't repeat normally, for example Alt+F4 + * - change keyboard layout without reconfiguring the computer + * - turn bouncing keys on or off, to annoy other people using your computer + * - random caps lock function + * - use arrow keys as mouse, without having to include a special driver in + * the OS. + * + * With a little tweaking on the hardware side, there should be even more + * possibilities: + * - turn the oldtimer-keyboard into a supermodern wireless bluetooth one + * - implement keylogger-funktionality, using for example an SD-card + * - include an USB-hub into the keyboard + * + * If you are just a little like me, it won't take you much brainstorming to + * come up with one useful -- or even better: useless -- ideas. ;-) + * + * \section sec_install Building and installing + * + * Both, the bootloader and firmware are simply built with "make". You may need + * to customize both makefiles to fit to your system. If you don't want to add + * new features, you don't need to build the software yourself. You can use the + * hex-files included in this package. + * + * \subsection sec_boot Bootloader + * + * I used the USBaspLoader from Objective Development, the same guys that wrote + * the AVR-USB-driver: http://www.obdev.at/products/avrusb/usbasploader.html + * + * The reason why I chose this over some other available USB-bootloaders is, + * that this one emulates a common ISP-programmer that is supported by avrdude. + * In this way, the same program can be used to program the chip that is used + * without a bootloader. + * + * To prepare the ATmega32, you have to connect it to your computer with the + * ISP-programmer of your choice and modify the makefile according to that. + * Then you enter the bootloader-directory and enter the following line: + * + * \code + * make fuse && make flash && make lock + * \endcode + * + * With 'fuse' you prepare the fuse-bits of your AVR, 'flash' transfers the + * bootloader to the device and 'lock' prevents you from overwriting the + * bootloader. Don't fear the locking: you can always reset it with your + * ordinary programmer. In fact, it is disabled in the moment you use your + * ordinary programmer to reflash the device, even without any special + * parameters. The locking only affects the bootloader behavior. + * + * Afterwards you can put the programmer back into the toolbox, you won't need + * it from here on. + * + * When you plug in the device while holding the minus-key on the number-keypad + * pressed, the keyboard indicates that it would like to get a new firmware by + * showing a running light on the LEDs. That firmware will be flashed over the + * normal USB-cable that the keyboard is connected with. + * + * \subsection sec_fw Firmware + * + * If you intend to recompile the firmware yourself, you will need avr-gcc and + * avr-libc (a C-library for the AVR controller). Please read the instructions + * at http://www.nongnu.org/avr-libc/user-manual/install_tools.html for how to + * install the GNU toolchain (avr-gcc, assembler, linker etc.) and avr-libc. + * + * Once you have the GNU toolchain for AVR microcontrollers installed, you can + * run "make" in the subdirectory "firmware". + * + * Afterwards -- or if you decided not to compile the firmware yourself -- you + * can flash it to the device: + * + * \code + * make program + * \endcode + * + * Remember that you have to start the bootloader at first: unplug the + * keyboard, hold the minus-key on the number-keypad pressed and replug it. If + * the modified keyboard is the only one within reach: good luck! ;-) + * + * \section sec_usage Usage + * + * Connect the keyboard to the USB-port. All LED should flash up to indicate + * that the device is initialized. + * + * Then you can use the keyboard as always. If additional features get + * implemented, you will be able to use them in their respective ways. + * + * \section sec_drawbacks Drawbacks + * + * I don't know if and how keyboard manufacturers face the problem of ghost + * keys, I didn't take special measurements for this. I hope that the engineers + * at IBM distributed the keys on the matrix in a way that minimizes this + * problem. + * + * \section sec_files Files in the distribution + * + * - \e Readme.txt: Documentation, created from the htmldoc-directory. + * - \e firmware: Source code of the controller firmware. + * - \e firmware/usbdrv: USB driver -- See Readme.txt in this directory for + * info. + * - \e bootloader: The USBaspLoader, properly configured for this project. I + * only modified the bootloaderconfig.h and the Makefile. + * - \e USBaspLoader.2008-02-05.tar.gz: The unmodified bootloader sources, for + * reference. + * - \e circuit: Circuit diagrams in PDF and KiCAD format. KiCAD is a free + * schematic- and layout-tool, you can learn more about it at its homepage: + * http://www.lis.inpg.fr/realise_au_lis/kicad/ + * - \e License.txt: Public license for all contents of this project, except + * for the USB driver. Look in firmware/usbdrv/License.txt for further info. + * - \e Changelog.txt: Logfile documenting changes in soft-, firm- and + * hardware. + * - \e refman.pdf: Full documentation of the software. + * + * \section sec_thanks Thanks! + * + * I'd like to thank Objective Development for the possibility to use + * their driver for my project. In fact, this project wouldn't exist without + * the driver. + * + * \section sec_license About the license + * + * My work - all contents except for the USB driver - is licensed under the GNU + * General Public License (GPL). A copy of the GPL is included in License.txt. + * The driver itself is licensed under a special license by Objective + * Development. See firmware/usbdrv/License.txt for further info. + * + * (c) 2008 by Ronald Schaten - http://www.schatenseite.de + */ + +#define F_CPU 12000000L ///< we use a 12MHz crystal + +#include +#include +#include +#include +#include +#include +#include + +#include "usbdrv.h" +#include "keycodes.h" + +/* ----------------------- hardware I/O abstraction ------------------------ */ + + +#define PORTCOLUMNS PORTB ///< port on which we read the state of the columns +#define PINCOLUMNS PINB ///< port on which we read the state of the columns +#define DDRCOLUMNS DDRB ///< port on which we read the state of the columns +#define PORTROWS1 PORTA ///< first port connected to the matrix rows +#define PINROWS1 PINA ///< first port connected to the matrix rows +#define DDRROWS1 DDRA ///< first port connected to the matrix rows +#define PORTROWS2 PORTC ///< second port connected to the matrix rows +#define PINROWS2 PINC ///< second port connected to the matrix rows +#define DDRROWS2 DDRC ///< second port connected to the matrix rows + +#define PORTLEDS PORTD ///< port on which the LEDs are connected +#define PINLEDS PIND ///< port on which the LEDs are connected +#define DDRLEDS DDRD ///< port on which the LEDs are connected +#define LEDSCROLL PIND4 ///< address of the scroll-lock LED +#define LEDCAPS PIND5 ///< address of the caps-lock LED +#define LEDNUM PIND6 ///< address of the num-lock LED + +#define PORTJUMPERS PORTD ///< port for additional jumpers +#define PINJUMPERS PIND ///< port for additional jumpers +#define DDRJUMPERS DDRD ///< port for additional jumpers +#define JUMPER0 PD1 ///< address for jumper 0 +#define JUMPER1 PD3 ///< address for jumper 1 +#define JUMPER2 PD7 ///< address for jumper 2 + +/** + * Initialize hardware. Configure ports as inputs and outputs, set USB reset + * condition, start timer and blink LEDs. + */ +static void hardwareInit(void) { + // column-port is input + PORTCOLUMNS = 0xff; + DDRCOLUMNS = 0x00; + + // row-ports are output + PORTROWS1 = 0xff; + DDRROWS1 = 0x00; + PORTROWS2 = 0xff; + DDRROWS2 = 0x00; + + // port D contains USB (D0, D2), + // LEDs (D4, D5, D6) + // and Jumpers (D1, D3, D7), + // so we call it PORTD instead of PORTJUMPERS or PORTLEDS + PORTD = 0xfa; // 1000 1010: activate pull-ups except on USB- and LED-lines + DDRD = 0x75; // 0111 0101: all pins input except USB (-> USB reset) and LED-pins + // USB Reset by device only required on Watchdog Reset + _delay_us(11); // delay >10ms for USB reset + DDRD = 0x70; // 0111 0000 bin: remove USB reset condition + + // configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms) + TCCR0 = 5; // timer 0 prescaler: 1024 + + // blink, to indicate power-on + PORTLEDS &= ~((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL)); + _delay_ms(50); + PORTLEDS |= ((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL)); +} + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +static uint8_t reportBuffer[8]; ///< buffer for HID reports +static uint8_t idleRate; ///< in 4ms units +static uint8_t protocolVer = 1; ///< 0 = boot protocol, 1 = report protocol +uint8_t expectReport = 0; ///< flag to indicate if we expect an USB-report + +#define LED_NUM 0x01 ///< num LED on a boot-protocol keyboard +#define LED_CAPS 0x02 ///< caps LED on a boot-protocol keyboard +#define LED_SCROLL 0x04 ///< scroll LED on a boot-protocol keyboard +#define LED_COMPOSE 0x08 ///< compose LED on a boot-protocol keyboard +#define LED_KANA 0x10 ///< kana LED on a boot-protocol keyboard +uint8_t LEDstate = 0; ///< current state of the LEDs + +/** USB report descriptor (length is defined in usbconfig.h). The report + * descriptor has been created with usb.org's "HID Descriptor Tool" which can + * be downloaded from http://www.usb.org/developers/hidpage/ (it's an .exe, but + * it even runs under Wine). + */ +char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; + +/** + * This function is called whenever we receive a setup request via USB. + * \param data[8] eight bytes of data we received + * \return number of bytes to use, or 0xff if usbFunctionWrite() should be + * called + */ +uint8_t usbFunctionSetup(uint8_t data[8]) { + usbRequest_t *rq = (void *)data; + usbMsgPtr = reportBuffer; + if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) { + // class request type + if (rq->bRequest == USBRQ_HID_GET_REPORT) { + // wValue: ReportType (highbyte), ReportID (lowbyte) + // we only have one report type, so don't look at wValue + return sizeof(reportBuffer); + } else if (rq->bRequest == USBRQ_HID_SET_REPORT) { + if (rq->wLength.word == 1) { + // We expect one byte reports + expectReport = 1; + return 0xff; // Call usbFunctionWrite with data + } + } 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 if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) { + if (rq->wValue.bytes[1] < 1) { + protocolVer = rq->wValue.bytes[1]; + } + } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) { + usbMsgPtr = &protocolVer; + return 1; + } + } else { + // no vendor specific requests implemented + } + return 0; +} + +/** + * The write function is called when LEDs should be set. Normally, we get only + * one byte that contains info about the LED states. + * \param data pointer to received data + * \param len number ob bytes received + * \return 0x01 + */ +uint8_t usbFunctionWrite(uchar *data, uchar len) { + if (expectReport && (len == 1)) { + LEDstate = data[0]; // Get the state of all 5 LEDs + if (LEDstate & LED_NUM) { // light up caps lock + PORTLEDS &= ~(1 << LEDNUM); + } else { + PORTLEDS |= (1 << LEDNUM); + } + if (LEDstate & LED_CAPS) { // light up caps lock + PORTLEDS &= ~(1 << LEDCAPS); + } else { + PORTLEDS |= (1 << LEDCAPS); + } + if (LEDstate & LED_SCROLL) { // light up caps lock + PORTLEDS &= ~(1 << LEDSCROLL); + } else { + PORTLEDS |= (1 << LEDSCROLL); + } + } + expectReport = 0; + return 0x01; +} + +/** + * Send a single report to the computer. This function is not used during + * normal typing, it is only used to send non-pressed keys to simulate input. + * \param mode modifier-byte + * \param key key-code + */ +void usbSendReport(uint8_t mode, uint8_t key) { + reportBuffer[0] = mode; + reportBuffer[1] = key; + while (!usbInterruptIsReady()); // wait + usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); // send +} + +/* ------------------------------------------------------------------------- */ + +uint8_t curmatrix[16]; ///< contains current state of the keyboard + +/** + * The keymatrix-array contains positions of keys in the matrix. Here you can + * see which row is connected to which column when a key is pressed. This array + * probably has to be modified if this firmware is ported to a different + * keyboard. + * \sa modmatrix + */ +const uint8_t PROGMEM keymatrix[16][8] = { + // 0 1 2 3 4 5 6 7 + {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 0 + {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 1 + {KEY_ESCAPE, KEY_Tab, KEY_grave, KEY_1, KEY_Q, KEY_A, KEY_Z, KEY_Reserved }, // 2 + {KEY_backslash, KEY_capslock, KEY_F1, KEY_2, KEY_W, KEY_S, KEY_X, KEY_Reserved }, // 3 + {KEY_F4, KEY_F3, KEY_F2, KEY_3, KEY_E, KEY_D, KEY_C, KEY_Reserved }, // 4 + {KEY_G, KEY_T, KEY_5, KEY_4, KEY_R, KEY_F, KEY_V, KEY_B }, // 5 + {KEY_F5, KEY_DELETE, KEY_F9, KEY_F10, KEY_Reserved, KEY_Reserved, KEY_Return, KEY_Spacebar }, // 6 + {KEY_H, KEY_Y, KEY_6, KEY_7, KEY_U, KEY_J, KEY_M, KEY_N }, // 7 + {KEY_F6, KEY_rbracket, KEY_equals, KEY_8, KEY_I, KEY_K, KEY_comma, KEY_Reserved }, // 8 + {KEY_Reserved, KEY_F7, KEY_F8, KEY_9, KEY_O, KEY_L, KEY_dot, KEY_Reserved }, // 9 + {KEY_apostroph, KEY_lbracket, KEY_minus, KEY_0, KEY_P, KEY_semicolon, KEY_hash, KEY_slash }, // 10 + {KEY_Reserved, KEY_KP4, KEY_DeleteForward, KEY_F11, KEY_KP7, KEY_KP1, KEY_NumLock, KEY_DownArrow }, // 11 + {KEY_KP0, KEY_KP5, KEY_Insert, KEY_F12, KEY_KP8, KEY_KP2, KEY_KPslash, KEY_RightArrow }, // 12 + {KEY_KPcomma, KEY_KP6, KEY_PageUp, KEY_PageDown, KEY_KP9, KEY_KP3, KEY_KPasterisk, KEY_KPminus }, // 13 + {KEY_UpArrow, KEY_Reserved, KEY_Home, KEY_End, KEY_KPplus, KEY_KPenter, KEY_Pause, KEY_LeftArrow }, // 14 + {KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_PrintScreen, KEY_ScrollLock, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 15 +}; + +/** + * The modmatrix-array contains positions of the modifier-keys in the matrix. + * It is built in the same way as the keymatrix-array. + * \sa keymatrix + */ +const uint8_t PROGMEM modmatrix[16][8] = { // contains positions of modifiers in the matrix + // 0 1 2 3 4 5 6 7 + {MOD_NONE, MOD_NONE, MOD_CONTROL_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_CONTROL_RIGHT, MOD_NONE }, // 0 + {MOD_NONE, MOD_SHIFT_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_SHIFT_RIGHT, MOD_NONE }, // 1 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 2 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 3 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 4 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 5 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 6 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 7 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 8 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 9 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 10 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 11 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 12 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 13 + {MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 14 + {MOD_ALT_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_ALT_RIGHT}, // 15 +}; + +/** + * This structure can be used as a container for a single 'key'. It consists of + * the key-code and the modifier-code. + */ +typedef struct { + uint8_t mode; + uint8_t key; +} Key; + +/** + * Convert an ASCII-character to the corresponding key-code and modifier-code + * combination. + * \parm character ASCII-character to convert + * \return structure containing the combination + */ +Key charToKey(char character) { + Key key; + // initialize with reserved values + key.mode = MOD_NONE; + key.key = KEY_Reserved; + if ((character >= 'a') && (character <= 'z')) { + // a..z + key.key = (character - 'a') + 0x04; + } else if ((character >= 'A') && (character <= 'Z')) { + // A..Z + key.mode = MOD_SHIFT_LEFT; + key.key = (character - 'A') + 0x04; + } else if ((character >= '1') && (character <= '9')) { + // 1..9 + key.key = (character - '1') + 0x1E; + } + // we can't map the other characters directly, so we switch... + switch (character) { + case '0': + key.key = KEY_0; break; + case '!': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_1; break; + /* + case '@': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_2; break; + case '#': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_3; break; + */ + case '$': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_4; break; + case '%': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_5; break; + case '^': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_6; break; + case '&': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_7; break; + case '*': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_8; break; + case '(': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_9; break; + case ')': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_0; break; + case ' ': + key.key = KEY_Spacebar; break; + case '-': + key.key = KEY_minus; break; + case '_': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_minus; break; + case '=': + key.key = KEY_equals; break; + case '+': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_equals; break; + case '[': + key.key = KEY_lbracket; break; + case '{': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_lbracket; break; + case ']': + key.key = KEY_rbracket; break; + case '}': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_rbracket; break; + case '\\': + key.key = KEY_backslash; break; + case '|': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_backslash; break; + case '#': + key.key = KEY_hash; break; + case '@': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_hash; break; + case ';': + key.key = KEY_semicolon; break; + case ':': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_semicolon; break; + case '\'': + key.key = KEY_apostroph; break; + case '"': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_apostroph; break; + case '`': + key.key = KEY_grave; break; + case '~': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_grave; break; + case ',': + key.key = KEY_comma; break; + case '<': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_comma; break; + case '.': + key.key = KEY_dot; break; + case '>': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_dot; break; + case '/': + key.key = KEY_slash; break; + case '?': + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_slash; break; + } + if (key.key == KEY_Reserved) { + // still reserved? WTF? return question mark... + key.mode = MOD_SHIFT_LEFT; + key.key = KEY_slash; + } + return key; +} + +/** + * Send a key to the computer, followed by the release of all keys. This can be + * used repetitively to send a string. + * \param keytosend key structure to send + */ +void sendKey(Key keytosend) { + usbSendReport(keytosend.mode, keytosend.key); + usbSendReport(0, 0); +} + +/** + * Send a string to the computer. This function converts each character of an + * ASCII-string to a key-structure and uses sendKey() to send it. + * \param string string to send + */ +void sendString(char* string) { + for (uint8_t i = 0; i < strlen(string); i++) { + Key key = charToKey(string[i]); + sendKey(key); + } +} + +/** + * Print the current state of the keyboard in a readable form. This function + * is used for debug-purposes only. + */ +void printMatrix(void) { + for (uint8_t i = 0; i <= 15; i++) { + char buffer[10]; + /* + sprintf(buffer, "%d%d%d%d%d%d%d%d.", + (curmatrix[i] & (1 << 0) ? 1 : 0), + (curmatrix[i] & (1 << 1) ? 1 : 0), + (curmatrix[i] & (1 << 2) ? 1 : 0), + (curmatrix[i] & (1 << 3) ? 1 : 0), + (curmatrix[i] & (1 << 4) ? 1 : 0), + (curmatrix[i] & (1 << 5) ? 1 : 0), + (curmatrix[i] & (1 << 6) ? 1 : 0), + (curmatrix[i] & (1 << 7) ? 1 : 0)); + */ + sprintf(buffer, "%2x", curmatrix[i]); + sendString(buffer); + if (i == 7) { + sendString(":"); + } else { + sendString("."); + } + } + sendString("---"); +} + +/** + * Scan and debounce keypresses. This is the main worker function for normal + * keyboard operation, the code contains lot of comments. Basically, it first + * scans the keyboard state. If a change is detected, it initializes a counter + * that is decreased each time this function is called. If the counter reaches + * 1, that means that the same scan result has been scanned ten times in a row, + * so we can be pretty sure that the keys are in a certain state (as in: not + * bouncing). Then, the codes for keys and modifiers are searched from the two + * arrays, the USB-message to send the state is prepared. The return value of + * this function indicates if the message has to be sent. + * \return flag to indicate whether something has changed + */ +uint8_t scankeys(void) { + static uint8_t debounce = 5; + uint8_t retval = 0; + for (uint8_t row = 0; row <= 15; row++) { + if (row <= 7) { + DDRROWS1 = (1 << row); + PORTROWS1 = ~(1 << row); + DDRROWS2 = 0x00; + PORTROWS2 = 0xff; + } else { + DDRROWS1 = 0x00; + PORTROWS1 = 0xff; + // (15 - row) looks a bit weird, you would expect (row - 8) here. + // This is because pins on PORTC are ordered in the other direction + // than on PORTA. With (15 - row), we have the bytes in the + // resulting matrix matching the pins of the keyboard connector. + DDRROWS2 = (1 << (15 - row)); + PORTROWS2 = ~(1 << (15 - row)); + } + _delay_us(30); + uint8_t data = ~PINCOLUMNS; + if (data != curmatrix[row]) { + // if a change was detected + debounce = 10; // activate debounce counter + curmatrix[row] = data; // and store the result + } + } + if (debounce) { + // Count down, but avoid underflow + debounce--; + } + if (debounce == 1) { + // debounce counter expired, create report + uint8_t reportIndex = 2; // reportBuffer[0] contains modifiers + memset(reportBuffer, 0, sizeof(reportBuffer)); // clear report buffer + for (uint8_t row = 0; row <= 15; row++) { // process all rows for key-codes + uint8_t data = curmatrix[row]; // restore buffer + if (data != 0xff) { // anything on this row? - optimization + for (uint8_t col = 0; col <= 7; col++) { // check every bit on this row + uint8_t key, modifier; + if (data & (1 << col)) { + key = pgm_read_byte(&keymatrix[row][col]); + modifier = pgm_read_byte(&modmatrix[row][col]); + } else { + key = KEY_Reserved; + modifier = MOD_NONE; + } + if (key != KEY_Reserved) { // keycode should be added to report + if (reportIndex >= sizeof(reportBuffer)) { // too many keycodes + if (!retval & 0x02) { // Only fill buffer once + memset(reportBuffer+2, KEY_ErrorRollOver, sizeof(reportBuffer)-2); + retval |= 0x02; // continue decoding to get modifiers + } + } else { + reportBuffer[reportIndex] = key; // set next available entry + reportIndex++; + } + } + if (modifier != MOD_NONE) { // modifier should be added to report + reportBuffer[0] |= modifier; + } + } + } + } + retval |= 0x01; // must have been a change at some point, since debounce is done + } + return retval; +} + +/* ------------------------------------------------------------------------- */ + +/** + * Main function, containing the main loop that manages timer- and + * USB-functionality. + * /return the obligatory integer that nobody cares about... + */ +int main(void) { + uint8_t updateNeeded = 0; + uint8_t idleCounter = 0; + wdt_enable(WDTO_2S); + hardwareInit(); + usbInit(); + sei(); + + scankeys(); + while (1) { + // main event loop + wdt_reset(); + usbPoll(); + + updateNeeded = scankeys(); // changes? + + // check timer if we need periodic reports + if (TIFR & (1 << TOV0)) { + TIFR = (1 << TOV0); // reset flag + if (idleRate != 0) { // do we need periodic reports? + if(idleCounter > 4){ // yes, but not yet + idleCounter -= 5; // 22ms in units of 4ms + } else { // yes, it is time now + updateNeeded = 1; + idleCounter = idleRate; + } + } + } + // if an update is needed, send the report + if (updateNeeded && usbInterruptIsReady()) { + updateNeeded = 0; + usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); + } + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/firmware/project.doxygen b/firmware/project.doxygen new file mode 100644 index 0000000..b0ce063 --- /dev/null +++ b/firmware/project.doxygen @@ -0,0 +1,1252 @@ +# Doxyfile 1.4.7 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Dulcimer" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = firmware/usbdrv bootloader/usbdrv + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = htmldoc + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latexdoc + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtfdoc + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = YES + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h new file mode 100644 index 0000000..713174f --- /dev/null +++ b/firmware/usbconfig.h @@ -0,0 +1,224 @@ +/** + * \file firmware/usbconfig.h + * \brief Configuration options for the USB-driver. + * + * This file is almost identical to the original usbconfig.h by Christian + * Starkjohann, in structure and content. + * + * It contains parts of the USB driver which can be configured and can or must + * be adapted to your hardware. + * \author Ronald Schaten + * \version $Id: usbconfig.h,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + * + * License: GNU GPL v2 (see License.txt) + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + +/* ---------------------------- Hardware Config ---------------------------- */ + +/** 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_IOPORTNAME D +/** 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_DMINUS_BIT 0 +/** This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port. Please note that D+ must also be connected + * to interrupt pin INT0! + */ +#define USB_CFG_DPLUS_BIT 2 + +/* ----------------------- Optional Hardware Config ------------------------ */ + +/* 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_IOPORTNAME D */ +/* 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. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ + +/* --------------------------- Functional Range ---------------------------- */ + +/** Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint 1. + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/** Define this to 1 if you want to compile a version with three endpoints: The + * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in + * endpoint 3. You must also enable endpoint 1 above. + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 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_IMPLEMENT_HALT 0 +/** 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_INTR_POLL_INTERVAL 10 +/** 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_IS_SELF_POWERED 0 +/** 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_MAX_BUS_POWER 100 +/** 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_WRITE 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_READ 0 +/** Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1. + * You must implement the function usbFunctionWriteOut() which receives all + * interrupt/bulk data sent to endpoint 1. + */ +#define USB_CFG_IMPLEMENT_FN_WRITEOUT 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_HAVE_FLOWCONTROL 0 + +/* -------------------------- Device Description --------------------------- */ + +/** We cannot use Obdev's free shared VID/PID pair because this is a HID. + * We use John Hyde's VID (author of the book "USB Design By Example") for + * this example instead. John has offered this VID for use by students for + * non-commercial devices. Well... This example is for demonstration and + * education only... DO NOT LET DEVICES WITH THIS VID ESCAPE YOUR LAB! + * The Product-ID is a random number. + * + * USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you use obdev's free shared + * VID/PID pair. Be sure to read USBID-License.txt for rules! + */ +#define USB_CFG_VENDOR_ID 0x42, 0x42 +/** This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you use obdev's free shared VID/PID pair. Be sure to read the rules in + * USBID-License.txt! + */ +#define USB_CFG_DEVICE_ID 0x31, 0xe1 +/** Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/** These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USBID-License.txt for + * details. + */ +#define USB_CFG_VENDOR_NAME 'w', 'w', 'w', '.', 's', 'c', 'h', 'a', 't', 'e', 'n', 's', 'e', 'i', 't', 'e', '.', 'd', 'e' +/** Length of USB_CFG_DEVICE_VERSION + */ +#define USB_CFG_VENDOR_NAME_LEN 19 +/** Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USBID-License.txt before you assign a name. + */ +#define USB_CFG_DEVICE_NAME 'D', 'u', 'l', 'c', 'i', 'm', 'e', 'r' +/** Length of USB_CFG_DEVICE_NAME + */ +#define USB_CFG_DEVICE_NAME_LEN 8 +/** See USB specification if you want to conform to an existing device class. + * This setting means to specify the class at the interface level. + */ +#define USB_CFG_DEVICE_CLASS 0 +/** See USB specification if you want to conform to an existing device subclass. + */ +#define USB_CFG_DEVICE_SUBCLASS 0 +/** See USB specification if you want to conform to an existing device class or + * protocol. This is HID class. + */ +#define USB_CFG_INTERFACE_CLASS 0x03 +/** See USB specification if you want to conform to an existing device class or + * protocol. This is a boot device. + */ +#define USB_CFG_INTERFACE_SUBCLASS 0x01 +/** See USB specification if you want to conform to an existing device class or + * protocol. This is keyboard protocol. + */ +#define USB_CFG_INTERFACE_PROTOCOL 0x01 +/** 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. + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 63 + +/* ------------------- 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) + * + */ + +#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 + +#endif /* __usbconfig_h_included__ */ diff --git a/firmware/usbdrv/Changelog.txt b/firmware/usbdrv/Changelog.txt new file mode 100644 index 0000000..a92d2d0 --- /dev/null +++ b/firmware/usbdrv/Changelog.txt @@ -0,0 +1,135 @@ +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 diff --git a/firmware/usbdrv/CommercialLicense.txt b/firmware/usbdrv/CommercialLicense.txt new file mode 100644 index 0000000..240e45f --- /dev/null +++ b/firmware/usbdrv/CommercialLicense.txt @@ -0,0 +1,155 @@ +AVR-USB Driver Software License Agreement +Version 2006-07-24 + +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 "AVR-USB" shall mean the firmware-only USB device implementation for +Atmel AVR microcontrollers distributed by OBJECTIVE DEVELOPMENT and +consisting of the files usbdrv.c, usbdrv.h, usbdrvasm.S, oddebug.c, +oddebug.h, usbdrvasm.asm, iarcompat.h and usbconfig-prototype.h. + + +2 LICENSE GRANTS + +2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source +code of AVR-USB. + +2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the +non-exclusive right to use and distribute AVR-USB with your hardware +product(s), restricted by the limitations in section 3 below. + +2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify +your copy of AVR-USB according to your needs. + +2.4 USB IDs. OBJECTIVE DEVELOPMENT grants you the exclusive rights to use +USB Product ID(s) sent to you in e-mail after receiving your payment in +conjunction with USB Vendor ID 5824. OBJECTIVE DEVELOPMENT has acquired an +exclusive license for this pair of USB identifiers from Wouter van Ooijen +(www.voti.nl), who has licensed the VID from the USB Implementers Forum, +Inc. (www.usb.org). + + +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 AVR-USB according to section 2 above in no more +than 5 hardware units. These units must not be sold for profit. + +Entry Level License: You may use AVR-USB according to section 2 above in no +more than 150 hardware units. + +Professional License: You may use AVR-USB according to section 2 above in +any number of hardware units, except for large scale production ("unlimited +fair use"). Quantities below 10,000 units are not considered large scale +production. If your reach quantities which are obviously large scale +production, you must pay a license fee of 0.10 EUR per unit for all units +above 10,000. + +3.2 Rental. You may not rent, lease, or lend AVR-USB or otherwise encumber +any copy of AVR-USB, or any of the rights granted herein. + +3.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 AVR-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/avrusb/license.html. You agree to pay the amount listed +there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor +or reseller. + + +5 COPYRIGHT AND OWNERSHIP + +AVR-USB is protected by copyright laws and international copyright +treaties, as well as other intellectual property laws and treaties. AVR-USB +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. AVR-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE +DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND +NON-INFRINGEMENT, WITH REGARD TO AVR-USB, AND THE PROVISION OF OR FAILURE +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 AVR-USB OR THE +PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE +DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY +CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS +AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR AVR-USB. + + +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/firmware/usbdrv/License.txt b/firmware/usbdrv/License.txt new file mode 100644 index 0000000..f6a232e --- /dev/null +++ b/firmware/usbdrv/License.txt @@ -0,0 +1,359 @@ +OBJECTIVE DEVELOPMENT GmbH's AVR-USB driver software is distributed under the +terms and conditions of the GNU GPL version 2, see the text below. In addition +to the requirements in the GPL, we STRONGLY ENCOURAGE you to do the following: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/avrusb/feedback.html for your submission. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/avrusb/ + +(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/firmware/usbdrv/Readme.txt b/firmware/usbdrv/Readme.txt new file mode 100644 index 0000000..345f090 --- /dev/null +++ b/firmware/usbdrv/Readme.txt @@ -0,0 +1,84 @@ +This is the Readme file to Objective Development's firmware-only USB driver +for Atmel AVR microcontrollers. For more information please visit +http://www.obdev.at/avrusb/ + +This directory contains the USB firmware only. Copy it as-is to your own +project and add your own version of "usbconfig.h". A template for your own +"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory. + + +TECHNICAL DOCUMENTATION +======================= +The technical documentation for the firmware driver is contained in the file +"usbdrv.h". Please read all of it carefully! + + +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 a single VID/PID pair for free. If you want to use +your own VID and PID instead of our's, define the macros "USB_CFG_VENDOR_ID" +and "USB_CFG_DEVICE_ID" accordingly in "usbconfig.h". + +To use our predefined VID/PID pair, you MUST conform to a couple of +requirements. See the file "USBID-License.txt" for details. + +Objective Development also has some offerings which include product IDs. See +http://www.obdev.at/avrusb/ for details. + + +HOST DRIVER +=========== +You have received this driver together with an example device implementation +and an example host driver. The host driver is based on libusb and compiles +on various Unix flavors (Linux, BSD, Mac OS X). It also compiles natively on +Windows using MinGW (see www.mingw.org) and libusb-win32 (see +libusb-win32.sourceforge.net). The "Automator" project contains a native +Windows host driver (not based on libusb) for Human Interface Devices. + + +DEVELOPMENT SYSTEM +================== +This driver has been developed and optimized for the GNU compiler version 3 +(gcc 3). It does work well with gcc 4 and future versions will probably be +optimized for gcc 4. We recommend that you use the GNU compiler suite because +it is freely available. AVR-USB has also been ported to the IAR compiler and +assembler. It has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 +with the "small" and "tiny" memory model. Please note that gcc is more +efficient for usbdrv.c because this module has been deliberately optimized +for gcc. + + +USING AVR-USB FOR FREE +====================== +The AVR firmware driver is published under the GNU General Public License +Version 2 (GPL2). See the file "License.txt" for details. + +If you decide for the free GPL2, we STRONGLY ENCOURAGE you to do the following +things IN ADDITION to the obligations from the GPL2: + +(1) Publish your entire project on a web site and drop us a note with the URL. +Use the form at http://www.obdev.at/avrusb/feedback.html for your submission. + +(2) Adhere to minimum publication standards. Please include AT LEAST: + - a circuit diagram in PDF, PNG or GIF format + - full source code for the host software + - a Readme.txt file in ASCII format which describes the purpose of the + project and what can be found in which directories and which files + - a reference to http://www.obdev.at/avrusb/ + +(3) If you improve the driver firmware itself, please give us a free license +to your modifications for our commercial license offerings. + + +COMMERCIAL LICENSES FOR AVR-USB +=============================== +If you don't want to publish your source code under the terms of the GPL2, +you can simply pay money for AVR-USB. As an additional benefit you get +USB PIDs for free, licensed exclusively to you. See the file +"CommercialLicense.txt" for details. + diff --git a/firmware/usbdrv/USBID-License.txt b/firmware/usbdrv/USBID-License.txt new file mode 100644 index 0000000..4739a57 --- /dev/null +++ b/firmware/usbdrv/USBID-License.txt @@ -0,0 +1,143 @@ +Royalty-Free Non-Exclusive License USB Product-ID +================================================= + +Version 2006-06-19 + +OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive +right to use three USB.org vendor-ID (VID) / product-ID (PID) pairs with +products based on Objective Development's firmware-only USB driver for +Atmel AVR microcontrollers: + + * VID = 5824 (=0x16c0) / PID = 1500 (=0x5dc) for devices implementing no + USB device class (vendor-class devices with USB class = 0xff). Devices + using this pair will be referred to as "VENDOR CLASS" devices. + + * VID = 5824 (=0x16c0) / PID = 1503 (=0x5df) for HID class devices + (excluding mice and keyboards). Devices using this pair will be referred + to as "HID CLASS" devices. + + * VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices + Devices using this pair will be referred to as "CDC-ACM CLASS" devices. + +Since the granted right is non-exclusive, the same VID/PID pairs may be +used by many companies and individuals for different products. To avoid +conflicts, your device and host driver software MUST adhere to the rules +outlined below. + +OBJECTIVE DEVELOPMENT Software GmbH has licensed these VID/PID pairs from +Wouter van Ooijen (see www.voti.nl), who has licensed the VID from the USB +Implementers Forum, Inc. (see www.usb.org). The VID is registered for the +company name "Van Ooijen Technische Informatica". + + +RULES AND RESTRICTIONS +====================== + +(1) The USB device MUST provide a textual representation of the +manufacturer and product identification. The manufacturer identification +MUST be available at least in USB language 0x0409 (English/US). + +(2) The textual manufacturer identification MUST contain either an Internet +domain name (e.g. "mycompany.com") registered and owned by you, or an +e-mail address under your control (e.g. "myname@gmx.net"). You can embed +the domain name or e-mail address in any string you like, e.g. "Objective +Development http://www.obdev.at/avrusb/". + +(3) You are responsible for retaining ownership of the domain or e-mail +address for as long as any of your products are in use. + +(4) You may choose any string for the textual product identification, as +long as this string is unique within the scope of your textual manufacturer +identification. + +(5) Matching of device-specific drivers MUST be based on the textual +manufacturer and product identification in addition to the usual VID/PID +matching. This means that operating system features which are based on +VID/PID matching only (e.g. Windows kernel level drivers, automatic actions +when the device is plugged in etc) MUST NOT be used. The driver matching +MUST be a comparison of the entire strings, NOT a sub-string match. For +CDC-ACM CLASS devices, a generic class driver should be used and the +matching is based on the USB device class. + +(6) The extent to which VID/PID matching is allowed for non device-specific +drivers or features depends on the operating system and particular VID/PID +pair used: + + * Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is + required and hence no VID/PID-only matching is allowed at all. + + * Windows: The operating system performs VID/PID matching for the kernel + level driver. You are REQUIRED to use libusb-win32 (see + http://libusb-win32.sourceforge.net/) as the kernel level driver for + VENDOR CLASS devices. HID CLASS devices all use the generic HID class + driver shipped with Windows, except mice and keyboards. You therefore + MUST NOT use any of the shared VID/PID pairs for mice or keyboards. + CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID + pair. This ".inf" file MUST load the "usbser" driver to configure the + device as modem (COM-port). + +(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any +problems which are caused by the shared use of these VID/PID pairs. You +have been warned that the sharing of VID/PID pairs may cause problems. If +you want to avoid them, get your own VID/PID pair for exclusive use. + + +HOW TO IMPLEMENT THESE RULES +============================ + +The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM +CLASS devices use the operating system's class driver and don't need a +custom driver. + +The host driver MUST iterate over all devices with the given VID/PID +numbers in their device descriptors and query the string representation for +the manufacturer name in USB language 0x0409 (English/US). It MUST compare +the ENTIRE string with your textual manufacturer identification chosen in +(2) above. A substring search for your domain or e-mail address is NOT +acceptable. The driver MUST NOT touch the device (other than querying the +descriptors) unless the strings match. + +For all USB devices with matching VID/PID and textual manufacturer +identification, the host driver must query the textual product +identification and string-compare it with the name of the product it can +control. It may only initialize the device if the product matches exactly. + +Objective Development provides examples for these matching rules with the +"PowerSwitch" project (using libusb) and with the "Automator" project +(using Windows calls on Windows and libusb on Unix). + + +Technical Notes: +================ + +Sharing the same VID/PID pair among devices is possible as long as ALL +drivers which match the VID/PID also perform matching on the textual +identification strings. This is easy on all operating systems except +Windows, since Windows establishes a static connection between the VID/PID +pair and a kernel level driver. All devices with the same VID/PID pair must +therefore use THE SAME kernel level driver. + +We therefore demand that you use libusb-win32 for VENDOR CLASS devices. +This is a generic kernel level driver which allows all types of USB access +for user space applications. This is only a partial solution of the +problem, though, because different device drivers may come with different +versions of libusb-win32 and they may not work with the libusb version of +the respective other driver. You are therefore encouraged to test your +driver against a broad range of libusb-win32 versions. Do not use new +features in new versions, or check for their existence before you use them. +When a new libusb-win32 becomes available, make sure that your driver is +compatible with it. + +For HID CLASS devices it is necessary that all those devices bind to the +same kernel driver: Microsoft's generic USB HID driver. This is true for +all HID devices except those with a specialized driver. Currently, the only +HIDs with specialized drivers are mice and keyboards. You therefore MUST +NOT use a shared VID/PID with mouse and keyboard devices. + +Sharing the same VID/PID among different products is unusual and probably +violates the USB specification. If you do it, you do it at your own risk. + +To avoid possible incompatibilities, we highly recommend that you get your +own VID/PID pair if you intend to sell your product. Objective +Development's commercial licenses for AVR-USB include a PID for +unrestricted exclusive use. diff --git a/firmware/usbdrv/iarcompat.h b/firmware/usbdrv/iarcompat.h new file mode 100644 index 0000000..a3f65a9 --- /dev/null +++ b/firmware/usbdrv/iarcompat.h @@ -0,0 +1,70 @@ +/* Name: iarcompat.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2006-03-01 + * Tabsize: 4 + * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: iarcompat.h,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + */ + +/* +General Description: +This header is included when we compile with the IAR C-compiler and assembler. +It defines macros for cross compatibility between gcc and IAR-cc. + +Thanks to Oleg Semyonov for his help with the IAR tools port! +*/ + +#ifndef __iarcompat_h_INCLUDED__ +#define __iarcompat_h_INCLUDED__ + +#if defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ + +/* Enable bit definitions */ +#ifndef ENABLE_BIT_DEFINITIONS +# define ENABLE_BIT_DEFINITIONS 1 +#endif + +/* Include IAR headers */ +#include +#ifndef __IAR_SYSTEMS_ASM__ +# include +#endif + +#define __attribute__(arg) +#define IAR_SECTION(section) @ section + +#ifndef USB_BUFFER_SECTION +# define USB_BUFFER_SECTION "TINY_Z" /* if user has not selected a named section */ +#endif + +#ifdef __IAR_SYSTEMS_ASM__ +# define __ASSEMBLER__ +#endif + +#ifdef __HAS_ELPM__ +# define PROGMEM __farflash +#else +# define PROGMEM __flash +#endif + +#define PRG_RDB(addr) (*(PROGMEM char *)(addr)) + +/* The following definitions are not needed by the driver, but may be of some + * help if you port a gcc based project to IAR. + */ +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() + +/* Depending on the device you use, you may get problems with the way usbdrv.h + * handles the differences between devices. Since IAR does not use #defines + * for MCU registers, we can't check for the existence of a particular + * register with an #ifdef. If the autodetection mechanism fails, include + * definitions for the required USB_INTR_* macros in your usbconfig.h. See + * usbconfig-prototype.h and usbdrv.h for details. + */ + +#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */ +#endif /* __iarcompat_h_INCLUDED__ */ diff --git a/firmware/usbdrv/oddebug.c b/firmware/usbdrv/oddebug.c new file mode 100644 index 0000000..93301f1 --- /dev/null +++ b/firmware/usbdrv/oddebug.c @@ -0,0 +1,50 @@ +/* Name: oddebug.c + * 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) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.c,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + */ + +#include "oddebug.h" + +#if DEBUG_LEVEL > 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/firmware/usbdrv/oddebug.h b/firmware/usbdrv/oddebug.h new file mode 100644 index 0000000..489890a --- /dev/null +++ b/firmware/usbdrv/oddebug.h @@ -0,0 +1,126 @@ +/* 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) or proprietary (CommercialLicense.txt) + * This Revision: $Id: oddebug.h,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + */ + +#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 "iarcompat.h" +#ifndef __IAR_SYSTEMS_ICC__ +# include +#endif + +#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< +# include +#endif +#include "usbdrv.h" +#include "oddebug.h" + +/* +General Description: +This module implements the C-part of the USB driver. See usbdrv.h for a +documentation of the entire driver. +*/ + +#ifndef IAR_SECTION +#define IAR_SECTION(arg) +#define __no_init +#endif +/* The macro IAR_SECTION is a hack to allow IAR-cc compatibility. On gcc, it + * is defined to nothing. __no_init is required on IAR. + */ + +/* ------------------------------------------------------------------------- */ + +/* raw USB registers / interface to assembler code: */ +uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ +uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */ +uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */ +uchar usbNewDeviceAddr; /* device ID which should be set after status phase */ +uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */ +volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ +uchar usbCurrentTok; /* last token received, if more than 1 rx endpoint: MSb=endpoint */ +uchar usbRxToken; /* token for data we received; if more than 1 rx endpoint: MSb=endpoint */ +uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */ +volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */ +uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT +volatile uchar usbTxLen1 = USBPID_NAK; /* TX count for endpoint 1 */ +uchar usbTxBuf1[USB_BUFSIZE]; /* TX data for endpoint 1 */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +volatile uchar usbTxLen3 = USBPID_NAK; /* TX count for endpoint 1 */ +uchar usbTxBuf3[USB_BUFSIZE]; /* TX data for endpoint 1 */ +#endif +#endif + +/* USB status registers / not shared with asm code */ +uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */ +static uchar usbMsgFlags; /* flag values see below */ + +#define USB_FLG_TX_PACKET (1<<0) +/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */ +#define USB_FLG_MSGPTR_IS_ROM (1<<6) +#define USB_FLG_USE_DEFAULT_RW (1<<7) + +/* +optimizing hints: +- do not post/pre inc/dec integer values in operations +- assign value of PRG_RDB() to register variables and don't use side effects in arg +- use narrow scope for variables which should be in X/Y/Z register +- assign char sized expressions to variables to force 8 bit arithmetics +*/ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_DESCR_PROPS_STRINGS == 0 + +#if USB_CFG_DESCR_PROPS_STRING_0 == 0 +#undef USB_CFG_DESCR_PROPS_STRING_0 +#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0) +PROGMEM char usbDescriptorString0[] = { /* language descriptor */ + 4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */ + 3, /* descriptor type */ + 0x09, 0x04, /* language index (0x0409 = US-English) */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_VENDOR +#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor) +PROGMEM int usbDescriptorStringVendor[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), + USB_CFG_VENDOR_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_DEVICE == 0 && USB_CFG_DEVICE_NAME_LEN +#undef USB_CFG_DESCR_PROPS_STRING_DEVICE +#define USB_CFG_DESCR_PROPS_STRING_DEVICE sizeof(usbDescriptorStringDevice) +PROGMEM int usbDescriptorStringDevice[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), + USB_CFG_DEVICE_NAME +}; +#endif + +#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN +#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber) +PROGMEM int usbDescriptorStringSerialNumber[] = { + USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), + USB_CFG_SERIAL_NUMBER +}; +#endif + +#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ + +#if USB_CFG_DESCR_PROPS_DEVICE == 0 +#undef USB_CFG_DESCR_PROPS_DEVICE +#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice) +PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */ + 18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ + USBDESCR_DEVICE, /* descriptor type */ + 0x01, 0x01, /* USB version supported */ + USB_CFG_DEVICE_CLASS, + USB_CFG_DEVICE_SUBCLASS, + 0, /* protocol */ + 8, /* max packet size */ + USB_CFG_VENDOR_ID, /* 2 bytes */ + 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_DEVICE != 0 ? 2 : 0, /* product string index */ + USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */ + 1, /* number of configurations */ +}; +#endif + +#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 +#undef USB_CFG_DESCR_PROPS_HID +#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */ +#endif + +#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 +#undef USB_CFG_DESCR_PROPS_CONFIGURATION +#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration) +PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ + 9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ + USBDESCR_CONFIG, /* descriptor type */ + 18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0, + /* total length of data returned (including inlined descriptors) */ + 1, /* number of interfaces in this configuration */ + 1, /* index of this configuration */ + 0, /* configuration name string index */ +#if USB_CFG_IS_SELF_POWERED + USBATTR_SELFPOWER, /* attributes */ +#else + USBATTR_BUSPOWER, /* attributes */ +#endif + USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ +/* interface descriptor follows inline: */ + 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ + USBDESCR_INTERFACE, /* descriptor type */ + 0, /* index of this interface */ + 0, /* alternate setting for this interface */ + USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ + USB_CFG_INTERFACE_CLASS, + USB_CFG_INTERFACE_SUBCLASS, + USB_CFG_INTERFACE_PROTOCOL, + 0, /* string index for interface */ +#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */ + 9, /* sizeof(usbDescrHID): length of descriptor in bytes */ + USBDESCR_HID, /* descriptor type: HID */ + 0x01, 0x01, /* BCD representation of HID version */ + 0x00, /* target country code */ + 0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ + 0x22, /* descriptor type: report */ + USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */ +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ + 7, /* sizeof(usbDescrEndpoint) */ + USBDESCR_ENDPOINT, /* descriptor type = endpoint */ + 0x81, /* IN endpoint number 1 */ + 0x03, /* attrib: Interrupt endpoint */ + 8, 0, /* maximum packet size */ + USB_CFG_INTR_POLL_INTERVAL, /* in ms */ +#endif +}; +#endif + +/* We don't use prog_int or prog_int16_t for compatibility with various libc + * versions. Here's an other compatibility hack: + */ +#ifndef PRG_RDB +#define PRG_RDB(addr) pgm_read_byte(addr) +#endif + +typedef union{ + unsigned word; + uchar *ptr; + uchar bytes[2]; +}converter_t; +/* We use this union to do type conversions. This is better optimized than + * type casts in gcc 3.4.3 and much better than using bit shifts to build + * ints from chars. Byte ordering is not a problem on an 8 bit platform. + */ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_HAVE_INTRIN_ENDPOINT +void usbSetInterrupt(uchar *data, uchar len) +{ +uchar *p, i; + +#if USB_CFG_IMPLEMENT_HALT + if(usbTxLen1 == USBPID_STALL) + return; +#endif +#if 0 /* No runtime checks! Caller is responsible for valid data! */ + if(len > 8) /* interrupt transfers are limited to 8 bytes */ + len = 8; +#endif + if(usbTxLen1 & 0x10){ /* packet buffer was empty */ + usbTxBuf1[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf1 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf1[1], len); + usbTxLen1 = len + 4; /* len must be given including sync byte */ + DBG2(0x21, usbTxBuf1, len + 3); +} +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +void usbSetInterrupt3(uchar *data, uchar len) +{ +uchar *p, i; + + if(usbTxLen3 & 0x10){ /* packet buffer was empty */ + usbTxBuf3[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ + }else{ + usbTxLen3 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ + } + p = usbTxBuf3 + 1; + for(i=len;i--;) + *p++ = *data++; + usbCrc16Append(&usbTxBuf3[1], len); + usbTxLen3 = len + 4; /* len must be given including sync byte */ + DBG2(0x23, usbTxBuf3, len + 3); +} +#endif + + +static uchar usbRead(uchar *data, uchar len) +{ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){ +#endif + uchar i = len, *r = usbMsgPtr; + if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ + while(i--){ + uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */ + *data++ = c; + r++; + } + }else{ /* RAM data */ + while(i--) + *data++ = *r++; + } + usbMsgPtr = r; + return len; +#if USB_CFG_IMPLEMENT_FN_READ + }else{ + if(len != 0) /* don't bother app with 0 sized reads */ + return usbFunctionRead(data, len); + return 0; + } +#endif +} + + +#define GET_DESCRIPTOR(cfgProp, staticName) \ + if(cfgProp){ \ + if((cfgProp) & USB_PROP_IS_RAM) \ + flags &= ~USB_FLG_MSGPTR_IS_ROM; \ + if((cfgProp) & USB_PROP_IS_DYNAMIC){ \ + replyLen = usbFunctionDescriptor(rq); \ + }else{ \ + replyData = (uchar *)(staticName); \ + SET_REPLY_LEN((cfgProp) & 0xff); \ + } \ + } +/* We use if() instead of #if in the macro above because #if can't be used + * in macros and the compiler optimizes constant conditions anyway. + */ + + +/* Don't make this function static to avoid inlining. + * The entire function would become too large and exceed the range of + * relative jumps. + * 2006-02-25: Either gcc 3.4.3 is better than the gcc used when the comment + * above was written, or other parts of the code have changed. We now get + * better results with an inlined function. Test condition: PowerSwitch code. + */ +static void usbProcessRx(uchar *data, uchar len) +{ +usbRequest_t *rq = (void *)data; +uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW; +/* We use if() cascades because the compare is done byte-wise while switch() + * is int-based. The if() cascades are therefore more efficient. + */ +/* usbRxToken can be: + * 0x2d 00101101 (USBPID_SETUP for endpoint 0) + * 0xe1 11100001 (USBPID_OUT for endpoint 0) + * 0xff 11111111 (USBPID_OUT for endpoint 1) + */ + DBG2(0x10 + ((usbRxToken >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */ +#if USB_CFG_IMPLEMENT_FN_WRITEOUT + if(usbRxToken == 0xff){ + usbFunctionWriteOut(data, len); + return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */ + } +#endif + if(usbRxToken == (uchar)USBPID_SETUP){ + usbTxLen = USBPID_NAK; /* abort pending transmit */ + if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */ + uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; + if(type == USBRQ_TYPE_STANDARD){ + #define SET_REPLY_LEN(len) replyLen = (len); usbMsgPtr = replyData + /* This macro ensures that replyLen and usbMsgPtr are always set in the same way. + * That allows optimization of common code in if() branches */ + uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */ + replyData[0] = 0; /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ + if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */ + uchar __attribute__((__unused__)) recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */ +#if USB_CFG_IS_SELF_POWERED + if(recipient == USBRQ_RCPT_DEVICE) + replyData[0] = USB_CFG_IS_SELF_POWERED; +#endif +#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT + if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */ + replyData[0] = usbTxLen1 == USBPID_STALL; +#endif + replyData[1] = 0; + SET_REPLY_LEN(2); + }else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */ + usbNewDeviceAddr = rq->wValue.bytes[0]; + }else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */ + flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW; + if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) + }else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){ /* 2 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) + }else if(rq->wValue.bytes[1] == USBDESCR_STRING){ /* 3 */ +#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC + if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) + flags &= ~USB_FLG_MSGPTR_IS_ROM; + replyLen = usbFunctionDescriptor(rq); +#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + if(rq->wValue.bytes[0] == 0){ /* descriptor index */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) + }else if(rq->wValue.bytes[0] == 1){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) + }else if(rq->wValue.bytes[0] == 2){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_DEVICE, usbDescriptorStringDevice) + }else if(rq->wValue.bytes[0] == 3){ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } +#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ + }else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) + }else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */ + GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) + }else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ + replyLen = usbFunctionDescriptor(rq); + } + }else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */ + replyData = &usbConfiguration; /* send current configuration value */ + SET_REPLY_LEN(1); + }else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */ + usbConfiguration = rq->wValue.bytes[0]; +#if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; +#endif + }else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */ + SET_REPLY_LEN(1); +#if USB_CFG_HAVE_INTRIN_ENDPOINT + }else if(rq->bRequest == USBRQ_SET_INTERFACE){ /* 11 */ + USB_SET_DATATOKEN1(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# endif +# if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; + }else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){ /* 1|3 */ + if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */ + usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; + USB_SET_DATATOKEN1(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# endif + } +# endif +#endif + }else{ + /* the following requests can be ignored, send default reply */ + /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */ + /* 12: SYNCH_FRAME */ + } + #undef SET_REPLY_LEN + }else{ /* not a standard request -- must be vendor or class request */ + replyLen = usbFunctionSetup(data); + } +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + if(replyLen == 0xff){ /* use user-supplied read/write function */ + if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){ + replyLen = rq->wLength.bytes[0]; /* IN transfers only */ + } + flags &= ~USB_FLG_USE_DEFAULT_RW; /* we have no valid msg, use user supplied read/write functions */ + }else /* The 'else' prevents that we limit a replyLen of 0xff to the maximum transfer len. */ +#endif + if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */ + replyLen = rq->wLength.bytes[0]; + } + /* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */ + }else{ /* DATA packet from out request */ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){ + uchar rval = usbFunctionWrite(data, len); + replyLen = 0xff; + if(rval == 0xff){ /* an error occurred */ + usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */ + usbTxLen = USBPID_STALL; + }else if(rval != 0){ /* This was the final package */ + replyLen = 0; /* answer with a zero-sized data packet */ + } + flags = 0; /* start with a DATA1 package, stay with user supplied write() function */ + } +#endif + } + usbMsgFlags = flags; + usbMsgLen = replyLen; +} + +/* ------------------------------------------------------------------------- */ + +static void usbBuildTxBlock(void) +{ +uchar wantLen, len, txLen, token; + + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + token = USBPID_DATA1; + if(usbMsgFlags & USB_FLG_TX_PACKET) + token = USBPID_DATA0; + usbMsgFlags++; + len = usbRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + usbCrc16Append(&usbTxBuf[1], len); + txLen = len + 4; /* length including sync byte */ + if(len < 8) /* a partial package identifies end of message */ + usbMsgLen = 0xff; + }else{ + txLen = USBPID_STALL; /* stall the endpoint */ + usbMsgLen = 0xff; + } + usbTxBuf[0] = token; + usbTxLen = txLen; + DBG2(0x20, usbTxBuf, txLen-1); +} + +static inline uchar isNotSE0(void) +{ +uchar rval; +/* We want to do + * return (USBIN & USBMASK); + * here, but the compiler does int-expansion acrobatics. + * We can avoid this by assigning to a char-sized variable. + */ + rval = USBIN & USBMASK; + return rval; +} + +/* ------------------------------------------------------------------------- */ + +void usbPoll(void) +{ +schar len; +uchar i; + + if((len = usbRxLen) > 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); + */ + usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len - 3); +#if USB_CFG_HAVE_FLOWCONTROL + if(usbRxLen > 0) /* only mark as available if not inactivated */ + usbRxLen = 0; +#else + usbRxLen = 0; /* mark rx buffer as available */ +#endif + } + if(usbTxLen & 0x10){ /* transmit system idle */ + if(usbMsgLen != 0xff){ /* transmit data pending? */ + usbBuildTxBlock(); + } + } + for(i = 10; i > 0; i--){ + if(isNotSE0()) + break; + } + if(i == 0){ /* RESET condition, called multiple times during reset */ + usbNewDeviceAddr = 0; + usbDeviceAddr = 0; +#if USB_CFG_IMPLEMENT_HALT + usbTxLen1 = USBPID_NAK; +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 + usbTxLen3 = USBPID_NAK; +#endif +#endif + DBG1(0xff, 0, 0); + } +} + +/* ------------------------------------------------------------------------- */ + +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); +#if USB_CFG_HAVE_INTRIN_ENDPOINT + USB_SET_DATATOKEN1(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# if USB_CFG_HAVE_INTRIN_ENDPOINT3 + USB_SET_DATATOKEN3(USBPID_DATA0); /* reset data toggling for interrupt endpoint */ +# endif +#endif +} + +/* ------------------------------------------------------------------------- */ diff --git a/firmware/usbdrv/usbdrv.h b/firmware/usbdrv/usbdrv.h new file mode 100644 index 0000000..c3adb85 --- /dev/null +++ b/firmware/usbdrv/usbdrv.h @@ -0,0 +1,633 @@ +/* Name: usbdrv.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrv.h,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + */ + +#ifndef __usbdrv_h_included__ +#define __usbdrv_h_included__ +#include "usbconfig.h" +#include "iarcompat.h" + +/* +Hardware Prerequisites: +======================= +USB lines D+ and D- MUST be wired to the same I/O port. D+ must (also) be +connected to INT0. D- requires a pullup of 1.5k to +3.5V (and the device +must be powered at 3.5V) to identify as low-speed USB device. A pullup of +1M SHOULD be connected from D+ to +3.5V to prevent interference when no USB +master is connected. We use D+ as interrupt source and not D- because it +does not trigger on keep-alive and RESET states. + +As a compile time option, the 1.5k pullup 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 12 MHz. This is more than the 10 MHz allowed by +an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock +relation is interpolated linearly, an ATtiny2313 meets the requirement by +specification. In practice, the AT90S2313 can be overclocked and works well. + + +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 up to four endpoints: One control endpoint (endpoint 0), +two interrupt-in (or bulk-in) endpoints (endpoint 1 and 3) and one +interrupt-out (or bulk-out) endpoint (endpoint 1). 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. +By default, only the control endpoint 0 is enabled. To get the other endpoints, +define USB_CFG_HAVE_INTRIN_ENDPOINT, USB_CFG_HAVE_INTRIN_ENDPOINT3 and/or +USB_CFG_IMPLEMENT_FN_WRITEOUT respectively (see usbconfig-prototype.h for +details). + +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 wiring the INT1 pin to D-. It is not necessary +to enable the interrupt, checking the interrupt pending flag should suffice. +Before entering sleep mode, the application should enable INT1 for a wakeup +on the next 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) +pullup resistor on D+. 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 20 cycles. This implies that all interrupt routines must either be +declared as "INTERRUPT" instead of "SIGNAL" (see "avr/signal.h") or that they +are written in assembler with "sei" as the first instruction. + +Maximum interrupt duration / CPU cycle consumption: +The driver handles all USB communication during the interrupt service +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 = 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 20070329 +/* 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 __ASSEMBLER__ + +#ifndef uchar +#define uchar unsigned char +#endif +#ifndef schar +#define schar signed char +#endif +/* shortcuts for well defined 8 bit integer types */ + +struct usbRequest; /* forward declaration */ + +extern void usbInit(void); +/* This function must be called before interrupts are enabled and the main + * loop is entered. + */ +extern 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 uchar *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. + */ +extern uchar usbFunctionSetup(uchar data[8]); +/* This function is called when the driver receives a SETUP transaction from + * the host which is not answered by the driver itself (in practice: class and + * vendor requests). All control transfers start with a SETUP transaction where + * 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 0xff in 'usbFunctionSetup()'. The driver + * will then call 'usbFunctionRead()' when data is needed. See the + * documentation for usbFunctionRead() for details. + * + * If the SETUP indicates a control-out transfer, the only way to receive the + * data from the host is through the 'usbFunctionWrite()' call. If you + * implement this function, you must return 0xff in 'usbFunctionSetup()' to + * indicate that 'usbFunctionWrite()' should be used. See the documentation of + * this function for more information. If you just want to ignore the data sent + * by the host, return 0 in 'usbFunctionSetup()'. + * + * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() + * are only done if enabled by the configuration in usbconfig.h. + */ +extern uchar usbFunctionDescriptor(struct usbRequest *rq); +/* You need to implement this function ONLY if you provide USB descriptors at + * runtime (which is an expert feature). It is very similar to + * usbFunctionSetup() above, but it is called only to request USB descriptor + * data. See the documentation of usbFunctionSetup() above for more info. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT +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. + */ +extern volatile uchar usbTxLen1; +#define usbInterruptIsReady() (usbTxLen1 & 0x10) +/* This macro indicates whether the last interrupt message has already been + * sent. If you set a new interrupt message before the old was sent, the + * message already buffered will be lost. + */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT3 +void usbSetInterrupt3(uchar *data, uchar len); +extern volatile uchar usbTxLen3; +#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 +extern 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 +extern 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 */ +#if USB_CFG_IMPLEMENT_FN_WRITEOUT +extern void usbFunctionWriteOut(uchar *data, uchar len); +/* This function is called by the driver when data on interrupt-out or bulk- + * out endpoint 1 is received. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT + * to 1 in usbconfig.h to get this function called. + */ +#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 +#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/firmware/usbdrv/usbdrvasm.S b/firmware/usbdrv/usbdrvasm.S new file mode 100644 index 0000000..7ba4b4b --- /dev/null +++ b/firmware/usbdrv/usbdrvasm.S @@ -0,0 +1,710 @@ +/* Name: usbdrvasm.S + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbdrvasm.S,v 1.1 2008/07/09 20:47:12 rschaten Exp $ + */ + +/* +General Description: +This module implements the assembler part of the USB driver. 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 +*/ + +#include "iarcompat.h" +#ifndef __IAR_SYSTEMS_ASM__ + /* configs for io.h */ +# define __SFR_OFFSET 0 +# define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ +# include /* for CPU I/O register definitions and vectors */ +#endif /* __IAR_SYSTEMS_ASM__ */ +#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 + +/* Some assembler dependent definitions and declarations: */ + +#ifdef __IAR_SYSTEMS_ASM__ + +# define nop2 rjmp $+2 /* jump to next instruction */ +# define XL r26 +# define XH r27 +# define YL r28 +# define YH r29 +# define ZL r30 +# define ZH r31 +# define lo8(x) LOW(x) +# define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */ + + extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset + extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen + extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3 + public usbCrc16 + public usbCrc16Append + + COMMON INTVEC + ORG INT0_vect + rjmp SIG_INTERRUPT0 + RSEG CODE + +#else /* __IAR_SYSTEMS_ASM__ */ + +# define nop2 rjmp .+0 /* jump to next instruction */ + + .text + .global SIG_INTERRUPT0 + .type SIG_INTERRUPT0, @function + .global usbCrc16 + .global usbCrc16Append + +#endif /* __IAR_SYSTEMS_ASM__ */ + + +;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. +SIG_INTERRUPT0: +;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 +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +waitForJ: + sbis USBIN, USBMINUS ;1 [40] wait for D- == 1 + rjmp waitForJ ;2 +waitForK: +;The following code results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + 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 ; undo the push from before + rjmp waitForK ; 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] + + +;---------------------------------------------------------------------------- +; Processing of received packet (numbers in brackets are cycles after end of SE0) +;---------------------------------------------------------------------------- +;This is the only non-error exit point for the software receiver loop +;we don't check any CRCs here because there is no time left. +#define token x1 +se0: ; [0] + subi cnt, USB_BUFSIZE ;1 [1] + neg cnt ;1 [2] + cpi cnt, 3 ;1 [3] + ldi x2, 1<