mirror of
https://github.com/raphnet/4nes4snes
synced 2024-12-21 14:38:50 -05:00
Initial revision
This commit is contained in:
commit
6c88641e07
36
Changelog.txt
Normal file
36
Changelog.txt
Normal file
@ -0,0 +1,36 @@
|
||||
--- v1.4 (Dec 3, 2006)
|
||||
- Added support for Atari style joysticks. Two button
|
||||
variations (SMS) are supported.
|
||||
- Added padding to nes report descriptor. This makes it
|
||||
work correcly on windows. Linux sure is tolerant...
|
||||
|
||||
--- v1.3 (Oct 28, 2006)
|
||||
- Fixed a bug in nes.c, snes.c and snesmouse.c which prevented the pullup
|
||||
on the data pin (from device) from being enabled. This resulted in
|
||||
random button toggling when no controller was connected.
|
||||
- A separate USB PID is used when in NES mode.
|
||||
- PD1 is now left as input (no pullup) since it is shorted with PD0 on the
|
||||
PCB rev.C. (And I didnt want to scrap a batch of 50 pcb nor cut a track
|
||||
and solder a wire 50 times...)
|
||||
|
||||
--- v1.2 (Oct 6, 2006)
|
||||
Added serial number
|
||||
Added support for Snes mouse (auto detected in snes mode)
|
||||
- Default speed: Low
|
||||
- 3 Speeds selectable by holding some buttons at
|
||||
startup (USB connect or mouse connect)
|
||||
Left+right buttons: Low speed
|
||||
Left buton: Medium speed
|
||||
Right button: High speed
|
||||
No button: Default speed when USB connect,
|
||||
continue using same speed for mouse (re)-connect
|
||||
|
||||
--- v1.1
|
||||
Reworked report descriptor for better behaviour
|
||||
in Windows and Mac OS X
|
||||
|
||||
--- v1.0 (Jul 5, 2006)
|
||||
Initial release:
|
||||
Snes gamepad support
|
||||
Nes gamepad support
|
||||
|
458
License.txt
Normal file
458
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.
|
70
Makefile
Normal file
70
Makefile
Normal file
@ -0,0 +1,70 @@
|
||||
# Name: Makefile
|
||||
# Project: HIDKeys
|
||||
# Author: Christian Starkjohann
|
||||
# Creation Date: 2006-02-02
|
||||
# Tabsize: 4
|
||||
# Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
# License: Proprietary, free under certain conditions. See Documentation.
|
||||
# This Revision: $Id: Makefile,v 1.1 2007-03-25 02:59:30 raph Exp $
|
||||
|
||||
UISP = uisp -dprog=stk500 -dpart=atmega8 -dserial=/dev/avr
|
||||
COMPILE = avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 #-DDEBUG_LEVEL=1
|
||||
COMMON_OBJS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o
|
||||
|
||||
OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o snes.o devdesc.o
|
||||
|
||||
|
||||
# symbolic targets:
|
||||
all: main.hex
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $< -o $@
|
||||
|
||||
.S.o:
|
||||
$(COMPILE) -x assembler-with-cpp -c $< -o $@
|
||||
# "-x assembler-with-cpp" should not be necessary since this is the default
|
||||
# file type for the .S (with capital S) extension. However, upper case
|
||||
# characters are not always preserved on Windows. To ensure WinAVR
|
||||
# compatibility define the file type manually.
|
||||
|
||||
.c.s:
|
||||
$(COMPILE) -S $< -o $@
|
||||
|
||||
|
||||
clean:
|
||||
rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s
|
||||
|
||||
# file targets:
|
||||
main.bin: $(COMMON_OBJS) snes.o devdesc.o
|
||||
$(COMPILE) -o main.bin $(OBJECTS) -Wl,-Map=main.map
|
||||
|
||||
main.hex: main.bin
|
||||
rm -f main.hex main.eep.hex
|
||||
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
|
||||
./checksize main.bin
|
||||
|
||||
flash: all
|
||||
#$(UISP) --erase --upload --verify if=main.hex
|
||||
$(UISP) --erase --upload if=main.hex
|
||||
|
||||
# Fuse high byte:
|
||||
# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)
|
||||
# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0
|
||||
# | | | | | +-------- BOOTSZ1
|
||||
# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase)
|
||||
# | | | +-------------- CKOPT (full output swing)
|
||||
# | | +---------------- SPIEN (allow serial programming)
|
||||
# | +------------------ WDTON (WDT not always on)
|
||||
# +-------------------- RSTDISBL (reset pin is enabled)
|
||||
# Fuse low byte:
|
||||
# 0x9f = 1 0 0 1 1 1 1 1
|
||||
# ^ ^ \ / \--+--/
|
||||
# | | | +------- CKSEL 3..0 (external >8M crystal)
|
||||
# | | +--------------- SUT 1..0 (crystal osc, BOD enabled)
|
||||
# | +------------------ BODEN (BrownOut Detector enabled)
|
||||
# +-------------------- BODLEVEL (2.7V)
|
||||
fuse:
|
||||
$(UISP) --wr_fuse_h=0xc9 --wr_fuse_l=0x9f
|
||||
|
||||
|
||||
|
75
Readme.txt
Normal file
75
Readme.txt
Normal file
@ -0,0 +1,75 @@
|
||||
This is 4nes3snes Readme.txt file.
|
||||
|
||||
Table of contents:
|
||||
|
||||
1) What is 4nes3snes?
|
||||
2) USB Implementation
|
||||
3) Compilation and installation
|
||||
4) License
|
||||
5) About the vendor id/product id pair:
|
||||
6) Where do I get more information and updates?
|
||||
|
||||
|
||||
1) What is 4nes3snes?
|
||||
--------------------
|
||||
4nes3snes if a firmware for Atmel ATmega8 which
|
||||
allows one to connect NES and SNES controllers to
|
||||
a PC using a single circuit. Here are the possible
|
||||
combinations:
|
||||
- 4 NES controllers
|
||||
- 3 SNES controllers
|
||||
- 2 SNES controllers + 2 NES controllers
|
||||
- 1 SNES controller + 3 NES controllers
|
||||
|
||||
The device connects to an USB port and appears to the
|
||||
PC as standard HID joystick with 4 axes and 32 buttons.
|
||||
The two first controllers get their D-PADs mapped to a
|
||||
pair of axes. The remaining controllers D-PADs
|
||||
are mapped to ordinary buttons.
|
||||
|
||||
|
||||
2) USB Implementation
|
||||
------------------
|
||||
4nes3snes uses the software-only usb driver from Objective Development.
|
||||
See http://www.obdev.at/products/avrusb/index.html
|
||||
|
||||
A good portion of 4nes3snes is based on Objective Development's
|
||||
HIDKeys example.
|
||||
|
||||
|
||||
3) Compilation and installation
|
||||
----------------------------
|
||||
First, you must compile it. To compile, you need a working avr-gcc and
|
||||
avr-libc. Under linux or cygwin, simply type make in the project directory.
|
||||
(assuming avr-gcc is in your path).
|
||||
|
||||
Next, you must upload the generated file (main.hex) to the Atmega8 using
|
||||
whatever tools you like. Personally, I use uisp. The 'flash' and 'fuse'
|
||||
targets in the makefile is a good example about how to use it.
|
||||
|
||||
The Atmega fuse bits must also be set properly. The idea behind this is to
|
||||
enable the external 12mhz crystal instead of the internal clock. Check the
|
||||
makefile for good fuse bytes values.
|
||||
|
||||
|
||||
4) License
|
||||
-------
|
||||
4nes3snes is released under Objective Development's extended GPL
|
||||
license. See License.txt
|
||||
|
||||
|
||||
5) About the vendor id/product id pair:
|
||||
------------------------------------
|
||||
Please dont re-use them for other projects. Instead,
|
||||
obtain your own. I got mine from mecanique:
|
||||
http://www.mecanique.co.uk/products/usb/pid.html
|
||||
|
||||
|
||||
6) Where do I get more information and updates?
|
||||
--------------------------------------------
|
||||
Visit 4nes3snes page:
|
||||
http://www.raphnet.net/electronique/4nes_3snes/index_en.php
|
||||
you may also contact me by email:
|
||||
Raphael Assenat <raph@raphnet.net>
|
||||
|
||||
|
35
checksize
Executable file
35
checksize
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
# Name: checksize
|
||||
# Project: AVR-USB
|
||||
# Author: Christian Starkjohann
|
||||
# Creation Date: 2004-12-29
|
||||
# Tabsize: 4
|
||||
# Copyright: (c) 2005 OBJECTIVE DEVELOPMENT Software GmbH.
|
||||
# Revision: $Id: checksize,v 1.1 2007-03-25 02:59:31 raph Exp $
|
||||
|
||||
error=0
|
||||
codelimit=8192
|
||||
datalimit=960 # leave 64 bytes for stack
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
codelimit="$2"
|
||||
fi
|
||||
if [ $# -gt 2 ]; then
|
||||
datalimit="$3"
|
||||
fi
|
||||
|
||||
set -- `avr-size -d "$1" | awk '/[0-9]/ {print $1 + $2, $2 + $3, $2}'`
|
||||
if [ $1 -gt $codelimit ]; then
|
||||
echo "*** code size $1 exceeds limit of $codelimit"
|
||||
error=1
|
||||
else
|
||||
echo "ROM: $1 bytes (data=$3)"
|
||||
fi
|
||||
if [ $2 -gt $datalimit ]; then
|
||||
echo "*** data size $2 exceeds limit of $datalimit"
|
||||
error=1
|
||||
else
|
||||
echo "RAM: $2 bytes"
|
||||
fi
|
||||
|
||||
exit $error
|
BIN
circuit/sch-connectors.png
Normal file
BIN
circuit/sch-connectors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
BIN
circuit/sch-core.png
Normal file
BIN
circuit/sch-core.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
36
devdesc.c
Normal file
36
devdesc.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include "devdesc.h"
|
||||
#include "usbconfig.h"
|
||||
|
||||
#define USBDESCR_DEVICE 1
|
||||
|
||||
const char usbDescrDevice[] PROGMEM = { /* USB device descriptor */
|
||||
18, /* sizeof(usbDescrDevice): 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 */
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
1, /* manufacturer string index */
|
||||
#else
|
||||
0, /* manufacturer string index */
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
2, /* product string index */
|
||||
#else
|
||||
0, /* product string index */
|
||||
#endif
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
3, /* serial number string index */
|
||||
#else
|
||||
0, /* serial number string index */
|
||||
#endif
|
||||
1, /* number of configurations */
|
||||
};
|
||||
|
||||
int getUsbDescrDevice_size(void) { return sizeof(usbDescrDevice); }
|
||||
|
10
devdesc.h
Normal file
10
devdesc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _devdesc_h__
|
||||
#define _devdesc_h__
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
extern const char usbDescrDevice[] PROGMEM;
|
||||
int getUsbDescrDevice_size(void);
|
||||
|
||||
#endif // _devdesc_h__
|
||||
|
22
gamepad.h
Normal file
22
gamepad.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _gamepad_h__
|
||||
#define _gamepad_h__
|
||||
|
||||
typedef struct {
|
||||
// size of reports built by buildReport
|
||||
int report_size;
|
||||
|
||||
int reportDescriptorSize;
|
||||
void *reportDescriptor; // must be in flash
|
||||
|
||||
int deviceDescriptorSize; // if 0, use default
|
||||
void *deviceDescriptor; // must be in flash
|
||||
|
||||
void (*init)(void);
|
||||
void (*update)(void);
|
||||
char (*changed)(void);
|
||||
void (*buildReport)(unsigned char *buf);
|
||||
} Gamepad;
|
||||
|
||||
#endif // _gamepad_h__
|
||||
|
||||
|
18
leds.h
Normal file
18
leds.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _leds_h__
|
||||
#define _leds_h__
|
||||
|
||||
#ifndef PORTD
|
||||
#include <avr/io.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define LED_OFF()
|
||||
#define LED_ON();
|
||||
#define LED_TOGGLE();
|
||||
|
||||
//#define LED_OFF() do { PORTD |= 0x20; } while(0)
|
||||
//#define LED_ON() do { PORTD &= ~0x20; } while(0)
|
||||
//#define LED_TOGGLE() do { PORTD ^= 0x20; } while(0)
|
||||
|
||||
#endif
|
||||
|
218
main.c
Normal file
218
main.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* Name: main.c
|
||||
* Project: Multiple NES/SNES to USB converter
|
||||
* Author: Raphael Assenat <raph@raphnet.net>
|
||||
* Copyright: (C) 2007 Raphael Assenat <raph@raphnet.net>
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* Tabsize: 4
|
||||
* Comments: Based on HID-Test by Christian Starkjohann
|
||||
*/
|
||||
|
||||
#define F_CPU 12000000L
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/delay.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "usbdrv.h"
|
||||
#include "oddebug.h"
|
||||
#include "gamepad.h"
|
||||
|
||||
#include "snes.h"
|
||||
|
||||
#include "leds.h"
|
||||
#include "devdesc.h"
|
||||
|
||||
int usbCfgSerialNumberStringDescriptor[] PROGMEM = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LENGTH),
|
||||
'1', '0', '0', '0'
|
||||
};
|
||||
|
||||
static Gamepad *curGamepad;
|
||||
|
||||
|
||||
/* ----------------------- hardware I/O abstraction ------------------------ */
|
||||
|
||||
static void hardwareInit(void)
|
||||
{
|
||||
uchar i, j;
|
||||
|
||||
// init port C as input with pullup
|
||||
DDRC = 0x00;
|
||||
PORTC = 0xff;
|
||||
|
||||
/* 1101 1000 bin: activate pull-ups except on USB lines
|
||||
*
|
||||
* USB signals are on bit 0 and 2.
|
||||
*
|
||||
* Bit 1 is connected with bit 0 (rev.C pcb error), so the pullup
|
||||
* is not enabled.
|
||||
* */
|
||||
PORTD = 0xf8;
|
||||
|
||||
/* Usb pin are init as outputs */
|
||||
DDRD = 0x01 | 0x04;
|
||||
|
||||
|
||||
j = 0;
|
||||
while(--j){ /* USB Reset by device only required on Watchdog Reset */
|
||||
i = 0;
|
||||
while(--i); /* delay >10ms for USB reset */
|
||||
}
|
||||
DDRD = 0x00; /* 0000 0000 bin: remove USB reset condition */
|
||||
/* configure timer 0 for a rate of 12M/(1024 * 256) = 45.78 Hz (~22ms) */
|
||||
TCCR0 = 5; /* timer 0 prescaler: 1024 */
|
||||
|
||||
TCCR2 = (1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);
|
||||
OCR2 = 196; // for 60 hz
|
||||
|
||||
}
|
||||
|
||||
static uchar reportBuffer[18]; /* buffer for HID reports */
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ----------------------------- USB interface ----------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static uchar idleRate; /* in 4 ms units */
|
||||
|
||||
|
||||
uchar usbFunctionSetup(uchar data[8])
|
||||
{
|
||||
usbRequest_t *rq = (void *)data;
|
||||
|
||||
usbMsgPtr = reportBuffer;
|
||||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
|
||||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
|
||||
/* we only have one report type, so don't look at wValue */
|
||||
curGamepad->buildReport(reportBuffer);
|
||||
return curGamepad->report_size;
|
||||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
|
||||
usbMsgPtr = &idleRate;
|
||||
return 1;
|
||||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
|
||||
idleRate = rq->wValue.bytes[1];
|
||||
}
|
||||
}else{
|
||||
/* no vendor specific requests implemented */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char must_report = 0, first_run = 1;
|
||||
uchar idleCounter = 0;
|
||||
// int run_mode;
|
||||
|
||||
// led pin as output
|
||||
// DDRD |= 0x20;
|
||||
|
||||
#if 0
|
||||
/* Dip switch common: DB0, outputs: DB1 and DB2 */
|
||||
DDRB |= 0x01;
|
||||
DDRB &= ~0x06;
|
||||
|
||||
PORTB |= 0x06; /* enable pull up on DB1 and DB2 */
|
||||
PORTB &= ~0x01; /* Set DB0 to low */
|
||||
|
||||
_delay_ms(10); /* let pins settle */
|
||||
run_mode = (PINB & 0x06)>>1;
|
||||
|
||||
switch(run_mode)
|
||||
{
|
||||
default:
|
||||
case 3:
|
||||
curGamepad = snesGetGamepad();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
curGamepad = snesGetGamepad();
|
||||
|
||||
// configure report descriptor according to
|
||||
// the current gamepad
|
||||
rt_usbHidReportDescriptor = curGamepad->reportDescriptor;
|
||||
rt_usbHidReportDescriptorSize = curGamepad->reportDescriptorSize;
|
||||
|
||||
if (curGamepad->deviceDescriptor != 0)
|
||||
{
|
||||
rt_usbDeviceDescriptor = (void*)curGamepad->deviceDescriptor;
|
||||
rt_usbDeviceDescriptorSize = curGamepad->deviceDescriptorSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use descriptor from devdesc.c
|
||||
//
|
||||
rt_usbDeviceDescriptor = (void*)usbDescrDevice;
|
||||
rt_usbDeviceDescriptorSize = getUsbDescrDevice_size();
|
||||
}
|
||||
|
||||
//wdt_enable(WDTO_2S);
|
||||
hardwareInit();
|
||||
curGamepad->init();
|
||||
odDebugInit();
|
||||
usbInit();
|
||||
sei();
|
||||
DBG1(0x00, 0, 0);
|
||||
|
||||
|
||||
for(;;){ /* main event loop */
|
||||
wdt_reset();
|
||||
|
||||
// this must be called at each 50 ms or less
|
||||
usbPoll();
|
||||
|
||||
if (first_run) {
|
||||
curGamepad->update();
|
||||
first_run = 0;
|
||||
}
|
||||
|
||||
if(TIFR & (1<<TOV0)){ /* 22 ms timer */
|
||||
TIFR = 1<<TOV0;
|
||||
if(idleRate != 0){
|
||||
if(idleCounter > 4){
|
||||
idleCounter -= 5; /* 22 ms in units of 4 ms */
|
||||
}else{
|
||||
idleCounter = idleRate;
|
||||
must_report = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TIFR & (1<<OCF2))
|
||||
{
|
||||
TIFR = 1<<OCF2;
|
||||
if (!must_report)
|
||||
{
|
||||
curGamepad->update();
|
||||
if (curGamepad->changed()) {
|
||||
must_report = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(must_report)
|
||||
{
|
||||
if (usbInterruptIsReady())
|
||||
{
|
||||
|
||||
must_report = 0;
|
||||
|
||||
curGamepad->buildReport(reportBuffer);
|
||||
usbSetInterrupt(reportBuffer, curGamepad->report_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
339
snes.c
Normal file
339
snes.c
Normal file
@ -0,0 +1,339 @@
|
||||
/* Name: snes.c
|
||||
* Project: Multiple NES/SNES to USB converter
|
||||
* Author: Raphael Assenat <raph@raphnet.net>
|
||||
* Copyright: (C) 2007 Raphael Assenat <raph@raphnet.net>
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* Tabsize: 4
|
||||
*/
|
||||
#define F_CPU 12000000L
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <string.h>
|
||||
#include "gamepad.h"
|
||||
#include "leds.h"
|
||||
#include "snes.h"
|
||||
|
||||
#define REPORT_SIZE 8
|
||||
#define GAMEPAD_BYTES 8 /* 2 byte per snes controller * 4 controllers */
|
||||
|
||||
/******** IO port definitions **************/
|
||||
#define SNES_LATCH_DDR DDRC
|
||||
#define SNES_LATCH_PORT PORTC
|
||||
#define SNES_LATCH_BIT (1<<4)
|
||||
|
||||
#define SNES_CLOCK_DDR DDRC
|
||||
#define SNES_CLOCK_PORT PORTC
|
||||
#define SNES_CLOCK_BIT (1<<5)
|
||||
|
||||
#define SNES_DATA_PORT PORTC
|
||||
#define SNES_DATA_DDR DDRC
|
||||
#define SNES_DATA_PIN PINC
|
||||
#define SNES_DATA_BIT1 (1<<3) /* controller 1 */
|
||||
#define SNES_DATA_BIT2 (1<<2) /* controller 2 */
|
||||
#define SNES_DATA_BIT3 (1<<1) /* controller 3 */
|
||||
#define SNES_DATA_BIT4 (1<<0) /* controller 4 */
|
||||
|
||||
/********* IO port manipulation macros **********/
|
||||
#define SNES_LATCH_LOW() do { SNES_LATCH_PORT &= ~(SNES_LATCH_BIT); } while(0)
|
||||
#define SNES_LATCH_HIGH() do { SNES_LATCH_PORT |= SNES_LATCH_BIT; } while(0)
|
||||
#define SNES_CLOCK_LOW() do { SNES_CLOCK_PORT &= ~(SNES_CLOCK_BIT); } while(0)
|
||||
#define SNES_CLOCK_HIGH() do { SNES_CLOCK_PORT |= SNES_CLOCK_BIT; } while(0)
|
||||
|
||||
#define SNES_GET_DATA1() (SNES_DATA_PIN & SNES_DATA_BIT1)
|
||||
#define SNES_GET_DATA2() (SNES_DATA_PIN & SNES_DATA_BIT2)
|
||||
#define SNES_GET_DATA3() (SNES_DATA_PIN & SNES_DATA_BIT3)
|
||||
#define SNES_GET_DATA4() (SNES_DATA_PIN & SNES_DATA_BIT4)
|
||||
|
||||
/*********** prototypes *************/
|
||||
static void snesInit(void);
|
||||
static void snesUpdate(void);
|
||||
static char snesChanged(void);
|
||||
static void snesBuildReport(unsigned char *reportBuffer);
|
||||
|
||||
|
||||
// the most recent bytes we fetched from the controller
|
||||
static unsigned char last_read_controller_bytes[GAMEPAD_BYTES];
|
||||
|
||||
// the most recently reported bytes
|
||||
static unsigned char last_reported_controller_bytes[GAMEPAD_BYTES];
|
||||
|
||||
// indicates if a controller is in NES mode
|
||||
static unsigned char nesMode=0; /* Bit0: controller 1, Bit1: controller 2...*/
|
||||
|
||||
static void snesInit(void)
|
||||
{
|
||||
unsigned char sreg;
|
||||
sreg = SREG;
|
||||
cli();
|
||||
|
||||
// clock and latch as output
|
||||
SNES_LATCH_DDR |= SNES_LATCH_BIT;
|
||||
SNES_CLOCK_DDR |= SNES_CLOCK_BIT;
|
||||
|
||||
// data as input
|
||||
SNES_DATA_DDR &= ~(SNES_DATA_BIT1 | SNES_DATA_BIT2 | SNES_DATA_BIT3 | SNES_DATA_BIT4 );
|
||||
// enable pullup. This should prevent random toggling of pins
|
||||
// when no controller is connected.
|
||||
SNES_DATA_PORT |= (SNES_DATA_BIT1 | SNES_DATA_BIT2 | SNES_DATA_BIT3 | SNES_DATA_BIT4 );
|
||||
|
||||
// clock is normally high
|
||||
SNES_CLOCK_PORT |= SNES_CLOCK_BIT;
|
||||
|
||||
// LATCH is Active HIGH
|
||||
SNES_LATCH_PORT &= ~(SNES_LATCH_BIT);
|
||||
|
||||
nesMode = 0;
|
||||
snesUpdate();
|
||||
|
||||
/* Snes controller buttons are sent in this order:
|
||||
* 1st byte: B Y SEL START UP DOWN LEFT RIGHT
|
||||
* 2nd byte: A X L R 1 1 1 1
|
||||
*
|
||||
* Nes controller buttons are sent in this order:
|
||||
* One byte: A B SEL START UP DOWN LEFT RIGHT
|
||||
*
|
||||
* When an additional byte is read from a NES controller,
|
||||
* all bits are 0. Because the data signal is active low,
|
||||
* this corresponds to pressed buttons. When we read
|
||||
* from the controller for the first time, detect NES
|
||||
* controllers by checking those 4 bits.
|
||||
**/
|
||||
if (last_read_controller_bytes[1]==0xFF)
|
||||
nesMode |= 1;
|
||||
if (last_read_controller_bytes[3]==0xFF)
|
||||
nesMode |= 2;
|
||||
|
||||
if (last_read_controller_bytes[5]==0xFF)
|
||||
nesMode |= 4;
|
||||
|
||||
/* The last controllers are always in NES mode. But
|
||||
* it is accessible only of the third is in NES mode
|
||||
* too. */
|
||||
if (last_read_controller_bytes[7]==0xFF)
|
||||
nesMode |= 8;
|
||||
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
Clock Cycle Button Reported
|
||||
=========== ===============
|
||||
1 B
|
||||
2 Y
|
||||
3 Select
|
||||
4 Start
|
||||
5 Up on joypad
|
||||
6 Down on joypad
|
||||
7 Left on joypad
|
||||
8 Right on joypad
|
||||
9 A
|
||||
10 X
|
||||
11 L
|
||||
12 R
|
||||
13 none (always high)
|
||||
14 none (always high)
|
||||
15 none (always high)
|
||||
16 none (always high)
|
||||
*
|
||||
*/
|
||||
|
||||
static void snesUpdate(void)
|
||||
{
|
||||
int i;
|
||||
unsigned char tmp1=0;
|
||||
unsigned char tmp2=0;
|
||||
unsigned char tmp3=0;
|
||||
unsigned char tmp4=0;
|
||||
|
||||
SNES_LATCH_HIGH();
|
||||
_delay_us(12);
|
||||
SNES_LATCH_LOW();
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
_delay_us(6);
|
||||
SNES_CLOCK_LOW();
|
||||
|
||||
tmp1 <<= 1;
|
||||
tmp2 <<= 1;
|
||||
tmp3 <<= 1;
|
||||
tmp4 <<= 1;
|
||||
if (!SNES_GET_DATA1()) { tmp1 |= 1; }
|
||||
if (!SNES_GET_DATA2()) { tmp2 |= 1; }
|
||||
if (!SNES_GET_DATA3()) { tmp3 |= 1; }
|
||||
if (!SNES_GET_DATA4()) { tmp4 |= 1; }
|
||||
|
||||
_delay_us(6);
|
||||
|
||||
SNES_CLOCK_HIGH();
|
||||
}
|
||||
last_read_controller_bytes[0] = tmp1;
|
||||
last_read_controller_bytes[2] = tmp2;
|
||||
last_read_controller_bytes[4] = tmp3;
|
||||
last_read_controller_bytes[6] = tmp4;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
_delay_us(6);
|
||||
|
||||
SNES_CLOCK_LOW();
|
||||
|
||||
// notice that this is different from above. We
|
||||
// want the bits to be in reverse-order
|
||||
tmp1 >>= 1;
|
||||
tmp2 >>= 1;
|
||||
tmp3 >>= 1;
|
||||
tmp4 >>= 1;
|
||||
if (!SNES_GET_DATA1()) { tmp1 |= 0x80; }
|
||||
if (!SNES_GET_DATA2()) { tmp2 |= 0x80; }
|
||||
if (!SNES_GET_DATA3()) { tmp3 |= 0x80; }
|
||||
if (!SNES_GET_DATA4()) { tmp4 |= 0x80; }
|
||||
|
||||
_delay_us(6);
|
||||
SNES_CLOCK_HIGH();
|
||||
}
|
||||
/* Force extra bits to 0 when in NES mode. Otherwise, if
|
||||
* we read zeros on the wire, we will have permanantly
|
||||
* pressed buttons */
|
||||
last_read_controller_bytes[1] = (nesMode & 1) ? 0x00 : tmp1;
|
||||
last_read_controller_bytes[3] = (nesMode & 2) ? 0x00 : tmp2;
|
||||
last_read_controller_bytes[5] = (nesMode & 4) ? 0x00 : tmp3;
|
||||
last_read_controller_bytes[7] = (nesMode & 8) ? 0x00 : tmp4;
|
||||
|
||||
}
|
||||
|
||||
static char snesChanged(void)
|
||||
{
|
||||
static int first = 1;
|
||||
if (first) { first = 0; return 1; }
|
||||
|
||||
return memcmp(last_read_controller_bytes,
|
||||
last_reported_controller_bytes, GAMEPAD_BYTES);
|
||||
}
|
||||
|
||||
static char getX(unsigned char nesByte1)
|
||||
{
|
||||
char x = 128;
|
||||
if (nesByte1&0x1) { x = 255; }
|
||||
if (nesByte1&0x2) { x = 0; }
|
||||
return x;
|
||||
}
|
||||
|
||||
static char getY(unsigned char nesByte1)
|
||||
{
|
||||
char y = 128;
|
||||
if (nesByte1&0x4) { y = 255; }
|
||||
if (nesByte1&0x8) { y = 0; }
|
||||
return y;
|
||||
}
|
||||
|
||||
static unsigned char snesReorderButtons(unsigned char bytes[2])
|
||||
{
|
||||
unsigned char v;
|
||||
|
||||
/* pack the snes button bits, which are on two bytes, in
|
||||
* one single byte. */
|
||||
v = (bytes[0]&0x80)>>7;
|
||||
v |= (bytes[0]&0x40)>>5;
|
||||
v |= (bytes[0]&0x20)>>3;
|
||||
v |= (bytes[0]&0x10)>>1;
|
||||
v |= (bytes[1]&0x0f)<<4;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void snesBuildReport(unsigned char *reportBuffer)
|
||||
{
|
||||
/* last_read_controller_bytes[] structure:
|
||||
*
|
||||
* [0] : controller 1, 8 first bits (dpad + start + sel + y|a + b)
|
||||
* [1] : controller 1, 8 snes extra bits (4 lower bits are buttons)
|
||||
*
|
||||
* [2] : controller 2, 8 first bits
|
||||
* [3] : controller 2, 4 extra snes buttons
|
||||
*
|
||||
* [4] : controller 3, 8 first bits
|
||||
* [5] : controller 3, 4 extra snes buttons
|
||||
*
|
||||
* [6] : controller 4, 8 first bits
|
||||
* [7] : controller 4, 4 extra snes buttons
|
||||
*/
|
||||
|
||||
if (reportBuffer != NULL)
|
||||
{
|
||||
reportBuffer[0]=getX(last_read_controller_bytes[0]);
|
||||
reportBuffer[1]=getY(last_read_controller_bytes[0]);
|
||||
reportBuffer[2]=getX(last_read_controller_bytes[2]);
|
||||
reportBuffer[3]=getY(last_read_controller_bytes[2]);
|
||||
|
||||
reportBuffer[4] = snesReorderButtons(&last_read_controller_bytes[0]);
|
||||
reportBuffer[5] = snesReorderButtons(&last_read_controller_bytes[2]);
|
||||
|
||||
if (nesMode & 0x04) {
|
||||
// Two last controllers are in NES mode.
|
||||
reportBuffer[6] = last_read_controller_bytes[4];
|
||||
reportBuffer[7] = last_read_controller_bytes[6];
|
||||
}
|
||||
else {
|
||||
// Third controller is in SNES mode. Use the two
|
||||
// last bytes for it. Sorry, no fourth controller.
|
||||
reportBuffer[6] = last_read_controller_bytes[4];
|
||||
reportBuffer[7] = last_read_controller_bytes[5];
|
||||
}
|
||||
|
||||
}
|
||||
memcpy(last_reported_controller_bytes,
|
||||
last_read_controller_bytes,
|
||||
GAMEPAD_BYTES);
|
||||
}
|
||||
|
||||
const char snes_usbHidReportDescriptor[] PROGMEM = {
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
0x09, 0x04, // USAGE (Joystick)
|
||||
0xa1, 0x01, // COLLECTION (Application)
|
||||
0x09, 0x01, // USAGE (Pointer)
|
||||
0xa1, 0x00, // COLLECTION (Physical)
|
||||
0x09, 0x30, // USAGE (X)
|
||||
0x09, 0x31, // USAGE (Y)
|
||||
0x09, 0x32, // USAGE (Z)
|
||||
0x09, 0x36, // USAGE (SLIDER)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
|
||||
0x75, 0x08, // REPORT_SIZE (8)
|
||||
0x95, 0x04, // REPORT_COUNT (4)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
0xc0, // END_COLLECTION
|
||||
|
||||
0x05, 0x09, // USAGE_PAGE (Button)
|
||||
0x19, 1, // USAGE_MINIMUM (Button 1)
|
||||
0x29, 32, // USAGE_MAXIMUM (Button 32)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||
0x75, 1, // REPORT_SIZE (1)
|
||||
0x95, 32, // REPORT_COUNT (32)
|
||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||
|
||||
0xc0 // END_COLLECTION
|
||||
};
|
||||
|
||||
Gamepad SnesGamepad = {
|
||||
report_size: REPORT_SIZE,
|
||||
reportDescriptorSize: sizeof(snes_usbHidReportDescriptor),
|
||||
init: snesInit,
|
||||
update: snesUpdate,
|
||||
changed: snesChanged,
|
||||
buildReport: snesBuildReport
|
||||
};
|
||||
|
||||
Gamepad *snesGetGamepad(void)
|
||||
{
|
||||
SnesGamepad.reportDescriptor = (void*)snes_usbHidReportDescriptor;
|
||||
|
||||
return &SnesGamepad;
|
||||
}
|
||||
|
166
usbconfig.h
Normal file
166
usbconfig.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* Name: usbconfig.h
|
||||
* Project: AVR USB driver
|
||||
* Author: Christian Starkjohann, Modified by Raphael Assenat <raph@raphnet.net>
|
||||
* 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.h,v 1.1 2007-03-25 02:59:31 raph Exp $
|
||||
*/
|
||||
|
||||
#ifndef __usbconfig_h_included__
|
||||
#define __usbconfig_h_included__
|
||||
|
||||
/*
|
||||
General Description:
|
||||
This file contains parts of the USB driver which can be configured and can or
|
||||
must be adapted to your hardware.
|
||||
*/
|
||||
|
||||
/* ---------------------------- Hardware Config ---------------------------- */
|
||||
|
||||
#define USB_CFG_IOPORT PORTD
|
||||
/* This is the port where the USB bus is connected. When you configure it to
|
||||
* "PORTB", the registers PORTB, PINB (=PORTB+2) and DDRB (=PORTB+1) 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 MUST be bit 0. All other values will result in a compile error!
|
||||
*/
|
||||
#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!
|
||||
*/
|
||||
|
||||
/* --------------------------- 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_IMPLEMENT_HALT 0
|
||||
/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
|
||||
* for endpoint 1 (interrupt endpoint). Although you may not need this feature,
|
||||
* it is required by the standard. We have made it a config option because it
|
||||
* bloats the code considerably.
|
||||
*/
|
||||
#define USB_CFG_INTR_POLL_INTERVAL 10
|
||||
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
|
||||
* interval. The value is in milliseconds and must not be less than 10 ms for
|
||||
* low speed devices.
|
||||
*/
|
||||
#define USB_CFG_IS_SELF_POWERED 0
|
||||
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
|
||||
* device is powered from the USB bus.
|
||||
*/
|
||||
#define USB_CFG_MAX_BUS_POWER 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.
|
||||
*/
|
||||
|
||||
/* -------------------------- Device Description --------------------------- */
|
||||
|
||||
/* We cannot use Obdev's free shared VID/PID pair because this is a HID.
|
||||
* We use John Hyde's VID (author of the book "USB Design By Example") for
|
||||
* this example instead. John has offered this VID for use by students for
|
||||
* non-commercial devices. Well... This example is for demonstration and
|
||||
* education only... DO NOT LET DEVICES WITH THIS VID ESCAPE YOUR LAB!
|
||||
* The Product-ID is a random number.
|
||||
*/
|
||||
#define USB_CFG_VENDOR_ID 0x81, 0x17
|
||||
/* USB vendor ID for the device, low byte first. If you have registered your
|
||||
* own Vendor ID, define it here. Otherwise you use obdev's free shared
|
||||
* VID/PID pair. Be sure to read USBID-License.txt for rules!
|
||||
*/
|
||||
#define USB_CFG_DEVICE_ID 0x9c, 0x0a
|
||||
/* This is the ID of the product, low byte first. It is interpreted in the
|
||||
* scope of the vendor ID. If you have registered your own VID with usb.org
|
||||
* or if you have licensed a PID from somebody else, define it here. Otherwise
|
||||
* you use obdev's free shared VID/PID pair. Be sure to read the rules in
|
||||
* USBID-License.txt!
|
||||
*/
|
||||
#define USB_CFG_DEVICE_VERSION 0x04, 0x01
|
||||
/* Version number of the device: Minor number first, then major number.
|
||||
*/
|
||||
#define USB_CFG_VENDOR_NAME 'r', 'a', 'p', 'h', 'n', 'e', 't', '.', 'n', 'e', 't'
|
||||
#define USB_CFG_VENDOR_NAME_LEN 11
|
||||
/* 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 '4',' ','A','x','e','s',',',' ', \
|
||||
'3','2',' ','B','u','t','t','o','n','s'
|
||||
#define USB_CFG_DEVICE_NAME_LEN 18
|
||||
/* Same as above for the device name. If you don't want a device name, undefine
|
||||
* the macros. See the file USBID-License.txt before you assign a name.
|
||||
*/
|
||||
#define USB_CFG_SERIAL_NUMBER_LENGTH 4
|
||||
/* Set this define to the number of charcters in the serial number if your
|
||||
* device should have a serial number to uniquely identify each hardware
|
||||
* instance. You must supply the serial number in a string descriptor with the
|
||||
* name "usbCfgSerialNumberStringDescriptor", e.g.:
|
||||
* #define USB_CFG_SERIAL_NUMBER_LENGTH 5
|
||||
* int usbCfgSerialNumberStringDescriptor[] PROGMEM = {
|
||||
* USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LENGTH),
|
||||
* '1', '2', '3', '4', '5'
|
||||
* };
|
||||
* See usbdrv.h for more information about the USB_STRING_DESCRIPTOR_HEADER()
|
||||
* macro or usbdrv.c for example string descriptors.
|
||||
* You may want to put "usbCfgSerialNumberStringDescriptor" at a constant
|
||||
* flash memory address (with magic linker commands) so that you don't need
|
||||
* to recompile if you change it.
|
||||
*/
|
||||
#define USB_CFG_DEVICE_CLASS 0 /* specify the class at the interface level */
|
||||
#define USB_CFG_DEVICE_SUBCLASS 0
|
||||
/* See USB specification if you want to conform to an existing device class.
|
||||
*/
|
||||
#define USB_CFG_INTERFACE_CLASS 0x03 /* HID class */
|
||||
#define USB_CFG_INTERFACE_SUBCLASS 0 /* no boot interface */
|
||||
#define USB_CFG_INTERFACE_PROTOCOL 0 /* no protocol */
|
||||
/* See USB specification if you want to conform to an existing device class or
|
||||
* protocol.
|
||||
*/
|
||||
//#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42
|
||||
/* Define this to the length of the HID report descriptor, if you implement
|
||||
* an HID device. Otherwise don't define it or define it to 0.
|
||||
*/
|
||||
|
||||
/* Define this if you want to be able to set the report descriptor
|
||||
* dynamically at runtime.
|
||||
* */
|
||||
#define USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
|
||||
/* Define this if you want to be able to set the device descriptor
|
||||
* dynamically at runtime.
|
||||
*/
|
||||
#define USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
|
||||
|
||||
#endif /* __usbconfig_h_included__ */
|
83
usbdrv/Changelog.txt
Normal file
83
usbdrv/Changelog.txt
Normal file
@ -0,0 +1,83 @@
|
||||
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
|
458
usbdrv/License.txt
Normal file
458
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.
|
87
usbdrv/Readme.txt
Normal file
87
usbdrv/Readme.txt
Normal file
@ -0,0 +1,87 @@
|
||||
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".
|
||||
|
||||
|
||||
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" memory model. The "tiny" memory is not supported. 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.
|
||||
|
||||
|
||||
|
132
usbdrv/USBID-License.txt
Normal file
132
usbdrv/USBID-License.txt
Normal file
@ -0,0 +1,132 @@
|
||||
Royalty-Free Non-Exclusive License USB Product-ID
|
||||
=================================================
|
||||
|
||||
Version 2006-02-20
|
||||
|
||||
OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive
|
||||
right to use two 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.
|
||||
|
||||
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.
|
||||
|
||||
(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 for both, the VENDOR and the HID CLASS devices 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.
|
||||
|
||||
(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 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.
|
63
usbdrv/iarcompat.h
Normal file
63
usbdrv/iarcompat.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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 2007-03-25 02:59:32 raph 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()
|
||||
|
||||
|
||||
#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */
|
||||
#endif /* __iarcompat_h_INCLUDED__ */
|
54
usbdrv/oddebug.c
Normal file
54
usbdrv/oddebug.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* 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 2007-03-25 02:59:31 raph Exp $
|
||||
*/
|
||||
|
||||
#include "iarcompat.h"
|
||||
#ifndef __IAR_SYSTEMS_ICC__
|
||||
# include <avr/io.h>
|
||||
#endif
|
||||
#include "oddebug.h"
|
||||
|
||||
#if DEBUG_LEVEL > 0
|
||||
|
||||
#warning "Debugging is turned on! Never compile production devices with debugging!"
|
||||
|
||||
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
|
120
usbdrv/oddebug.h
Normal file
120
usbdrv/oddebug.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* 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 2007-03-25 02:59:32 raph 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
|
||||
|
||||
#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__ */
|
559
usbdrv/usbdrv.c
Normal file
559
usbdrv/usbdrv.c
Normal file
@ -0,0 +1,559 @@
|
||||
/* 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 2007-03-25 02:59:32 raph Exp $
|
||||
*/
|
||||
|
||||
#include "iarcompat.h"
|
||||
#ifndef __IAR_SYSTEMS_ICC__
|
||||
# include <avr/io.h>
|
||||
# include <avr/pgmspace.h>
|
||||
#endif
|
||||
#include "usbdrv.h"
|
||||
#include "oddebug.h"
|
||||
#include "../leds.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 */
|
||||
uchar usbRxToken; /* token for data we received */
|
||||
uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
|
||||
volatile schar usbTxLen = -1; /* number of bytes to transmit with next IN token */
|
||||
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
/* uchar usbRxEndp; endpoint which was addressed (1 bit in MSB) [not impl] */
|
||||
volatile schar usbTxLen1 = -1; /* TX count for endpoint 1 */
|
||||
uchar usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */
|
||||
#endif
|
||||
uchar usbAckBuf[1] = {USBPID_ACK}; /* transmit buffer for ack tokens */
|
||||
uchar usbNakBuf[1] = {USBPID_NAK}; /* transmit buffer for nak tokens */
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
/* Parameters that are configurable at runtime */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
const char *rt_usbHidReportDescriptor;
|
||||
uchar rt_usbHidReportDescriptorSize;
|
||||
#endif
|
||||
#ifdef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
const char *rt_usbDeviceDescriptor;
|
||||
uchar rt_usbDeviceDescriptorSize;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
static PROGMEM char usbDescrDevice[] = { /* USB device descriptor */
|
||||
18, /* sizeof(usbDescrDevice): 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 */
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
1, /* manufacturer string index */
|
||||
#else
|
||||
0, /* manufacturer string index */
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
2, /* product string index */
|
||||
#else
|
||||
0, /* product string index */
|
||||
#endif
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
3, /* serial number string index */
|
||||
#else
|
||||
0, /* serial number string index */
|
||||
#endif
|
||||
1, /* number of configurations */
|
||||
};
|
||||
#endif
|
||||
|
||||
static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
||||
9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
|
||||
USBDESCR_CONFIG, /* descriptor type */
|
||||
(18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
||||
+ 9
|
||||
#endif
|
||||
), 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_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME) /* 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 */
|
||||
#ifndef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
0, /* substituted with real value on the fly in usbRead */
|
||||
#else
|
||||
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH,
|
||||
#endif
|
||||
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
|
||||
};
|
||||
|
||||
static PROGMEM char usbDescrString0[] = { /* language descriptor */
|
||||
4, /* sizeof(usbDescrString0): length of descriptor in bytes */
|
||||
3, /* descriptor type */
|
||||
0x09, 0x04, /* language index (0x0409 = US-English) */
|
||||
};
|
||||
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
static PROGMEM int usbDescrString1[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
|
||||
USB_CFG_VENDOR_NAME
|
||||
};
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
static PROGMEM int usbDescrString2[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
|
||||
USB_CFG_DEVICE_NAME
|
||||
};
|
||||
#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
|
||||
static uchar usbTxPacketCnt1;
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
static uchar usbHalted1; /* not 0 if endpoint 1 is halted */
|
||||
#endif
|
||||
|
||||
void usbSetInterrupt(uchar *data, uchar len)
|
||||
{
|
||||
uchar *p, i;
|
||||
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
if(usbHalted1)
|
||||
return;
|
||||
#endif
|
||||
if(len > 8) /* interrupt transfers are limited to 8 bytes */
|
||||
len = 8;
|
||||
i = USBPID_DATA1;
|
||||
if(usbTxPacketCnt1 & 1)
|
||||
i = USBPID_DATA0;
|
||||
if(usbTxLen1 < 0){ /* packet buffer was empty */
|
||||
usbTxPacketCnt1++;
|
||||
}else{
|
||||
usbTxLen1 = -1; /* 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 */
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x21, usbTxBuf1, usbTxLen1-1);
|
||||
#else
|
||||
DBG1(0x21, usbTxBuf1 + 1, 2);
|
||||
#endif
|
||||
}
|
||||
#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 */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
if ((usbDescrConfig + 18 + 7) == (void*)r) {
|
||||
*data++ = rt_usbHidReportDescriptorSize;
|
||||
}
|
||||
else {
|
||||
*data++ = c;
|
||||
}
|
||||
#else
|
||||
*data++ = c;
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, len);
|
||||
#else
|
||||
DBG1(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, 2);
|
||||
#endif
|
||||
if(usbRxToken == (uchar)USBPID_SETUP){
|
||||
if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */
|
||||
uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
|
||||
if(type == USBRQ_TYPE_STANDARD){
|
||||
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(usbHalted1 && recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */
|
||||
replyData[0] = 1;
|
||||
#endif
|
||||
replyData[1] = 0;
|
||||
replyLen = 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] == 1){ /* descriptor type requested */
|
||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
replyLen = sizeof(usbDescrDevice);
|
||||
replyData = (uchar *)usbDescrDevice;
|
||||
#else
|
||||
replyLen = rt_usbDeviceDescriptorSize;
|
||||
replyData = (uchar *)rt_usbDeviceDescriptor;
|
||||
#endif
|
||||
}else if(rq->wValue.bytes[1] == 2){
|
||||
replyLen = sizeof(usbDescrConfig);
|
||||
replyData = (uchar *)usbDescrConfig;
|
||||
}else if(rq->wValue.bytes[1] == 3){ /* string descriptor */
|
||||
if(rq->wValue.bytes[0] == 0){ /* descriptor index */
|
||||
replyLen = sizeof(usbDescrString0);
|
||||
replyData = (uchar *)usbDescrString0;
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
}else if(rq->wValue.bytes[0] == 1){
|
||||
replyLen = sizeof(usbDescrString1);
|
||||
replyData = (uchar *)usbDescrString1;
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
}else if(rq->wValue.bytes[0] == 2){
|
||||
replyLen = sizeof(usbDescrString2);
|
||||
replyData = (uchar *)usbDescrString2;
|
||||
#endif
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
}else if(rq->wValue.bytes[0] == 3){
|
||||
replyLen = 2 * USB_CFG_SERIAL_NUMBER_LENGTH + 2;
|
||||
replyData = (uchar *)usbCfgSerialNumberStringDescriptor;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
||||
else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */
|
||||
replyLen = 9;
|
||||
replyData = (uchar *)usbDescrConfig + 18;
|
||||
}else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
replyLen = USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH;
|
||||
replyData = (uchar *)usbHidReportDescriptor;
|
||||
#endif
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
replyLen = rt_usbHidReportDescriptorSize;
|
||||
replyData = (uchar *)rt_usbHidReportDescriptor;
|
||||
//replyData = snes_usbHidReportDescriptor;
|
||||
// if (replyData != (void*)0x86) { LED_ON(); }
|
||||
// if (replyLen != 42) { LED_ON(); }
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */
|
||||
replyLen = 1;
|
||||
replyData = &usbConfiguration; /* send current configuration value */
|
||||
}else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */
|
||||
usbConfiguration = rq->wValue.bytes[0];
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
usbHalted1 = 0;
|
||||
#endif
|
||||
}else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */
|
||||
replyLen = 1;
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
}else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){ /* 1|3 */
|
||||
if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */
|
||||
usbHalted1 = rq->bRequest - 1;
|
||||
if(usbHalted1){
|
||||
usbTxBuf1[0] = USBPID_STALL;
|
||||
usbTxLen1 = 2; /* length including sync byte */
|
||||
}
|
||||
usbTxPacketCnt1 = 0; /* reset data toggling for interrupt endpoint */
|
||||
}
|
||||
#endif
|
||||
}else if(rq->bRequest == USBRQ_SET_INTERFACE){ /* 11 */
|
||||
usbTxPacketCnt1 = 0; /* reset data toggling for interrupt endpoint */
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
usbHalted1 = 0;
|
||||
#endif
|
||||
#endif
|
||||
}else{
|
||||
/* the following requests can be ignored, send default reply */
|
||||
/* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
|
||||
/* 12: SYNCH_FRAME */
|
||||
}
|
||||
usbMsgPtr = replyData;
|
||||
if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* max length is in */
|
||||
replyLen = rq->wLength.bytes[0];
|
||||
}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 = 0; /* we have no valid msg, use user supplied read/write functions */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* 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 ACK [has been done by ASM module when OUT token arrived] */
|
||||
usbTxBuf[0] = USBPID_STALL;
|
||||
usbTxLen = 2; /* length including sync byte */
|
||||
}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 */
|
||||
}
|
||||
#else
|
||||
replyLen = 0; /* send zero-sized block as ACK */
|
||||
#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{
|
||||
token = USBPID_STALL;
|
||||
txLen = 2; /* length including sync byte */
|
||||
usbMsgLen = 0xff;
|
||||
}
|
||||
usbTxBuf[0] = token;
|
||||
usbTxLen = txLen;
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x20, usbTxBuf, txLen-1);
|
||||
#else
|
||||
DBG1(0x20, usbTxBuf + 1, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
usbRxLen = 0; /* mark rx buffer as available */
|
||||
}
|
||||
if(usbMsgLen != 0xff){ /* transmit data pending? */
|
||||
if(usbTxLen < 0) /* 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
|
||||
usbHalted1 = 0;
|
||||
#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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
472
usbdrv/usbdrv.h
Normal file
472
usbdrv/usbdrv.h
Normal file
@ -0,0 +1,472 @@
|
||||
/* 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 2007-03-25 02:59:32 raph 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. Line D- MUST be wired
|
||||
to bit number 0. 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 two endpoints: One control endpoint (endpoint 0) and
|
||||
one interrupt-in endpoint (endpoint 1) where the device can send interrupt
|
||||
data to the host. Endpoint 1 is only compiled in if
|
||||
USB_CFG_HAVE_INTRIN_ENDPOINT is defined to 1 in usbconfig.h.
|
||||
|
||||
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 20060314
|
||||
/* 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 */
|
||||
|
||||
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.
|
||||
*/
|
||||
#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 schar usbTxLen1;
|
||||
#define usbInterruptIsReady() (usbTxLen1 == -1)
|
||||
/* 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.
|
||||
*/
|
||||
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
extern PROGMEM const 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 */
|
||||
#ifdef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
extern const char *rt_usbDeviceDescriptor;
|
||||
extern uchar rt_usbDeviceDescriptorSize;
|
||||
#endif
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
/* If you have many different HID report descriptors and
|
||||
* you want to select one of them at runtime (dip switchs?),
|
||||
* set those globals variables before initializing the driver.
|
||||
*/
|
||||
extern const char *rt_usbHidReportDescriptor;
|
||||
extern uchar rt_usbHidReportDescriptorSize;
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
#ifdef USB_CFG_PULLUP_IOPORT
|
||||
#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(uchar *data, uchar 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.
|
||||
*/
|
||||
extern unsigned usbCrc16Append(unsigned char *data, unsigned char 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_SERIAL_NUMBER_LENGTH
|
||||
extern PROGMEM int usbCfgSerialNumberStringDescriptor[];
|
||||
/* This array of unicode characters (prefixed by a string descriptor header as
|
||||
* explained above) represents the serial number of the device.
|
||||
*/
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------- Constant definitions -------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
|
||||
#error "You MUST NOT use obdev's shared VID/PID with HID class devices!"
|
||||
/* The shared VID/PID must be used in conjunction with libusb (see license for
|
||||
* the IDs). This contradicts HID usage (at least on Windows).
|
||||
*/
|
||||
#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
|
||||
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free PID */
|
||||
#endif
|
||||
|
||||
#ifndef USB_BUFFER_SECTION
|
||||
# define USB_BUFFER_SECTION ".bss" /* if user has not selected a named section */
|
||||
#endif
|
||||
|
||||
/* I/O definitions for assembler module */
|
||||
#define USBOUT USB_CFG_IOPORT /* output port for USB bits */
|
||||
#define USB_PULLUP_OUT USB_CFG_PULLUP_IOPORT
|
||||
#ifdef __ASSEMBLER__
|
||||
/* the following two lines must start in column 0 for IAR assembler */
|
||||
USBIN = (USB_CFG_IOPORT - 2) /* input port for USB bits */
|
||||
USBDDR = (USB_CFG_IOPORT - 1) /* data direction for USB bits */
|
||||
#else
|
||||
#define USBIN (*(&USB_CFG_IOPORT - 2)) /* input port for USB bits */
|
||||
#define USBDDR (*(&USB_CFG_IOPORT - 1)) /* data direction for USB bits */
|
||||
#define USB_PULLUP_DDR (*(&USB_CFG_PULLUP_IOPORT - 1))
|
||||
#endif
|
||||
#if USB_CFG_DMINUS_BIT != 0
|
||||
# error "USB_CFG_DMINUS_BIT MUST be 0!"
|
||||
#endif
|
||||
#define USBMINUS 0 /* D- MUST be on bit 0 */
|
||||
#define USBIDLE 0x01 /* value representing J state */
|
||||
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | 1) /* mask for USB I/O bits */
|
||||
|
||||
#define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */
|
||||
|
||||
/* Try to find registers and bits responsible for ext interrupt 0 */
|
||||
|
||||
#if defined EICRA
|
||||
# define USB_INTR_CFG EICRA
|
||||
#else
|
||||
# define USB_INTR_CFG MCUCR
|
||||
#endif
|
||||
#define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */
|
||||
#define USB_INTR_CFG_CLR 0 /* no bits to clear */
|
||||
|
||||
#if defined GIMSK
|
||||
# define USB_INTR_ENABLE GIMSK
|
||||
#elif defined EIMSK
|
||||
# define USB_INTR_ENABLE EIMSK
|
||||
#else
|
||||
# define USB_INTR_ENABLE GICR
|
||||
#endif
|
||||
#define USB_INTR_ENABLE_BIT INT0
|
||||
|
||||
#if defined EIFR
|
||||
# define USB_INTR_PENDING EIFR
|
||||
#else
|
||||
# define USB_INTR_PENDING GIFR
|
||||
#endif
|
||||
#define USB_INTR_PENDING_BIT INTF0
|
||||
|
||||
/*
|
||||
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__ */
|
758
usbdrv/usbdrvasm.S
Normal file
758
usbdrv/usbdrvasm.S
Normal file
@ -0,0 +1,758 @@
|
||||
/* 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 2007-03-25 02:59:31 raph 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!
|
||||
*/
|
||||
|
||||
#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, usbNakBuf, usbAckBuf, usbTxLen1, usbTxBuf1
|
||||
public usbCrc16
|
||||
public usbCrc16Append
|
||||
|
||||
# ifndef IVT_BASE_ADDRESS
|
||||
# define IVT_BASE_ADDRESS 0
|
||||
# endif
|
||||
|
||||
ASEG
|
||||
ORG INT0_vect + IVT_BASE_ADDRESS
|
||||
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, 0 ;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
|
||||
ror x2 ;1
|
||||
ldi shift, 0x7f ;1 The last bit of the sync pattern was a "no change"
|
||||
ror shift ;1
|
||||
push YH ;2 -> 7
|
||||
in x2, USBIN ;1 <-- sample bit 1, timing: edge + {2, 6} cycles
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;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
|
||||
ror x2 ;1
|
||||
ror shift ;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
|
||||
ror x1 ;1
|
||||
ror shift ;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, 0xc0 ;1 (0xff03 >> 2) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit6 ;2
|
||||
|
||||
stuffed6: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0a ;1
|
||||
andi x3, 0x81 ;1 (0xff03 >> 1) & 0xff
|
||||
ori shift, 0xfc ;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 [we can save andi x3 here]
|
||||
ori shift, 0xfc ;1
|
||||
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, 0xfe ;1 (0xff03 >> 7) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit1 ;2
|
||||
|
||||
;-----------------------------
|
||||
rxLoop:
|
||||
brlo stuffed5 ;1
|
||||
rxbit6:
|
||||
in x1, USBIN ;1 <-- sample bit 6
|
||||
andi x1, USBMASK ;1
|
||||
breq se0a ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed6 ;1
|
||||
rxbit7:
|
||||
in x2, USBIN ;1 <-- sample bit 7
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;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, 4 ;1
|
||||
brlo stuffed7 ;1
|
||||
unstuffed7:
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo 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
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed1 ;1
|
||||
rxbit2:
|
||||
in x1, USBIN ;1 <-- sample bit 2
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed2 ;1
|
||||
rxbit3:
|
||||
in x2, USBIN ;1 <-- sample bit 3
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
dec cnt ;1 check for buffer overflow
|
||||
breq overflow ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed3 ;1
|
||||
rxbit4:
|
||||
in x1, USBIN ;1 <-- sample bit 4
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed4 ;1
|
||||
rxbit5:
|
||||
in x2, USBIN ;1 <-- sample bit 5
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
rjmp rxLoop ;2
|
||||
;-----------------------------
|
||||
|
||||
stuffed1: ;1 for branch taken
|
||||
in x2, USBIN ;1 <-- sample @ +1
|
||||
andi x2, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xfc ;1 (0xff03 >> 6) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit2 ;2
|
||||
|
||||
stuffed2: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xf8 ;1 (0xff03 >> 5) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit3 ;2
|
||||
|
||||
stuffed3: ;1 for branch taken
|
||||
in x2, USBIN ;1 <-- sample @ +1
|
||||
andi x2, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xf0 ;1 (0xff03 >> 4) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit4 ;2
|
||||
|
||||
stuffed4: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xe0 ;1 (0xff03 >> 3) & 0xff
|
||||
ori shift, 0xfc ;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
|
||||
cpi cnt, -1 ;1
|
||||
breq sendNakAndReti ;1 -> {27, 35} from SE0 end
|
||||
ldi x1, -1 ;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 -1:
|
||||
; We should set it back to -1 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 to -1 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
|
||||
sts usbCurrentTok, x1 ;2
|
||||
#if 0 /* we implement only one rx endpoint */
|
||||
sts usbRxEndp, x3 ;2 only stored if we may have to distinguish endpoints
|
||||
#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. ### This mechanism assumes that NO OUT OR SETUP package
|
||||
;is ever sent to endpoint 1. We would abort transmission for endpoint 0
|
||||
;in this case.
|
||||
ldi x1, -1 ;1
|
||||
sts usbMsgLen, x1 ;2
|
||||
sts usbTxLen, x1 ;2 abort transmission
|
||||
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
|
||||
|
||||
|
||||
sendNakAndReti: ; 21 cycles until SOP
|
||||
ldi YL, lo8(usbNakBuf) ;1
|
||||
ldi YH, hi8(usbNakBuf) ;1
|
||||
rjmp usbSendToken ;2
|
||||
|
||||
sendAckAndReti: ; 19 cycles until SOP
|
||||
ldi YL, lo8(usbAckBuf) ;1
|
||||
ldi YH, hi8(usbAckBuf) ;1
|
||||
usbSendToken:
|
||||
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 16 cycles after call
|
||||
push x4 ;2
|
||||
in x1, USBOUT ;1
|
||||
cbr x1, USBMASK ;1 mask out data bits
|
||||
ori x1, USBIDLE ;1 idle
|
||||
out USBOUT, x1 ;1 prepare idle state
|
||||
ldi x4, USBMASK ;1 exor mask
|
||||
in x2, USBDDR ;1
|
||||
ori x2, USBMASK ;1 set both pins to output
|
||||
out USBDDR, x2 ;1 <-- acquire bus now
|
||||
; 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:
|
||||
lds cnt, usbTxLen1
|
||||
cpi cnt, -1
|
||||
breq sendNakAndReti
|
||||
ldi x1, -1
|
||||
sts usbTxLen1, x1
|
||||
ldi YL, lo8(usbTxBuf1)
|
||||
ldi YH, hi8(usbTxBuf1)
|
||||
rjmp usbSendAndReti
|
||||
#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:
|
||||
lds x2, usbNewDeviceAddr ;2
|
||||
subi YL, lo8(usbNakBuf + 2) ;1
|
||||
sbci YH, hi8(usbNakBuf + 2) ;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
|
||||
*/
|
||||
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
usbdrv/usbdrvasm.asm
Normal file
21
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 2007-03-25 02:59:31 raph 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
|
Loading…
Reference in New Issue
Block a user