mirror of
https://github.com/raphnet/4nes4snes
synced 2024-12-21 22:48:51 -05:00
update driver
This commit is contained in:
parent
4c4ad386e5
commit
958c62b658
@ -81,3 +81,88 @@ Scroll down to the bottom to see the most recent changes.
|
|||||||
with a zero length.
|
with a zero length.
|
||||||
|
|
||||||
* Release 2006-03-14
|
* Release 2006-03-14
|
||||||
|
|
||||||
|
- Improved IAR C support: tiny memory model, more devices
|
||||||
|
- Added template usbconfig.h file under the name usbconfig-prototype.h
|
||||||
|
|
||||||
|
* Release 2006-03-26
|
||||||
|
|
||||||
|
- Added provision for one more interrupt-in endpoint (endpoint 3).
|
||||||
|
- Added provision for one interrupt-out endpoint (endpoint 1).
|
||||||
|
- Added flowcontrol macros for USB.
|
||||||
|
- Added provision for custom configuration descriptor.
|
||||||
|
- Allow ANY two port bits for D+ and D-.
|
||||||
|
- Merged (optional) receive endpoint number into global usbRxToken variable.
|
||||||
|
- Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the
|
||||||
|
variable name from the single port letter instead of computing the address
|
||||||
|
of related ports from the output-port address.
|
||||||
|
|
||||||
|
* Release 2006-06-26
|
||||||
|
|
||||||
|
- Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the
|
||||||
|
new features.
|
||||||
|
- Removed "#warning" directives because IAR does not understand them. Use
|
||||||
|
unused static variables instead to generate a warning.
|
||||||
|
- Do not include <avr/io.h> when compiling with IAR.
|
||||||
|
- Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each
|
||||||
|
USB descriptor should be handled. It is now possible to provide descriptor
|
||||||
|
data in Flash, RAM or dynamically at runtime.
|
||||||
|
- STALL is now a status in usbTxLen* instead of a message. We can now conform
|
||||||
|
to the spec and leave the stall status pending until it is cleared.
|
||||||
|
- Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the
|
||||||
|
application code to reset data toggling on interrupt pipes.
|
||||||
|
|
||||||
|
* Release 2006-07-18
|
||||||
|
|
||||||
|
- Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes
|
||||||
|
an assembler error.
|
||||||
|
- usbDeviceDisconnect() takes pull-up resistor to high impedance now.
|
||||||
|
|
||||||
|
* Release 2007-02-01
|
||||||
|
|
||||||
|
- Merged in some code size improvements from usbtiny (thanks to Dick
|
||||||
|
Streefland for these optimizations!)
|
||||||
|
- Special alignment requirement for usbRxBuf not required any more. Thanks
|
||||||
|
again to Dick Streefland for this hint!
|
||||||
|
- Reverted to "#warning" instead of unused static variables -- new versions
|
||||||
|
of IAR CC should handle this directive.
|
||||||
|
- Changed Open Source license to GNU GPL v2 in order to make linking against
|
||||||
|
other free libraries easier. We no longer require publication of the
|
||||||
|
circuit diagrams, but we STRONGLY encourage it. If you improve the driver
|
||||||
|
itself, PLEASE grant us a royalty free license to your changes for our
|
||||||
|
commercial license.
|
||||||
|
|
||||||
|
* Release 2007-03-29
|
||||||
|
|
||||||
|
- New configuration option "USB_PUBLIC" in usbconfig.h.
|
||||||
|
- Set USB version number to 1.10 instead of 1.01.
|
||||||
|
- Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and
|
||||||
|
USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences
|
||||||
|
to USB_CFG_DESCR_PROPS_STRING_PRODUCT.
|
||||||
|
- New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver
|
||||||
|
code.
|
||||||
|
- New assembler module for 16 MHz crystal.
|
||||||
|
- usbdrvasm.S contains common code only, clock-specific parts have been moved
|
||||||
|
to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively.
|
||||||
|
|
||||||
|
* Release 2007-06-25
|
||||||
|
|
||||||
|
- 16 MHz module: Do SE0 check in stuffed bits as well.
|
||||||
|
|
||||||
|
* Release 2007-07-07
|
||||||
|
|
||||||
|
- Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary
|
||||||
|
for negative values.
|
||||||
|
- Added 15 MHz module contributed by V. Bosch.
|
||||||
|
- Interrupt vector name can now be configured. This is useful if somebody
|
||||||
|
wants to use a different hardware interrupt than INT0.
|
||||||
|
|
||||||
|
* Release 2007-08-07
|
||||||
|
|
||||||
|
- Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is
|
||||||
|
not exceeded.
|
||||||
|
- More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN,
|
||||||
|
USB_COUNT_SOF
|
||||||
|
- USB_INTR_PENDING can now be a memory address
|
||||||
|
|
||||||
|
* Release 2007-09-19
|
||||||
|
@ -1,121 +1,22 @@
|
|||||||
PREFACE
|
OBJECTIVE DEVELOPMENT GmbH's AVR-USB driver software is distributed under the
|
||||||
|
terms and conditions of the GNU GPL version 2, see the text below. In addition
|
||||||
|
to the requirements in the GPL, we STRONGLY ENCOURAGE you to do the following:
|
||||||
|
|
||||||
Conceiving and understanding a new license is not an easy task. To make things
|
(1) Publish your entire project on a web site and drop us a note with the URL.
|
||||||
easier for both, the author and the licensee, we have decided to base our
|
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
|
||||||
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
|
(2) Adhere to minimum publication standards. Please include AT LEAST:
|
||||||
(GPL). However, we cannot use the GNU GPL directly for the following reasons:
|
- a circuit diagram in PDF, PNG or GIF format
|
||||||
|
- full source code for the host software
|
||||||
|
- a Readme.txt file in ASCII format which describes the purpose of the
|
||||||
|
project and what can be found in which directories and which files
|
||||||
|
- a reference to http://www.obdev.at/avrusb/
|
||||||
|
|
||||||
(1) It was not intended for projects involving hardware -- we must extend the
|
(3) If you improve the driver firmware itself, please give us a free license
|
||||||
term "source code" to at least the circuit diagram.
|
to your modifications for our commercial license offerings.
|
||||||
(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
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
|
@ -3,13 +3,82 @@ for Atmel AVR microcontrollers. For more information please visit
|
|||||||
http://www.obdev.at/avrusb/
|
http://www.obdev.at/avrusb/
|
||||||
|
|
||||||
This directory contains the USB firmware only. Copy it as-is to your own
|
This directory contains the USB firmware only. Copy it as-is to your own
|
||||||
project and add your own version of "usbconfig.h".
|
project and add your own version of "usbconfig.h". A template for your own
|
||||||
|
"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory.
|
||||||
|
|
||||||
|
|
||||||
TECHNICAL DOCUMENTATION
|
TECHNICAL DOCUMENTATION
|
||||||
=======================
|
=======================
|
||||||
The technical documentation for the firmware driver is contained in the file
|
The technical documentation (API) for the firmware driver is contained in the
|
||||||
"usbdrv.h". Please read all of it carefully!
|
file "usbdrv.h". Please read all of it carefully! Configuration options are
|
||||||
|
documented in "usbconfig-prototype.h".
|
||||||
|
|
||||||
|
The driver consists of the following files:
|
||||||
|
Readme.txt ............. The file you are currently reading.
|
||||||
|
Changelog.txt .......... Release notes for all versions of the driver.
|
||||||
|
usbdrv.h ............... Driver interface definitions and technical docs.
|
||||||
|
* usbdrv.c ............... High level language part of the driver. Link this
|
||||||
|
module to your code!
|
||||||
|
* usbdrvasm.S ............ Assembler part of the driver. This module is mostly
|
||||||
|
a stub and includes one of the usbdrvasm*.S files
|
||||||
|
depending on processor clock. Link this module to
|
||||||
|
your code!
|
||||||
|
usbdrvasm12.S .......... 12 MHz version of the assembler routines. Included
|
||||||
|
by usbdrvasm.S, don't link it directly!
|
||||||
|
usbdrvasm16.S .......... 16 MHz version of the assembler routines. Included
|
||||||
|
by usbdrvasm.S, don't link it directly!
|
||||||
|
usbdrvasm165.S ......... 16.5 MHz version of the assembler routines including
|
||||||
|
a PLL so that an 1% accurate RC oscillator can be
|
||||||
|
used. Included by usbdrvasm.S, don't link directly!
|
||||||
|
usbconfig-prototype.h .. Prototype for your own usbdrv.h file.
|
||||||
|
* oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is
|
||||||
|
defined to a value greater than 0. Link this module
|
||||||
|
to your code!
|
||||||
|
oddebug.h .............. Interface definitions of the debug module.
|
||||||
|
iarcompat.h ............ Compatibility definitions for IAR C-compiler.
|
||||||
|
usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this
|
||||||
|
module instead of usbdrvasm.S when you assembler
|
||||||
|
with IAR's tools.
|
||||||
|
License.txt ............ Open Source license for this driver.
|
||||||
|
CommercialLicense.txt .. Optional commercial license for this driver.
|
||||||
|
USBID-License.txt ...... Terms and conditions for using particular USB ID
|
||||||
|
values for particular purposes.
|
||||||
|
|
||||||
|
(*) ... These files should be linked to your project.
|
||||||
|
|
||||||
|
|
||||||
|
CPU CORE CLOCK FREQUENCY
|
||||||
|
========================
|
||||||
|
We supply assembler modules for clock frequencies of 12 MHz, 16 MHz and
|
||||||
|
16.5 MHz. Other clock rates are not supported. The actual clock rate must be
|
||||||
|
configured in usbdrv.h unless you use the default 12 MHz.
|
||||||
|
|
||||||
|
12 MHz Clock
|
||||||
|
This is the traditional clock rate of AVR-USB because it's the lowest clock
|
||||||
|
rate where the timing constraints of the USB spec can be met.
|
||||||
|
|
||||||
|
16 MHz Clock
|
||||||
|
This clock rate has been added for users of the Arduino board and other
|
||||||
|
ready-made boards which come with a fixed 16 MHz crystal. It's also an option
|
||||||
|
if you need the slightly higher clock rate for performance reasons. Since
|
||||||
|
16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code
|
||||||
|
is somewhat tricky and has to insert a leap cycle every third byte.
|
||||||
|
|
||||||
|
16.5 MHz Clock
|
||||||
|
The assembler module for this clock rate differs from the other modules because
|
||||||
|
it has been built for an RC oscillator with only 1% precision. The receiver
|
||||||
|
code inserts leap cycles to compensate for clock deviations. 1% is also the
|
||||||
|
precision which can be achieved by calibrating the internal RC oscillator of
|
||||||
|
the AVR. Please note that only AVRs with internal 64 MHz PLL oscillator can be
|
||||||
|
used since the 8 MHz RC oscillator cannot be trimmed up to 16.5 MHz. This
|
||||||
|
includes the very popular ATTiny25, ATTiny45, ATTiny85 series as well as the
|
||||||
|
ATTiny26.
|
||||||
|
|
||||||
|
We recommend that you obtain appropriate calibration values for 16.5 MHz core
|
||||||
|
clock at programming time and store it in flash or EEPROM or compute the value
|
||||||
|
from a reference clock at run time. However, since Atmel's 8 MHz calibration
|
||||||
|
is much more precise than the guaranteed 10%, it's usually possible to add a
|
||||||
|
fixed offset to this value.
|
||||||
|
|
||||||
|
|
||||||
USB IDENTIFIERS
|
USB IDENTIFIERS
|
||||||
@ -26,6 +95,9 @@ and "USB_CFG_DEVICE_ID" accordingly in "usbconfig.h".
|
|||||||
To use our predefined VID/PID pair, you MUST conform to a couple of
|
To use our predefined VID/PID pair, you MUST conform to a couple of
|
||||||
requirements. See the file "USBID-License.txt" for details.
|
requirements. See the file "USBID-License.txt" for details.
|
||||||
|
|
||||||
|
Objective Development also has some offerings which include product IDs. See
|
||||||
|
http://www.obdev.at/avrusb/ for details.
|
||||||
|
|
||||||
|
|
||||||
HOST DRIVER
|
HOST DRIVER
|
||||||
===========
|
===========
|
||||||
@ -44,44 +116,37 @@ This driver has been developed and optimized for the GNU compiler version 3
|
|||||||
optimized for gcc 4. We recommend that you use the GNU compiler suite because
|
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
|
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
|
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
|
with the "small" and "tiny" memory model. Please note that gcc is more
|
||||||
note that gcc is more efficient for usbdrv.c because this module has been
|
efficient for usbdrv.c because this module has been deliberately optimized
|
||||||
deliberately optimized for gcc.
|
for gcc.
|
||||||
|
|
||||||
|
|
||||||
USING AVR-USB FOR FREE
|
USING AVR-USB FOR FREE
|
||||||
======================
|
======================
|
||||||
The AVR firmware driver is published under an Open Source compliant license.
|
The AVR firmware driver is published under the GNU General Public License
|
||||||
See the file "License.txt" for details. Since it is not obvious for many
|
Version 2 (GPL2). See the file "License.txt" for details.
|
||||||
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
|
If you decide for the free GPL2, we STRONGLY ENCOURAGE you to do the following
|
||||||
by Objective Development. You must give us a worldwide, perpetual,
|
things IN ADDITION to the obligations from the GPL2:
|
||||||
irrevocable royalty free license for your modifications.
|
|
||||||
|
|
||||||
(2) Since you own the code you have written (except where you modify our
|
(1) Publish your entire project on a web site and drop us a note with the URL.
|
||||||
driver), you can (at least in principle) determine the license for it freely.
|
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
|
||||||
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
|
(2) Adhere to minimum publication standards. Please include AT LEAST:
|
||||||
note with the URL. The publication must meet certain formal criteria (files
|
- a circuit diagram in PDF, PNG or GIF format
|
||||||
distributed, file formats etc.). See the file "License.txt" for details.
|
- full source code for the host software
|
||||||
|
- a Readme.txt file in ASCII format which describes the purpose of the
|
||||||
|
project and what can be found in which directories and which files
|
||||||
|
- a reference to http://www.obdev.at/avrusb/
|
||||||
|
|
||||||
Other than that, you are allowed to manufacture any number of units and sell
|
(3) If you improve the driver firmware itself, please give us a free license
|
||||||
them for any price. If you like our driver, we also encourage you to make a
|
to your modifications for our commercial license offerings.
|
||||||
donation on our web site.
|
|
||||||
|
|
||||||
|
|
||||||
COMMERCIAL LICENSES FOR AVR-USB
|
COMMERCIAL LICENSES FOR AVR-USB
|
||||||
===============================
|
===============================
|
||||||
If you don't want to publish your source code and the circuit diagrams under
|
If you don't want to publish your source code under the terms of the GPL2,
|
||||||
an Open Source license, you can simply pay money for AVR-USB. As an
|
you can simply pay money for AVR-USB. As an additional benefit you get
|
||||||
additional benefit you get USB PIDs for free, licensed exclusively to you.
|
USB PIDs for free, licensed exclusively to you. See the file
|
||||||
See http://www.obdev.at/products/avrusb/license.html for details.
|
"CommercialLicense.txt" for details.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
Royalty-Free Non-Exclusive License USB Product-ID
|
Royalty-Free Non-Exclusive License USB Product-ID
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
Version 2006-02-20
|
Version 2006-06-19
|
||||||
|
|
||||||
OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive
|
OBJECTIVE DEVELOPMENT Software GmbH hereby grants you the non-exclusive
|
||||||
right to use two USB.org vendor-ID (VID) / product-ID (PID) pairs with
|
right to use three USB.org vendor-ID (VID) / product-ID (PID) pairs with
|
||||||
products based on Objective Development's firmware-only USB driver for
|
products based on Objective Development's firmware-only USB driver for
|
||||||
Atmel AVR microcontrollers:
|
Atmel AVR microcontrollers:
|
||||||
|
|
||||||
@ -16,6 +16,9 @@ Atmel AVR microcontrollers:
|
|||||||
(excluding mice and keyboards). Devices using this pair will be referred
|
(excluding mice and keyboards). Devices using this pair will be referred
|
||||||
to as "HID CLASS" devices.
|
to as "HID CLASS" devices.
|
||||||
|
|
||||||
|
* VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices
|
||||||
|
Devices using this pair will be referred to as "CDC-ACM CLASS" devices.
|
||||||
|
|
||||||
Since the granted right is non-exclusive, the same VID/PID pairs may be
|
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
|
used by many companies and individuals for different products. To avoid
|
||||||
conflicts, your device and host driver software MUST adhere to the rules
|
conflicts, your device and host driver software MUST adhere to the rules
|
||||||
@ -52,15 +55,16 @@ manufacturer and product identification in addition to the usual VID/PID
|
|||||||
matching. This means that operating system features which are based on
|
matching. This means that operating system features which are based on
|
||||||
VID/PID matching only (e.g. Windows kernel level drivers, automatic actions
|
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
|
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.
|
MUST be a comparison of the entire strings, NOT a sub-string match. For
|
||||||
|
CDC-ACM CLASS devices, a generic class driver should be used and the
|
||||||
|
matching is based on the USB device class.
|
||||||
|
|
||||||
(6) The extent to which VID/PID matching is allowed for non device-specific
|
(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
|
drivers or features depends on the operating system and particular VID/PID
|
||||||
pair used:
|
pair used:
|
||||||
|
|
||||||
* Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is
|
* 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
|
required and hence no VID/PID-only matching is allowed at all.
|
||||||
VID/PID-only matching is allowed at all.
|
|
||||||
|
|
||||||
* Windows: The operating system performs VID/PID matching for the kernel
|
* Windows: The operating system performs VID/PID matching for the kernel
|
||||||
level driver. You are REQUIRED to use libusb-win32 (see
|
level driver. You are REQUIRED to use libusb-win32 (see
|
||||||
@ -68,6 +72,9 @@ pair used:
|
|||||||
VENDOR CLASS devices. HID CLASS devices all use the generic HID class
|
VENDOR CLASS devices. HID CLASS devices all use the generic HID class
|
||||||
driver shipped with Windows, except mice and keyboards. You therefore
|
driver shipped with Windows, except mice and keyboards. You therefore
|
||||||
MUST NOT use any of the shared VID/PID pairs for mice or keyboards.
|
MUST NOT use any of the shared VID/PID pairs for mice or keyboards.
|
||||||
|
CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID
|
||||||
|
pair. This ".inf" file MUST load the "usbser" driver to configure the
|
||||||
|
device as modem (COM-port).
|
||||||
|
|
||||||
(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any
|
(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any
|
||||||
problems which are caused by the shared use of these VID/PID pairs. You
|
problems which are caused by the shared use of these VID/PID pairs. You
|
||||||
@ -78,6 +85,10 @@ you want to avoid them, get your own VID/PID pair for exclusive use.
|
|||||||
HOW TO IMPLEMENT THESE RULES
|
HOW TO IMPLEMENT THESE RULES
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM
|
||||||
|
CLASS devices use the operating system's class driver and don't need a
|
||||||
|
custom driver.
|
||||||
|
|
||||||
The host driver MUST iterate over all devices with the given VID/PID
|
The host driver MUST iterate over all devices with the given VID/PID
|
||||||
numbers in their device descriptors and query the string representation for
|
numbers in their device descriptors and query the string representation for
|
||||||
the manufacturer name in USB language 0x0409 (English/US). It MUST compare
|
the manufacturer name in USB language 0x0409 (English/US). It MUST compare
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
* Creation Date: 2006-03-01
|
* Creation Date: 2006-03-01
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: iarcompat.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
* This Revision: $Id: iarcompat.h,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -58,6 +58,13 @@ Thanks to Oleg Semyonov for his help with the IAR tools port!
|
|||||||
#define sei() __enable_interrupt()
|
#define sei() __enable_interrupt()
|
||||||
#define wdt_reset() __watchdog_reset()
|
#define wdt_reset() __watchdog_reset()
|
||||||
|
|
||||||
|
/* Depending on the device you use, you may get problems with the way usbdrv.h
|
||||||
|
* handles the differences between devices. Since IAR does not use #defines
|
||||||
|
* for MCU registers, we can't check for the existence of a particular
|
||||||
|
* register with an #ifdef. If the autodetection mechanism fails, include
|
||||||
|
* definitions for the required USB_INTR_* macros in your usbconfig.h. See
|
||||||
|
* usbconfig-prototype.h and usbdrv.h for details.
|
||||||
|
*/
|
||||||
|
|
||||||
#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */
|
#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */
|
||||||
#endif /* __iarcompat_h_INCLUDED__ */
|
#endif /* __iarcompat_h_INCLUDED__ */
|
||||||
|
@ -4,19 +4,15 @@
|
|||||||
* Creation Date: 2005-01-16
|
* Creation Date: 2005-01-16
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: oddebug.c,v 1.1 2007-03-25 02:59:31 raph Exp $
|
* This Revision: $Id: oddebug.c,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "iarcompat.h"
|
|
||||||
#ifndef __IAR_SYSTEMS_ICC__
|
|
||||||
# include <avr/io.h>
|
|
||||||
#endif
|
|
||||||
#include "oddebug.h"
|
#include "oddebug.h"
|
||||||
|
|
||||||
#if DEBUG_LEVEL > 0
|
#if DEBUG_LEVEL > 0
|
||||||
|
|
||||||
#warning "Debugging is turned on! Never compile production devices with debugging!"
|
#warning "Never compile production devices with debugging enabled"
|
||||||
|
|
||||||
static void uartPutc(char c)
|
static void uartPutc(char c)
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
* Creation Date: 2005-01-16
|
* Creation Date: 2005-01-16
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: oddebug.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
* This Revision: $Id: oddebug.h,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __oddebug_h_included__
|
#ifndef __oddebug_h_included__
|
||||||
@ -28,6 +28,12 @@ the output and a memory block to dump in hex ('data' and 'len').
|
|||||||
# define F_CPU 12000000 /* 12 MHz */
|
# define F_CPU 12000000 /* 12 MHz */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* make sure we have the UART defines: */
|
||||||
|
#include "iarcompat.h"
|
||||||
|
#ifndef __IAR_SYSTEMS_ICC__
|
||||||
|
# include <avr/io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef uchar
|
#ifndef uchar
|
||||||
# define uchar unsigned char
|
# define uchar unsigned char
|
||||||
#endif
|
#endif
|
||||||
|
493
usbdrv/usbdrv.c
493
usbdrv/usbdrv.c
@ -4,8 +4,8 @@
|
|||||||
* Creation Date: 2004-12-29
|
* Creation Date: 2004-12-29
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: usbdrv.c,v 1.1 2007-03-25 02:59:32 raph Exp $
|
* This Revision: $Id: usbdrv.c,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "iarcompat.h"
|
#include "iarcompat.h"
|
||||||
@ -15,7 +15,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "usbdrv.h"
|
#include "usbdrv.h"
|
||||||
#include "oddebug.h"
|
#include "oddebug.h"
|
||||||
#include "../leds.h"
|
|
||||||
/*
|
/*
|
||||||
General Description:
|
General Description:
|
||||||
This module implements the C-part of the USB driver. See usbdrv.h for a
|
This module implements the C-part of the USB driver. See usbdrv.h for a
|
||||||
@ -33,49 +33,38 @@ documentation of the entire driver.
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* raw USB registers / interface to assembler code: */
|
/* raw USB registers / interface to assembler code: */
|
||||||
/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
|
uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
|
||||||
__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 usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */
|
||||||
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
|
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
|
||||||
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
|
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
|
||||||
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
|
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
|
||||||
uchar usbInputBuf; /* ptr to raw buffer used for receiving */
|
volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */
|
||||||
uchar usbAppBuf; /* ptr to raw buffer passed to app for processing */
|
uchar usbCurrentTok; /* last token received, if more than 1 rx endpoint: MSb=endpoint */
|
||||||
volatile schar usbRxLen; /* = 0; number of bytes in usbAppBuf; 0 means free */
|
uchar usbRxToken; /* token for data we received; if more than 1 rx endpoint: MSb=endpoint */
|
||||||
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) */
|
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 */
|
volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */
|
||||||
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */
|
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */
|
||||||
|
# if USB_COUNT_SOF
|
||||||
|
volatile uchar usbSofCount; /* incremented by assembler module every SOF */
|
||||||
|
# endif
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||||
/* uchar usbRxEndp; endpoint which was addressed (1 bit in MSB) [not impl] */
|
volatile uchar usbTxLen1 = USBPID_NAK; /* TX count for endpoint 1 */
|
||||||
volatile schar usbTxLen1 = -1; /* TX count for endpoint 1 */
|
uchar usbTxBuf1[USB_BUFSIZE]; /* TX data for endpoint 1 */
|
||||||
uchar usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
volatile uchar usbTxLen3 = USBPID_NAK; /* TX count for endpoint 3 */
|
||||||
|
uchar usbTxBuf3[USB_BUFSIZE]; /* TX data for endpoint 3 */
|
||||||
|
#endif
|
||||||
#endif
|
#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 */
|
/* USB status registers / not shared with asm code */
|
||||||
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
|
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
|
||||||
static uchar usbMsgFlags; /* flag values see below */
|
static uchar usbMsgFlags; /* flag values see below */
|
||||||
static uchar usbIsReset; /* = 0; USB bus is in reset phase */
|
|
||||||
|
|
||||||
#define USB_FLG_TX_PACKET (1<<0)
|
#define USB_FLG_TX_PACKET (1<<0)
|
||||||
/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
|
/* 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_MSGPTR_IS_ROM (1<<6)
|
||||||
#define USB_FLG_USE_DEFAULT_RW (1<<7)
|
#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:
|
optimizing hints:
|
||||||
- do not post/pre inc/dec integer values in operations
|
- do not post/pre inc/dec integer values in operations
|
||||||
@ -86,45 +75,81 @@ optimizing hints:
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
#if USB_CFG_DESCR_PROPS_STRINGS == 0
|
||||||
static PROGMEM char usbDescrDevice[] = { /* USB device descriptor */
|
|
||||||
18, /* sizeof(usbDescrDevice): length of descriptor in bytes */
|
#if USB_CFG_DESCR_PROPS_STRING_0 == 0
|
||||||
USBDESCR_DEVICE, /* descriptor type */
|
#undef USB_CFG_DESCR_PROPS_STRING_0
|
||||||
0x01, 0x01, /* USB version supported */
|
#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0)
|
||||||
|
PROGMEM char usbDescriptorString0[] = { /* language descriptor */
|
||||||
|
4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */
|
||||||
|
3, /* descriptor type */
|
||||||
|
0x09, 0x04, /* language index (0x0409 = US-English) */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
|
||||||
|
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor)
|
||||||
|
PROGMEM int usbDescriptorStringVendor[] = {
|
||||||
|
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
|
||||||
|
USB_CFG_VENDOR_NAME
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN
|
||||||
|
#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice)
|
||||||
|
PROGMEM int usbDescriptorStringDevice[] = {
|
||||||
|
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
|
||||||
|
USB_CFG_DEVICE_NAME
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN
|
||||||
|
#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber)
|
||||||
|
PROGMEM int usbDescriptorStringSerialNumber[] = {
|
||||||
|
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
|
||||||
|
USB_CFG_SERIAL_NUMBER
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */
|
||||||
|
|
||||||
|
#if USB_CFG_DESCR_PROPS_DEVICE == 0
|
||||||
|
#undef USB_CFG_DESCR_PROPS_DEVICE
|
||||||
|
#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice)
|
||||||
|
PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */
|
||||||
|
18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
|
||||||
|
USBDESCR_DEVICE, /* descriptor type */
|
||||||
|
0x10, 0x01, /* USB version supported */
|
||||||
USB_CFG_DEVICE_CLASS,
|
USB_CFG_DEVICE_CLASS,
|
||||||
USB_CFG_DEVICE_SUBCLASS,
|
USB_CFG_DEVICE_SUBCLASS,
|
||||||
0, /* protocol */
|
0, /* protocol */
|
||||||
8, /* max packet size */
|
8, /* max packet size */
|
||||||
USB_CFG_VENDOR_ID, /* 2 bytes */
|
USB_CFG_VENDOR_ID, /* 2 bytes */
|
||||||
USB_CFG_DEVICE_ID, /* 2 bytes */
|
USB_CFG_DEVICE_ID, /* 2 bytes */
|
||||||
USB_CFG_DEVICE_VERSION, /* 2 bytes */
|
USB_CFG_DEVICE_VERSION, /* 2 bytes */
|
||||||
#if USB_CFG_VENDOR_NAME_LEN
|
USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */
|
||||||
1, /* manufacturer string index */
|
USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */
|
||||||
#else
|
USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */
|
||||||
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 */
|
1, /* number of configurations */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0
|
||||||
9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
|
#undef USB_CFG_DESCR_PROPS_HID
|
||||||
USBDESCR_CONFIG, /* descriptor type */
|
#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */
|
||||||
(18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT
|
|
||||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
|
||||||
+ 9
|
|
||||||
#endif
|
#endif
|
||||||
), 0, /* total length of data returned (including inlined descriptors) */
|
|
||||||
|
#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0
|
||||||
|
#undef USB_CFG_DESCR_PROPS_CONFIGURATION
|
||||||
|
#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration)
|
||||||
|
PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */
|
||||||
|
9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
|
||||||
|
USBDESCR_CONFIG, /* descriptor type */
|
||||||
|
18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff), 0,
|
||||||
|
/* total length of data returned (including inlined descriptors) */
|
||||||
1, /* number of interfaces in this configuration */
|
1, /* number of interfaces in this configuration */
|
||||||
1, /* index of this configuration */
|
1, /* index of this configuration */
|
||||||
0, /* configuration name string index */
|
0, /* configuration name string index */
|
||||||
@ -144,19 +169,14 @@ static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
|||||||
USB_CFG_INTERFACE_SUBCLASS,
|
USB_CFG_INTERFACE_SUBCLASS,
|
||||||
USB_CFG_INTERFACE_PROTOCOL,
|
USB_CFG_INTERFACE_PROTOCOL,
|
||||||
0, /* string index for interface */
|
0, /* string index for interface */
|
||||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME) /* HID descriptor */
|
#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */
|
||||||
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
|
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
|
||||||
USBDESCR_HID, /* descriptor type: HID */
|
USBDESCR_HID, /* descriptor type: HID */
|
||||||
0x01, 0x01, /* BCD representation of HID version */
|
0x01, 0x01, /* BCD representation of HID version */
|
||||||
0x00, /* target country code */
|
0x00, /* target country code */
|
||||||
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
|
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
|
||||||
0x22, /* descriptor type: report */
|
0x22, /* descriptor type: report */
|
||||||
#ifndef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */
|
||||||
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
|
#endif
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
|
||||||
7, /* sizeof(usbDescrEndpoint) */
|
7, /* sizeof(usbDescrEndpoint) */
|
||||||
@ -167,24 +187,6 @@ static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
|||||||
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
|
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
||||||
/* We don't use prog_int or prog_int16_t for compatibility with various libc
|
/* We don't use prog_int or prog_int16_t for compatibility with various libc
|
||||||
@ -207,45 +209,53 @@ typedef union{
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||||
static uchar usbTxPacketCnt1;
|
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len)
|
||||||
#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;
|
uchar *p, i;
|
||||||
|
|
||||||
#if USB_CFG_IMPLEMENT_HALT
|
#if USB_CFG_IMPLEMENT_HALT
|
||||||
if(usbHalted1)
|
if(usbTxLen1 == USBPID_STALL)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
#if 0 /* No runtime checks! Caller is responsible for valid data! */
|
||||||
if(len > 8) /* interrupt transfers are limited to 8 bytes */
|
if(len > 8) /* interrupt transfers are limited to 8 bytes */
|
||||||
len = 8;
|
len = 8;
|
||||||
i = USBPID_DATA1;
|
#endif
|
||||||
if(usbTxPacketCnt1 & 1)
|
if(usbTxLen1 & 0x10){ /* packet buffer was empty */
|
||||||
i = USBPID_DATA0;
|
usbTxBuf1[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
|
||||||
if(usbTxLen1 < 0){ /* packet buffer was empty */
|
|
||||||
usbTxPacketCnt1++;
|
|
||||||
}else{
|
}else{
|
||||||
usbTxLen1 = -1; /* avoid sending incomplete interrupt data */
|
usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
|
||||||
}
|
}
|
||||||
p = usbTxBuf1;
|
p = usbTxBuf1 + 1;
|
||||||
*p++ = i;
|
|
||||||
for(i=len;i--;)
|
for(i=len;i--;)
|
||||||
*p++ = *data++;
|
*p++ = *data++;
|
||||||
usbCrc16Append(&usbTxBuf1[1], len);
|
usbCrc16Append(&usbTxBuf1[1], len);
|
||||||
usbTxLen1 = len + 4; /* len must be given including sync byte */
|
usbTxLen1 = len + 4; /* len must be given including sync byte */
|
||||||
#if DEBUG_LEVEL > 1
|
DBG2(0x21, usbTxBuf1, len + 3);
|
||||||
DBG2(0x21, usbTxBuf1, usbTxLen1-1);
|
}
|
||||||
#else
|
|
||||||
DBG1(0x21, usbTxBuf1 + 1, 2);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len)
|
||||||
|
{
|
||||||
|
uchar *p, i;
|
||||||
|
|
||||||
|
if(usbTxLen3 & 0x10){ /* packet buffer was empty */
|
||||||
|
usbTxBuf3[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
|
||||||
|
}else{
|
||||||
|
usbTxLen3 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
|
||||||
|
}
|
||||||
|
p = usbTxBuf3 + 1;
|
||||||
|
for(i=len;i--;)
|
||||||
|
*p++ = *data++;
|
||||||
|
usbCrc16Append(&usbTxBuf3[1], len);
|
||||||
|
usbTxLen3 = len + 4; /* len must be given including sync byte */
|
||||||
|
DBG2(0x23, usbTxBuf3, len + 3);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static uchar usbRead(uchar *data, uchar len)
|
static uchar usbRead(uchar *data, uchar len)
|
||||||
{
|
{
|
||||||
#if USB_CFG_IMPLEMENT_FN_READ
|
#if USB_CFG_IMPLEMENT_FN_READ
|
||||||
if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){
|
if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){
|
||||||
@ -254,17 +264,7 @@ static uchar usbRead(uchar *data, uchar len)
|
|||||||
if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */
|
if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */
|
||||||
while(i--){
|
while(i--){
|
||||||
uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */
|
uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */
|
||||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
*data++ = c;
|
||||||
if ((usbDescrConfig + 18 + 7) == (void*)r) {
|
|
||||||
*data++ = rt_usbHidReportDescriptorSize;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*data++ = c;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
*data++ = c;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
}else{ /* RAM data */
|
}else{ /* RAM data */
|
||||||
@ -282,6 +282,23 @@ static uchar usbRead(uchar *data, uchar len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_DESCRIPTOR(cfgProp, staticName) \
|
||||||
|
if(cfgProp){ \
|
||||||
|
if((cfgProp) & USB_PROP_IS_RAM) \
|
||||||
|
flags &= ~USB_FLG_MSGPTR_IS_ROM; \
|
||||||
|
if((cfgProp) & USB_PROP_IS_DYNAMIC){ \
|
||||||
|
replyLen = usbFunctionDescriptor(rq); \
|
||||||
|
}else{ \
|
||||||
|
replyData = (uchar *)(staticName); \
|
||||||
|
SET_REPLY_LEN((cfgProp) & 0xff); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
/* We use if() instead of #if in the macro above because #if can't be used
|
||||||
|
* in macros and the compiler optimizes constant conditions anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Don't make this function static to avoid inlining.
|
/* Don't make this function static to avoid inlining.
|
||||||
* The entire function would become too large and exceed the range of
|
* The entire function would become too large and exceed the range of
|
||||||
* relative jumps.
|
* relative jumps.
|
||||||
@ -293,20 +310,32 @@ static void usbProcessRx(uchar *data, uchar len)
|
|||||||
{
|
{
|
||||||
usbRequest_t *rq = (void *)data;
|
usbRequest_t *rq = (void *)data;
|
||||||
uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
||||||
|
|
||||||
|
|
||||||
/* We use if() cascades because the compare is done byte-wise while switch()
|
/* We use if() cascades because the compare is done byte-wise while switch()
|
||||||
* is int-based. The if() cascades are therefore more efficient.
|
* is int-based. The if() cascades are therefore more efficient.
|
||||||
*/
|
*/
|
||||||
#if DEBUG_LEVEL > 1
|
/* usbRxToken can be:
|
||||||
DBG2(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, len);
|
* 0x2d 00101101 (USBPID_SETUP for endpoint 0)
|
||||||
#else
|
* 0xe1 11100001 (USBPID_OUT for endpoint 0)
|
||||||
DBG1(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, 2);
|
* 0xff 11111111 (USBPID_OUT for endpoint 1)
|
||||||
|
*/
|
||||||
|
DBG2(0x10 + ((usbRxToken >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */
|
||||||
|
#ifdef USB_RX_USER_HOOK
|
||||||
|
USB_RX_USER_HOOK(data, len)
|
||||||
|
#endif
|
||||||
|
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
|
||||||
|
if(usbRxToken == 0xff){
|
||||||
|
usbFunctionWriteOut(data, len);
|
||||||
|
return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if(usbRxToken == (uchar)USBPID_SETUP){
|
if(usbRxToken == (uchar)USBPID_SETUP){
|
||||||
|
usbTxLen = USBPID_NAK; /* abort pending transmit */
|
||||||
if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */
|
if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */
|
||||||
uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
|
uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
|
||||||
if(type == USBRQ_TYPE_STANDARD){
|
if(type == USBRQ_TYPE_STANDARD){
|
||||||
|
#define SET_REPLY_LEN(len) replyLen = (len); usbMsgPtr = replyData
|
||||||
|
/* This macro ensures that replyLen and usbMsgPtr are always set in the same way.
|
||||||
|
* That allows optimization of common code in if() branches */
|
||||||
uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */
|
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 */
|
replyData[0] = 0; /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */
|
||||||
if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */
|
if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */
|
||||||
@ -316,112 +345,93 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
|||||||
replyData[0] = USB_CFG_IS_SELF_POWERED;
|
replyData[0] = USB_CFG_IS_SELF_POWERED;
|
||||||
#endif
|
#endif
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT
|
#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 */
|
if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */
|
||||||
replyData[0] = 1;
|
replyData[0] = usbTxLen1 == USBPID_STALL;
|
||||||
#endif
|
#endif
|
||||||
replyData[1] = 0;
|
replyData[1] = 0;
|
||||||
replyLen = 2;
|
SET_REPLY_LEN(2);
|
||||||
}else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */
|
}else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */
|
||||||
usbNewDeviceAddr = rq->wValue.bytes[0];
|
usbNewDeviceAddr = rq->wValue.bytes[0];
|
||||||
}else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */
|
}else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */
|
||||||
flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW;
|
flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW;
|
||||||
if(rq->wValue.bytes[1] == 1){ /* descriptor type requested */
|
if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */
|
||||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice)
|
||||||
replyLen = sizeof(usbDescrDevice);
|
}else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){ /* 2 */
|
||||||
replyData = (uchar *)usbDescrDevice;
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration)
|
||||||
#else
|
}else if(rq->wValue.bytes[1] == USBDESCR_STRING){ /* 3 */
|
||||||
replyLen = rt_usbDeviceDescriptorSize;
|
#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC
|
||||||
replyData = (uchar *)rt_usbDeviceDescriptor;
|
if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM)
|
||||||
#endif
|
flags &= ~USB_FLG_MSGPTR_IS_ROM;
|
||||||
}else if(rq->wValue.bytes[1] == 2){
|
replyLen = usbFunctionDescriptor(rq);
|
||||||
replyLen = sizeof(usbDescrConfig);
|
#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
|
||||||
replyData = (uchar *)usbDescrConfig;
|
|
||||||
}else if(rq->wValue.bytes[1] == 3){ /* string descriptor */
|
|
||||||
if(rq->wValue.bytes[0] == 0){ /* descriptor index */
|
if(rq->wValue.bytes[0] == 0){ /* descriptor index */
|
||||||
replyLen = sizeof(usbDescrString0);
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0)
|
||||||
replyData = (uchar *)usbDescrString0;
|
|
||||||
#if USB_CFG_VENDOR_NAME_LEN
|
|
||||||
}else if(rq->wValue.bytes[0] == 1){
|
}else if(rq->wValue.bytes[0] == 1){
|
||||||
replyLen = sizeof(usbDescrString1);
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor)
|
||||||
replyData = (uchar *)usbDescrString1;
|
|
||||||
#endif
|
|
||||||
#if USB_CFG_DEVICE_NAME_LEN
|
|
||||||
}else if(rq->wValue.bytes[0] == 2){
|
}else if(rq->wValue.bytes[0] == 2){
|
||||||
replyLen = sizeof(usbDescrString2);
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice)
|
||||||
replyData = (uchar *)usbDescrString2;
|
|
||||||
#endif
|
|
||||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
|
||||||
}else if(rq->wValue.bytes[0] == 3){
|
}else if(rq->wValue.bytes[0] == 3){
|
||||||
replyLen = 2 * USB_CFG_SERIAL_NUMBER_LENGTH + 2;
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber)
|
||||||
replyData = (uchar *)usbCfgSerialNumberStringDescriptor;
|
}else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
|
||||||
#endif
|
replyLen = usbFunctionDescriptor(rq);
|
||||||
}
|
}
|
||||||
}
|
#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
|
||||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */
|
||||||
else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */
|
}else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */
|
||||||
replyLen = 9;
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18)
|
||||||
replyData = (uchar *)usbDescrConfig + 18;
|
|
||||||
}else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */
|
}else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */
|
||||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport)
|
||||||
replyLen = USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH;
|
#endif /* USB_CFG_DESCR_PROPS_HID_REPORT */
|
||||||
replyData = (uchar *)usbHidReportDescriptor;
|
}else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
|
||||||
#endif
|
replyLen = usbFunctionDescriptor(rq);
|
||||||
#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 */
|
}else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */
|
||||||
replyLen = 1;
|
|
||||||
replyData = &usbConfiguration; /* send current configuration value */
|
replyData = &usbConfiguration; /* send current configuration value */
|
||||||
|
SET_REPLY_LEN(1);
|
||||||
}else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */
|
}else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */
|
||||||
usbConfiguration = rq->wValue.bytes[0];
|
usbConfiguration = rq->wValue.bytes[0];
|
||||||
#if USB_CFG_IMPLEMENT_HALT
|
#if USB_CFG_IMPLEMENT_HALT
|
||||||
usbHalted1 = 0;
|
usbTxLen1 = USBPID_NAK;
|
||||||
#endif
|
#endif
|
||||||
}else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */
|
}else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */
|
||||||
replyLen = 1;
|
SET_REPLY_LEN(1);
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||||
#if USB_CFG_IMPLEMENT_HALT
|
}else if(rq->bRequest == USBRQ_SET_INTERFACE){ /* 11 */
|
||||||
|
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
|
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
|
# endif
|
||||||
|
# if USB_CFG_IMPLEMENT_HALT
|
||||||
|
usbTxLen1 = USBPID_NAK;
|
||||||
}else if(rq->bRequest == USBRQ_CLEAR_FEATURE || rq->bRequest == USBRQ_SET_FEATURE){ /* 1|3 */
|
}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 */
|
if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */
|
||||||
usbHalted1 = rq->bRequest - 1;
|
usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL;
|
||||||
if(usbHalted1){
|
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
usbTxBuf1[0] = USBPID_STALL;
|
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
usbTxLen1 = 2; /* length including sync byte */
|
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
}
|
# endif
|
||||||
usbTxPacketCnt1 = 0; /* reset data toggling for interrupt endpoint */
|
|
||||||
}
|
}
|
||||||
#endif
|
# 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
|
#endif
|
||||||
}else{
|
}else{
|
||||||
/* the following requests can be ignored, send default reply */
|
/* the following requests can be ignored, send default reply */
|
||||||
/* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
|
/* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
|
||||||
/* 12: SYNCH_FRAME */
|
/* 12: SYNCH_FRAME */
|
||||||
}
|
}
|
||||||
usbMsgPtr = replyData;
|
#undef SET_REPLY_LEN
|
||||||
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 */
|
}else{ /* not a standard request -- must be vendor or class request */
|
||||||
replyLen = usbFunctionSetup(data);
|
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
|
|
||||||
}
|
}
|
||||||
|
#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
|
||||||
|
if(replyLen == 0xff){ /* use user-supplied read/write function */
|
||||||
|
if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){
|
||||||
|
replyLen = rq->wLength.bytes[0]; /* IN transfers only */
|
||||||
|
}
|
||||||
|
flags &= ~USB_FLG_USE_DEFAULT_RW; /* we have no valid msg, use user supplied read/write functions */
|
||||||
|
}else /* The 'else' prevents that we limit a replyLen of 0xff to the maximum transfer len. */
|
||||||
|
#endif
|
||||||
|
if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */
|
||||||
|
replyLen = rq->wLength.bytes[0];
|
||||||
}
|
}
|
||||||
/* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */
|
/* make sure that data packets which are sent as ACK to an OUT transfer are always zero sized */
|
||||||
}else{ /* DATA packet from out request */
|
}else{ /* DATA packet from out request */
|
||||||
@ -430,16 +440,13 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
|||||||
uchar rval = usbFunctionWrite(data, len);
|
uchar rval = usbFunctionWrite(data, len);
|
||||||
replyLen = 0xff;
|
replyLen = 0xff;
|
||||||
if(rval == 0xff){ /* an error occurred */
|
if(rval == 0xff){ /* an error occurred */
|
||||||
/* usbMsgLen = 0xff; cancel potentially pending ACK [has been done by ASM module when OUT token arrived] */
|
usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */
|
||||||
usbTxBuf[0] = USBPID_STALL;
|
usbTxLen = USBPID_STALL;
|
||||||
usbTxLen = 2; /* length including sync byte */
|
|
||||||
}else if(rval != 0){ /* This was the final package */
|
}else if(rval != 0){ /* This was the final package */
|
||||||
replyLen = 0; /* answer with a zero-sized data packet */
|
replyLen = 0; /* answer with a zero-sized data packet */
|
||||||
}
|
}
|
||||||
flags = 0; /* start with a DATA1 package, stay with user supplied write() function */
|
flags = 0; /* start with a DATA1 package, stay with user supplied write() function */
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
replyLen = 0; /* send zero-sized block as ACK */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
usbMsgFlags = flags;
|
usbMsgFlags = flags;
|
||||||
@ -450,7 +457,7 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
|||||||
|
|
||||||
static void usbBuildTxBlock(void)
|
static void usbBuildTxBlock(void)
|
||||||
{
|
{
|
||||||
uchar wantLen, len, txLen, token;
|
uchar wantLen, len, txLen, token;
|
||||||
|
|
||||||
wantLen = usbMsgLen;
|
wantLen = usbMsgLen;
|
||||||
if(wantLen > 8)
|
if(wantLen > 8)
|
||||||
@ -462,22 +469,17 @@ uchar wantLen, len, txLen, token;
|
|||||||
usbMsgFlags++;
|
usbMsgFlags++;
|
||||||
len = usbRead(usbTxBuf + 1, wantLen);
|
len = usbRead(usbTxBuf + 1, wantLen);
|
||||||
if(len <= 8){ /* valid data packet */
|
if(len <= 8){ /* valid data packet */
|
||||||
usbCrc16Append(usbTxBuf + 1, len);
|
usbCrc16Append(&usbTxBuf[1], len);
|
||||||
txLen = len + 4; /* length including sync byte */
|
txLen = len + 4; /* length including sync byte */
|
||||||
if(len < 8) /* a partial package identifies end of message */
|
if(len < 8) /* a partial package identifies end of message */
|
||||||
usbMsgLen = 0xff;
|
usbMsgLen = 0xff;
|
||||||
}else{
|
}else{
|
||||||
token = USBPID_STALL;
|
txLen = USBPID_STALL; /* stall the endpoint */
|
||||||
txLen = 2; /* length including sync byte */
|
|
||||||
usbMsgLen = 0xff;
|
usbMsgLen = 0xff;
|
||||||
}
|
}
|
||||||
usbTxBuf[0] = token;
|
usbTxBuf[0] = token;
|
||||||
usbTxLen = txLen;
|
usbTxLen = txLen;
|
||||||
#if DEBUG_LEVEL > 1
|
|
||||||
DBG2(0x20, usbTxBuf, txLen-1);
|
DBG2(0x20, usbTxBuf, txLen-1);
|
||||||
#else
|
|
||||||
DBG1(0x20, usbTxBuf + 1, 2);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uchar isNotSE0(void)
|
static inline uchar isNotSE0(void)
|
||||||
@ -494,59 +496,52 @@ uchar rval;
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
void usbPoll(void)
|
USB_PUBLIC void usbPoll(void)
|
||||||
{
|
{
|
||||||
uchar len;
|
schar len;
|
||||||
|
uchar i;
|
||||||
|
|
||||||
if((len = usbRxLen) > 0){
|
if((len = usbRxLen) > 0){
|
||||||
/* We could check CRC16 here -- but ACK has already been sent anyway. If you
|
/* 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
|
* 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,
|
* code and report errors back to the host. Since the ACK was already sent,
|
||||||
* retries must be handled on application level.
|
* retries must be handled on application level.
|
||||||
* unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);
|
* unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3);
|
||||||
*/
|
*/
|
||||||
len -= 3; /* remove PID and CRC */
|
usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len - 3);
|
||||||
if(len < 128){ /* no overflow */
|
#if USB_CFG_HAVE_FLOWCONTROL
|
||||||
converter_t appBuf;
|
if(usbRxLen > 0) /* only mark as available if not inactivated */
|
||||||
appBuf.ptr = (uchar *)usbRxBuf;
|
usbRxLen = 0;
|
||||||
appBuf.bytes[0] = usbAppBuf;
|
#else
|
||||||
appBuf.bytes[0]++;
|
usbRxLen = 0; /* mark rx buffer as available */
|
||||||
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
|
#endif
|
||||||
DBG1(0xff, 0, 0);
|
}
|
||||||
notUsbReset:;
|
if(usbTxLen & 0x10){ /* transmit system idle */
|
||||||
|
if(usbMsgLen != 0xff){ /* transmit data pending? */
|
||||||
|
usbBuildTxBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(i = 10; i > 0; i--){
|
||||||
|
if(isNotSE0())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(i == 0){ /* RESET condition, called multiple times during reset */
|
||||||
|
usbNewDeviceAddr = 0;
|
||||||
|
usbDeviceAddr = 0;
|
||||||
|
#if USB_CFG_IMPLEMENT_HALT
|
||||||
|
usbTxLen1 = USBPID_NAK;
|
||||||
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
usbTxLen3 = USBPID_NAK;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
DBG1(0xff, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
void usbInit(void)
|
USB_PUBLIC void usbInit(void)
|
||||||
{
|
{
|
||||||
usbInputBuf = (uchar)usbRxBuf[0];
|
|
||||||
usbAppBuf = (uchar)usbRxBuf[1];
|
|
||||||
#if USB_INTR_CFG_SET != 0
|
#if USB_INTR_CFG_SET != 0
|
||||||
USB_INTR_CFG |= USB_INTR_CFG_SET;
|
USB_INTR_CFG |= USB_INTR_CFG_SET;
|
||||||
#endif
|
#endif
|
||||||
@ -554,6 +549,12 @@ void usbInit(void)
|
|||||||
USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
|
USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
|
||||||
#endif
|
#endif
|
||||||
USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
|
USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
|
||||||
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||||
|
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
|
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
429
usbdrv/usbdrv.h
429
usbdrv/usbdrv.h
@ -4,8 +4,8 @@
|
|||||||
* Creation Date: 2004-12-29
|
* Creation Date: 2004-12-29
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: usbdrv.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
* This Revision: $Id: usbdrv.h,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __usbdrv_h_included__
|
#ifndef __usbdrv_h_included__
|
||||||
@ -16,12 +16,14 @@
|
|||||||
/*
|
/*
|
||||||
Hardware Prerequisites:
|
Hardware Prerequisites:
|
||||||
=======================
|
=======================
|
||||||
USB lines D+ and D- MUST be wired to the same I/O port. Line D- MUST be wired
|
USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+
|
||||||
to bit number 0. D+ must also be connected to INT0. D- requires a pullup of
|
triggers the interrupt (best achieved by using INT0 for D+), but it is also
|
||||||
1.5k to +3.5V (and the device must be powered at 3.5V) to identify as
|
possible to trigger the interrupt from D-. If D- is used, interrupts are also
|
||||||
low-speed USB device. A pullup of 1M SHOULD be connected from D+ to +3.5V to
|
triggered by SOF packets. D- requires a pullup of 1.5k to +3.5V (and the device
|
||||||
prevent interference when no USB master is connected. We use D+ as interrupt
|
must be powered at 3.5V) to identify as low-speed USB device. A pullup of
|
||||||
source and not D- because it does not trigger on keep-alive and RESET states.
|
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
|
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
|
switchable to allow the device to disconnect at will. See the definition of
|
||||||
@ -29,27 +31,12 @@ usbDeviceConnect() and usbDeviceDisconnect() further down in this file.
|
|||||||
|
|
||||||
Please adapt the values in usbconfig.h according to your hardware!
|
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
|
The device MUST be clocked at exactly 12 MHz, 15 MHz or 16 MHz
|
||||||
an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock
|
or at 16.5 MHz +/- 1%. See usbconfig-prototype.h for details.
|
||||||
relation is interpolated linearly, an ATtiny2313 meets the requirement by
|
|
||||||
specification. In practice, the AT90S2313 can be overclocked and works well.
|
|
||||||
|
|
||||||
|
|
||||||
Limitations:
|
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:
|
Robustness with respect to communication errors:
|
||||||
The driver assumes error-free communication. It DOES check for errors in
|
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,
|
the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
|
||||||
@ -59,13 +46,6 @@ 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
|
performance does not permit that. The driver does not check Data0/Data1
|
||||||
toggling, but application software can implement the check.
|
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:
|
Input characteristics:
|
||||||
Since no differential receiver circuit is used, electrical interference
|
Since no differential receiver circuit is used, electrical interference
|
||||||
robustness may suffer. The driver samples only one of the data lines with
|
robustness may suffer. The driver samples only one of the data lines with
|
||||||
@ -75,10 +55,16 @@ 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.
|
requires detection of asymmetric states at high bit rate for SE0 detection.
|
||||||
|
|
||||||
Number of endpoints:
|
Number of endpoints:
|
||||||
The driver supports up to two endpoints: One control endpoint (endpoint 0) and
|
The driver supports up to four endpoints: One control endpoint (endpoint 0),
|
||||||
one interrupt-in endpoint (endpoint 1) where the device can send interrupt
|
two interrupt-in (or bulk-in) endpoints (endpoint 1 and 3) and one
|
||||||
data to the host. Endpoint 1 is only compiled in if
|
interrupt-out (or bulk-out) endpoint (endpoint 1). Please note that the USB
|
||||||
USB_CFG_HAVE_INTRIN_ENDPOINT is defined to 1 in usbconfig.h.
|
standard forbids bulk endpoints for low speed devices! Most operating systems
|
||||||
|
allow them anyway, but the AVR will spend 90% of the CPU time in the USB
|
||||||
|
interrupt polling for bulk data.
|
||||||
|
By default, only the control endpoint 0 is enabled. To get the other endpoints,
|
||||||
|
define USB_CFG_HAVE_INTRIN_ENDPOINT, USB_CFG_HAVE_INTRIN_ENDPOINT3 and/or
|
||||||
|
USB_CFG_IMPLEMENT_FN_WRITEOUT respectively (see usbconfig-prototype.h for
|
||||||
|
details).
|
||||||
|
|
||||||
Maximum data payload:
|
Maximum data payload:
|
||||||
Data payload of control in and out transfers may be up to 254 bytes. In order
|
Data payload of control in and out transfers may be up to 254 bytes. In order
|
||||||
@ -92,7 +78,7 @@ 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.
|
CPU in sleep mode. The driver does not implement suspend handling by itself.
|
||||||
However, the application may implement activity monitoring and wakeup from
|
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
|
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
|
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.
|
to enable the interrupt, checking the interrupt pending flag should suffice.
|
||||||
Before entering sleep mode, the application should enable INT1 for a wakeup
|
Before entering sleep mode, the application should enable INT1 for a wakeup
|
||||||
on the next bus activity.
|
on the next bus activity.
|
||||||
@ -100,21 +86,22 @@ on the next bus activity.
|
|||||||
Operation without an USB master:
|
Operation without an USB master:
|
||||||
The driver behaves neutral without connection to an USB master if D- reads
|
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)
|
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
|
pullup resistor on D+ (interrupt). If D- becomes statically 0, the driver may
|
||||||
the interrupt routine.
|
block in the interrupt routine.
|
||||||
|
|
||||||
Interrupt latency:
|
Interrupt latency:
|
||||||
The application must ensure that the USB interrupt is not disabled for more
|
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
|
than 25 cycles (this is for 12 MHz, faster clocks allow longer latency).
|
||||||
declared as "INTERRUPT" instead of "SIGNAL" (see "avr/signal.h") or that they
|
This implies that all interrupt routines must either be declared as "INTERRUPT"
|
||||||
are written in assembler with "sei" as the first instruction.
|
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:
|
Maximum interrupt duration / CPU cycle consumption:
|
||||||
The driver handles all USB communication during the interrupt service
|
The driver handles all USB communication during the interrupt service
|
||||||
routine. The routine will not return before an entire USB message is received
|
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
|
and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if
|
||||||
conforms to the standard. The driver will consume CPU cycles for all USB
|
the host conforms to the standard. The driver will consume CPU cycles for all
|
||||||
messages, even if they address another (low-speed) device on the same bus.
|
USB messages, even if they address another (low-speed) device on the same bus.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -122,7 +109,7 @@ messages, even if they address another (low-speed) device on the same bus.
|
|||||||
/* --------------------------- Module Interface ---------------------------- */
|
/* --------------------------- Module Interface ---------------------------- */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#define USBDRV_VERSION 20060314
|
#define USBDRV_VERSION 20070919
|
||||||
/* This define uniquely identifies a driver version. It is a decimal number
|
/* 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
|
* 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
|
* driver's behavior or interface changes, you can use this constant to
|
||||||
@ -130,8 +117,18 @@ messages, even if they address another (low-speed) device on the same bus.
|
|||||||
* older than 2006-01-25.
|
* older than 2006-01-25.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
|
||||||
|
|
||||||
|
#ifndef USB_PUBLIC
|
||||||
|
#define USB_PUBLIC
|
||||||
|
#endif
|
||||||
|
/* USB_PUBLIC is used as declaration attribute for all functions exported by
|
||||||
|
* the USB driver. The default is no attribute (see above). You may define it
|
||||||
|
* to static either in usbconfig.h or from the command line if you include
|
||||||
|
* usbdrv.c instead of linking against it. Including the C module of the driver
|
||||||
|
* directly in your code saves a couple of bytes in flash memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
#ifndef uchar
|
#ifndef uchar
|
||||||
#define uchar unsigned char
|
#define uchar unsigned char
|
||||||
#endif
|
#endif
|
||||||
@ -140,23 +137,25 @@ messages, even if they address another (low-speed) device on the same bus.
|
|||||||
#endif
|
#endif
|
||||||
/* shortcuts for well defined 8 bit integer types */
|
/* shortcuts for well defined 8 bit integer types */
|
||||||
|
|
||||||
extern void usbInit(void);
|
struct usbRequest; /* forward declaration */
|
||||||
|
|
||||||
|
USB_PUBLIC void usbInit(void);
|
||||||
/* This function must be called before interrupts are enabled and the main
|
/* This function must be called before interrupts are enabled and the main
|
||||||
* loop is entered.
|
* loop is entered.
|
||||||
*/
|
*/
|
||||||
extern void usbPoll(void);
|
USB_PUBLIC void usbPoll(void);
|
||||||
/* This function must be called at regular intervals from the main loop.
|
/* This function must be called at regular intervals from the main loop.
|
||||||
* Maximum delay between calls is somewhat less than 50ms (USB timeout for
|
* Maximum delay between calls is somewhat less than 50ms (USB timeout for
|
||||||
* accepting a Setup message). Otherwise the device will not be recognized.
|
* accepting a Setup message). Otherwise the device will not be recognized.
|
||||||
* Please note that debug outputs through the UART take ~ 0.5ms per byte
|
* Please note that debug outputs through the UART take ~ 0.5ms per byte
|
||||||
* at 19200 bps.
|
* at 19200 bps.
|
||||||
*/
|
*/
|
||||||
extern uchar *usbMsgPtr;
|
extern uchar *usbMsgPtr;
|
||||||
/* This variable may be used to pass transmit data to the driver from the
|
/* This variable may be used to pass transmit data to the driver from the
|
||||||
* implementation of usbFunctionWrite(). It is also used internally by the
|
* implementation of usbFunctionWrite(). It is also used internally by the
|
||||||
* driver for standard control requests.
|
* driver for standard control requests.
|
||||||
*/
|
*/
|
||||||
extern uchar usbFunctionSetup(uchar data[8]);
|
USB_PUBLIC uchar usbFunctionSetup(uchar data[8]);
|
||||||
/* This function is called when the driver receives a SETUP transaction from
|
/* 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
|
* 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
|
* vendor requests). All control transfers start with a SETUP transaction where
|
||||||
@ -183,23 +182,36 @@ extern uchar usbFunctionSetup(uchar data[8]);
|
|||||||
* Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
|
* Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
|
||||||
* are only done if enabled by the configuration in usbconfig.h.
|
* are only done if enabled by the configuration in usbconfig.h.
|
||||||
*/
|
*/
|
||||||
|
USB_PUBLIC uchar usbFunctionDescriptor(struct usbRequest *rq);
|
||||||
|
/* You need to implement this function ONLY if you provide USB descriptors at
|
||||||
|
* runtime (which is an expert feature). It is very similar to
|
||||||
|
* usbFunctionSetup() above, but it is called only to request USB descriptor
|
||||||
|
* data. See the documentation of usbFunctionSetup() above for more info.
|
||||||
|
*/
|
||||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||||
void usbSetInterrupt(uchar *data, uchar len);
|
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len);
|
||||||
/* This function sets the message which will be sent during the next interrupt
|
/* 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
|
* 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
|
* a length of 8 bytes. The message may be 0 bytes long just to indicate the
|
||||||
* interrupt status to the host.
|
* interrupt status to the host.
|
||||||
* If you need to transfer more bytes, use a control read after the interrupt.
|
* If you need to transfer more bytes, use a control read after the interrupt.
|
||||||
*/
|
*/
|
||||||
extern volatile schar usbTxLen1;
|
extern volatile uchar usbTxLen1;
|
||||||
#define usbInterruptIsReady() (usbTxLen1 == -1)
|
#define usbInterruptIsReady() (usbTxLen1 & 0x10)
|
||||||
/* This macro indicates whether the last interrupt message has already been
|
/* 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
|
* sent. If you set a new interrupt message before the old was sent, the
|
||||||
* message already buffered will be lost.
|
* message already buffered will be lost.
|
||||||
*/
|
*/
|
||||||
|
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||||
|
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len);
|
||||||
|
extern volatile uchar usbTxLen3;
|
||||||
|
#define usbInterruptIsReady3() (usbTxLen3 & 0x10)
|
||||||
|
/* Same as above for endpoint 3 */
|
||||||
|
#endif
|
||||||
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
|
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
|
||||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */
|
||||||
extern PROGMEM const char usbHidReportDescriptor[];
|
#define usbHidReportDescriptor usbDescriptorHidReport
|
||||||
|
/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */
|
||||||
/* If you implement an HID device, you need to provide a report descriptor.
|
/* 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
|
* The HID report descriptor syntax is a bit complex. If you understand how
|
||||||
* report descriptors are constructed, we recommend that you use the HID
|
* report descriptors are constructed, we recommend that you use the HID
|
||||||
@ -207,21 +219,8 @@ extern PROGMEM const char usbHidReportDescriptor[];
|
|||||||
* Otherwise you should probably start with a working example.
|
* Otherwise you should probably start with a working example.
|
||||||
*/
|
*/
|
||||||
#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
|
#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
|
#if USB_CFG_IMPLEMENT_FN_WRITE
|
||||||
extern uchar usbFunctionWrite(uchar *data, uchar len);
|
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len);
|
||||||
/* This function is called by the driver to provide a control transfer's
|
/* 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
|
* 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
|
* total count provided in the current control transfer can be obtained from
|
||||||
@ -239,7 +238,7 @@ extern uchar usbFunctionWrite(uchar *data, uchar len);
|
|||||||
*/
|
*/
|
||||||
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
|
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
|
||||||
#if USB_CFG_IMPLEMENT_FN_READ
|
#if USB_CFG_IMPLEMENT_FN_READ
|
||||||
extern uchar usbFunctionRead(uchar *data, uchar len);
|
USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len);
|
||||||
/* This function is called by the driver to ask the application for a control
|
/* 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
|
* 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
|
* bytes each. You should copy the data to the location given by 'data' and
|
||||||
@ -250,26 +249,37 @@ extern uchar usbFunctionRead(uchar *data, uchar len);
|
|||||||
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
|
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
|
||||||
*/
|
*/
|
||||||
#endif /* USB_CFG_IMPLEMENT_FN_READ */
|
#endif /* USB_CFG_IMPLEMENT_FN_READ */
|
||||||
#ifdef USB_CFG_PULLUP_IOPORT
|
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
|
||||||
|
USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len);
|
||||||
|
/* This function is called by the driver when data on interrupt-out or bulk-
|
||||||
|
* out endpoint 1 is received. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT
|
||||||
|
* to 1 in usbconfig.h to get this function called.
|
||||||
|
*/
|
||||||
|
#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */
|
||||||
|
#ifdef USB_CFG_PULLUP_IOPORTNAME
|
||||||
#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \
|
#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \
|
||||||
(USB_PULLUP_OUT |= (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
|
/* 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 bus. It is only available if you have defined the constants
|
||||||
* USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
|
* USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
|
||||||
*/
|
*/
|
||||||
#define usbDeviceDisconnect() (USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT))
|
#define usbDeviceDisconnect() ((USB_PULLUP_DDR &= ~(1<<USB_CFG_PULLUP_BIT)), \
|
||||||
|
(USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT)))
|
||||||
/* This macro (intended to look like a function) disconnects the device from
|
/* 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
|
* 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.
|
* USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
|
||||||
*/
|
*/
|
||||||
#endif /* USB_CFG_PULLUP_IOPORT */
|
#endif /* USB_CFG_PULLUP_IOPORT */
|
||||||
extern unsigned usbCrc16(uchar *data, uchar len);
|
extern unsigned usbCrc16(unsigned data, uchar len);
|
||||||
|
#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
|
||||||
/* This function calculates the binary complement of the data CRC used in
|
/* This function calculates the binary complement of the data CRC used in
|
||||||
* USB data packets. The value is used to build raw transmit packets.
|
* 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
|
* You may want to use this function for data checksums or to verify received
|
||||||
* data.
|
* data. We enforce 16 bit calling conventions for compatibility with IAR's
|
||||||
|
* tiny memory model.
|
||||||
*/
|
*/
|
||||||
extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
|
extern unsigned usbCrc16Append(unsigned data, uchar len);
|
||||||
|
#define usbCrc16Append(data, len) usbCrc16Append((unsigned)(data), len)
|
||||||
/* This function is equivalent to usbCrc16() above, except that it appends
|
/* This function is equivalent to usbCrc16() above, except that it appends
|
||||||
* the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
|
* the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
|
||||||
* bytes.
|
* bytes.
|
||||||
@ -281,27 +291,173 @@ extern uchar usbConfiguration;
|
|||||||
* You may want to reflect the "configured" status with a LED on the device or
|
* 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.
|
* switch on high power parts of the circuit only if the device is configured.
|
||||||
*/
|
*/
|
||||||
|
#if USB_COUNT_SOF
|
||||||
|
extern volatile uchar usbSofCount;
|
||||||
|
/* This variable is incremented on every SOF packet. It is only available if
|
||||||
|
* the macro USB_COUNT_SOF is defined to a value != 0.
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8))
|
#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8))
|
||||||
/* This macro builds a descriptor header for a string descriptor given the
|
/* 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.
|
* string's length. See usbdrv.c for an example how to use it.
|
||||||
*/
|
*/
|
||||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
#if USB_CFG_HAVE_FLOWCONTROL
|
||||||
extern PROGMEM int usbCfgSerialNumberStringDescriptor[];
|
extern volatile schar usbRxLen;
|
||||||
/* This array of unicode characters (prefixed by a string descriptor header as
|
#define usbDisableAllRequests() usbRxLen = -1
|
||||||
* explained above) represents the serial number of the device.
|
/* Must be called from usbFunctionWrite(). This macro disables all data input
|
||||||
|
* from the USB interface. Requests from the host are answered with a NAK
|
||||||
|
* while they are disabled.
|
||||||
|
*/
|
||||||
|
#define usbEnableAllRequests() usbRxLen = 0
|
||||||
|
/* May only be called if requests are disabled. This macro enables input from
|
||||||
|
* the USB interface after it has been disabled with usbDisableAllRequests().
|
||||||
|
*/
|
||||||
|
#define usbAllRequestsAreDisabled() (usbRxLen < 0)
|
||||||
|
/* Use this macro to find out whether requests are disabled. It may be needed
|
||||||
|
* to ensure that usbEnableAllRequests() is never called when requests are
|
||||||
|
* enabled.
|
||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define USB_SET_DATATOKEN1(token) usbTxBuf1[0] = token
|
||||||
|
#define USB_SET_DATATOKEN3(token) usbTxBuf3[0] = token
|
||||||
|
/* These two macros can be used by application software to reset data toggling
|
||||||
|
* for interrupt-in endpoints 1 and 3.
|
||||||
|
*/
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* ----------------- Definitions for Descriptor Properties ----------------- */
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* This is advanced stuff. See usbconfig-prototype.h for more information
|
||||||
|
* about the various methods to define USB descriptors. If you do nothing,
|
||||||
|
* the default descriptors will be used.
|
||||||
|
*/
|
||||||
|
#define USB_PROP_IS_DYNAMIC (1 << 8)
|
||||||
|
/* If this property is set for a descriptor, usbFunctionDescriptor() will be
|
||||||
|
* used to obtain the particular descriptor.
|
||||||
|
*/
|
||||||
|
#define USB_PROP_IS_RAM (1 << 9)
|
||||||
|
/* If this property is set for a descriptor, the data is read from RAM
|
||||||
|
* memory instead of Flash. The property is used for all methods to provide
|
||||||
|
* external descriptors.
|
||||||
|
*/
|
||||||
|
#define USB_PROP_LENGTH(len) ((len) & 0xff)
|
||||||
|
/* If a static external descriptor is used, this is the total length of the
|
||||||
|
* descriptor in bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* all descriptors which may have properties: */
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_DEVICE
|
||||||
|
#define USB_CFG_DESCR_PROPS_DEVICE 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_CONFIGURATION
|
||||||
|
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_STRINGS
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRINGS 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_STRING_0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_0 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_STRING_PRODUCT
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_HID
|
||||||
|
#define USB_CFG_DESCR_PROPS_HID 0
|
||||||
|
#endif
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_HID_REPORT)
|
||||||
|
# undef USB_CFG_DESCR_PROPS_HID_REPORT
|
||||||
|
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */
|
||||||
|
# define USB_CFG_DESCR_PROPS_HID_REPORT USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||||
|
# else
|
||||||
|
# define USB_CFG_DESCR_PROPS_HID_REPORT 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef USB_CFG_DESCR_PROPS_UNKNOWN
|
||||||
|
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ------------------ forward declaration of descriptors ------------------- */
|
||||||
|
/* If you use external static descriptors, they must be stored in global
|
||||||
|
* arrays as declared below:
|
||||||
|
*/
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
char usbDescriptorDevice[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
char usbDescriptorConfiguration[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
char usbDescriptorHidReport[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
char usbDescriptorString0[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
int usbDescriptorStringVendor[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
int usbDescriptorStringDevice[];
|
||||||
|
|
||||||
|
extern
|
||||||
|
#if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
|
||||||
|
PROGMEM
|
||||||
|
#endif
|
||||||
|
int usbDescriptorStringSerialNumber[];
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLER__ */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* ------------------------ General Purpose Macros ------------------------- */
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define USB_CONCAT(a, b) a ## b
|
||||||
|
#define USB_CONCAT_EXPANDED(a, b) USB_CONCAT(a, b)
|
||||||
|
|
||||||
|
#define USB_OUTPORT(name) USB_CONCAT(PORT, name)
|
||||||
|
#define USB_INPORT(name) USB_CONCAT(PIN, name)
|
||||||
|
#define USB_DDRPORT(name) USB_CONCAT(DDR, name)
|
||||||
|
/* The double-define trick above lets us concatenate strings which are
|
||||||
|
* defined by macros.
|
||||||
|
*/
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* ------------------------- Constant definitions -------------------------- */
|
/* ------------------------- Constant definitions -------------------------- */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
|
#if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
|
||||||
#error "You MUST NOT use obdev's shared VID/PID with HID class devices!"
|
#warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h"
|
||||||
/* The shared VID/PID must be used in conjunction with libusb (see license for
|
/* If the user has not defined IDs, we default to obdev's free IDs.
|
||||||
* the IDs). This contradicts HID usage (at least on Windows).
|
* See USBID-License.txt for details.
|
||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -311,59 +467,79 @@ extern PROGMEM int usbCfgSerialNumberStringDescriptor[];
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef USB_CFG_DEVICE_ID
|
#ifndef USB_CFG_DEVICE_ID
|
||||||
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free PID */
|
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||||
|
# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* 1503 in dec, shared PID for HIDs */
|
||||||
|
# elif USB_CFG_INTERFACE_CLASS == 2
|
||||||
|
# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* 1505 in dec, shared PID for CDC Modems */
|
||||||
|
# else
|
||||||
|
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* 1500 in dec, obdev's free PID */
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef USB_BUFFER_SECTION
|
/* Derive Output, Input and DataDirection ports from port names */
|
||||||
# define USB_BUFFER_SECTION ".bss" /* if user has not selected a named section */
|
#ifndef USB_CFG_IOPORTNAME
|
||||||
|
#error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* I/O definitions for assembler module */
|
#define USBOUT USB_OUTPORT(USB_CFG_IOPORTNAME)
|
||||||
#define USBOUT USB_CFG_IOPORT /* output port for USB bits */
|
#define USB_PULLUP_OUT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||||
#define USB_PULLUP_OUT USB_CFG_PULLUP_IOPORT
|
#define USBIN USB_INPORT(USB_CFG_IOPORTNAME)
|
||||||
#ifdef __ASSEMBLER__
|
#define USBDDR USB_DDRPORT(USB_CFG_IOPORTNAME)
|
||||||
/* the following two lines must start in column 0 for IAR assembler */
|
#define USB_PULLUP_DDR USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||||
USBIN = (USB_CFG_IOPORT - 2) /* input port for USB bits */
|
|
||||||
USBDDR = (USB_CFG_IOPORT - 1) /* data direction for USB bits */
|
#define USBMINUS USB_CFG_DMINUS_BIT
|
||||||
#else
|
#define USBPLUS USB_CFG_DPLUS_BIT
|
||||||
#define USBIN (*(&USB_CFG_IOPORT - 2)) /* input port for USB bits */
|
#define USBIDLE (1<<USB_CFG_DMINUS_BIT) /* value representing J state */
|
||||||
#define USBDDR (*(&USB_CFG_IOPORT - 1)) /* data direction for USB bits */
|
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT)) /* mask for USB I/O bits */
|
||||||
#define USB_PULLUP_DDR (*(&USB_CFG_PULLUP_IOPORT - 1))
|
|
||||||
|
/* defines for backward compatibility with older driver versions: */
|
||||||
|
#define USB_CFG_IOPORT USB_OUTPORT(USB_CFG_IOPORTNAME)
|
||||||
|
#ifdef USB_CFG_PULLUP_IOPORTNAME
|
||||||
|
#define USB_CFG_PULLUP_IOPORT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||||
#endif
|
#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 */
|
#define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */
|
||||||
|
|
||||||
/* Try to find registers and bits responsible for ext interrupt 0 */
|
/* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */
|
||||||
|
|
||||||
#if defined EICRA
|
#ifndef USB_INTR_CFG /* allow user to override our default */
|
||||||
# define USB_INTR_CFG EICRA
|
# if defined EICRA
|
||||||
#else
|
# define USB_INTR_CFG EICRA
|
||||||
# define USB_INTR_CFG MCUCR
|
# else
|
||||||
|
# define USB_INTR_CFG MCUCR
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef USB_INTR_CFG_SET /* allow user to override our default */
|
||||||
|
# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */
|
||||||
|
#endif
|
||||||
|
#ifndef USB_INTR_CFG_CLR /* allow user to override our default */
|
||||||
|
# define USB_INTR_CFG_CLR 0 /* no bits to clear */
|
||||||
#endif
|
#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
|
#ifndef USB_INTR_ENABLE /* allow user to override our default */
|
||||||
# define USB_INTR_ENABLE GIMSK
|
# if defined GIMSK
|
||||||
#elif defined EIMSK
|
# define USB_INTR_ENABLE GIMSK
|
||||||
# define USB_INTR_ENABLE EIMSK
|
# elif defined EIMSK
|
||||||
#else
|
# define USB_INTR_ENABLE EIMSK
|
||||||
# define USB_INTR_ENABLE GICR
|
# else
|
||||||
|
# define USB_INTR_ENABLE GICR
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
|
||||||
|
# define USB_INTR_ENABLE_BIT INT0
|
||||||
#endif
|
#endif
|
||||||
#define USB_INTR_ENABLE_BIT INT0
|
|
||||||
|
|
||||||
#if defined EIFR
|
#ifndef USB_INTR_PENDING /* allow user to override our default */
|
||||||
# define USB_INTR_PENDING EIFR
|
# if defined EIFR
|
||||||
#else
|
# define USB_INTR_PENDING EIFR
|
||||||
# define USB_INTR_PENDING GIFR
|
# else
|
||||||
|
# define USB_INTR_PENDING GIFR
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef USB_INTR_PENDING_BIT /* allow user to override our default */
|
||||||
|
# define USB_INTR_PENDING_BIT INTF0
|
||||||
#endif
|
#endif
|
||||||
#define USB_INTR_PENDING_BIT INTF0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The defines above don't work for the following chips
|
The defines above don't work for the following chips
|
||||||
@ -392,7 +568,14 @@ at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM
|
|||||||
#define USBPID_NAK 0x5a
|
#define USBPID_NAK 0x5a
|
||||||
#define USBPID_STALL 0x1e
|
#define USBPID_STALL 0x1e
|
||||||
|
|
||||||
|
#ifndef USB_INITIAL_DATATOKEN
|
||||||
|
#define USB_INITIAL_DATATOKEN USBPID_DATA0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
extern uchar usbTxBuf1[USB_BUFSIZE], usbTxBuf3[USB_BUFSIZE];
|
||||||
|
|
||||||
typedef union usbWord{
|
typedef union usbWord{
|
||||||
unsigned word;
|
unsigned word;
|
||||||
uchar bytes[2];
|
uchar bytes[2];
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
/* Name: usbdrvasm.S
|
/* Name: usbdrvasm.S
|
||||||
* Project: AVR USB driver
|
* Project: AVR USB driver
|
||||||
* Author: Christian Starkjohann
|
* Author: Christian Starkjohann
|
||||||
* Creation Date: 2004-12-29
|
* Creation Date: 2007-06-13
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: usbdrvasm.S,v 1.1 2007-03-25 02:59:31 raph Exp $
|
* Revision: $Id: usbdrvasm.S,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
General Description:
|
General Description:
|
||||||
This module implements the assembler part of the USB driver. See usbdrv.h
|
This module is the assembler part of the USB driver. This file contains
|
||||||
for a description of the entire driver.
|
general code (preprocessor acrobatics and CRC computation) and then includes
|
||||||
Since almost all of this code is timing critical, don't change unless you
|
the file appropriate for the given clock rate.
|
||||||
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"
|
#include "iarcompat.h"
|
||||||
@ -26,7 +24,6 @@ of CPU cycles, but even an exact number of cycles!
|
|||||||
#endif /* __IAR_SYSTEMS_ASM__ */
|
#endif /* __IAR_SYSTEMS_ASM__ */
|
||||||
#include "usbdrv.h" /* for common defs */
|
#include "usbdrv.h" /* for common defs */
|
||||||
|
|
||||||
|
|
||||||
/* register names */
|
/* register names */
|
||||||
#define x1 r16
|
#define x1 r16
|
||||||
#define x2 r17
|
#define x2 r17
|
||||||
@ -34,6 +31,9 @@ of CPU cycles, but even an exact number of cycles!
|
|||||||
#define cnt r19
|
#define cnt r19
|
||||||
#define x3 r20
|
#define x3 r20
|
||||||
#define x4 r21
|
#define x4 r21
|
||||||
|
#define bitcnt r22
|
||||||
|
#define phase x4
|
||||||
|
#define leap x4
|
||||||
|
|
||||||
/* Some assembler dependent definitions and declarations: */
|
/* Some assembler dependent definitions and declarations: */
|
||||||
|
|
||||||
@ -47,615 +47,55 @@ of CPU cycles, but even an exact number of cycles!
|
|||||||
# define ZL r30
|
# define ZL r30
|
||||||
# define ZH r31
|
# define ZH r31
|
||||||
# define lo8(x) LOW(x)
|
# define lo8(x) LOW(x)
|
||||||
# define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */
|
# define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */
|
||||||
|
|
||||||
extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBuf
|
extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
|
||||||
extern usbCurrentTok, usbRxLen, usbRxToken, usbAppBuf, usbTxLen
|
extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
|
||||||
extern usbTxBuf, usbMsgLen, usbNakBuf, usbAckBuf, usbTxLen1, usbTxBuf1
|
extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3
|
||||||
|
# if USB_COUNT_SOF
|
||||||
|
extern usbSofCount
|
||||||
|
# endif
|
||||||
public usbCrc16
|
public usbCrc16
|
||||||
public usbCrc16Append
|
public usbCrc16Append
|
||||||
|
|
||||||
# ifndef IVT_BASE_ADDRESS
|
COMMON INTVEC
|
||||||
# define IVT_BASE_ADDRESS 0
|
# ifndef USB_INTR_VECTOR
|
||||||
# endif
|
ORG INT0_vect
|
||||||
|
# else /* USB_INTR_VECTOR */
|
||||||
ASEG
|
ORG USB_INTR_VECTOR
|
||||||
ORG INT0_vect + IVT_BASE_ADDRESS
|
# undef USB_INTR_VECTOR
|
||||||
rjmp SIG_INTERRUPT0
|
# endif /* USB_INTR_VECTOR */
|
||||||
|
# define USB_INTR_VECTOR usbInterruptHandler
|
||||||
|
rjmp USB_INTR_VECTOR
|
||||||
RSEG CODE
|
RSEG CODE
|
||||||
|
|
||||||
#else /* __IAR_SYSTEMS_ASM__ */
|
#else /* __IAR_SYSTEMS_ASM__ */
|
||||||
|
|
||||||
# define nop2 rjmp .+0 /* jump to next instruction */
|
# define nop2 rjmp .+0 /* jump to next instruction */
|
||||||
|
|
||||||
|
# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
|
||||||
|
# define USB_INTR_VECTOR SIG_INTERRUPT0
|
||||||
|
# endif
|
||||||
.text
|
.text
|
||||||
.global SIG_INTERRUPT0
|
.global USB_INTR_VECTOR
|
||||||
.type SIG_INTERRUPT0, @function
|
.type USB_INTR_VECTOR, @function
|
||||||
.global usbCrc16
|
.global usbCrc16
|
||||||
.global usbCrc16Append
|
.global usbCrc16Append
|
||||||
|
|
||||||
#endif /* __IAR_SYSTEMS_ASM__ */
|
#endif /* __IAR_SYSTEMS_ASM__ */
|
||||||
|
|
||||||
|
|
||||||
SIG_INTERRUPT0:
|
#if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
|
||||||
;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
|
# define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
|
||||||
;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
|
# define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
|
||||||
;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable
|
#else /* It's a memory address, use lds and sts */
|
||||||
;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes
|
# define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
|
||||||
usbInterrupt:
|
# define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
|
||||||
;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
|
#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
|
; Utility functions
|
||||||
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__
|
#ifdef __IAR_SYSTEMS_ASM__
|
||||||
/* Register assignments for usbCrc16 on IAR cc */
|
/* Register assignments for usbCrc16 on IAR cc */
|
||||||
@ -663,6 +103,8 @@ bitstuff7: ;1 (for branch taken)
|
|||||||
* First parameter passed in r16/r17, second in r18/r19 and so on.
|
* 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)
|
* Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
|
||||||
* Result is passed in r16/r17
|
* Result is passed in r16/r17
|
||||||
|
* In case of the "tiny" memory model, pointers are only 8 bit with no
|
||||||
|
* padding. We therefore pass argument 1 as "16 bit unsigned".
|
||||||
*/
|
*/
|
||||||
RTMODEL "__rt_version", "3"
|
RTMODEL "__rt_version", "3"
|
||||||
/* The line above will generate an error if cc calling conventions change.
|
/* The line above will generate an error if cc calling conventions change.
|
||||||
@ -756,3 +198,24 @@ usbCrc16Append:
|
|||||||
st ptr+, resCrcL
|
st ptr+, resCrcL
|
||||||
st ptr+, resCrcH
|
st ptr+, resCrcH
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; Now include the clock rate specific code
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef USB_CFG_CLOCK_KHZ
|
||||||
|
# define USB_CFG_CLOCK_KHZ 12000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USB_CFG_CLOCK_KHZ == 12000
|
||||||
|
# include "usbdrvasm12.S"
|
||||||
|
#elif USB_CFG_CLOCK_KHZ == 15000
|
||||||
|
# include "usbdrvasm15.S"
|
||||||
|
#elif USB_CFG_CLOCK_KHZ == 16000
|
||||||
|
# include "usbdrvasm16.S"
|
||||||
|
#elif USB_CFG_CLOCK_KHZ == 16500
|
||||||
|
# include "usbdrvasm165.S"
|
||||||
|
#else
|
||||||
|
# error "USB_CFG_CLOCK_KHZ is not one of the supported rates!"
|
||||||
|
#endif
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
* Creation Date: 2006-03-01
|
* Creation Date: 2006-03-01
|
||||||
* Tabsize: 4
|
* Tabsize: 4
|
||||||
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
* License: Proprietary, free under certain conditions. See Documentation.
|
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||||
* This Revision: $Id: usbdrvasm.asm,v 1.1 2007-03-25 02:59:31 raph Exp $
|
* This Revision: $Id: usbdrvasm.asm,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user