First version
This commit is contained in:
		
							
								
								
									
										115
									
								
								firmware/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								firmware/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| 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 <avr/io.h> 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 | ||||
							
								
								
									
										458
									
								
								firmware/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										458
									
								
								firmware/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,458 @@ | ||||
| PREFACE | ||||
|  | ||||
| Conceiving and understanding a new license is not an easy task. To make things | ||||
| easier for both, the author and the licensee, we have decided to base our | ||||
| license for the USB driver on an existing license with well-understood | ||||
| properties. | ||||
|  | ||||
| Our favorite choice for the base license was the GNU General Public License | ||||
| (GPL). However, we cannot use the GNU GPL directly for the following reasons: | ||||
|  | ||||
| (1) It was not intended for projects involving hardware -- we must extend the | ||||
|     term "source code" to at least the circuit diagram. | ||||
| (2) The GNU GPL does not require publication. Only if a binary is published, | ||||
|     it requires that the source is published as well. This is reasonable for | ||||
|     software because unpublished software is of little relevance. For projects | ||||
|     involving hardware, we want to REQUIRE publication. More than that, we | ||||
|     even want to define HOW the publication must be done (files contained, | ||||
|     file formats etc). | ||||
| (3) As the author of the software, we can distribute it under more than one | ||||
|     license. For people who don't want to meet the obligations of the GNU GPL, | ||||
|     we want to offer commercial licenses. To avoid a split in revisions of | ||||
|     the driver, we need special privileges to distribute contributed | ||||
|     modifications under proprietary licenses. | ||||
|  | ||||
| We can not simply modify the GNU GPL and incorporate our changes because the | ||||
| Free Software Foundation (FSF) who holds the copyright for the text of the | ||||
| GNU GPL does not allow modifications. We therefore set up our own small | ||||
| license which incorporates the GNU GPL by reference: | ||||
|  | ||||
|  | ||||
|  | ||||
| LICENSE FOR PROJECTS BUILT WITH "OBJECTIVE DEVELOPMENT'S | ||||
| FIRMWARE-ONLY USB-DRIVER FOR ATMEL'S AVR MICROCONTROLLERS" | ||||
| Version 2006-01 | ||||
|  | ||||
|  | ||||
| I. Definitions | ||||
|  | ||||
| "OBDEV" shall mean OBJECTIVE DEVELOPMENT Software GmbH or any legal successor | ||||
| thereof. | ||||
|  | ||||
| "Software Source Code" shall mean the preferred form of the software for | ||||
| making modifications to it. | ||||
|  | ||||
| "USB Driver" shall mean the Software Source Code for OBDEV's firmware-only | ||||
| USB-driver for Atmel's AVR microcontrollers. | ||||
|  | ||||
| "Function" shall mean the Software Source Code for all software executed on | ||||
| the microcontroller except the USB Driver. | ||||
|  | ||||
| "Host Software" shall mean the Software Source Code for all software required | ||||
| to control the USB device from the USB host running any operating system. | ||||
|  | ||||
| "Project" shall mean the USB Driver, the Function, the Host Software, circuit | ||||
| diagrams of the controller based hardware and accompanying documentation. | ||||
|  | ||||
| "source code" shall have the same meaning as the term "Project" above. | ||||
|  | ||||
| "Web Site" shall mean a collection of text and multimedia documents accessible | ||||
| worldwide over internet through the HyperText Transfer Protocol (HTTP) on | ||||
| TCP port 80 (standard HTTP port). | ||||
|  | ||||
|  | ||||
| II. General License Terms | ||||
| The general terms of this license consist of the GNU General Public License | ||||
| Version 2 (GNU GPL2) which is hereby incorporated into this section as though | ||||
| it were fully set forth here. A copy of the GNU GPL2 is included for your | ||||
| convenience in appendix A of this license. | ||||
|  | ||||
| The term "source code" in the GNU GPL2 is to be understood as defined in | ||||
| section I above. If any term or definition in section I, III, IV or V | ||||
| conflicts with the GNU GPL2, the term or definition in section I, III, IV or | ||||
| V has precedence of the GNU GPL2. | ||||
|  | ||||
|  | ||||
| III. Distribution of the Project | ||||
| The distributed form of a Project must contain at least the following files: | ||||
| (a) Software Source Code files for the USB Driver, the Function and the Host | ||||
|     Software. | ||||
| (b) Circuit diagrams for the hardware in PDF, PNG or GIF image file format. | ||||
| (c) A file with name "Readme.txt" in ASCII format with at least the following | ||||
|     content (in English language): | ||||
|     - An explanation what the Project does. | ||||
|     - What to do with the distributed files (installation procedure etc.). | ||||
|     - A reference to Objective Development's USB driver. | ||||
|     - Your (author's) name and contact information. E-mail and/or URL is | ||||
|       sufficient. | ||||
| (d) Optionally a text file with a description of the circuit diagram, an | ||||
|     explanation of special (software) techniques used etc.  | ||||
| (e) A copy of this license in a file with the name "License.txt". This copy | ||||
|     can be in the "usbdrv" subdirectory which contains the driver. | ||||
|  | ||||
|  | ||||
| IV. Requirement for Publication | ||||
| All modifications and derived work (Projects using the USB Driver) MUST be | ||||
| distributed (published) as described in section III above on a Web Site. The | ||||
| main page must reproduce at least a description of the Project (e.g. as | ||||
| contained in the "Readme.txt" file distributed) and a download link for the | ||||
| entire Project. The URL of the main page must be submitted to OBDEV. OBDEV | ||||
| will provide a mechanism for submitting Project URLs and for publishing | ||||
| Projects on their Web Site. The Project must remain available for at least | ||||
| twelve (12) months after the initial publication or at least six (6) months | ||||
| after a subsequent version of that particular Project has been published. | ||||
|  | ||||
|  | ||||
| V. Author Privileges | ||||
| OBDEV reserves the right to distribute the USB Driver and all modified | ||||
| versions under other (proprietary) licenses. If you modify the USB Driver | ||||
| under the grants of this license, you therefore grant OBDEV (in addition to | ||||
| the grants of the GNU GPL2) a worldwide, perpetual, irrevocable royalty free | ||||
| license for your modifications. OBDEV shall not automatically gain rights | ||||
| other than those of the GNU GPL2 in the other parts of the Project. This | ||||
| section V overrides possibly contradicting terms in the GNU GPL2 referenced | ||||
| in section II. | ||||
|  | ||||
|  | ||||
| APPENDIX A | ||||
|  | ||||
|                     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. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     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. | ||||
|  | ||||
|   <signature of Ty Coon>, 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. | ||||
							
								
								
									
										88
									
								
								firmware/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								firmware/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| 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. | ||||
|  | ||||
|  | ||||
| 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 an Open Source compliant license. | ||||
| See the file "License.txt" for details. Since it is not obvious for many | ||||
| people how this license applies to their own projects, here's a short guide: | ||||
|  | ||||
| (1) The USB driver and all your modifications to the driver itself are owned | ||||
| by Objective Development. You must give us a worldwide, perpetual, | ||||
| irrevocable royalty free license for your modifications. | ||||
|  | ||||
| (2) Since you own the code you have written (except where you modify our | ||||
| driver), you can (at least in principle) determine the license for it freely. | ||||
| However, to "pay" for the USB driver code you link against, we demand that | ||||
| you choose an Open Source compliant license (compatible with our license) for | ||||
| your source code and the hardware circuit diagrams. Simply attach your | ||||
| license of choice to your parts of the project and leave our "License.txt" in | ||||
| the "usbdrv" subdirectory. | ||||
|  | ||||
| (3) We also demand that you publish your work on the Internet and drop us a | ||||
| note with the URL. The publication must meet certain formal criteria (files | ||||
| distributed, file formats etc.). See the file "License.txt" for details. | ||||
|  | ||||
| Other than that, you are allowed to manufacture any number of units and sell | ||||
| them for any price. If you like our driver, we also encourage you to make a | ||||
| donation on our web site. | ||||
|  | ||||
|  | ||||
| COMMERCIAL LICENSES FOR AVR-USB | ||||
| =============================== | ||||
| If you don't want to publish your source code and the circuit diagrams under | ||||
| an Open Source license, you can simply pay money for AVR-USB. As an | ||||
| additional benefit you get USB PIDs for free, licensed exclusively to you. | ||||
| See http://www.obdev.at/products/avrusb/license.html for details. | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										143
									
								
								firmware/usbdrv/USBID-License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								firmware/usbdrv/USBID-License.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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. | ||||
							
								
								
									
										70
									
								
								firmware/usbdrv/iarcompat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								firmware/usbdrv/iarcompat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: iarcompat.h,v 1.1 2006/10/28 12:40:42 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 <ioavr.h> | ||||
| #ifndef __IAR_SYSTEMS_ASM__ | ||||
| #   include <inavr.h> | ||||
| #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__ */ | ||||
							
								
								
									
										53
									
								
								firmware/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								firmware/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| /* 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: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: oddebug.c,v 1.1 2006/10/28 12:40:42 rschaten Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "oddebug.h" | ||||
|  | ||||
| #if DEBUG_LEVEL > 0 | ||||
|  | ||||
| static uchar Warning__Never_compile_production_devices_with_debugging; | ||||
| /* The "#warning" preprocessor directive is non-standard. The unused static | ||||
|  * variable above should give a compiler warning on all compilers. | ||||
|  */ | ||||
|  | ||||
| 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 | ||||
							
								
								
									
										126
									
								
								firmware/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								firmware/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: oddebug.h,v 1.1 2006/10/28 12:40:42 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 <avr/io.h> | ||||
| #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<<ODDBG_TXEN); | ||||
|     ODDBG_UBRR = F_CPU / (19200 * 16L) - 1; | ||||
| } | ||||
| #else | ||||
| #   define odDebugInit() | ||||
| #endif | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| #endif /* __oddebug_h_included__ */ | ||||
							
								
								
									
										265
									
								
								firmware/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								firmware/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,265 @@ | ||||
| /* Name: usbconfig.h | ||||
|  * Project: AVR USB driver | ||||
|  * Author: Christian Starkjohann | ||||
|  * Creation Date: 2005-04-01 | ||||
|  * Tabsize: 4 | ||||
|  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||
|  * License: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: usbconfig-prototype.h,v 1.1 2006/10/28 12:40:42 rschaten Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __usbconfig_h_included__ | ||||
| #define __usbconfig_h_included__ | ||||
|  | ||||
| /* | ||||
| General Description: | ||||
| This file is an example configuration (with inline documentation) for the USB | ||||
| driver. It configures AVR-USB for an ATMega8 with USB D+ connected to Port D | ||||
| bit 2 (which is also hardware interrupt 0) and USB D- to Port D bit 0. You may | ||||
| wire the lines to any other port, as long as D- is on bit 0 and D+ is also | ||||
| wired to INT0. | ||||
| To create your own usbconfig.h file, copy this file to the directory | ||||
| containing "usbdrv" (that is your project firmware source directory) and | ||||
| rename it to "usbconfig.h". Then edit it accordingly. | ||||
| */ | ||||
|  | ||||
| /* ---------------------------- Hardware Config ---------------------------- */ | ||||
|  | ||||
| #define USB_CFG_IOPORTNAME      D | ||||
| /* This is the port where the USB bus is connected. When you configure it to | ||||
|  * "B", the registers PORTB, PINB and DDRB will be used. | ||||
|  */ | ||||
| #define USB_CFG_DMINUS_BIT      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. | ||||
|  */ | ||||
| #define USB_CFG_DPLUS_BIT       2 | ||||
| /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. | ||||
|  * This may be any bit in the port. Please note that D+ must also be connected | ||||
|  * to interrupt pin INT0! | ||||
|  */ | ||||
|  | ||||
| /* ----------------------- Optional Hardware Config ------------------------ */ | ||||
|  | ||||
| /* #define USB_CFG_PULLUP_IOPORTNAME   D */ | ||||
| /* If you connect the 1.5k pullup resistor from D- to a port pin instead of | ||||
|  * V+, you can connect and disconnect the device from firmware by calling | ||||
|  * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). | ||||
|  * This constant defines the port on which the pullup resistor is connected. | ||||
|  */ | ||||
| /* #define USB_CFG_PULLUP_BIT          4 */ | ||||
| /* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined | ||||
|  * above) where the 1.5k pullup resistor is connected. See description | ||||
|  * above for details. | ||||
|  */ | ||||
| /* #define  USB_BUFFER_SECTION         ".bss" */ | ||||
| /* The USB receive buffer (variable "usbRxBuf") with a length of 22 bytes | ||||
|  * MUST NOT cross a 256 byte boundary. We have introduced this configuration | ||||
|  * option to allow you to change the data segment where this buffer is | ||||
|  * allocated. If you have problems with the default segment (start of .bss), | ||||
|  * you may change this setting. See the comment in usbdrv.h for details. | ||||
|  * On IAR C, the default is the TINY_Z segment (first 256 bytes). You must | ||||
|  * change this default for devices which don't have RAM below 0x100. | ||||
|  */ | ||||
|  | ||||
| /* --------------------------- Functional Range ---------------------------- */ | ||||
|  | ||||
| #define USB_CFG_HAVE_INTRIN_ENDPOINT    1 | ||||
| /* Define this to 1 if you want to compile a version with two endpoints: The | ||||
|  * default control endpoint 0 and an interrupt-in endpoint 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      20 | ||||
| /* If you compile a version with endpoint 1 (interrupt-in), this is the poll | ||||
|  * interval. The value is in milliseconds and must not be less than 10 ms for | ||||
|  * low speed devices. | ||||
|  */ | ||||
| #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_SAMPLE_EXACT            1 | ||||
| /* This variable affects Sampling Jitter for USB receiving. When it is 0, the | ||||
|  * driver guarantees a sampling window of 1/2 bit. The USB spec requires | ||||
|  * that the receiver has at most 1/4 bit sampling window. The 1/2 bit window | ||||
|  * should still work reliably enough because we work at low speed. If you want | ||||
|  * to meet the spec, set this value to 1. This will unroll a loop which | ||||
|  * results in bigger code size. | ||||
|  * If you have problems with long cables, try setting this value to 1. | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_WRITE      0 | ||||
| /* Set this to 1 if you want usbFunctionWrite() to be called for control-out | ||||
|  * transfers. Set it to 0 if you don't need it and want to save a couple of | ||||
|  * bytes. | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_READ       0 | ||||
| /* Set this to 1 if you need to send control replies which are generated | ||||
|  * "on the fly" when usbFunctionRead() is called. If you only want to send | ||||
|  * data from a static buffer, set it to 0 and return the data from | ||||
|  * usbFunctionSetup(). This saves a couple of bytes. | ||||
|  */ | ||||
| #define USB_CFG_IMPLEMENT_FN_WRITEOUT   0 | ||||
| /* Define this to 1 if you want to use interrupt-out (or bulk out) 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 | ||||
| /* USB vendor ID for the device, low byte first. If you have registered your | ||||
|  * own Vendor ID, define it here. Otherwise you use obdev's free shared | ||||
|  * VID/PID pair. Be sure to read USBID-License.txt for rules! | ||||
|  * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. | ||||
|  * Use this VID/PID pair ONLY if you understand the implications! | ||||
|  */ | ||||
| #define  USB_CFG_DEVICE_ID       0xdf, 0x05 | ||||
| /* This is the ID of the product, low byte first. It is interpreted in the | ||||
|  * scope of the vendor ID. If you have registered your own VID with usb.org | ||||
|  * or if you have licensed a PID from somebody else, define it here. Otherwise | ||||
|  * you use obdev's free shared VID/PID pair. Be sure to read the rules in | ||||
|  * USBID-License.txt! | ||||
|  * This template uses obdev's shared VID/PID pair for HIDs: 0x16c0/0x5df. | ||||
|  * Use this VID/PID pair ONLY if you understand the implications! | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_VERSION  0x00, 0x01 | ||||
| /* Version number of the device: Minor number first, then major number. | ||||
|  */ | ||||
| #define USB_CFG_VENDOR_NAME     'w', 'w', 'w', '.', 'o', 'b', 'd', 'e', 'v', '.', 'a', 't' | ||||
| #define USB_CFG_VENDOR_NAME_LEN 12 | ||||
| /* 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     'T', 'e', 'm', 'p', 'l', 'a', 't', 'e' | ||||
| #define USB_CFG_DEVICE_NAME_LEN 8 | ||||
| /* Same as above for the device name. If you don't want a device name, undefine | ||||
|  * the macros. See the file USBID-License.txt before you assign a name if you | ||||
|  * use a shared VID/PID. | ||||
|  */ | ||||
| /*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */ | ||||
| /*#define USB_CFG_SERIAL_NUMBER_LEN   0 */ | ||||
| /* Same as above for the serial number. If you don't want a serial number, | ||||
|  * undefine the macros. | ||||
|  * It may be useful to provide the serial number through other means than at | ||||
|  * compile time. See the section about descriptor properties below for how | ||||
|  * to fine tune control over USB descriptors such as the string descriptor | ||||
|  * for the serial number. | ||||
|  */ | ||||
| #define USB_CFG_DEVICE_CLASS        0 | ||||
| #define USB_CFG_DEVICE_SUBCLASS     0 | ||||
| /* See USB specification if you want to conform to an existing device class. | ||||
|  */ | ||||
| #define USB_CFG_INTERFACE_CLASS     3   /* HID */ | ||||
| #define USB_CFG_INTERFACE_SUBCLASS  0 | ||||
| #define USB_CFG_INTERFACE_PROTOCOL  0 | ||||
| /* See USB specification if you want to conform to an existing device class or | ||||
|  * protocol. | ||||
|  * This template defines a HID class device. If you implement a vendor class | ||||
|  * device, set USB_CFG_INTERFACE_CLASS to 0 and USB_CFG_DEVICE_CLASS to 0xff. | ||||
|  */ | ||||
| #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    42  /* total length of report descriptor */ | ||||
| /* Define this to the length of the HID report descriptor, if you implement | ||||
|  * an HID device. Otherwise don't define it or define it to 0. | ||||
|  * Since this template defines a HID device, it must also specify a HID | ||||
|  * report descriptor length. You must add a PROGMEM character array named | ||||
|  * "usbHidReportDescriptor" to your code which contains the report descriptor. | ||||
|  * Don't forget to keep the array and this define in sync! | ||||
|  */ | ||||
|  | ||||
| /* ------------------- 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__ */ | ||||
							
								
								
									
										572
									
								
								firmware/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										572
									
								
								firmware/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,572 @@ | ||||
| /* Name: usbdrv.c | ||||
|  * Project: AVR USB driver | ||||
|  * Author: Christian Starkjohann | ||||
|  * Creation Date: 2004-12-29 | ||||
|  * Tabsize: 4 | ||||
|  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||
|  * License: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: usbdrv.c,v 1.1 2006/10/28 12:40:42 rschaten Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "iarcompat.h" | ||||
| #ifndef __IAR_SYSTEMS_ICC__ | ||||
| #   include <avr/io.h> | ||||
| #   include <avr/pgmspace.h> | ||||
| #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: */ | ||||
| /* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */ | ||||
| __no_init uchar usbRxBuf[2][USB_BUFSIZE] __attribute__ ((section (USB_BUFFER_SECTION))) IAR_SECTION(USB_BUFFER_SECTION);/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ | ||||
| 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 */ | ||||
| uchar       usbInputBuf;        /* ptr to raw buffer used for receiving */ | ||||
| uchar       usbAppBuf;          /* ptr to raw buffer passed to app for processing */ | ||||
| volatile schar usbRxLen;        /* = 0; number of bytes in usbAppBuf; 0 means free */ | ||||
| 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 */ | ||||
| static uchar    usbIsReset;     /* = 0; USB bus is in reset phase */ | ||||
|  | ||||
| #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 | ||||
| uchar   usbTxPacketCnt1; | ||||
|  | ||||
| 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 | ||||
|     i = USBPID_DATA1; | ||||
|     if(usbTxPacketCnt1 & 1) | ||||
|         i = USBPID_DATA0; | ||||
|     if(usbTxLen1 & 0x10){       /* packet buffer was empty */ | ||||
|         usbTxPacketCnt1++; | ||||
|     }else{ | ||||
|         usbTxLen1 = USBPID_NAK; /* avoid sending incomplete interrupt data */ | ||||
|     } | ||||
|     p = usbTxBuf1; | ||||
|     *p++ = i; | ||||
|     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 | ||||
| uchar   usbTxPacketCnt3; | ||||
|  | ||||
| void    usbSetInterrupt3(uchar *data, uchar len) | ||||
| { | ||||
| uchar       *p, i; | ||||
|  | ||||
|     i = USBPID_DATA1; | ||||
|     if(usbTxPacketCnt3 & 1) | ||||
|         i = USBPID_DATA0; | ||||
|     if(usbTxLen3 & 0x10){       /* packet buffer was empty */ | ||||
|         usbTxPacketCnt3++; | ||||
|     }else{ | ||||
|         usbTxLen3 = USBPID_NAK; /* avoid sending incomplete interrupt data */ | ||||
|     } | ||||
|     p = usbTxBuf3; | ||||
|     *p++ = i; | ||||
|     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. | ||||
|  */ | ||||
|     DBG2(0x10 + ((usbRxToken >> 6) & 3), data, len); | ||||
| #if USB_CFG_IMPLEMENT_FN_WRITEOUT | ||||
|     if(usbRxToken & 0x80){ | ||||
|         usbFunctionWriteOut(data, len); | ||||
|         return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */ | ||||
|     } | ||||
|     if(usbRxToken == (uchar)(USBPID_SETUP & 0x7f)){ /* MSb contains endpoint (== 0) */ | ||||
| #else | ||||
|     if(usbRxToken == (uchar)USBPID_SETUP){ | ||||
| #endif | ||||
|         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 */ | ||||
|                     usbTxPacketCnt1 = 0;        /* reset data toggling for interrupt endpoint */ | ||||
| #   if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||
|                     usbTxPacketCnt3 = 0;        /* 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; | ||||
|                         usbTxPacketCnt1 = 0;    /* reset data toggling for interrupt endpoint */ | ||||
| #       if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||
|                         usbTxPacketCnt3 = 0;    /* 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) | ||||
| { | ||||
| uchar   len; | ||||
|  | ||||
|     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((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3); | ||||
|  */ | ||||
|         len -= 3;       /* remove PID and CRC */ | ||||
|         if(len < 128){  /* no overflow */ | ||||
|             converter_t appBuf; | ||||
|             appBuf.ptr = (uchar *)usbRxBuf; | ||||
|             appBuf.bytes[0] = usbAppBuf; | ||||
|             appBuf.bytes[0]++; | ||||
|             usbProcessRx(appBuf.ptr, len); | ||||
|         } | ||||
| #if USB_CFG_HAVE_FLOWCONTROL | ||||
|         if(usbRxLen > 0)    /* only mark as available if not inactivated */ | ||||
|             usbRxLen = 0; | ||||
| #else | ||||
|         usbRxLen = 0;   /* mark rx buffer as available */ | ||||
| #endif | ||||
|     } | ||||
|     if(usbMsgLen != 0xff){  /* transmit data pending? */ | ||||
|         if(usbTxLen & 0x10) /* transmit system idle */ | ||||
|             usbBuildTxBlock(); | ||||
|     } | ||||
|     if(isNotSE0()){ /* SE0 state */ | ||||
|         usbIsReset = 0; | ||||
|     }else{ | ||||
|         /* check whether SE0 lasts for more than 2.5us (3.75 bit times) */ | ||||
|         if(!usbIsReset){ | ||||
|             uchar i; | ||||
|             for(i=100;i;i--){ | ||||
|                 if(isNotSE0()) | ||||
|                     goto notUsbReset; | ||||
|             } | ||||
|             usbIsReset = 1; | ||||
|             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); | ||||
| notUsbReset:; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| void    usbInit(void) | ||||
| { | ||||
|     usbInputBuf = (uchar)usbRxBuf[0]; | ||||
|     usbAppBuf = (uchar)usbRxBuf[1]; | ||||
| #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); | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
							
								
								
									
										657
									
								
								firmware/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										657
									
								
								firmware/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,657 @@ | ||||
| /* 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: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: usbdrv.h,v 1.1 2006/10/28 12:40:42 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: | ||||
| ============ | ||||
| Compiling: | ||||
| You should link the usbdrv.o module first because it has special alignment | ||||
| requirements for the receive buffer (the buffer must not cross a 256 byte | ||||
| page boundary, it must not even touch it at the end). If you can't link it | ||||
| first, you must use other measures to ensure alignment. | ||||
| Note: gcc does not always assign variable addresses in the order as the modules | ||||
| are linked or the variables are declared. You can choose a memory section for | ||||
| the receive buffer with the configuration option "USB_BUFFER_SECTION". This | ||||
| option defaults to ".bss". If you use your own section, you can place it at | ||||
| an arbitrary location with a linker option similar to | ||||
| "-Wl,--section-start=.mybuffer=0x800060". Use "avr-nm -ng" on the binary and | ||||
| search for "usbRxBuf" to find tbe base address of the 22 bytes rx buffer. | ||||
|  | ||||
| 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. | ||||
|  | ||||
| Sampling jitter: | ||||
| The driver guarantees a sampling window of 1/2 bit. The USB spec requires | ||||
| that the receiver has at most 1/4 bit sampling window. The 1/2 bit window | ||||
| should still work reliably enough because we work at low speed. If you want | ||||
| to meet the spec, define the macro "USB_CFG_SAMPLE_EXACT" to 1 in usbconfig.h. | ||||
| This will unroll a loop which results in bigger code size. | ||||
|  | ||||
| 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  20060718 | ||||
| /* 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<<USB_CFG_PULLUP_BIT)), \ | ||||
|                                   (USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT))) | ||||
| /* This macro (intended to look like a function) connects the device to the | ||||
|  * USB bus. It is only available if you have defined the constants | ||||
|  * USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h. | ||||
|  */ | ||||
| #define usbDeviceDisconnect()   (USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT)) | ||||
| /* This macro (intended to look like a function) disconnects the device from | ||||
|  * the USB bus. It is only available if you have defined the constants | ||||
|  * USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h. | ||||
|  */ | ||||
| #endif /* USB_CFG_PULLUP_IOPORT */ | ||||
| extern unsigned usbCrc16(unsigned data, uchar len); | ||||
| #define usbCrc16(data, len) usbCrc16((unsigned)(data), len) | ||||
| /* This function calculates the binary complement of the data CRC used in | ||||
|  * USB data packets. The value is used to build raw transmit packets. | ||||
|  * You may want to use this function for data checksums or to verify received | ||||
|  * data. We enforce 16 bit calling conventions for compatibility with IAR's | ||||
|  * tiny memory model. | ||||
|  */ | ||||
| extern unsigned usbCrc16Append(unsigned data, uchar len); | ||||
| #define usbCrc16Append(data, len)    usbCrc16Append((unsigned)(data), len) | ||||
| /* This function is equivalent to usbCrc16() above, except that it appends | ||||
|  * the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len' | ||||
|  * bytes. | ||||
|  */ | ||||
| extern uchar    usbConfiguration; | ||||
| /* This value contains the current configuration set by the host. The driver | ||||
|  * allows setting and querying of this variable with the USB SET_CONFIGURATION | ||||
|  * and GET_CONFIGURATION requests, but does not use it otherwise. | ||||
|  * You may want to reflect the "configured" status with a LED on the device or | ||||
|  * switch on high power parts of the circuit only if the device is configured. | ||||
|  */ | ||||
| #define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8)) | ||||
| /* This macro builds a descriptor header for a string descriptor given the | ||||
|  * string's length. See usbdrv.c for an example how to use it. | ||||
|  */ | ||||
| #if USB_CFG_HAVE_FLOWCONTROL | ||||
| extern volatile schar   usbRxLen; | ||||
| #define usbDisableAllRequests()     usbRxLen = -1 | ||||
| /* Must be called from usbFunctionWrite(). This macro disables all data input | ||||
|  * from the USB interface. Requests from the host are answered with a NAK | ||||
|  * while they are disabled. | ||||
|  */ | ||||
| #define usbEnableAllRequests()      usbRxLen = 0 | ||||
| /* May only be called if requests are disabled. This macro enables input from | ||||
|  * the USB interface after it has been disabled with usbDisableAllRequests(). | ||||
|  */ | ||||
| #define usbAllRequestsAreDisabled() (usbRxLen < 0) | ||||
| /* Use this macro to find out whether requests are disabled. It may be needed | ||||
|  * to ensure that usbEnableAllRequests() is never called when requests are | ||||
|  * enabled. | ||||
|  */ | ||||
| #endif | ||||
|  | ||||
| extern uchar    usbTxPacketCnt1; | ||||
| extern uchar    usbTxPacketCnt3; | ||||
| /* The two variables above are mostly for internal use by the driver. You may | ||||
|  * have to reset usbTxPacketCnt1 to 0 if you start data toggling at DATA0 for | ||||
|  * interrupt-IN endpoint 1 and usbTxPacketCnt3 for interrupt-IN endpoint 3 | ||||
|  * respectively. | ||||
|  */ | ||||
|  | ||||
| #endif  /* __ASSEMBLER__ */ | ||||
|  | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
| /* ----------------- Definitions for Descriptor Properties ----------------- */ | ||||
| /* ------------------------------------------------------------------------- */ | ||||
| /* This is advanced stuff. See usbconfig-prototype.h for more information | ||||
|  * about the various methods to define USB descriptors. If you do nothing, | ||||
|  * the default descriptors will be used. | ||||
|  */ | ||||
| #define USB_PROP_IS_DYNAMIC     (1 << 8) | ||||
| /* If this property is set for a descriptor, usbFunctionDescriptor() will be | ||||
|  * used to obtain the particular descriptor. | ||||
|  */ | ||||
| #define USB_PROP_IS_RAM         (1 << 9) | ||||
| /* If this property is set for a descriptor, the data is read from RAM | ||||
|  * memory instead of Flash. The property is used for all methods to provide | ||||
|  * external descriptors. | ||||
|  */ | ||||
| #define USB_PROP_LENGTH(len)    ((len) & 0xff) | ||||
| /* If a static external descriptor is used, this is the total length of the | ||||
|  * descriptor in bytes. | ||||
|  */ | ||||
|  | ||||
| /* all descriptors which may have properties: */ | ||||
| #ifndef USB_CFG_DESCR_PROPS_DEVICE | ||||
| #define USB_CFG_DESCR_PROPS_DEVICE                  0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_CONFIGURATION | ||||
| #define USB_CFG_DESCR_PROPS_CONFIGURATION           0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_STRINGS | ||||
| #define USB_CFG_DESCR_PROPS_STRINGS                 0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_STRING_0 | ||||
| #define USB_CFG_DESCR_PROPS_STRING_0                0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||
| #define USB_CFG_DESCR_PROPS_STRING_VENDOR           0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_STRING_DEVICE | ||||
| #define USB_CFG_DESCR_PROPS_STRING_DEVICE           0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||
| #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0 | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_HID | ||||
| #define USB_CFG_DESCR_PROPS_HID                     0 | ||||
| #endif | ||||
| #if !(USB_CFG_DESCR_PROPS_HID_REPORT) | ||||
| #   undef USB_CFG_DESCR_PROPS_HID_REPORT | ||||
| #   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */ | ||||
| #       define USB_CFG_DESCR_PROPS_HID_REPORT       USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH | ||||
| #   else | ||||
| #       define USB_CFG_DESCR_PROPS_HID_REPORT       0 | ||||
| #   endif | ||||
| #endif | ||||
| #ifndef USB_CFG_DESCR_PROPS_UNKNOWN | ||||
| #define USB_CFG_DESCR_PROPS_UNKNOWN                 0 | ||||
| #endif | ||||
|  | ||||
| /* ------------------ forward declaration of descriptors ------------------- */ | ||||
| /* If you use external static descriptors, they must be stored in global | ||||
|  * arrays as declared below: | ||||
|  */ | ||||
| #ifndef __ASSEMBLER__ | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| char usbDescriptorDevice[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| char usbDescriptorConfiguration[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| char usbDescriptorHidReport[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| char usbDescriptorString0[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| int usbDescriptorStringVendor[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| int usbDescriptorStringDevice[]; | ||||
|  | ||||
| extern | ||||
| #if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM) | ||||
| PROGMEM | ||||
| #endif | ||||
| int usbDescriptorStringSerialNumber[]; | ||||
|  | ||||
| #endif /* __ASSEMBLER__ */ | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
| /* ------------------------ General Purpose Macros ------------------------- */ | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| #define USB_CONCAT(a, b)            a ## b | ||||
| #define USB_CONCAT_EXPANDED(a, b)   USB_CONCAT(a, b) | ||||
|  | ||||
| #define USB_OUTPORT(name)           USB_CONCAT(PORT, name) | ||||
| #define USB_INPORT(name)            USB_CONCAT(PIN, name) | ||||
| #define USB_DDRPORT(name)           USB_CONCAT(DDR, name) | ||||
| /* The double-define trick above lets us concatenate strings which are | ||||
|  * defined by macros. | ||||
|  */ | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
| /* ------------------------- Constant definitions -------------------------- */ | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| #if !defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID | ||||
| static uchar Warning_You_should_define_USB_CFG_VENDOR_ID_and_USB_CFG_DEVICE_ID_in_usbconfig_h; | ||||
| /* The unused variable above should generate a warning on all compilers. IAR cc | ||||
|  * does not understand the "#warning" preprocessor direcetive. | ||||
|  * If the user has not defined IDs, we default to obdev's free IDs. | ||||
|  * See USBID-License.txt for details. | ||||
|  */ | ||||
| #endif | ||||
|  | ||||
| /* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */ | ||||
| #ifndef USB_CFG_VENDOR_ID | ||||
| #   define  USB_CFG_VENDOR_ID   0xc0, 0x16  /* 5824 in dec, stands for VOTI */ | ||||
| #endif | ||||
|  | ||||
| #ifndef USB_CFG_DEVICE_ID | ||||
| #   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH | ||||
| #       define USB_CFG_DEVICE_ID    0xdf, 0x05  /* 1503 in dec, shared PID for HIDs */ | ||||
| #   elif USB_CFG_INTERFACE_CLASS == 2 | ||||
| #       define USB_CFG_DEVICE_ID    0xe1, 0x05  /* 1505 in dec, shared PID for CDC Modems */ | ||||
| #   else | ||||
| #       define USB_CFG_DEVICE_ID    0xdc, 0x05  /* 1500 in dec, obdev's free PID */ | ||||
| #   endif | ||||
| #endif | ||||
|  | ||||
| #ifndef USB_BUFFER_SECTION | ||||
| #   define  USB_BUFFER_SECTION  ".bss"      /* if user has not selected a named section */ | ||||
| #endif | ||||
|  | ||||
| /* Derive Output, Input and DataDirection ports from port names */ | ||||
| #ifndef USB_CFG_IOPORTNAME | ||||
| #error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h" | ||||
| #endif | ||||
|  | ||||
| #define USBOUT          USB_OUTPORT(USB_CFG_IOPORTNAME) | ||||
| #define USB_PULLUP_OUT  USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||
| #define USBIN           USB_INPORT(USB_CFG_IOPORTNAME) | ||||
| #define USBDDR          USB_DDRPORT(USB_CFG_IOPORTNAME) | ||||
| #define USB_PULLUP_DDR  USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||
|  | ||||
| #define USBMINUS    USB_CFG_DMINUS_BIT | ||||
| #define USBPLUS     USB_CFG_DPLUS_BIT | ||||
| #define USBIDLE     (1<<USB_CFG_DMINUS_BIT) /* value representing J state */ | ||||
| #define USBMASK     ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT))  /* mask for USB I/O bits */ | ||||
|  | ||||
| /* defines for backward compatibility with older driver versions: */ | ||||
| #define USB_CFG_IOPORT          USB_OUTPORT(USB_CFG_IOPORTNAME) | ||||
| #ifdef USB_CFG_PULLUP_IOPORTNAME | ||||
| #define USB_CFG_PULLUP_IOPORT   USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #define USB_BUFSIZE     11  /* PID, 8 bytes data, 2 bytes CRC */ | ||||
|  | ||||
| /* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */ | ||||
|  | ||||
| #ifndef USB_INTR_CFG    /* allow user to override our default */ | ||||
| #   if defined  EICRA | ||||
| #       define USB_INTR_CFG EICRA | ||||
| #   else | ||||
| #       define USB_INTR_CFG MCUCR | ||||
| #   endif | ||||
| #endif | ||||
| #ifndef USB_INTR_CFG_SET    /* allow user to override our default */ | ||||
| #   define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01))    /* cfg for rising edge */ | ||||
| #endif | ||||
| #ifndef USB_INTR_CFG_CLR    /* allow user to override our default */ | ||||
| #   define USB_INTR_CFG_CLR 0    /* no bits to clear */ | ||||
| #endif | ||||
|  | ||||
| #ifndef USB_INTR_ENABLE     /* allow user to override our default */ | ||||
| #   if defined GIMSK | ||||
| #       define USB_INTR_ENABLE  GIMSK | ||||
| #   elif defined EIMSK | ||||
| #       define USB_INTR_ENABLE  EIMSK | ||||
| #   else | ||||
| #       define USB_INTR_ENABLE  GICR | ||||
| #   endif | ||||
| #endif | ||||
| #ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */ | ||||
| #   define USB_INTR_ENABLE_BIT  INT0 | ||||
| #endif | ||||
|  | ||||
| #ifndef USB_INTR_PENDING    /* allow user to override our default */ | ||||
| #   if defined  EIFR | ||||
| #       define USB_INTR_PENDING EIFR | ||||
| #   else | ||||
| #       define USB_INTR_PENDING GIFR | ||||
| #   endif | ||||
| #endif | ||||
| #ifndef USB_INTR_PENDING_BIT    /* allow user to override our default */ | ||||
| #   define USB_INTR_PENDING_BIT INTF0 | ||||
| #endif | ||||
|  | ||||
| /* | ||||
| The defines above don't work for the following chips | ||||
| at90c8534: no ISC0?, no PORTB, can't find a data sheet | ||||
| at86rf401: no PORTB, no MCUCR etc, low clock rate | ||||
| atmega103: no ISC0? (maybe omission in header, can't find data sheet) | ||||
| atmega603: not defined in avr-libc | ||||
| at43usb320, at43usb355, at76c711: have USB anyway | ||||
| at94k: is different... | ||||
|  | ||||
| at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM | ||||
| */ | ||||
|  | ||||
| /* ------------------------------------------------------------------------- */ | ||||
| /* ----------------- USB Specification Constants and Types ----------------- */ | ||||
| /* ------------------------------------------------------------------------- */ | ||||
|  | ||||
| /* USB Token values */ | ||||
| #define USBPID_SETUP    0x2d | ||||
| #define USBPID_OUT      0xe1 | ||||
| #define USBPID_IN       0x69 | ||||
| #define USBPID_DATA0    0xc3 | ||||
| #define USBPID_DATA1    0x4b | ||||
|  | ||||
| #define USBPID_ACK      0xd2 | ||||
| #define USBPID_NAK      0x5a | ||||
| #define USBPID_STALL    0x1e | ||||
|  | ||||
| #ifndef __ASSEMBLER__ | ||||
| typedef union usbWord{ | ||||
|     unsigned    word; | ||||
|     uchar       bytes[2]; | ||||
| }usbWord_t; | ||||
|  | ||||
| typedef struct usbRequest{ | ||||
|     uchar       bmRequestType; | ||||
|     uchar       bRequest; | ||||
|     usbWord_t   wValue; | ||||
|     usbWord_t   wIndex; | ||||
|     usbWord_t   wLength; | ||||
| }usbRequest_t; | ||||
| /* This structure matches the 8 byte setup request */ | ||||
| #endif | ||||
|  | ||||
| /* bmRequestType field in USB setup: | ||||
|  * d t t r r r r r, where | ||||
|  * d ..... direction: 0=host->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__ */ | ||||
							
								
								
									
										784
									
								
								firmware/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										784
									
								
								firmware/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,784 @@ | ||||
| /* Name: usbdrvasm.S | ||||
|  * Project: AVR USB driver | ||||
|  * Author: Christian Starkjohann | ||||
|  * Creation Date: 2004-12-29 | ||||
|  * Tabsize: 4 | ||||
|  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||
|  * License: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: usbdrvasm.S,v 1.1 2006/10/28 12:40:42 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 <avr/io.h> /* 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, usbInputBuf | ||||
|     extern  usbCurrentTok, usbRxLen, usbRxToken, usbAppBuf, 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__ */ | ||||
|  | ||||
|  | ||||
| SIG_INTERRUPT0: | ||||
| ;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: 32 cycles -> max 25 cycles interrupt disable | ||||
| ;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes | ||||
| usbInterrupt: | ||||
| ;order of registers pushed: | ||||
| ;x1, SREG, x2, cnt, shift, [YH, YL, x3] | ||||
|     push    x1              ;2  push only what is necessary to sync with edge ASAP | ||||
|     in      x1, SREG        ;1 | ||||
|     push    x1              ;2 | ||||
| ;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) | ||||
| #if !USB_CFG_SAMPLE_EXACT | ||||
|     ldi     x1, 5           ;1 setup a timeout for waitForK | ||||
| #endif | ||||
| waitForJ: | ||||
|     sbis    USBIN, USBMINUS ;1 wait for D- == 1 | ||||
|     rjmp    waitForJ        ;2 | ||||
| #if USB_CFG_SAMPLE_EXACT | ||||
| ;The following code represents the unrolled loop in the else branch. It | ||||
| ;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 | ||||
|     nop | ||||
|     nop2 | ||||
| foundK: | ||||
| #else | ||||
| waitForK: | ||||
|     dec     x1              ;1 | ||||
|     sbic    USBIN, USBMINUS ;1 wait for D- == 0 | ||||
|     brne    waitForK        ;2 | ||||
| #endif | ||||
| ;{2, 6} 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: | ||||
|     push    x2              ;2 | ||||
|     push    cnt             ;2 | ||||
|     push    shift           ;2 | ||||
| shortcutEntry: | ||||
|     ldi     cnt, 1          ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled) | ||||
|     ldi     x2, 1<<USB_CFG_DPLUS_BIT    ;1 -> 8   edge sync ended with D- == 0 | ||||
| ;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure) | ||||
| waitNoChange: | ||||
|     in      x1, USBIN       ;1 <-- sample, timing: edge + {2, 6} cycles | ||||
|     eor     x2, x1          ;1 | ||||
|     sbrc    x2, USBMINUS    ;1 | 2 | ||||
|     ldi     cnt, 2          ;1 | 0 cnt = numBits - 1 (because dec follows) | ||||
|     mov     x2, x1          ;1 | ||||
|     dec     cnt             ;1 | ||||
|     brne    waitNoChange    ;2 | 1 | ||||
|     sbrc    x1, USBMINUS    ;2 | ||||
|     rjmp    sofError        ;0 two consecutive "1" bits -> framing error | ||||
| ;start reading data, but don't check for bitstuffing because these are the | ||||
| ;first bits. Use the cycles for initialization instead. Note that we read and | ||||
| ;store the binary complement of the data stream because eor results in 1 for | ||||
| ;a change and 0 for no change. | ||||
|     in      x1, USBIN       ;1 <-- sample bit 0, timing: edge + {3, 7} cycles | ||||
|     eor     x2, x1          ;1 | ||||
|     ldi     shift, 0x00     ;1 prepare for bitstuff check later on in loop | ||||
|     bst     x2, USBMINUS    ;1 | ||||
|     bld     shift, 0        ;1 | ||||
|     push    YH              ;2 -> 7 | ||||
|     in      x2, USBIN       ;1 <-- sample bit 1, timing: edge + {2, 6} cycles | ||||
|     eor     x1, x2          ;1 | ||||
|     bst     x1, USBMINUS    ;1 | ||||
|     bld     shift, 1        ;1 | ||||
|     push    YL              ;2 | ||||
|     lds     YL, usbInputBuf ;2 -> 8 | ||||
|     in      x1, USBIN       ;1 <-- sample bit 2, timing: edge + {2, 6} cycles | ||||
|     eor     x2, x1          ;1 | ||||
|     bst     x2, USBMINUS    ;1 | ||||
|     bld     shift, 2        ;1 | ||||
|     ldi     cnt, USB_BUFSIZE;1 | ||||
|     ldi     YH, hi8(usbRxBuf);1 assume that usbRxBuf does not cross a page | ||||
|     push    x3              ;2 -> 8 | ||||
|     in      x2, USBIN       ;1 <-- sample bit 3, timing: edge + {2, 6} cycles | ||||
|     eor     x1, x2          ;1 | ||||
|     bst     x1, USBMINUS    ;1 | ||||
|     bld     shift, 3        ;1 | ||||
|     ser     x3              ;1 | ||||
|     nop                     ;1 | ||||
|     rjmp    rxbit4          ;2 -> 8 | ||||
|  | ||||
| shortcutToStart:            ;{,43} into next frame: max 5.5 sync bits missed | ||||
| #if !USB_CFG_SAMPLE_EXACT | ||||
|     ldi     x1, 5           ;2 setup timeout | ||||
| #endif | ||||
| waitForJ1: | ||||
|     sbis    USBIN, USBMINUS ;1 wait for D- == 1 | ||||
|     rjmp    waitForJ1       ;2 | ||||
| #if USB_CFG_SAMPLE_EXACT | ||||
| ;The following code represents the unrolled loop in the else branch. It | ||||
| ;results in a sampling window of 1/4 bit which meets the spec. | ||||
|     sbis    USBIN, USBMINUS | ||||
|     rjmp    foundK1 | ||||
|     sbis    USBIN, USBMINUS | ||||
|     rjmp    foundK1 | ||||
|     sbis    USBIN, USBMINUS | ||||
|     rjmp    foundK1 | ||||
|     nop | ||||
|     nop2 | ||||
| foundK1: | ||||
| #else | ||||
| waitForK1: | ||||
|     dec     x1              ;1 | ||||
|     sbic    USBIN, USBMINUS ;1 wait for D- == 0 | ||||
|     brne    waitForK1       ;2 | ||||
| #endif | ||||
|     pop     YH              ;2 correct stack alignment | ||||
|     nop2                    ;2 delay for the same time as the pushes in the original code | ||||
|     rjmp    shortcutEntry   ;2 | ||||
|  | ||||
| ; ################# receiver loop ################# | ||||
| ; extra jobs done during bit interval: | ||||
| ; bit 6:    se0 check | ||||
| ; bit 7:    or, store, clear | ||||
| ; bit 0:    recover from delay  [SE0 is unreliable here due to bit dribbling in hubs] | ||||
| ; bit 1:    se0 check | ||||
| ; bit 2:    se0 check | ||||
| ; bit 3:    overflow check | ||||
| ; bit 4:    se0 check | ||||
| ; bit 5:    rjmp | ||||
|  | ||||
| ; stuffed* helpers have the functionality of a subroutine, but we can't afford | ||||
| ; the overhead of a call. We therefore need a separate routine for each caller | ||||
| ; which jumps back appropriately. | ||||
|  | ||||
| stuffed5:               ;1 for branch taken | ||||
|     in      x2, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x2, USBMASK ;1 | ||||
|     breq    se0a        ;1 | ||||
|     andi    x3, ~0x20   ;1 | ||||
|     ori     shift, 0x20 ;1 | ||||
|     rjmp    rxbit6      ;2 | ||||
|  | ||||
| stuffed6:               ;1 for branch taken | ||||
|     in      x1, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0a        ;1 | ||||
|     andi    x3, ~0x40   ;1 | ||||
|     ori     shift, 0x40 ;1 | ||||
|     rjmp    rxbit7      ;2 | ||||
|  | ||||
| ; This is somewhat special because it has to compensate for the delay in bit 7 | ||||
| stuffed7:               ;1 for branch taken | ||||
|     andi    x1, USBMASK ;1 already sampled by caller | ||||
|     breq    se0a        ;1 | ||||
|     mov     x2, x1      ;1 ensure correct NRZI sequence | ||||
|     ori     shift, 0x80 ;1 no need to set reconstruction in x3: shift has already been used | ||||
|     in      x1, USBIN   ;1 <-- sample bit 0 | ||||
|     rjmp    unstuffed7  ;2 | ||||
|  | ||||
| stuffed0:               ;1 for branch taken | ||||
|     in      x1, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0a        ;1 | ||||
|     andi    x3, ~0x01   ;1 | ||||
|     ori     shift, 0x01 ;1 | ||||
|     rjmp    rxbit1      ;2 | ||||
|  | ||||
| ;----------------------------- | ||||
| rxLoop: | ||||
|     breq    stuffed5    ;1 | ||||
| rxbit6: | ||||
|     in      x1, USBIN   ;1 <-- sample bit 6 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0a        ;1 | ||||
|     eor     x2, x1      ;1 | ||||
|     bst     x2, USBMINUS;1 | ||||
|     bld     shift, 6    ;1 | ||||
|     cpi     shift, 0x02 ;1 | ||||
|     brlo    stuffed6    ;1 | ||||
| rxbit7: | ||||
|     in      x2, USBIN   ;1 <-- sample bit 7 | ||||
|     eor     x1, x2      ;1 | ||||
|     bst     x1, USBMINUS;1 | ||||
|     bld     shift, 7    ;1 | ||||
|     eor     x3, shift   ;1 x3 is 0 at bit locations we changed, 1 at others | ||||
|     st      y+, x3      ;2 the eor above reconstructed modified bits and inverted rx data | ||||
|     ser     x3          ;1 | ||||
| rxbit0: | ||||
|     in      x1, USBIN   ;1 <-- sample bit 0 | ||||
|     cpi     shift, 0x04 ;1 | ||||
|     brlo    stuffed7    ;1 | ||||
| unstuffed7: | ||||
|     eor     x2, x1      ;1 | ||||
|     bst     x2, USBMINUS;1 | ||||
|     bld     shift, 0    ;1 | ||||
|     andi    shift, 0xf9 ;1 | ||||
|     breq    stuffed0    ;1 | ||||
| rxbit1: | ||||
|     in      x2, USBIN   ;1 <-- sample bit 1 | ||||
|     andi    x2, USBMASK ;1 | ||||
| se0a:                   ; enlarge jump range to SE0 | ||||
|     breq    se0         ;1 check for SE0 more often close to start of byte | ||||
|     eor     x1, x2      ;1 | ||||
|     bst     x1, USBMINUS;1 | ||||
|     bld     shift, 1    ;1 | ||||
|     andi    shift, 0xf3 ;1 | ||||
|     breq    stuffed1    ;1 | ||||
| rxbit2: | ||||
|     in      x1, USBIN   ;1 <-- sample bit 2 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     eor     x2, x1      ;1 | ||||
|     bst     x2, USBMINUS;1 | ||||
|     bld     shift, 2    ;1 | ||||
|     andi    shift, 0xe7 ;1 | ||||
|     breq    stuffed2    ;1 | ||||
| rxbit3: | ||||
|     in      x2, USBIN   ;1 <-- sample bit 3 | ||||
|     eor     x1, x2      ;1 | ||||
|     bst     x1, USBMINUS;1 | ||||
|     bld     shift, 3    ;1 | ||||
|     dec     cnt         ;1  check for buffer overflow | ||||
|     breq    overflow    ;1 | ||||
|     andi    shift, 0xcf ;1 | ||||
|     breq    stuffed3    ;1 | ||||
| rxbit4: | ||||
|     in      x1, USBIN   ;1 <-- sample bit 4 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     eor     x2, x1      ;1 | ||||
|     bst     x2, USBMINUS;1 | ||||
|     bld     shift, 4    ;1 | ||||
|     andi    shift, 0x9f ;1 | ||||
|     breq    stuffed4    ;1 | ||||
| rxbit5: | ||||
|     in      x2, USBIN   ;1 <-- sample bit 5 | ||||
|     eor     x1, x2      ;1 | ||||
|     bst     x1, USBMINUS;1 | ||||
|     bld     shift, 5    ;1 | ||||
|     andi    shift, 0x3f ;1 | ||||
|     rjmp    rxLoop      ;2 | ||||
| ;----------------------------- | ||||
|  | ||||
| stuffed1:               ;1 for branch taken | ||||
|     in      x2, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x2, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     andi    x3, ~0x02   ;1 | ||||
|     ori     shift, 0x02 ;1 | ||||
|     rjmp    rxbit2      ;2 | ||||
|  | ||||
| stuffed2:               ;1 for branch taken | ||||
|     in      x1, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     andi    x3, ~0x04   ;1 | ||||
|     ori     shift, 0x04 ;1 | ||||
|     rjmp    rxbit3      ;2 | ||||
|  | ||||
| stuffed3:               ;1 for branch taken | ||||
|     in      x2, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x2, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     andi    x3, ~0x08   ;1 | ||||
|     ori     shift, 0x08 ;1 | ||||
|     rjmp    rxbit4      ;2 | ||||
|  | ||||
| stuffed4:               ;1 for branch taken | ||||
|     in      x1, USBIN   ;1 <-- sample @ +1 | ||||
|     andi    x1, USBMASK ;1 | ||||
|     breq    se0         ;1 | ||||
|     andi    x3, ~0x10   ;1 | ||||
|     ori     shift, 0x10 ;1 | ||||
|     rjmp    rxbit5      ;2 | ||||
|  | ||||
| ;################ end receiver loop ############### | ||||
|  | ||||
| overflow:                   ; ignore package if buffer overflow | ||||
|     rjmp    rxDoReturn      ; enlarge jump range | ||||
|  | ||||
| ;This is the only non-error exit point for the software receiver loop | ||||
| ;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0 | ||||
| ;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start | ||||
| ;we don't check any CRCs here because there is no time left. | ||||
| se0:                            ;{-6, 2} from end of SE0 / {,4} into next frame | ||||
|     mov     cnt, YL             ;1 assume buffer in lower 256 bytes of memory | ||||
|     lds     YL, usbInputBuf     ;2 reposition to buffer start | ||||
|     sub     cnt, YL             ;1 length of message | ||||
|     ldi     x1, 1<<USB_INTR_PENDING_BIT ;1 | ||||
|     cpi     cnt, 3              ;1 | ||||
|     out     USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame | ||||
|     brlo    rxDoReturn          ;1 ensure valid packet size, ignore others | ||||
|     ld      x1, y               ;2 PID | ||||
|     ldd     x2, y+1             ;2 ADDR + 1 bit endpoint number | ||||
|     mov     x3, x2              ;1 store for endpoint number | ||||
|     andi    x2, 0x7f            ;1 mask endpoint number bit | ||||
|     lds     shift, usbDeviceAddr;2 | ||||
|     cpi     x1, USBPID_SETUP    ;1 | ||||
|     breq    isSetupOrOut        ;2 -> 19 = {13, 21} from SE0 end | ||||
|     cpi     x1, USBPID_OUT      ;1 | ||||
|     breq    isSetupOrOut        ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame | ||||
|     cpi     x1, USBPID_IN       ;1 | ||||
|     breq    handleIn            ;1 | ||||
| #define USB_DATA_MASK   ~(USBPID_DATA0 ^ USBPID_DATA1) | ||||
|     andi    x1, USB_DATA_MASK   ;1 | ||||
|     cpi     x1, USBPID_DATA0 & USB_DATA_MASK ;1 | ||||
|     brne    rxDoReturn          ;1 not a data PID -- ignore | ||||
| isData: | ||||
|     lds     x2, usbCurrentTok   ;2 | ||||
|     tst     x2                  ;1 | ||||
|     breq    rxDoReturn          ;1 for other device or spontaneous data -- ignore | ||||
|     lds     x1, usbRxLen        ;2 | ||||
|     cpi     x1, 0               ;1 | ||||
|     brne    sendNakAndReti      ;1 no buffer space available / {30, 38} from SE0 end | ||||
| ; 2006-03-11: The following two lines fix a problem where the device was not | ||||
| ; recognized if usbPoll() was called less frequently than once every 4 ms. | ||||
|     cpi     cnt, 4              ;1 zero sized data packets are status phase only -- ignore and ack | ||||
|     brmi    sendAckAndReti      ;1 keep rx buffer clean -- we must not NAK next SETUP | ||||
|     sts     usbRxLen, cnt       ;2 store received data, swap buffers | ||||
|     sts     usbRxToken, x2      ;2 | ||||
|     lds     x1, usbAppBuf       ;2 | ||||
|     sts     usbAppBuf, YL       ;2 | ||||
|     sts     usbInputBuf, x1     ;2 buffers now swapped | ||||
|     rjmp    sendAckAndReti      ;2 -> {43, 51} from SE0 end | ||||
|  | ||||
| handleIn:                       ; {18, 26} from SE0 end | ||||
|     cp      x2, shift           ;1 shift contains our device addr | ||||
|     brne    rxDoReturn          ;1 other device | ||||
| #if USB_CFG_HAVE_INTRIN_ENDPOINT | ||||
|     sbrc    x3, 7               ;2 x3 contains addr + endpoint | ||||
|     rjmp    handleIn1           ;0 | ||||
| #endif | ||||
|     lds     cnt, usbTxLen       ;2 | ||||
|     sbrc    cnt, 4              ;2 | ||||
|     rjmp    sendCntAndReti      ;0 -> {27, 35} from SE0 end | ||||
|     ldi     x1, USBPID_NAK      ;1 | ||||
|     sts     usbTxLen, x1        ;2 buffer is now free | ||||
|     ldi     YL, lo8(usbTxBuf)   ;1 | ||||
|     ldi     YH, hi8(usbTxBuf)   ;1 | ||||
|     rjmp    usbSendAndReti      ;2 -> {34, 43} from SE0 end | ||||
|  | ||||
| ; Comment about when to set usbTxLen to USBPID_NAK: | ||||
| ; We should set it back when we receive the ACK from the host. This would | ||||
| ; be simple to implement: One static variable which stores whether the last | ||||
| ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the | ||||
| ; ACK. However, we set it back immediately when we send the package, | ||||
| ; assuming that no error occurs and the host sends an ACK. We save one byte | ||||
| ; RAM this way and avoid potential problems with endless retries. The rest of | ||||
| ; the driver assumes error-free transfers anyway. | ||||
|  | ||||
| otherOutOrSetup: | ||||
|     clr     x1 | ||||
|     sts     usbCurrentTok, x1 | ||||
| rxDoReturn: | ||||
|     pop     x3                  ;2 | ||||
|     pop     YL                  ;2 | ||||
|     pop     YH                  ;2 | ||||
|     rjmp    sofError            ;2 | ||||
|  | ||||
| isSetupOrOut:                   ; we must be fast here -- a data package may follow / {,24} into next frame | ||||
|     cp      x2, shift           ;1 shift contains our device addr | ||||
|     brne    otherOutOrSetup     ;1 other device -- ignore | ||||
| #if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we need second OUT endpoint, store endpoint address */ | ||||
|     andi    x1, 0x7f            ;1 mask out MSb in token | ||||
|     andi    x3, 0x80            ;1 mask out all but endpoint address | ||||
|     or      x1, x3              ;1 merge endpoint into currentToken | ||||
|     sts     usbCurrentTok, x1   ;2 | ||||
|     brmi    dontResetEP0        ;1 endpoint 1 -> don't reset endpoint 0 input | ||||
| #else | ||||
|     sts     usbCurrentTok, x1   ;2 | ||||
| #endif | ||||
| ;A transmission can still have data in the output buffer while we receive a | ||||
| ;SETUP package with an IN phase. To avoid that the old data is sent as a reply, | ||||
| ;we abort transmission. We don't need to reset usbMsgLen because it is used | ||||
| ;from the main loop only where the setup is processed anyway. | ||||
|     ldi     x1, USBPID_NAK      ;1 | ||||
|     sts     usbTxLen, x1        ;2 abort transmission | ||||
| dontResetEP0: | ||||
|     pop     x3                  ;2 | ||||
|     pop     YL                  ;2 | ||||
|     in      x1, USB_INTR_PENDING;1 | ||||
|     sbrc    x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame | ||||
|     rjmp    shortcutToStart     ;2 save the pops and pushes -- a new interrupt is aready pending | ||||
| ;If the jump above was not taken, we can be at {,2} into the next frame here | ||||
|     pop     YH                  ;2 | ||||
| txDoReturn: | ||||
| sofError:                       ; error in start of frame -- ignore frame | ||||
|     ldi     x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag | ||||
|     out     USB_INTR_PENDING, x1;1 | ||||
|     pop     shift               ;2 | ||||
|     pop     cnt                 ;2 | ||||
|     pop     x2                  ;2 | ||||
|     pop     x1                  ;2 | ||||
|     out     SREG, x1            ;1 | ||||
|     pop     x1                  ;2 | ||||
|     reti                        ;4 -> {,21} into next frame -> up to 3 sync bits missed | ||||
|  | ||||
| sendCntAndReti:                 ; 19 cycles until SOP | ||||
|     mov     x3, cnt             ;1 | ||||
|     rjmp    usbSendX3           ;2 | ||||
| sendNakAndReti:                 ; 19 cycles until SOP | ||||
|     ldi     x3, USBPID_NAK      ;1 | ||||
|     rjmp    usbSendX3           ;2 | ||||
| sendAckAndReti:                 ; 17 cycles until SOP | ||||
|     ldi     x3, USBPID_ACK      ;1 | ||||
| usbSendX3: | ||||
|     ldi     YL, 20              ;1 'x3' is R20 | ||||
|     ldi     YH, 0               ;1 | ||||
|     ldi     cnt, 2              ;1 | ||||
| ;;;;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 | ||||
| usbSendAndReti:             ; SOP starts 13 cycles after call | ||||
|     push    x4              ;2 | ||||
|     ldi     x4, USBMASK     ;1 exor mask | ||||
|     sbi     USBOUT, USBMINUS;1 prepare idle state; D+ and D- must have been 0 (no pullups) | ||||
|     in      x1, USBOUT      ;1 port mirror for tx loop | ||||
|     sbi     USBDDR, USBMINUS;1 | ||||
|     sbi     USBDDR, USBPLUS ;1 set D+ and D- to output: acquire bus | ||||
| ; need not init x2 (bitstuff history) because sync starts with 0 | ||||
|     ldi     shift, 0x80     ;1 sync byte is first byte sent | ||||
|     rjmp    txLoop          ;2 -> 13 + 3 = 16 cycles until SOP | ||||
|  | ||||
| #if USB_CFG_HAVE_INTRIN_ENDPOINT    /* placed here due to relative jump range */ | ||||
| handleIn1:                  ;{23, 31} from SE0 | ||||
|     ldi     x1, USBPID_NAK  ;1 | ||||
| #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||
| ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint | ||||
|     ldd     x2, y+2         ;2 | ||||
|     sbrc    x2, 0           ;2 1 | ||||
|     rjmp    handleIn3       ;0 2 | ||||
| #endif | ||||
|     lds     cnt, usbTxLen1  ;2 | ||||
|     sbrc    cnt, 4          ;2 | ||||
|     rjmp    sendCntAndReti  ;0 | ||||
|     sts     usbTxLen1, x1   ;2 | ||||
|     ldi     YL, lo8(usbTxBuf1);1 | ||||
|     ldi     YH, hi8(usbTxBuf1);1 | ||||
|     rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {34, 42} from SE0 | ||||
|  | ||||
| #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||
| handleIn3: | ||||
|     lds     cnt, usbTxLen3  ;2 | ||||
|     sbrc    cnt, 4          ;2 | ||||
|     rjmp    sendCntAndReti  ;0 | ||||
|     sts     usbTxLen3, x1   ;2 | ||||
|     ldi     YL, lo8(usbTxBuf3);1 | ||||
|     ldi     YH, hi8(usbTxBuf3);1 | ||||
|     rjmp    usbSendAndReti  ;2 -> arrives at usbSendAndReti {39, 47} from SE0 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| 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 | ||||
|     ldi     x2, 0           ;1 | ||||
|     sec                     ;1 set carry so that brsh will not jump | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     rjmp    didStuff1       ;2 jump back 1 cycle earler | ||||
| bitstuff2:                  ;1 (for branch taken) | ||||
|     eor     x1, x4          ;1 | ||||
|     ldi     x2, 0           ;1 | ||||
|     rjmp    didStuff2       ;2 jump back 3 cycles earlier and do out | ||||
| bitstuff3:                  ;1 (for branch taken) | ||||
|     eor     x1, x4          ;1 | ||||
|     ldi     x2, 0           ;1 | ||||
|     rjmp    didStuff3       ;2 jump back earlier | ||||
|  | ||||
| txLoop: | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff0: | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     brsh    bitstuff0       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     ror     x2              ;1 | ||||
|     cpi     x2, 0xfc        ;1 | ||||
| didStuff1: | ||||
|     brsh    bitstuff1       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff2: | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     brsh    bitstuff2       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff3: | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     brsh    bitstuff3       ;1 | ||||
|     nop2                    ;2 | ||||
|     ld      x3, y+          ;2 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff4: | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     brsh    bitstuff4       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     ror     x2              ;1 | ||||
|     cpi     x2, 0xfc        ;1 | ||||
| didStuff5: | ||||
|     brsh    bitstuff5       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff6: | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     brsh    bitstuff6       ;1 | ||||
|     sbrs    shift, 0        ;1 | ||||
|     eor     x1, x4          ;1 | ||||
|     ror     shift           ;1 | ||||
|     ror     x2              ;1 | ||||
| didStuff7: | ||||
|     cpi     x2, 0xfc        ;1 | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     brsh    bitstuff7       ;1 | ||||
|     mov     shift, x3       ;1 | ||||
|     dec     cnt             ;1 | ||||
|     brne    txLoop          ;2 | 1 | ||||
|     cbr     x1, USBMASK     ;1 prepare SE0 [spec says EOP may be 15 to 18 cycles] | ||||
|     pop     x4              ;2 | ||||
|     out     USBOUT, x1      ;1 <-- out SE0 -- from now 2 bits = 16 cycles until bus idle | ||||
|     ldi     cnt, 2          ;| takes cnt * 3 cycles | ||||
| se0Delay:                   ;| | ||||
|     dec     cnt             ;| | ||||
|     brne    se0Delay        ;| -> 2 * 3 = 6 cycles | ||||
| ;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 | ||||
|     subi    YL, 20 + 2          ;1 | ||||
|     sbci    YH, 0               ;1 | ||||
|     breq    skipAddrAssign      ;2 | ||||
|     sts     usbDeviceAddr, x2   ;0  if not skipped: SE0 is one cycle longer | ||||
| skipAddrAssign: | ||||
| ;end of usbDeviceAddress transfer | ||||
|     ori     x1, USBIDLE     ;1 | ||||
|     in      x2, USBDDR      ;1 | ||||
|     cbr     x2, USBMASK     ;1 set both pins to input | ||||
|     out     USBOUT, x1      ;1 <-- out J (idle) -- end of SE0 (EOP signal) | ||||
|     cbr     x1, USBMASK     ;1 configure no pullup on both pins | ||||
|     pop     x3              ;2 | ||||
|     pop     YL              ;2 | ||||
|     out     USBDDR, x2      ;1 <-- release bus now | ||||
|     out     USBOUT, x1      ;1 set pullup state | ||||
|     pop     YH              ;2 | ||||
|     rjmp    txDoReturn      ;2 [we want to jump to rxDoReturn, but this saves cycles] | ||||
|  | ||||
|  | ||||
| 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 | ||||
| bitstuff5:                  ;1 (for branch taken) | ||||
|     eor     x1, x4          ;1 | ||||
|     ldi     x2, 0           ;1 | ||||
|     sec                     ;1 set carry so that brsh is not taken | ||||
|     out     USBOUT, x1      ;1 <-- out | ||||
|     rjmp    didStuff5       ;2 jump back 1 cycle earlier | ||||
| bitstuff6:                  ;1 (for branch taken) | ||||
|     eor     x1, x4          ;1 | ||||
|     ldi     x2, 0           ;1 | ||||
|     rjmp    didStuff6       ;2 jump back 3 cycles earlier and do out there | ||||
| bitstuff7:                  ;1 (for branch taken) | ||||
|     eor     x1, x4          ;1 | ||||
|     ldi     x2, 0           ;1 | ||||
|     rjmp    didStuff7       ;2 jump back 4 cycles earlier | ||||
|  | ||||
| ; ######################## 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 | ||||
							
								
								
									
										21
									
								
								firmware/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								firmware/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							| @@ -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: Proprietary, free under certain conditions. See Documentation. | ||||
|  * This Revision: $Id: usbdrvasm.asm,v 1.1 2006/10/28 12:40:42 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 | ||||
		Reference in New Issue
	
	Block a user