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.
|
||||
|
||||
* 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
|
||||
easier for both, the author and the licensee, we have decided to base our
|
||||
license for the USB driver on an existing license with well-understood
|
||||
properties.
|
||||
(1) Publish your entire project on a web site and drop us a note with the URL.
|
||||
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
|
||||
|
||||
Our favorite choice for the base license was the GNU General Public License
|
||||
(GPL). However, we cannot use the GNU GPL directly for the following reasons:
|
||||
(2) Adhere to minimum publication standards. Please include AT LEAST:
|
||||
- a circuit diagram in PDF, PNG or GIF format
|
||||
- full source code for the host software
|
||||
- a Readme.txt file in ASCII format which describes the purpose of the
|
||||
project and what can be found in which directories and which files
|
||||
- a reference to http://www.obdev.at/avrusb/
|
||||
|
||||
(1) It was not intended for projects involving hardware -- we must extend the
|
||||
term "source code" to at least the circuit diagram.
|
||||
(2) The GNU GPL does not require publication. Only if a binary is published,
|
||||
it requires that the source is published as well. This is reasonable for
|
||||
software because unpublished software is of little relevance. For projects
|
||||
involving hardware, we want to REQUIRE publication. More than that, we
|
||||
even want to define HOW the publication must be done (files contained,
|
||||
file formats etc).
|
||||
(3) As the author of the software, we can distribute it under more than one
|
||||
license. For people who don't want to meet the obligations of the GNU GPL,
|
||||
we want to offer commercial licenses. To avoid a split in revisions of
|
||||
the driver, we need special privileges to distribute contributed
|
||||
modifications under proprietary licenses.
|
||||
|
||||
We can not simply modify the GNU GPL and incorporate our changes because the
|
||||
Free Software Foundation (FSF) who holds the copyright for the text of the
|
||||
GNU GPL does not allow modifications. We therefore set up our own small
|
||||
license which incorporates the GNU GPL by reference:
|
||||
(3) If you improve the driver firmware itself, please give us a free license
|
||||
to your modifications for our commercial license offerings.
|
||||
|
||||
|
||||
|
||||
LICENSE FOR PROJECTS BUILT WITH "OBJECTIVE DEVELOPMENT'S
|
||||
FIRMWARE-ONLY USB-DRIVER FOR ATMEL'S AVR MICROCONTROLLERS"
|
||||
Version 2006-01
|
||||
|
||||
|
||||
I. Definitions
|
||||
|
||||
"OBDEV" shall mean OBJECTIVE DEVELOPMENT Software GmbH or any legal successor
|
||||
thereof.
|
||||
|
||||
"Software Source Code" shall mean the preferred form of the software for
|
||||
making modifications to it.
|
||||
|
||||
"USB Driver" shall mean the Software Source Code for OBDEV's firmware-only
|
||||
USB-driver for Atmel's AVR microcontrollers.
|
||||
|
||||
"Function" shall mean the Software Source Code for all software executed on
|
||||
the microcontroller except the USB Driver.
|
||||
|
||||
"Host Software" shall mean the Software Source Code for all software required
|
||||
to control the USB device from the USB host running any operating system.
|
||||
|
||||
"Project" shall mean the USB Driver, the Function, the Host Software, circuit
|
||||
diagrams of the controller based hardware and accompanying documentation.
|
||||
|
||||
"source code" shall have the same meaning as the term "Project" above.
|
||||
|
||||
"Web Site" shall mean a collection of text and multimedia documents accessible
|
||||
worldwide over internet through the HyperText Transfer Protocol (HTTP) on
|
||||
TCP port 80 (standard HTTP port).
|
||||
|
||||
|
||||
II. General License Terms
|
||||
The general terms of this license consist of the GNU General Public License
|
||||
Version 2 (GNU GPL2) which is hereby incorporated into this section as though
|
||||
it were fully set forth here. A copy of the GNU GPL2 is included for your
|
||||
convenience in appendix A of this license.
|
||||
|
||||
The term "source code" in the GNU GPL2 is to be understood as defined in
|
||||
section I above. If any term or definition in section I, III, IV or V
|
||||
conflicts with the GNU GPL2, the term or definition in section I, III, IV or
|
||||
V has precedence of the GNU GPL2.
|
||||
|
||||
|
||||
III. Distribution of the Project
|
||||
The distributed form of a Project must contain at least the following files:
|
||||
(a) Software Source Code files for the USB Driver, the Function and the Host
|
||||
Software.
|
||||
(b) Circuit diagrams for the hardware in PDF, PNG or GIF image file format.
|
||||
(c) A file with name "Readme.txt" in ASCII format with at least the following
|
||||
content (in English language):
|
||||
- An explanation what the Project does.
|
||||
- What to do with the distributed files (installation procedure etc.).
|
||||
- A reference to Objective Development's USB driver.
|
||||
- Your (author's) name and contact information. E-mail and/or URL is
|
||||
sufficient.
|
||||
(d) Optionally a text file with a description of the circuit diagram, an
|
||||
explanation of special (software) techniques used etc.
|
||||
(e) A copy of this license in a file with the name "License.txt". This copy
|
||||
can be in the "usbdrv" subdirectory which contains the driver.
|
||||
|
||||
|
||||
IV. Requirement for Publication
|
||||
All modifications and derived work (Projects using the USB Driver) MUST be
|
||||
distributed (published) as described in section III above on a Web Site. The
|
||||
main page must reproduce at least a description of the Project (e.g. as
|
||||
contained in the "Readme.txt" file distributed) and a download link for the
|
||||
entire Project. The URL of the main page must be submitted to OBDEV. OBDEV
|
||||
will provide a mechanism for submitting Project URLs and for publishing
|
||||
Projects on their Web Site. The Project must remain available for at least
|
||||
twelve (12) months after the initial publication or at least six (6) months
|
||||
after a subsequent version of that particular Project has been published.
|
||||
|
||||
|
||||
V. Author Privileges
|
||||
OBDEV reserves the right to distribute the USB Driver and all modified
|
||||
versions under other (proprietary) licenses. If you modify the USB Driver
|
||||
under the grants of this license, you therefore grant OBDEV (in addition to
|
||||
the grants of the GNU GPL2) a worldwide, perpetual, irrevocable royalty free
|
||||
license for your modifications. OBDEV shall not automatically gain rights
|
||||
other than those of the GNU GPL2 in the other parts of the Project. This
|
||||
section V overrides possibly contradicting terms in the GNU GPL2 referenced
|
||||
in section II.
|
||||
|
||||
|
||||
APPENDIX A
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
|
@ -3,13 +3,82 @@ for Atmel AVR microcontrollers. For more information please visit
|
||||
http://www.obdev.at/avrusb/
|
||||
|
||||
This directory contains the USB firmware only. Copy it as-is to your own
|
||||
project and add your own version of "usbconfig.h".
|
||||
project and add your own version of "usbconfig.h". A template for your own
|
||||
"usbconfig.h" can be found in "usbconfig-prototype.h" in this directory.
|
||||
|
||||
|
||||
TECHNICAL DOCUMENTATION
|
||||
=======================
|
||||
The technical documentation for the firmware driver is contained in the file
|
||||
"usbdrv.h". Please read all of it carefully!
|
||||
The technical documentation (API) for the firmware driver is contained in the
|
||||
file "usbdrv.h". Please read all of it carefully! Configuration options are
|
||||
documented in "usbconfig-prototype.h".
|
||||
|
||||
The driver consists of the following files:
|
||||
Readme.txt ............. The file you are currently reading.
|
||||
Changelog.txt .......... Release notes for all versions of the driver.
|
||||
usbdrv.h ............... Driver interface definitions and technical docs.
|
||||
* usbdrv.c ............... High level language part of the driver. Link this
|
||||
module to your code!
|
||||
* usbdrvasm.S ............ Assembler part of the driver. This module is mostly
|
||||
a stub and includes one of the usbdrvasm*.S files
|
||||
depending on processor clock. Link this module to
|
||||
your code!
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
===========
|
||||
@ -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
|
||||
it is freely available. AVR-USB has also been ported to the IAR compiler and
|
||||
assembler. It has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8
|
||||
with the "small" memory model. The "tiny" memory is not supported. Please
|
||||
note that gcc is more efficient for usbdrv.c because this module has been
|
||||
deliberately optimized for gcc.
|
||||
with the "small" and "tiny" memory model. Please note that gcc is more
|
||||
efficient for usbdrv.c because this module has been deliberately optimized
|
||||
for gcc.
|
||||
|
||||
|
||||
USING AVR-USB FOR FREE
|
||||
======================
|
||||
The AVR firmware driver is published under an Open Source compliant license.
|
||||
See the file "License.txt" for details. Since it is not obvious for many
|
||||
people how this license applies to their own projects, here's a short guide:
|
||||
The AVR firmware driver is published under the GNU General Public License
|
||||
Version 2 (GPL2). See the file "License.txt" for details.
|
||||
|
||||
(1) The USB driver and all your modifications to the driver itself are owned
|
||||
by Objective Development. You must give us a worldwide, perpetual,
|
||||
irrevocable royalty free license for your modifications.
|
||||
If you decide for the free GPL2, we STRONGLY ENCOURAGE you to do the following
|
||||
things IN ADDITION to the obligations from the GPL2:
|
||||
|
||||
(2) Since you own the code you have written (except where you modify our
|
||||
driver), you can (at least in principle) determine the license for it freely.
|
||||
However, to "pay" for the USB driver code you link against, we demand that
|
||||
you choose an Open Source compliant license (compatible with our license) for
|
||||
your source code and the hardware circuit diagrams. Simply attach your
|
||||
license of choice to your parts of the project and leave our "License.txt" in
|
||||
the "usbdrv" subdirectory.
|
||||
(1) Publish your entire project on a web site and drop us a note with the URL.
|
||||
Use the form at http://www.obdev.at/avrusb/feedback.html for your submission.
|
||||
|
||||
(3) We also demand that you publish your work on the Internet and drop us a
|
||||
note with the URL. The publication must meet certain formal criteria (files
|
||||
distributed, file formats etc.). See the file "License.txt" for details.
|
||||
(2) Adhere to minimum publication standards. Please include AT LEAST:
|
||||
- a circuit diagram in PDF, PNG or GIF format
|
||||
- full source code for the host software
|
||||
- a Readme.txt file in ASCII format which describes the purpose of the
|
||||
project and what can be found in which directories and which files
|
||||
- a reference to http://www.obdev.at/avrusb/
|
||||
|
||||
Other than that, you are allowed to manufacture any number of units and sell
|
||||
them for any price. If you like our driver, we also encourage you to make a
|
||||
donation on our web site.
|
||||
(3) If you improve the driver firmware itself, please give us a free license
|
||||
to your modifications for our commercial license offerings.
|
||||
|
||||
|
||||
COMMERCIAL LICENSES FOR AVR-USB
|
||||
===============================
|
||||
If you don't want to publish your source code and the circuit diagrams under
|
||||
an Open Source license, you can simply pay money for AVR-USB. As an
|
||||
additional benefit you get USB PIDs for free, licensed exclusively to you.
|
||||
See http://www.obdev.at/products/avrusb/license.html for details.
|
||||
|
||||
|
||||
If you don't want to publish your source code under the terms of the GPL2,
|
||||
you can simply pay money for AVR-USB. As an additional benefit you get
|
||||
USB PIDs for free, licensed exclusively to you. See the file
|
||||
"CommercialLicense.txt" for details.
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
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
|
||||
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
|
||||
Atmel AVR microcontrollers:
|
||||
|
||||
@ -16,6 +16,9 @@ Atmel AVR microcontrollers:
|
||||
(excluding mice and keyboards). Devices using this pair will be referred
|
||||
to as "HID CLASS" devices.
|
||||
|
||||
* VID = 5824 (=0x16c0) / PID = 1505 (=0x5e1) for CDC class modem devices
|
||||
Devices using this pair will be referred to as "CDC-ACM CLASS" devices.
|
||||
|
||||
Since the granted right is non-exclusive, the same VID/PID pairs may be
|
||||
used by many companies and individuals for different products. To avoid
|
||||
conflicts, your device and host driver software MUST adhere to the rules
|
||||
@ -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
|
||||
VID/PID matching only (e.g. Windows kernel level drivers, automatic actions
|
||||
when the device is plugged in etc) MUST NOT be used. The driver matching
|
||||
MUST be a comparison of the entire strings, NOT a sub-string match.
|
||||
MUST be a comparison of the entire strings, NOT a sub-string match. For
|
||||
CDC-ACM CLASS devices, a generic class driver should be used and the
|
||||
matching is based on the USB device class.
|
||||
|
||||
(6) The extent to which VID/PID matching is allowed for non device-specific
|
||||
drivers or features depends on the operating system and particular VID/PID
|
||||
pair used:
|
||||
|
||||
* Mac OS X, Linux, FreeBSD and other Unixes: No VID/PID matching is
|
||||
required for both, the VENDOR and the HID CLASS devices and hence no
|
||||
VID/PID-only matching is allowed at all.
|
||||
required and hence no VID/PID-only matching is allowed at all.
|
||||
|
||||
* Windows: The operating system performs VID/PID matching for the kernel
|
||||
level driver. You are REQUIRED to use libusb-win32 (see
|
||||
@ -68,6 +72,9 @@ pair used:
|
||||
VENDOR CLASS devices. HID CLASS devices all use the generic HID class
|
||||
driver shipped with Windows, except mice and keyboards. You therefore
|
||||
MUST NOT use any of the shared VID/PID pairs for mice or keyboards.
|
||||
CDC-ACM CLASS devices require a ".inf" file which matches on the VID/PID
|
||||
pair. This ".inf" file MUST load the "usbser" driver to configure the
|
||||
device as modem (COM-port).
|
||||
|
||||
(7) OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any
|
||||
problems which are caused by the shared use of these VID/PID pairs. You
|
||||
@ -78,6 +85,10 @@ you want to avoid them, get your own VID/PID pair for exclusive use.
|
||||
HOW TO IMPLEMENT THESE RULES
|
||||
============================
|
||||
|
||||
The following rules are for VENDOR CLASS and HID CLASS devices. CDC-ACM
|
||||
CLASS devices use the operating system's class driver and don't need a
|
||||
custom driver.
|
||||
|
||||
The host driver MUST iterate over all devices with the given VID/PID
|
||||
numbers in their device descriptors and query the string representation for
|
||||
the manufacturer name in USB language 0x0409 (English/US). It MUST compare
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Creation Date: 2006-03-01
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: iarcompat.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* 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 wdt_reset() __watchdog_reset()
|
||||
|
||||
/* Depending on the device you use, you may get problems with the way usbdrv.h
|
||||
* handles the differences between devices. Since IAR does not use #defines
|
||||
* for MCU registers, we can't check for the existence of a particular
|
||||
* register with an #ifdef. If the autodetection mechanism fails, include
|
||||
* definitions for the required USB_INTR_* macros in your usbconfig.h. See
|
||||
* usbconfig-prototype.h and usbdrv.h for details.
|
||||
*/
|
||||
|
||||
#endif /* defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__ */
|
||||
#endif /* __iarcompat_h_INCLUDED__ */
|
||||
|
@ -4,19 +4,15 @@
|
||||
* Creation Date: 2005-01-16
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: oddebug.c,v 1.1 2007-03-25 02:59:31 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* 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"
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Creation Date: 2005-01-16
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: oddebug.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: oddebug.h,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||
*/
|
||||
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
/* make sure we have the UART defines: */
|
||||
#include "iarcompat.h"
|
||||
#ifndef __IAR_SYSTEMS_ICC__
|
||||
# include <avr/io.h>
|
||||
#endif
|
||||
|
||||
#ifndef uchar
|
||||
# define uchar unsigned char
|
||||
#endif
|
||||
|
493
usbdrv/usbdrv.c
493
usbdrv/usbdrv.c
@ -4,8 +4,8 @@
|
||||
* Creation Date: 2004-12-29
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: usbdrv.c,v 1.1 2007-03-25 02:59:32 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: usbdrv.c,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||
*/
|
||||
|
||||
#include "iarcompat.h"
|
||||
@ -15,7 +15,7 @@
|
||||
#endif
|
||||
#include "usbdrv.h"
|
||||
#include "oddebug.h"
|
||||
#include "../leds.h"
|
||||
|
||||
/*
|
||||
General Description:
|
||||
This module implements the C-part of the USB driver. See usbdrv.h for a
|
||||
@ -33,49 +33,38 @@ documentation of the entire driver.
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* raw USB registers / interface to assembler code: */
|
||||
/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
|
||||
__no_init uchar usbRxBuf[2][USB_BUFSIZE] __attribute__ ((section (USB_BUFFER_SECTION))) IAR_SECTION(USB_BUFFER_SECTION);/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
|
||||
uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
|
||||
uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */
|
||||
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
|
||||
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
|
||||
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
|
||||
uchar usbInputBuf; /* ptr to raw buffer used for receiving */
|
||||
uchar usbAppBuf; /* ptr to raw buffer passed to app for processing */
|
||||
volatile schar usbRxLen; /* = 0; number of bytes in usbAppBuf; 0 means free */
|
||||
uchar usbCurrentTok; /* last token received */
|
||||
uchar usbRxToken; /* token for data we received */
|
||||
volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */
|
||||
uchar usbCurrentTok; /* last token received, if more than 1 rx endpoint: MSb=endpoint */
|
||||
uchar usbRxToken; /* token for data we received; if more than 1 rx endpoint: MSb=endpoint */
|
||||
uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
|
||||
volatile schar usbTxLen = -1; /* number of bytes to transmit with next IN token */
|
||||
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */
|
||||
volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */
|
||||
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */
|
||||
# if USB_COUNT_SOF
|
||||
volatile uchar usbSofCount; /* incremented by assembler module every SOF */
|
||||
# endif
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
/* uchar usbRxEndp; endpoint which was addressed (1 bit in MSB) [not impl] */
|
||||
volatile schar usbTxLen1 = -1; /* TX count for endpoint 1 */
|
||||
uchar usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */
|
||||
volatile uchar usbTxLen1 = USBPID_NAK; /* TX count for endpoint 1 */
|
||||
uchar usbTxBuf1[USB_BUFSIZE]; /* TX data for endpoint 1 */
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||
volatile uchar usbTxLen3 = USBPID_NAK; /* TX count for endpoint 3 */
|
||||
uchar usbTxBuf3[USB_BUFSIZE]; /* TX data for endpoint 3 */
|
||||
#endif
|
||||
#endif
|
||||
uchar usbAckBuf[1] = {USBPID_ACK}; /* transmit buffer for ack tokens */
|
||||
uchar usbNakBuf[1] = {USBPID_NAK}; /* transmit buffer for nak tokens */
|
||||
|
||||
/* USB status registers / not shared with asm code */
|
||||
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
|
||||
static uchar usbMsgFlags; /* flag values see below */
|
||||
static uchar usbIsReset; /* = 0; USB bus is in reset phase */
|
||||
|
||||
#define USB_FLG_TX_PACKET (1<<0)
|
||||
/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
|
||||
#define USB_FLG_MSGPTR_IS_ROM (1<<6)
|
||||
#define USB_FLG_USE_DEFAULT_RW (1<<7)
|
||||
|
||||
|
||||
/* Parameters that are configurable at runtime */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
const char *rt_usbHidReportDescriptor;
|
||||
uchar rt_usbHidReportDescriptorSize;
|
||||
#endif
|
||||
#ifdef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
const char *rt_usbDeviceDescriptor;
|
||||
uchar rt_usbDeviceDescriptorSize;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
optimizing hints:
|
||||
- do not post/pre inc/dec integer values in operations
|
||||
@ -86,45 +75,81 @@ optimizing hints:
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
static PROGMEM char usbDescrDevice[] = { /* USB device descriptor */
|
||||
18, /* sizeof(usbDescrDevice): length of descriptor in bytes */
|
||||
USBDESCR_DEVICE, /* descriptor type */
|
||||
0x01, 0x01, /* USB version supported */
|
||||
#if USB_CFG_DESCR_PROPS_STRINGS == 0
|
||||
|
||||
#if USB_CFG_DESCR_PROPS_STRING_0 == 0
|
||||
#undef USB_CFG_DESCR_PROPS_STRING_0
|
||||
#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0)
|
||||
PROGMEM char usbDescriptorString0[] = { /* language descriptor */
|
||||
4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */
|
||||
3, /* descriptor type */
|
||||
0x09, 0x04, /* language index (0x0409 = US-English) */
|
||||
};
|
||||
#endif
|
||||
|
||||
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
|
||||
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
|
||||
#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor)
|
||||
PROGMEM int usbDescriptorStringVendor[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
|
||||
USB_CFG_VENDOR_NAME
|
||||
};
|
||||
#endif
|
||||
|
||||
#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN
|
||||
#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT
|
||||
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice)
|
||||
PROGMEM int usbDescriptorStringDevice[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
|
||||
USB_CFG_DEVICE_NAME
|
||||
};
|
||||
#endif
|
||||
|
||||
#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN
|
||||
#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
|
||||
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber)
|
||||
PROGMEM int usbDescriptorStringSerialNumber[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
|
||||
USB_CFG_SERIAL_NUMBER
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */
|
||||
|
||||
#if USB_CFG_DESCR_PROPS_DEVICE == 0
|
||||
#undef USB_CFG_DESCR_PROPS_DEVICE
|
||||
#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice)
|
||||
PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */
|
||||
18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
|
||||
USBDESCR_DEVICE, /* descriptor type */
|
||||
0x10, 0x01, /* USB version supported */
|
||||
USB_CFG_DEVICE_CLASS,
|
||||
USB_CFG_DEVICE_SUBCLASS,
|
||||
0, /* protocol */
|
||||
8, /* max packet size */
|
||||
USB_CFG_VENDOR_ID, /* 2 bytes */
|
||||
USB_CFG_DEVICE_ID, /* 2 bytes */
|
||||
0, /* protocol */
|
||||
8, /* max packet size */
|
||||
USB_CFG_VENDOR_ID, /* 2 bytes */
|
||||
USB_CFG_DEVICE_ID, /* 2 bytes */
|
||||
USB_CFG_DEVICE_VERSION, /* 2 bytes */
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
1, /* manufacturer string index */
|
||||
#else
|
||||
0, /* manufacturer string index */
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
2, /* product string index */
|
||||
#else
|
||||
0, /* product string index */
|
||||
#endif
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
3, /* serial number string index */
|
||||
#else
|
||||
0, /* serial number string index */
|
||||
#endif
|
||||
USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */
|
||||
USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */
|
||||
USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */
|
||||
1, /* number of configurations */
|
||||
};
|
||||
#endif
|
||||
|
||||
static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
||||
9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
|
||||
USBDESCR_CONFIG, /* descriptor type */
|
||||
(18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
||||
+ 9
|
||||
#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0
|
||||
#undef USB_CFG_DESCR_PROPS_HID
|
||||
#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */
|
||||
#endif
|
||||
), 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, /* index of this configuration */
|
||||
0, /* configuration name string index */
|
||||
@ -144,19 +169,14 @@ static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
||||
USB_CFG_INTERFACE_SUBCLASS,
|
||||
USB_CFG_INTERFACE_PROTOCOL,
|
||||
0, /* string index for interface */
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME) /* HID descriptor */
|
||||
#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */
|
||||
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
|
||||
USBDESCR_HID, /* descriptor type: HID */
|
||||
0x01, 0x01, /* BCD representation of HID version */
|
||||
0x00, /* target country code */
|
||||
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
|
||||
0x22, /* descriptor type: report */
|
||||
#ifndef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
0, /* substituted with real value on the fly in usbRead */
|
||||
#else
|
||||
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH,
|
||||
#endif
|
||||
0, /* total length of report descriptor */
|
||||
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */
|
||||
#endif
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
|
||||
7, /* sizeof(usbDescrEndpoint) */
|
||||
@ -167,24 +187,6 @@ static PROGMEM char usbDescrConfig[] = { /* USB configuration descriptor */
|
||||
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
|
||||
#endif
|
||||
};
|
||||
|
||||
static PROGMEM char usbDescrString0[] = { /* language descriptor */
|
||||
4, /* sizeof(usbDescrString0): length of descriptor in bytes */
|
||||
3, /* descriptor type */
|
||||
0x09, 0x04, /* language index (0x0409 = US-English) */
|
||||
};
|
||||
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
static PROGMEM int usbDescrString1[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
|
||||
USB_CFG_VENDOR_NAME
|
||||
};
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
static PROGMEM int usbDescrString2[] = {
|
||||
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
|
||||
USB_CFG_DEVICE_NAME
|
||||
};
|
||||
#endif
|
||||
|
||||
/* We don't use prog_int or prog_int16_t for compatibility with various libc
|
||||
@ -207,45 +209,53 @@ typedef union{
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
static uchar usbTxPacketCnt1;
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
static uchar usbHalted1; /* not 0 if endpoint 1 is halted */
|
||||
#endif
|
||||
|
||||
void usbSetInterrupt(uchar *data, uchar len)
|
||||
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len)
|
||||
{
|
||||
uchar *p, i;
|
||||
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
if(usbHalted1)
|
||||
if(usbTxLen1 == USBPID_STALL)
|
||||
return;
|
||||
#endif
|
||||
#if 0 /* No runtime checks! Caller is responsible for valid data! */
|
||||
if(len > 8) /* interrupt transfers are limited to 8 bytes */
|
||||
len = 8;
|
||||
i = USBPID_DATA1;
|
||||
if(usbTxPacketCnt1 & 1)
|
||||
i = USBPID_DATA0;
|
||||
if(usbTxLen1 < 0){ /* packet buffer was empty */
|
||||
usbTxPacketCnt1++;
|
||||
#endif
|
||||
if(usbTxLen1 & 0x10){ /* packet buffer was empty */
|
||||
usbTxBuf1[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
|
||||
}else{
|
||||
usbTxLen1 = -1; /* avoid sending incomplete interrupt data */
|
||||
usbTxLen1 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
|
||||
}
|
||||
p = usbTxBuf1;
|
||||
*p++ = i;
|
||||
p = usbTxBuf1 + 1;
|
||||
for(i=len;i--;)
|
||||
*p++ = *data++;
|
||||
usbCrc16Append(&usbTxBuf1[1], len);
|
||||
usbTxLen1 = len + 4; /* len must be given including sync byte */
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x21, usbTxBuf1, usbTxLen1-1);
|
||||
#else
|
||||
DBG1(0x21, usbTxBuf1 + 1, 2);
|
||||
DBG2(0x21, usbTxBuf1, len + 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len)
|
||||
{
|
||||
uchar *p, i;
|
||||
|
||||
if(usbTxLen3 & 0x10){ /* packet buffer was empty */
|
||||
usbTxBuf3[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
|
||||
}else{
|
||||
usbTxLen3 = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
|
||||
}
|
||||
p = usbTxBuf3 + 1;
|
||||
for(i=len;i--;)
|
||||
*p++ = *data++;
|
||||
usbCrc16Append(&usbTxBuf3[1], len);
|
||||
usbTxLen3 = len + 4; /* len must be given including sync byte */
|
||||
DBG2(0x23, usbTxBuf3, len + 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static uchar usbRead(uchar *data, uchar len)
|
||||
static uchar usbRead(uchar *data, uchar len)
|
||||
{
|
||||
#if USB_CFG_IMPLEMENT_FN_READ
|
||||
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 */
|
||||
while(i--){
|
||||
uchar c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
if ((usbDescrConfig + 18 + 7) == (void*)r) {
|
||||
*data++ = rt_usbHidReportDescriptorSize;
|
||||
}
|
||||
else {
|
||||
*data++ = c;
|
||||
}
|
||||
#else
|
||||
*data++ = c;
|
||||
#endif
|
||||
|
||||
*data++ = c;
|
||||
r++;
|
||||
}
|
||||
}else{ /* RAM data */
|
||||
@ -282,6 +282,23 @@ static uchar usbRead(uchar *data, uchar len)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define GET_DESCRIPTOR(cfgProp, staticName) \
|
||||
if(cfgProp){ \
|
||||
if((cfgProp) & USB_PROP_IS_RAM) \
|
||||
flags &= ~USB_FLG_MSGPTR_IS_ROM; \
|
||||
if((cfgProp) & USB_PROP_IS_DYNAMIC){ \
|
||||
replyLen = usbFunctionDescriptor(rq); \
|
||||
}else{ \
|
||||
replyData = (uchar *)(staticName); \
|
||||
SET_REPLY_LEN((cfgProp) & 0xff); \
|
||||
} \
|
||||
}
|
||||
/* We use if() instead of #if in the macro above because #if can't be used
|
||||
* in macros and the compiler optimizes constant conditions anyway.
|
||||
*/
|
||||
|
||||
|
||||
/* Don't make this function static to avoid inlining.
|
||||
* The entire function would become too large and exceed the range of
|
||||
* relative jumps.
|
||||
@ -293,20 +310,32 @@ static void usbProcessRx(uchar *data, uchar len)
|
||||
{
|
||||
usbRequest_t *rq = (void *)data;
|
||||
uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
||||
|
||||
|
||||
/* We use if() cascades because the compare is done byte-wise while switch()
|
||||
* is int-based. The if() cascades are therefore more efficient.
|
||||
*/
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, len);
|
||||
#else
|
||||
DBG1(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, 2);
|
||||
/* usbRxToken can be:
|
||||
* 0x2d 00101101 (USBPID_SETUP for endpoint 0)
|
||||
* 0xe1 11100001 (USBPID_OUT for endpoint 0)
|
||||
* 0xff 11111111 (USBPID_OUT for endpoint 1)
|
||||
*/
|
||||
DBG2(0x10 + ((usbRxToken >> 1) & 3), data, len); /* SETUP0=12; OUT0=10; OUT1=13 */
|
||||
#ifdef USB_RX_USER_HOOK
|
||||
USB_RX_USER_HOOK(data, len)
|
||||
#endif
|
||||
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
|
||||
if(usbRxToken == 0xff){
|
||||
usbFunctionWriteOut(data, len);
|
||||
return; /* no reply expected, hence no usbMsgPtr, usbMsgFlags, usbMsgLen set */
|
||||
}
|
||||
#endif
|
||||
if(usbRxToken == (uchar)USBPID_SETUP){
|
||||
usbTxLen = USBPID_NAK; /* abort pending transmit */
|
||||
if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */
|
||||
uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
|
||||
if(type == USBRQ_TYPE_STANDARD){
|
||||
#define SET_REPLY_LEN(len) replyLen = (len); usbMsgPtr = replyData
|
||||
/* This macro ensures that replyLen and usbMsgPtr are always set in the same way.
|
||||
* That allows optimization of common code in if() branches */
|
||||
uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */
|
||||
replyData[0] = 0; /* common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */
|
||||
if(rq->bRequest == USBRQ_GET_STATUS){ /* 0 */
|
||||
@ -316,112 +345,93 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
||||
replyData[0] = USB_CFG_IS_SELF_POWERED;
|
||||
#endif
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_IMPLEMENT_HALT
|
||||
if(usbHalted1 && recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */
|
||||
replyData[0] = 1;
|
||||
if(recipient == USBRQ_RCPT_ENDPOINT && rq->wIndex.bytes[0] == 0x81) /* request status for endpoint 1 */
|
||||
replyData[0] = usbTxLen1 == USBPID_STALL;
|
||||
#endif
|
||||
replyData[1] = 0;
|
||||
replyLen = 2;
|
||||
SET_REPLY_LEN(2);
|
||||
}else if(rq->bRequest == USBRQ_SET_ADDRESS){ /* 5 */
|
||||
usbNewDeviceAddr = rq->wValue.bytes[0];
|
||||
}else if(rq->bRequest == USBRQ_GET_DESCRIPTOR){ /* 6 */
|
||||
flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW;
|
||||
if(rq->wValue.bytes[1] == 1){ /* descriptor type requested */
|
||||
#ifndef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
replyLen = sizeof(usbDescrDevice);
|
||||
replyData = (uchar *)usbDescrDevice;
|
||||
#else
|
||||
replyLen = rt_usbDeviceDescriptorSize;
|
||||
replyData = (uchar *)rt_usbDeviceDescriptor;
|
||||
#endif
|
||||
}else if(rq->wValue.bytes[1] == 2){
|
||||
replyLen = sizeof(usbDescrConfig);
|
||||
replyData = (uchar *)usbDescrConfig;
|
||||
}else if(rq->wValue.bytes[1] == 3){ /* string descriptor */
|
||||
if(rq->wValue.bytes[1] == USBDESCR_DEVICE){ /* 1 */
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice)
|
||||
}else if(rq->wValue.bytes[1] == USBDESCR_CONFIG){ /* 2 */
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration)
|
||||
}else if(rq->wValue.bytes[1] == USBDESCR_STRING){ /* 3 */
|
||||
#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC
|
||||
if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM)
|
||||
flags &= ~USB_FLG_MSGPTR_IS_ROM;
|
||||
replyLen = usbFunctionDescriptor(rq);
|
||||
#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
|
||||
if(rq->wValue.bytes[0] == 0){ /* descriptor index */
|
||||
replyLen = sizeof(usbDescrString0);
|
||||
replyData = (uchar *)usbDescrString0;
|
||||
#if USB_CFG_VENDOR_NAME_LEN
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0)
|
||||
}else if(rq->wValue.bytes[0] == 1){
|
||||
replyLen = sizeof(usbDescrString1);
|
||||
replyData = (uchar *)usbDescrString1;
|
||||
#endif
|
||||
#if USB_CFG_DEVICE_NAME_LEN
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor)
|
||||
}else if(rq->wValue.bytes[0] == 2){
|
||||
replyLen = sizeof(usbDescrString2);
|
||||
replyData = (uchar *)usbDescrString2;
|
||||
#endif
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice)
|
||||
}else if(rq->wValue.bytes[0] == 3){
|
||||
replyLen = 2 * USB_CFG_SERIAL_NUMBER_LENGTH + 2;
|
||||
replyData = (uchar *)usbCfgSerialNumberStringDescriptor;
|
||||
#endif
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber)
|
||||
}else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
|
||||
replyLen = usbFunctionDescriptor(rq);
|
||||
}
|
||||
}
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH || defined(USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME)
|
||||
else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */
|
||||
replyLen = 9;
|
||||
replyData = (uchar *)usbDescrConfig + 18;
|
||||
#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
|
||||
#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */
|
||||
}else if(rq->wValue.bytes[1] == USBDESCR_HID){ /* 0x21 */
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18)
|
||||
}else if(rq->wValue.bytes[1] == USBDESCR_HID_REPORT){ /* 0x22 */
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
replyLen = USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH;
|
||||
replyData = (uchar *)usbHidReportDescriptor;
|
||||
#endif
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
replyLen = rt_usbHidReportDescriptorSize;
|
||||
replyData = (uchar *)rt_usbHidReportDescriptor;
|
||||
//replyData = snes_usbHidReportDescriptor;
|
||||
// if (replyData != (void*)0x86) { LED_ON(); }
|
||||
// if (replyLen != 42) { LED_ON(); }
|
||||
#endif
|
||||
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport)
|
||||
#endif /* USB_CFG_DESCR_PROPS_HID_REPORT */
|
||||
}else if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
|
||||
replyLen = usbFunctionDescriptor(rq);
|
||||
}
|
||||
#endif
|
||||
}else if(rq->bRequest == USBRQ_GET_CONFIGURATION){ /* 8 */
|
||||
replyLen = 1;
|
||||
replyData = &usbConfiguration; /* send current configuration value */
|
||||
SET_REPLY_LEN(1);
|
||||
}else if(rq->bRequest == USBRQ_SET_CONFIGURATION){ /* 9 */
|
||||
usbConfiguration = rq->wValue.bytes[0];
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
usbHalted1 = 0;
|
||||
usbTxLen1 = USBPID_NAK;
|
||||
#endif
|
||||
}else if(rq->bRequest == USBRQ_GET_INTERFACE){ /* 10 */
|
||||
replyLen = 1;
|
||||
SET_REPLY_LEN(1);
|
||||
#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 */
|
||||
if(rq->wValue.bytes[0] == 0 && rq->wIndex.bytes[0] == 0x81){ /* feature 0 == HALT for endpoint == 1 */
|
||||
usbHalted1 = rq->bRequest - 1;
|
||||
if(usbHalted1){
|
||||
usbTxBuf1[0] = USBPID_STALL;
|
||||
usbTxLen1 = 2; /* length including sync byte */
|
||||
}
|
||||
usbTxPacketCnt1 = 0; /* reset data toggling for interrupt endpoint */
|
||||
usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL;
|
||||
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
}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{
|
||||
/* the following requests can be ignored, send default reply */
|
||||
/* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
|
||||
/* 12: SYNCH_FRAME */
|
||||
}
|
||||
usbMsgPtr = replyData;
|
||||
if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* max length is in */
|
||||
replyLen = rq->wLength.bytes[0];
|
||||
#undef SET_REPLY_LEN
|
||||
}else{ /* not a standard request -- must be vendor or class request */
|
||||
replyLen = usbFunctionSetup(data);
|
||||
#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
|
||||
if(replyLen == 0xff){ /* use user-supplied read/write function */
|
||||
if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_DEVICE_TO_HOST){
|
||||
replyLen = rq->wLength.bytes[0]; /* IN transfers only */
|
||||
}
|
||||
flags = 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 */
|
||||
}else{ /* DATA packet from out request */
|
||||
@ -430,16 +440,13 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
||||
uchar rval = usbFunctionWrite(data, len);
|
||||
replyLen = 0xff;
|
||||
if(rval == 0xff){ /* an error occurred */
|
||||
/* usbMsgLen = 0xff; cancel potentially pending ACK [has been done by ASM module when OUT token arrived] */
|
||||
usbTxBuf[0] = USBPID_STALL;
|
||||
usbTxLen = 2; /* length including sync byte */
|
||||
usbMsgLen = 0xff; /* cancel potentially pending data packet for ACK */
|
||||
usbTxLen = USBPID_STALL;
|
||||
}else if(rval != 0){ /* This was the final package */
|
||||
replyLen = 0; /* answer with a zero-sized data packet */
|
||||
}
|
||||
flags = 0; /* start with a DATA1 package, stay with user supplied write() function */
|
||||
}
|
||||
#else
|
||||
replyLen = 0; /* send zero-sized block as ACK */
|
||||
#endif
|
||||
}
|
||||
usbMsgFlags = flags;
|
||||
@ -450,7 +457,7 @@ uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
|
||||
|
||||
static void usbBuildTxBlock(void)
|
||||
{
|
||||
uchar wantLen, len, txLen, token;
|
||||
uchar wantLen, len, txLen, token;
|
||||
|
||||
wantLen = usbMsgLen;
|
||||
if(wantLen > 8)
|
||||
@ -462,22 +469,17 @@ uchar wantLen, len, txLen, token;
|
||||
usbMsgFlags++;
|
||||
len = usbRead(usbTxBuf + 1, wantLen);
|
||||
if(len <= 8){ /* valid data packet */
|
||||
usbCrc16Append(usbTxBuf + 1, len);
|
||||
usbCrc16Append(&usbTxBuf[1], len);
|
||||
txLen = len + 4; /* length including sync byte */
|
||||
if(len < 8) /* a partial package identifies end of message */
|
||||
usbMsgLen = 0xff;
|
||||
}else{
|
||||
token = USBPID_STALL;
|
||||
txLen = 2; /* length including sync byte */
|
||||
txLen = USBPID_STALL; /* stall the endpoint */
|
||||
usbMsgLen = 0xff;
|
||||
}
|
||||
usbTxBuf[0] = token;
|
||||
usbTxLen = txLen;
|
||||
#if DEBUG_LEVEL > 1
|
||||
DBG2(0x20, usbTxBuf, txLen-1);
|
||||
#else
|
||||
DBG1(0x20, usbTxBuf + 1, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uchar isNotSE0(void)
|
||||
@ -494,59 +496,52 @@ uchar rval;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void usbPoll(void)
|
||||
USB_PUBLIC void usbPoll(void)
|
||||
{
|
||||
uchar len;
|
||||
schar len;
|
||||
uchar i;
|
||||
|
||||
if((len = usbRxLen) > 0){
|
||||
/* We could check CRC16 here -- but ACK has already been sent anyway. If you
|
||||
* need data integrity checks with this driver, check the CRC in your app
|
||||
* code and report errors back to the host. Since the ACK was already sent,
|
||||
* retries must be handled on application level.
|
||||
* unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);
|
||||
* unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3);
|
||||
*/
|
||||
len -= 3; /* remove PID and CRC */
|
||||
if(len < 128){ /* no overflow */
|
||||
converter_t appBuf;
|
||||
appBuf.ptr = (uchar *)usbRxBuf;
|
||||
appBuf.bytes[0] = usbAppBuf;
|
||||
appBuf.bytes[0]++;
|
||||
usbProcessRx(appBuf.ptr, len);
|
||||
}
|
||||
usbRxLen = 0; /* mark rx buffer as available */
|
||||
}
|
||||
if(usbMsgLen != 0xff){ /* transmit data pending? */
|
||||
if(usbTxLen < 0) /* transmit system idle */
|
||||
usbBuildTxBlock();
|
||||
}
|
||||
if(isNotSE0()){ /* SE0 state */
|
||||
usbIsReset = 0;
|
||||
}else{
|
||||
/* check whether SE0 lasts for more than 2.5us (3.75 bit times) */
|
||||
if(!usbIsReset){
|
||||
uchar i;
|
||||
for(i=100;i;i--){
|
||||
if(isNotSE0())
|
||||
goto notUsbReset;
|
||||
}
|
||||
usbIsReset = 1;
|
||||
usbNewDeviceAddr = 0;
|
||||
usbDeviceAddr = 0;
|
||||
#if USB_CFG_IMPLEMENT_HALT
|
||||
usbHalted1 = 0;
|
||||
usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len - 3);
|
||||
#if USB_CFG_HAVE_FLOWCONTROL
|
||||
if(usbRxLen > 0) /* only mark as available if not inactivated */
|
||||
usbRxLen = 0;
|
||||
#else
|
||||
usbRxLen = 0; /* mark rx buffer as available */
|
||||
#endif
|
||||
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
|
||||
USB_INTR_CFG |= USB_INTR_CFG_SET;
|
||||
#endif
|
||||
@ -554,6 +549,12 @@ void usbInit(void)
|
||||
USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
|
||||
#endif
|
||||
USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
429
usbdrv/usbdrv.h
429
usbdrv/usbdrv.h
@ -4,8 +4,8 @@
|
||||
* Creation Date: 2004-12-29
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: usbdrv.h,v 1.1 2007-03-25 02:59:32 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: usbdrv.h,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||
*/
|
||||
|
||||
#ifndef __usbdrv_h_included__
|
||||
@ -16,12 +16,14 @@
|
||||
/*
|
||||
Hardware Prerequisites:
|
||||
=======================
|
||||
USB lines D+ and D- MUST be wired to the same I/O port. Line D- MUST be wired
|
||||
to bit number 0. D+ must also be connected to INT0. D- requires a pullup of
|
||||
1.5k to +3.5V (and the device must be powered at 3.5V) to identify as
|
||||
low-speed USB device. A pullup of 1M SHOULD be connected from D+ to +3.5V to
|
||||
prevent interference when no USB master is connected. We use D+ as interrupt
|
||||
source and not D- because it does not trigger on keep-alive and RESET states.
|
||||
USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+
|
||||
triggers the interrupt (best achieved by using INT0 for D+), but it is also
|
||||
possible to trigger the interrupt from D-. If D- is used, interrupts are also
|
||||
triggered by SOF packets. D- requires a pullup of 1.5k to +3.5V (and the device
|
||||
must be powered at 3.5V) to identify as low-speed USB device. A pullup of
|
||||
1M SHOULD be connected from D+ to +3.5V to prevent interference when no USB
|
||||
master is connected. We use D+ as interrupt source and not D- because it
|
||||
does not trigger on keep-alive and RESET states.
|
||||
|
||||
As a compile time option, the 1.5k pullup resistor on D- can be made
|
||||
switchable to allow the device to disconnect at will. See the definition of
|
||||
@ -29,27 +31,12 @@ usbDeviceConnect() and usbDeviceDisconnect() further down in this file.
|
||||
|
||||
Please adapt the values in usbconfig.h according to your hardware!
|
||||
|
||||
The device MUST be clocked at 12 MHz. This is more than the 10 MHz allowed by
|
||||
an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock
|
||||
relation is interpolated linearly, an ATtiny2313 meets the requirement by
|
||||
specification. In practice, the AT90S2313 can be overclocked and works well.
|
||||
The device MUST be clocked at exactly 12 MHz, 15 MHz or 16 MHz
|
||||
or at 16.5 MHz +/- 1%. See usbconfig-prototype.h for details.
|
||||
|
||||
|
||||
Limitations:
|
||||
============
|
||||
Compiling:
|
||||
You should link the usbdrv.o module first because it has special alignment
|
||||
requirements for the receive buffer (the buffer must not cross a 256 byte
|
||||
page boundary, it must not even touch it at the end). If you can't link it
|
||||
first, you must use other measures to ensure alignment.
|
||||
Note: gcc does not always assign variable addresses in the order as the modules
|
||||
are linked or the variables are declared. You can choose a memory section for
|
||||
the receive buffer with the configuration option "USB_BUFFER_SECTION". This
|
||||
option defaults to ".bss". If you use your own section, you can place it at
|
||||
an arbitrary location with a linker option similar to
|
||||
"-Wl,--section-start=.mybuffer=0x800060". Use "avr-nm -ng" on the binary and
|
||||
search for "usbRxBuf" to find tbe base address of the 22 bytes rx buffer.
|
||||
|
||||
Robustness with respect to communication errors:
|
||||
The driver assumes error-free communication. It DOES check for errors in
|
||||
the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
|
||||
@ -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
|
||||
toggling, but application software can implement the check.
|
||||
|
||||
Sampling jitter:
|
||||
The driver guarantees a sampling window of 1/2 bit. The USB spec requires
|
||||
that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
|
||||
should still work reliably enough because we work at low speed. If you want
|
||||
to meet the spec, define the macro "USB_CFG_SAMPLE_EXACT" to 1 in usbconfig.h.
|
||||
This will unroll a loop which results in bigger code size.
|
||||
|
||||
Input characteristics:
|
||||
Since no differential receiver circuit is used, electrical interference
|
||||
robustness may suffer. The driver samples only one of the data lines with
|
||||
@ -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.
|
||||
|
||||
Number of endpoints:
|
||||
The driver supports up to two endpoints: One control endpoint (endpoint 0) and
|
||||
one interrupt-in endpoint (endpoint 1) where the device can send interrupt
|
||||
data to the host. Endpoint 1 is only compiled in if
|
||||
USB_CFG_HAVE_INTRIN_ENDPOINT is defined to 1 in usbconfig.h.
|
||||
The driver supports up to four endpoints: One control endpoint (endpoint 0),
|
||||
two interrupt-in (or bulk-in) endpoints (endpoint 1 and 3) and one
|
||||
interrupt-out (or bulk-out) endpoint (endpoint 1). Please note that the USB
|
||||
standard forbids bulk endpoints for low speed devices! Most operating systems
|
||||
allow them anyway, but the AVR will spend 90% of the CPU time in the USB
|
||||
interrupt polling for bulk data.
|
||||
By default, only the control endpoint 0 is enabled. To get the other endpoints,
|
||||
define USB_CFG_HAVE_INTRIN_ENDPOINT, USB_CFG_HAVE_INTRIN_ENDPOINT3 and/or
|
||||
USB_CFG_IMPLEMENT_FN_WRITEOUT respectively (see usbconfig-prototype.h for
|
||||
details).
|
||||
|
||||
Maximum data payload:
|
||||
Data payload of control in and out transfers may be up to 254 bytes. In order
|
||||
@ -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.
|
||||
However, the application may implement activity monitoring and wakeup from
|
||||
sleep. The host sends regular SE0 states on the bus to keep it active. These
|
||||
SE0 states can be detected by wiring the INT1 pin to D+. It is not necessary
|
||||
SE0 states can be detected by wiring the INT1 pin to D-. It is not necessary
|
||||
to enable the interrupt, checking the interrupt pending flag should suffice.
|
||||
Before entering sleep mode, the application should enable INT1 for a wakeup
|
||||
on the next bus activity.
|
||||
@ -100,21 +86,22 @@ on the next bus activity.
|
||||
Operation without an USB master:
|
||||
The driver behaves neutral without connection to an USB master if D- reads
|
||||
as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M)
|
||||
pullup resistor on D+. If D- becomes statically 0, the driver may block in
|
||||
the interrupt routine.
|
||||
pullup resistor on D+ (interrupt). If D- becomes statically 0, the driver may
|
||||
block in the interrupt routine.
|
||||
|
||||
Interrupt latency:
|
||||
The application must ensure that the USB interrupt is not disabled for more
|
||||
than 20 cycles. This implies that all interrupt routines must either be
|
||||
declared as "INTERRUPT" instead of "SIGNAL" (see "avr/signal.h") or that they
|
||||
are written in assembler with "sei" as the first instruction.
|
||||
than 25 cycles (this is for 12 MHz, faster clocks allow longer latency).
|
||||
This implies that all interrupt routines must either be declared as "INTERRUPT"
|
||||
instead of "SIGNAL" (see "avr/signal.h") or that they are written in assembler
|
||||
with "sei" as the first instruction.
|
||||
|
||||
Maximum interrupt duration / CPU cycle consumption:
|
||||
The driver handles all USB communication during the interrupt service
|
||||
routine. The routine will not return before an entire USB message is received
|
||||
and the reply is sent. This may be up to ca. 1200 cycles = 100us if the host
|
||||
conforms to the standard. The driver will consume CPU cycles for all USB
|
||||
messages, even if they address another (low-speed) device on the same bus.
|
||||
and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if
|
||||
the host conforms to the standard. The driver will consume CPU cycles for all
|
||||
USB messages, even if they address another (low-speed) device on the same bus.
|
||||
|
||||
*/
|
||||
|
||||
@ -122,7 +109,7 @@ messages, even if they address another (low-speed) device on the same bus.
|
||||
/* --------------------------- Module Interface ---------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define USBDRV_VERSION 20060314
|
||||
#define USBDRV_VERSION 20070919
|
||||
/* This define uniquely identifies a driver version. It is a decimal number
|
||||
* constructed from the driver's release date in the form YYYYMMDD. If the
|
||||
* driver's behavior or interface changes, you can use this constant to
|
||||
@ -130,8 +117,18 @@ messages, even if they address another (low-speed) device on the same bus.
|
||||
* 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
|
||||
#define uchar unsigned char
|
||||
#endif
|
||||
@ -140,23 +137,25 @@ messages, even if they address another (low-speed) device on the same bus.
|
||||
#endif
|
||||
/* 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
|
||||
* loop is entered.
|
||||
*/
|
||||
extern void usbPoll(void);
|
||||
USB_PUBLIC void usbPoll(void);
|
||||
/* This function must be called at regular intervals from the main loop.
|
||||
* Maximum delay between calls is somewhat less than 50ms (USB timeout for
|
||||
* accepting a Setup message). Otherwise the device will not be recognized.
|
||||
* Please note that debug outputs through the UART take ~ 0.5ms per byte
|
||||
* at 19200 bps.
|
||||
*/
|
||||
extern uchar *usbMsgPtr;
|
||||
extern uchar *usbMsgPtr;
|
||||
/* This variable may be used to pass transmit data to the driver from the
|
||||
* implementation of usbFunctionWrite(). It is also used internally by the
|
||||
* driver for standard control requests.
|
||||
*/
|
||||
extern uchar usbFunctionSetup(uchar data[8]);
|
||||
USB_PUBLIC uchar usbFunctionSetup(uchar data[8]);
|
||||
/* This function is called when the driver receives a SETUP transaction from
|
||||
* the host which is not answered by the driver itself (in practice: class and
|
||||
* vendor requests). All control transfers start with a SETUP transaction where
|
||||
@ -183,23 +182,36 @@ extern uchar usbFunctionSetup(uchar data[8]);
|
||||
* Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
|
||||
* are only done if enabled by the configuration in usbconfig.h.
|
||||
*/
|
||||
USB_PUBLIC uchar usbFunctionDescriptor(struct usbRequest *rq);
|
||||
/* You need to implement this function ONLY if you provide USB descriptors at
|
||||
* runtime (which is an expert feature). It is very similar to
|
||||
* usbFunctionSetup() above, but it is called only to request USB descriptor
|
||||
* data. See the documentation of usbFunctionSetup() above for more info.
|
||||
*/
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
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
|
||||
* IN transfer. The message is copied to an internal buffer and must not exceed
|
||||
* a length of 8 bytes. The message may be 0 bytes long just to indicate the
|
||||
* interrupt status to the host.
|
||||
* If you need to transfer more bytes, use a control read after the interrupt.
|
||||
*/
|
||||
extern volatile schar usbTxLen1;
|
||||
#define usbInterruptIsReady() (usbTxLen1 == -1)
|
||||
extern volatile uchar usbTxLen1;
|
||||
#define usbInterruptIsReady() (usbTxLen1 & 0x10)
|
||||
/* This macro indicates whether the last interrupt message has already been
|
||||
* sent. If you set a new interrupt message before the old was sent, the
|
||||
* message already buffered will be lost.
|
||||
*/
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
|
||||
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len);
|
||||
extern volatile uchar usbTxLen3;
|
||||
#define usbInterruptIsReady3() (usbTxLen3 & 0x10)
|
||||
/* Same as above for endpoint 3 */
|
||||
#endif
|
||||
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
|
||||
extern PROGMEM const char usbHidReportDescriptor[];
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */
|
||||
#define usbHidReportDescriptor usbDescriptorHidReport
|
||||
/* should be declared as: PROGMEM char usbHidReportDescriptor[]; */
|
||||
/* If you implement an HID device, you need to provide a report descriptor.
|
||||
* The HID report descriptor syntax is a bit complex. If you understand how
|
||||
* report descriptors are constructed, we recommend that you use the HID
|
||||
@ -207,21 +219,8 @@ extern PROGMEM const char usbHidReportDescriptor[];
|
||||
* Otherwise you should probably start with a working example.
|
||||
*/
|
||||
#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
|
||||
#ifdef USB_CFG_DEVICE_DESCRIPTOR_RUNTIME
|
||||
extern const char *rt_usbDeviceDescriptor;
|
||||
extern uchar rt_usbDeviceDescriptorSize;
|
||||
#endif
|
||||
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_RUNTIME
|
||||
/* If you have many different HID report descriptors and
|
||||
* you want to select one of them at runtime (dip switchs?),
|
||||
* set those globals variables before initializing the driver.
|
||||
*/
|
||||
extern const char *rt_usbHidReportDescriptor;
|
||||
extern uchar rt_usbHidReportDescriptorSize;
|
||||
#endif
|
||||
|
||||
#if USB_CFG_IMPLEMENT_FN_WRITE
|
||||
extern uchar usbFunctionWrite(uchar *data, uchar len);
|
||||
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len);
|
||||
/* This function is called by the driver to provide a control transfer's
|
||||
* payload data (control-out). It is called in chunks of up to 8 bytes. The
|
||||
* total count provided in the current control transfer can be obtained from
|
||||
@ -239,7 +238,7 @@ extern uchar usbFunctionWrite(uchar *data, uchar len);
|
||||
*/
|
||||
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
|
||||
#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
|
||||
* 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
|
||||
@ -250,26 +249,37 @@ extern uchar usbFunctionRead(uchar *data, uchar len);
|
||||
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
|
||||
*/
|
||||
#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)), \
|
||||
(USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT)))
|
||||
/* This macro (intended to look like a function) connects the device to the
|
||||
* USB bus. It is only available if you have defined the constants
|
||||
* USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
|
||||
*/
|
||||
#define usbDeviceDisconnect() (USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT))
|
||||
#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
|
||||
* the USB bus. It is only available if you have defined the constants
|
||||
* USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT in usbconfig.h.
|
||||
*/
|
||||
#endif /* USB_CFG_PULLUP_IOPORT */
|
||||
extern unsigned usbCrc16(uchar *data, uchar len);
|
||||
extern unsigned usbCrc16(unsigned data, uchar len);
|
||||
#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
|
||||
/* This function calculates the binary complement of the data CRC used in
|
||||
* USB data packets. The value is used to build raw transmit packets.
|
||||
* You may want to use this function for data checksums or to verify received
|
||||
* data.
|
||||
* 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
|
||||
* the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
|
||||
* bytes.
|
||||
@ -281,27 +291,173 @@ extern uchar usbConfiguration;
|
||||
* 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.
|
||||
*/
|
||||
#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))
|
||||
/* This macro builds a descriptor header for a string descriptor given the
|
||||
* string's length. See usbdrv.c for an example how to use it.
|
||||
*/
|
||||
#if USB_CFG_SERIAL_NUMBER_LENGTH
|
||||
extern PROGMEM int usbCfgSerialNumberStringDescriptor[];
|
||||
/* This array of unicode characters (prefixed by a string descriptor header as
|
||||
* explained above) represents the serial number of the device.
|
||||
#if USB_CFG_HAVE_FLOWCONTROL
|
||||
extern volatile schar usbRxLen;
|
||||
#define usbDisableAllRequests() usbRxLen = -1
|
||||
/* Must be called from usbFunctionWrite(). This macro disables all data input
|
||||
* from the USB interface. Requests from the host are answered with a NAK
|
||||
* while they are disabled.
|
||||
*/
|
||||
#define usbEnableAllRequests() usbRxLen = 0
|
||||
/* May only be called if requests are disabled. This macro enables input from
|
||||
* the USB interface after it has been disabled with usbDisableAllRequests().
|
||||
*/
|
||||
#define usbAllRequestsAreDisabled() (usbRxLen < 0)
|
||||
/* Use this macro to find out whether requests are disabled. It may be needed
|
||||
* to ensure that usbEnableAllRequests() is never called when requests are
|
||||
* enabled.
|
||||
*/
|
||||
#endif
|
||||
|
||||
#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__ */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ----------------- 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 -------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
|
||||
#error "You MUST NOT use obdev's shared VID/PID with HID class devices!"
|
||||
/* The shared VID/PID must be used in conjunction with libusb (see license for
|
||||
* the IDs). This contradicts HID usage (at least on Windows).
|
||||
#if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
|
||||
#warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h"
|
||||
/* If the user has not defined IDs, we default to obdev's free IDs.
|
||||
* See USBID-License.txt for details.
|
||||
*/
|
||||
#endif
|
||||
|
||||
@ -311,59 +467,79 @@ extern PROGMEM int usbCfgSerialNumberStringDescriptor[];
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifndef USB_BUFFER_SECTION
|
||||
# define USB_BUFFER_SECTION ".bss" /* if user has not selected a named section */
|
||||
/* Derive Output, Input and DataDirection ports from port names */
|
||||
#ifndef USB_CFG_IOPORTNAME
|
||||
#error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h"
|
||||
#endif
|
||||
|
||||
/* I/O definitions for assembler module */
|
||||
#define USBOUT USB_CFG_IOPORT /* output port for USB bits */
|
||||
#define USB_PULLUP_OUT USB_CFG_PULLUP_IOPORT
|
||||
#ifdef __ASSEMBLER__
|
||||
/* the following two lines must start in column 0 for IAR assembler */
|
||||
USBIN = (USB_CFG_IOPORT - 2) /* input port for USB bits */
|
||||
USBDDR = (USB_CFG_IOPORT - 1) /* data direction for USB bits */
|
||||
#else
|
||||
#define USBIN (*(&USB_CFG_IOPORT - 2)) /* input port for USB bits */
|
||||
#define USBDDR (*(&USB_CFG_IOPORT - 1)) /* data direction for USB bits */
|
||||
#define USB_PULLUP_DDR (*(&USB_CFG_PULLUP_IOPORT - 1))
|
||||
#define USBOUT USB_OUTPORT(USB_CFG_IOPORTNAME)
|
||||
#define USB_PULLUP_OUT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||
#define USBIN USB_INPORT(USB_CFG_IOPORTNAME)
|
||||
#define USBDDR USB_DDRPORT(USB_CFG_IOPORTNAME)
|
||||
#define USB_PULLUP_DDR USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||
|
||||
#define USBMINUS USB_CFG_DMINUS_BIT
|
||||
#define USBPLUS USB_CFG_DPLUS_BIT
|
||||
#define USBIDLE (1<<USB_CFG_DMINUS_BIT) /* value representing J state */
|
||||
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT)) /* mask for USB I/O bits */
|
||||
|
||||
/* defines for backward compatibility with older driver versions: */
|
||||
#define USB_CFG_IOPORT USB_OUTPORT(USB_CFG_IOPORTNAME)
|
||||
#ifdef USB_CFG_PULLUP_IOPORTNAME
|
||||
#define USB_CFG_PULLUP_IOPORT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
|
||||
#endif
|
||||
#if USB_CFG_DMINUS_BIT != 0
|
||||
# error "USB_CFG_DMINUS_BIT MUST be 0!"
|
||||
#endif
|
||||
#define USBMINUS 0 /* D- MUST be on bit 0 */
|
||||
#define USBIDLE 0x01 /* value representing J state */
|
||||
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | 1) /* mask for USB I/O bits */
|
||||
|
||||
|
||||
#define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */
|
||||
|
||||
/* Try to find registers and bits responsible for ext interrupt 0 */
|
||||
/* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */
|
||||
|
||||
#if defined EICRA
|
||||
# define USB_INTR_CFG EICRA
|
||||
#else
|
||||
# define USB_INTR_CFG MCUCR
|
||||
#ifndef USB_INTR_CFG /* allow user to override our default */
|
||||
# if defined EICRA
|
||||
# define USB_INTR_CFG EICRA
|
||||
# else
|
||||
# define USB_INTR_CFG MCUCR
|
||||
# endif
|
||||
#endif
|
||||
#ifndef USB_INTR_CFG_SET /* allow user to override our default */
|
||||
# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */
|
||||
#endif
|
||||
#ifndef USB_INTR_CFG_CLR /* allow user to override our default */
|
||||
# define USB_INTR_CFG_CLR 0 /* no bits to clear */
|
||||
#endif
|
||||
#define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */
|
||||
#define USB_INTR_CFG_CLR 0 /* no bits to clear */
|
||||
|
||||
#if defined GIMSK
|
||||
# define USB_INTR_ENABLE GIMSK
|
||||
#elif defined EIMSK
|
||||
# define USB_INTR_ENABLE EIMSK
|
||||
#else
|
||||
# define USB_INTR_ENABLE GICR
|
||||
#ifndef USB_INTR_ENABLE /* allow user to override our default */
|
||||
# if defined GIMSK
|
||||
# define USB_INTR_ENABLE GIMSK
|
||||
# elif defined EIMSK
|
||||
# define USB_INTR_ENABLE EIMSK
|
||||
# else
|
||||
# define USB_INTR_ENABLE GICR
|
||||
# endif
|
||||
#endif
|
||||
#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
|
||||
# define USB_INTR_ENABLE_BIT INT0
|
||||
#endif
|
||||
#define USB_INTR_ENABLE_BIT INT0
|
||||
|
||||
#if defined EIFR
|
||||
# define USB_INTR_PENDING EIFR
|
||||
#else
|
||||
# define USB_INTR_PENDING GIFR
|
||||
#ifndef USB_INTR_PENDING /* allow user to override our default */
|
||||
# if defined EIFR
|
||||
# define USB_INTR_PENDING EIFR
|
||||
# else
|
||||
# define USB_INTR_PENDING GIFR
|
||||
# endif
|
||||
#endif
|
||||
#ifndef USB_INTR_PENDING_BIT /* allow user to override our default */
|
||||
# define USB_INTR_PENDING_BIT INTF0
|
||||
#endif
|
||||
#define USB_INTR_PENDING_BIT INTF0
|
||||
|
||||
/*
|
||||
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_STALL 0x1e
|
||||
|
||||
#ifndef USB_INITIAL_DATATOKEN
|
||||
#define USB_INITIAL_DATATOKEN USBPID_DATA0
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
extern uchar usbTxBuf1[USB_BUFSIZE], usbTxBuf3[USB_BUFSIZE];
|
||||
|
||||
typedef union usbWord{
|
||||
unsigned word;
|
||||
uchar bytes[2];
|
||||
|
@ -1,20 +1,18 @@
|
||||
/* Name: usbdrvasm.S
|
||||
* Project: AVR USB driver
|
||||
* Author: Christian Starkjohann
|
||||
* Creation Date: 2004-12-29
|
||||
* Creation Date: 2007-06-13
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: usbdrvasm.S,v 1.1 2007-03-25 02:59:31 raph Exp $
|
||||
* Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* Revision: $Id: usbdrvasm.S,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
General Description:
|
||||
This module implements the assembler part of the USB driver. See usbdrv.h
|
||||
for a description of the entire driver.
|
||||
Since almost all of this code is timing critical, don't change unless you
|
||||
really know what you are doing! Many parts require not only a maximum number
|
||||
of CPU cycles, but even an exact number of cycles!
|
||||
This module is the assembler part of the USB driver. This file contains
|
||||
general code (preprocessor acrobatics and CRC computation) and then includes
|
||||
the file appropriate for the given clock rate.
|
||||
*/
|
||||
|
||||
#include "iarcompat.h"
|
||||
@ -26,7 +24,6 @@ of CPU cycles, but even an exact number of cycles!
|
||||
#endif /* __IAR_SYSTEMS_ASM__ */
|
||||
#include "usbdrv.h" /* for common defs */
|
||||
|
||||
|
||||
/* register names */
|
||||
#define x1 r16
|
||||
#define x2 r17
|
||||
@ -34,6 +31,9 @@ of CPU cycles, but even an exact number of cycles!
|
||||
#define cnt r19
|
||||
#define x3 r20
|
||||
#define x4 r21
|
||||
#define bitcnt r22
|
||||
#define phase x4
|
||||
#define leap x4
|
||||
|
||||
/* Some assembler dependent definitions and declarations: */
|
||||
|
||||
@ -47,615 +47,55 @@ of CPU cycles, but even an exact number of cycles!
|
||||
# define ZL r30
|
||||
# define ZH r31
|
||||
# define lo8(x) LOW(x)
|
||||
# define hi8(x) ((x)>>8) /* not HIGH to allow XLINK to make a proper range check */
|
||||
# define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */
|
||||
|
||||
extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBuf
|
||||
extern usbCurrentTok, usbRxLen, usbRxToken, usbAppBuf, usbTxLen
|
||||
extern usbTxBuf, usbMsgLen, usbNakBuf, usbAckBuf, usbTxLen1, usbTxBuf1
|
||||
extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
|
||||
extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
|
||||
extern usbTxBuf, usbMsgLen, usbTxLen1, usbTxBuf1, usbTxLen3, usbTxBuf3
|
||||
# if USB_COUNT_SOF
|
||||
extern usbSofCount
|
||||
# endif
|
||||
public usbCrc16
|
||||
public usbCrc16Append
|
||||
|
||||
# ifndef IVT_BASE_ADDRESS
|
||||
# define IVT_BASE_ADDRESS 0
|
||||
# endif
|
||||
|
||||
ASEG
|
||||
ORG INT0_vect + IVT_BASE_ADDRESS
|
||||
rjmp SIG_INTERRUPT0
|
||||
COMMON INTVEC
|
||||
# ifndef USB_INTR_VECTOR
|
||||
ORG INT0_vect
|
||||
# else /* USB_INTR_VECTOR */
|
||||
ORG USB_INTR_VECTOR
|
||||
# undef USB_INTR_VECTOR
|
||||
# endif /* USB_INTR_VECTOR */
|
||||
# define USB_INTR_VECTOR usbInterruptHandler
|
||||
rjmp USB_INTR_VECTOR
|
||||
RSEG CODE
|
||||
|
||||
#else /* __IAR_SYSTEMS_ASM__ */
|
||||
|
||||
# define nop2 rjmp .+0 /* jump to next instruction */
|
||||
|
||||
# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
|
||||
# define USB_INTR_VECTOR SIG_INTERRUPT0
|
||||
# endif
|
||||
.text
|
||||
.global SIG_INTERRUPT0
|
||||
.type SIG_INTERRUPT0, @function
|
||||
.global USB_INTR_VECTOR
|
||||
.type USB_INTR_VECTOR, @function
|
||||
.global usbCrc16
|
||||
.global usbCrc16Append
|
||||
|
||||
#endif /* __IAR_SYSTEMS_ASM__ */
|
||||
|
||||
|
||||
SIG_INTERRUPT0:
|
||||
;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
|
||||
;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
|
||||
;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable
|
||||
;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes
|
||||
usbInterrupt:
|
||||
;order of registers pushed:
|
||||
;x1, SREG, x2, cnt, shift, [YH, YL, x3]
|
||||
push x1 ;2 push only what is necessary to sync with edge ASAP
|
||||
in x1, SREG ;1
|
||||
push x1 ;2
|
||||
;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
|
||||
;sync up with J to K edge during sync pattern -- use fastest possible loops
|
||||
;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
|
||||
#if !USB_CFG_SAMPLE_EXACT
|
||||
ldi x1, 5 ;1 setup a timeout for waitForK
|
||||
#endif
|
||||
waitForJ:
|
||||
sbis USBIN, USBMINUS ;1 wait for D- == 1
|
||||
rjmp waitForJ ;2
|
||||
#if USB_CFG_SAMPLE_EXACT
|
||||
;The following code represents the unrolled loop in the else branch. It
|
||||
;results in a sampling window of 1/4 bit which meets the spec.
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK
|
||||
nop
|
||||
nop2
|
||||
foundK:
|
||||
#else
|
||||
waitForK:
|
||||
dec x1 ;1
|
||||
sbic USBIN, USBMINUS ;1 wait for D- == 0
|
||||
brne waitForK ;2
|
||||
#endif
|
||||
;{2, 6} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
|
||||
;we have 1 bit time for setup purposes, then sample again:
|
||||
push x2 ;2
|
||||
push cnt ;2
|
||||
push shift ;2
|
||||
shortcutEntry:
|
||||
ldi cnt, 1 ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled)
|
||||
ldi x2, 1<<USB_CFG_DPLUS_BIT ;1 -> 8 edge sync ended with D- == 0
|
||||
;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure)
|
||||
waitNoChange:
|
||||
in x1, USBIN ;1 <-- sample, timing: edge + {2, 6} cycles
|
||||
eor x2, x1 ;1
|
||||
sbrc x2, 0 ;1 | 2
|
||||
ldi cnt, 2 ;1 | 0 cnt = numBits - 1 (because dec follows)
|
||||
mov x2, x1 ;1
|
||||
dec cnt ;1
|
||||
brne waitNoChange ;2 | 1
|
||||
sbrc x1, USBMINUS ;2
|
||||
rjmp sofError ;0 two consecutive "1" bits -> framing error
|
||||
;start reading data, but don't check for bitstuffing because these are the
|
||||
;first bits. Use the cycles for initialization instead. Note that we read and
|
||||
;store the binary complement of the data stream because eor results in 1 for
|
||||
;a change and 0 for no change.
|
||||
in x1, USBIN ;1 <-- sample bit 0, timing: edge + {3, 7} cycles
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ldi shift, 0x7f ;1 The last bit of the sync pattern was a "no change"
|
||||
ror shift ;1
|
||||
push YH ;2 -> 7
|
||||
in x2, USBIN ;1 <-- sample bit 1, timing: edge + {2, 6} cycles
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
push YL ;2
|
||||
lds YL, usbInputBuf ;2 -> 8
|
||||
in x1, USBIN ;1 <-- sample bit 2, timing: edge + {2, 6} cycles
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
ldi cnt, USB_BUFSIZE;1
|
||||
ldi YH, hi8(usbRxBuf);1 assume that usbRxBuf does not cross a page
|
||||
push x3 ;2 -> 8
|
||||
in x2, USBIN ;1 <-- sample bit 3, timing: edge + {2, 6} cycles
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
ser x3 ;1
|
||||
nop ;1
|
||||
rjmp rxbit4 ;2 -> 8
|
||||
|
||||
shortcutToStart: ;{,43} into next frame: max 5.5 sync bits missed
|
||||
#if !USB_CFG_SAMPLE_EXACT
|
||||
ldi x1, 5 ;2 setup timeout
|
||||
#endif
|
||||
waitForJ1:
|
||||
sbis USBIN, USBMINUS ;1 wait for D- == 1
|
||||
rjmp waitForJ1 ;2
|
||||
#if USB_CFG_SAMPLE_EXACT
|
||||
;The following code represents the unrolled loop in the else branch. It
|
||||
;results in a sampling window of 1/4 bit which meets the spec.
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK1
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK1
|
||||
sbis USBIN, USBMINUS
|
||||
rjmp foundK1
|
||||
nop
|
||||
nop2
|
||||
foundK1:
|
||||
#else
|
||||
waitForK1:
|
||||
dec x1 ;1
|
||||
sbic USBIN, USBMINUS ;1 wait for D- == 0
|
||||
brne waitForK1 ;2
|
||||
#endif
|
||||
pop YH ;2 correct stack alignment
|
||||
nop2 ;2 delay for the same time as the pushes in the original code
|
||||
rjmp shortcutEntry ;2
|
||||
|
||||
; ################# receiver loop #################
|
||||
; extra jobs done during bit interval:
|
||||
; bit 6: se0 check
|
||||
; bit 7: or, store, clear
|
||||
; bit 0: recover from delay [SE0 is unreliable here due to bit dribbling in hubs]
|
||||
; bit 1: se0 check
|
||||
; bit 2: se0 check
|
||||
; bit 3: overflow check
|
||||
; bit 4: se0 check
|
||||
; bit 5: rjmp
|
||||
|
||||
; stuffed* helpers have the functionality of a subroutine, but we can't afford
|
||||
; the overhead of a call. We therefore need a separate routine for each caller
|
||||
; which jumps back appropriately.
|
||||
|
||||
stuffed5: ;1 for branch taken
|
||||
in x2, USBIN ;1 <-- sample @ +1
|
||||
andi x2, USBMASK ;1
|
||||
breq se0a ;1
|
||||
andi x3, 0xc0 ;1 (0xff03 >> 2) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit6 ;2
|
||||
|
||||
stuffed6: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0a ;1
|
||||
andi x3, 0x81 ;1 (0xff03 >> 1) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit7 ;2
|
||||
|
||||
; This is somewhat special because it has to compensate for the delay in bit 7
|
||||
stuffed7: ;1 for branch taken
|
||||
andi x1, USBMASK ;1 already sampled by caller
|
||||
breq se0a ;1
|
||||
mov x2, x1 ;1 ensure correct NRZI sequence [we can save andi x3 here]
|
||||
ori shift, 0xfc ;1
|
||||
in x1, USBIN ;1 <-- sample bit 0
|
||||
rjmp unstuffed7 ;2
|
||||
|
||||
stuffed0: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0a ;1
|
||||
andi x3, 0xfe ;1 (0xff03 >> 7) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit1 ;2
|
||||
|
||||
;-----------------------------
|
||||
rxLoop:
|
||||
brlo stuffed5 ;1
|
||||
rxbit6:
|
||||
in x1, USBIN ;1 <-- sample bit 6
|
||||
andi x1, USBMASK ;1
|
||||
breq se0a ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed6 ;1
|
||||
rxbit7:
|
||||
in x2, USBIN ;1 <-- sample bit 7
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
eor x3, shift ;1 x3 is 0 at bit locations we changed, 1 at others
|
||||
st y+, x3 ;2 the eor above reconstructed modified bits and inverted rx data
|
||||
ser x3 ;1
|
||||
rxbit0:
|
||||
in x1, USBIN ;1 <-- sample bit 0
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed7 ;1
|
||||
unstuffed7:
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed0 ;1
|
||||
rxbit1:
|
||||
in x2, USBIN ;1 <-- sample bit 1
|
||||
andi x2, USBMASK ;1
|
||||
se0a: ; enlarge jump range to SE0
|
||||
breq se0 ;1 check for SE0 more often close to start of byte
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed1 ;1
|
||||
rxbit2:
|
||||
in x1, USBIN ;1 <-- sample bit 2
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed2 ;1
|
||||
rxbit3:
|
||||
in x2, USBIN ;1 <-- sample bit 3
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
dec cnt ;1 check for buffer overflow
|
||||
breq overflow ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed3 ;1
|
||||
rxbit4:
|
||||
in x1, USBIN ;1 <-- sample bit 4
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
eor x2, x1 ;1
|
||||
ror x2 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
brlo stuffed4 ;1
|
||||
rxbit5:
|
||||
in x2, USBIN ;1 <-- sample bit 5
|
||||
eor x1, x2 ;1
|
||||
ror x1 ;1
|
||||
ror shift ;1
|
||||
cpi shift, 4 ;1
|
||||
rjmp rxLoop ;2
|
||||
;-----------------------------
|
||||
|
||||
stuffed1: ;1 for branch taken
|
||||
in x2, USBIN ;1 <-- sample @ +1
|
||||
andi x2, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xfc ;1 (0xff03 >> 6) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit2 ;2
|
||||
|
||||
stuffed2: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xf8 ;1 (0xff03 >> 5) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit3 ;2
|
||||
|
||||
stuffed3: ;1 for branch taken
|
||||
in x2, USBIN ;1 <-- sample @ +1
|
||||
andi x2, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xf0 ;1 (0xff03 >> 4) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit4 ;2
|
||||
|
||||
stuffed4: ;1 for branch taken
|
||||
in x1, USBIN ;1 <-- sample @ +1
|
||||
andi x1, USBMASK ;1
|
||||
breq se0 ;1
|
||||
andi x3, 0xe0 ;1 (0xff03 >> 3) & 0xff
|
||||
ori shift, 0xfc ;1
|
||||
rjmp rxbit5 ;2
|
||||
|
||||
;################ end receiver loop ###############
|
||||
|
||||
overflow: ; ignore package if buffer overflow
|
||||
rjmp rxDoReturn ; enlarge jump range
|
||||
|
||||
;This is the only non-error exit point for the software receiver loop
|
||||
;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0
|
||||
;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start
|
||||
;we don't check any CRCs here because there is no time left.
|
||||
se0: ;{-6, 2} from end of SE0 / {,4} into next frame
|
||||
mov cnt, YL ;1 assume buffer in lower 256 bytes of memory
|
||||
lds YL, usbInputBuf ;2 reposition to buffer start
|
||||
sub cnt, YL ;1 length of message
|
||||
ldi x1, 1<<USB_INTR_PENDING_BIT ;1
|
||||
cpi cnt, 3 ;1
|
||||
out USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame
|
||||
brlo rxDoReturn ;1 ensure valid packet size, ignore others
|
||||
ld x1, y ;2 PID
|
||||
ldd x2, y+1 ;2 ADDR + 1 bit endpoint number
|
||||
mov x3, x2 ;1 store for endpoint number
|
||||
andi x2, 0x7f ;1 mask endpoint number bit
|
||||
lds shift, usbDeviceAddr;2
|
||||
cpi x1, USBPID_SETUP ;1
|
||||
breq isSetupOrOut ;2 -> 19 = {13, 21} from SE0 end
|
||||
cpi x1, USBPID_OUT ;1
|
||||
breq isSetupOrOut ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame
|
||||
cpi x1, USBPID_IN ;1
|
||||
breq handleIn ;1
|
||||
#define USB_DATA_MASK ~(USBPID_DATA0 ^ USBPID_DATA1)
|
||||
andi x1, USB_DATA_MASK ;1
|
||||
cpi x1, USBPID_DATA0 & USB_DATA_MASK ;1
|
||||
brne rxDoReturn ;1 not a data PID -- ignore
|
||||
isData:
|
||||
lds x2, usbCurrentTok ;2
|
||||
tst x2 ;1
|
||||
breq rxDoReturn ;1 for other device or spontaneous data -- ignore
|
||||
lds x1, usbRxLen ;2
|
||||
cpi x1, 0 ;1
|
||||
brne sendNakAndReti ;1 no buffer space available / {30, 38} from SE0 end
|
||||
; 2006-03-11: The following two lines fix a problem where the device was not
|
||||
; recognized if usbPoll() was called less frequently than once every 4 ms.
|
||||
cpi cnt, 4 ;1 zero sized data packets are status phase only -- ignore and ack
|
||||
brmi sendAckAndReti ;1 keep rx buffer clean -- we must not NAK next SETUP
|
||||
sts usbRxLen, cnt ;2 store received data, swap buffers
|
||||
sts usbRxToken, x2 ;2
|
||||
lds x1, usbAppBuf ;2
|
||||
sts usbAppBuf, YL ;2
|
||||
sts usbInputBuf, x1 ;2 buffers now swapped
|
||||
rjmp sendAckAndReti ;2 -> {43, 51} from SE0 end
|
||||
|
||||
handleIn: ; {18, 26} from SE0 end
|
||||
cp x2, shift ;1 shift contains our device addr
|
||||
brne rxDoReturn ;1 other device
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT
|
||||
sbrc x3, 7 ;2 x3 contains addr + endpoint
|
||||
rjmp handleIn1 ;0
|
||||
#endif
|
||||
lds cnt, usbTxLen ;2
|
||||
cpi cnt, -1 ;1
|
||||
breq sendNakAndReti ;1 -> {27, 35} from SE0 end
|
||||
ldi x1, -1 ;1
|
||||
sts usbTxLen, x1 ;2 buffer is now free
|
||||
ldi YL, lo8(usbTxBuf) ;1
|
||||
ldi YH, hi8(usbTxBuf) ;1
|
||||
rjmp usbSendAndReti ;2 -> {34, 43} from SE0 end
|
||||
|
||||
; Comment about when to set usbTxLen to -1:
|
||||
; We should set it back to -1 when we receive the ACK from the host. This would
|
||||
; be simple to implement: One static variable which stores whether the last
|
||||
; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
|
||||
; ACK. However, we set it back to -1 immediately when we send the package,
|
||||
; assuming that no error occurs and the host sends an ACK. We save one byte
|
||||
; RAM this way and avoid potential problems with endless retries. The rest of
|
||||
; the driver assumes error-free transfers anyway.
|
||||
|
||||
otherOutOrSetup:
|
||||
clr x1
|
||||
sts usbCurrentTok, x1
|
||||
rxDoReturn:
|
||||
pop x3 ;2
|
||||
pop YL ;2
|
||||
pop YH ;2
|
||||
rjmp sofError ;2
|
||||
|
||||
isSetupOrOut: ; we must be fast here -- a data package may follow / {,24} into next frame
|
||||
cp x2, shift ;1 shift contains our device addr
|
||||
brne otherOutOrSetup ;1 other device -- ignore
|
||||
sts usbCurrentTok, x1 ;2
|
||||
#if 0 /* we implement only one rx endpoint */
|
||||
sts usbRxEndp, x3 ;2 only stored if we may have to distinguish endpoints
|
||||
#endif
|
||||
;A transmission can still have data in the output buffer while we receive a
|
||||
;SETUP package with an IN phase. To avoid that the old data is sent as a reply,
|
||||
;we abort transmission. ### This mechanism assumes that NO OUT OR SETUP package
|
||||
;is ever sent to endpoint 1. We would abort transmission for endpoint 0
|
||||
;in this case.
|
||||
ldi x1, -1 ;1
|
||||
sts usbMsgLen, x1 ;2
|
||||
sts usbTxLen, x1 ;2 abort transmission
|
||||
pop x3 ;2
|
||||
pop YL ;2
|
||||
in x1, USB_INTR_PENDING;1
|
||||
sbrc x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame
|
||||
rjmp shortcutToStart ;2 save the pops and pushes -- a new interrupt is aready pending
|
||||
;If the jump above was not taken, we can be at {,2} into the next frame here
|
||||
pop YH ;2
|
||||
txDoReturn:
|
||||
sofError: ; error in start of frame -- ignore frame
|
||||
ldi x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag
|
||||
out USB_INTR_PENDING, x1;1
|
||||
pop shift ;2
|
||||
pop cnt ;2
|
||||
pop x2 ;2
|
||||
pop x1 ;2
|
||||
out SREG, x1 ;1
|
||||
pop x1 ;2
|
||||
reti ;4 -> {,21} into next frame -> up to 3 sync bits missed
|
||||
|
||||
|
||||
sendNakAndReti: ; 21 cycles until SOP
|
||||
ldi YL, lo8(usbNakBuf) ;1
|
||||
ldi YH, hi8(usbNakBuf) ;1
|
||||
rjmp usbSendToken ;2
|
||||
|
||||
sendAckAndReti: ; 19 cycles until SOP
|
||||
ldi YL, lo8(usbAckBuf) ;1
|
||||
ldi YH, hi8(usbAckBuf) ;1
|
||||
usbSendToken:
|
||||
ldi cnt, 2 ;1
|
||||
;;;;rjmp usbSendAndReti fallthrough
|
||||
|
||||
; USB spec says:
|
||||
; idle = J
|
||||
; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
|
||||
; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
|
||||
; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
|
||||
|
||||
;usbSend:
|
||||
;pointer to data in 'Y'
|
||||
;number of bytes in 'cnt' -- including sync byte
|
||||
;uses: x1...x4, shift, cnt, Y
|
||||
usbSendAndReti: ; SOP starts 16 cycles after call
|
||||
push x4 ;2
|
||||
in x1, USBOUT ;1
|
||||
cbr x1, USBMASK ;1 mask out data bits
|
||||
ori x1, USBIDLE ;1 idle
|
||||
out USBOUT, x1 ;1 prepare idle state
|
||||
ldi x4, USBMASK ;1 exor mask
|
||||
in x2, USBDDR ;1
|
||||
ori x2, USBMASK ;1 set both pins to output
|
||||
out USBDDR, x2 ;1 <-- acquire bus now
|
||||
; need not init x2 (bitstuff history) because sync starts with 0
|
||||
ldi shift, 0x80 ;1 sync byte is first byte sent
|
||||
rjmp txLoop ;2 -> 13 + 3 = 16 cycles until SOP
|
||||
|
||||
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
|
||||
handleIn1:
|
||||
lds cnt, usbTxLen1
|
||||
cpi cnt, -1
|
||||
breq sendNakAndReti
|
||||
ldi x1, -1
|
||||
sts usbTxLen1, x1
|
||||
ldi YL, lo8(usbTxBuf1)
|
||||
ldi YH, hi8(usbTxBuf1)
|
||||
rjmp usbSendAndReti
|
||||
#if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
|
||||
# define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
|
||||
# define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
|
||||
#else /* It's a memory address, use lds and sts */
|
||||
# define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
|
||||
# define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
|
||||
#endif
|
||||
|
||||
bitstuff0: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
rjmp didStuff0 ;2 branch back 2 cycles earlier
|
||||
bitstuff1: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
sec ;1 set carry so that brsh will not jump
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
rjmp didStuff1 ;2 jump back 1 cycle earler
|
||||
bitstuff2: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
rjmp didStuff2 ;2 jump back 3 cycles earlier and do out
|
||||
bitstuff3: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
rjmp didStuff3 ;2 jump back earlier
|
||||
|
||||
txLoop:
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff0:
|
||||
cpi x2, 0xfc ;1
|
||||
brsh bitstuff0 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
ror x2 ;1
|
||||
cpi x2, 0xfc ;1
|
||||
didStuff1:
|
||||
brsh bitstuff1 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff2:
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
cpi x2, 0xfc ;1
|
||||
brsh bitstuff2 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff3:
|
||||
cpi x2, 0xfc ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
brsh bitstuff3 ;1
|
||||
nop2 ;2
|
||||
ld x3, y+ ;2
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff4:
|
||||
cpi x2, 0xfc ;1
|
||||
brsh bitstuff4 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
ror x2 ;1
|
||||
cpi x2, 0xfc ;1
|
||||
didStuff5:
|
||||
brsh bitstuff5 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff6:
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
cpi x2, 0xfc ;1
|
||||
brsh bitstuff6 ;1
|
||||
sbrs shift, 0 ;1
|
||||
eor x1, x4 ;1
|
||||
ror shift ;1
|
||||
ror x2 ;1
|
||||
didStuff7:
|
||||
cpi x2, 0xfc ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
brsh bitstuff7 ;1
|
||||
mov shift, x3 ;1
|
||||
dec cnt ;1
|
||||
brne txLoop ;2 | 1
|
||||
cbr x1, USBMASK ;1 prepare SE0 [spec says EOP may be 15 to 18 cycles]
|
||||
pop x4 ;2
|
||||
out USBOUT, x1 ;1 <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
|
||||
ldi cnt, 2 ;| takes cnt * 3 cycles
|
||||
se0Delay: ;|
|
||||
dec cnt ;|
|
||||
brne se0Delay ;| -> 2 * 3 = 6 cycles
|
||||
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
|
||||
lds x2, usbNewDeviceAddr ;2
|
||||
subi YL, lo8(usbNakBuf + 2) ;1
|
||||
sbci YH, hi8(usbNakBuf + 2) ;1
|
||||
breq skipAddrAssign ;2
|
||||
sts usbDeviceAddr, x2 ;0 if not skipped: SE0 is one cycle longer
|
||||
skipAddrAssign:
|
||||
;end of usbDeviceAddress transfer
|
||||
ori x1, USBIDLE ;1
|
||||
in x2, USBDDR ;1
|
||||
cbr x2, USBMASK ;1 set both pins to input
|
||||
out USBOUT, x1 ;1 <-- out J (idle) -- end of SE0 (EOP signal)
|
||||
cbr x1, USBMASK ;1 configure no pullup on both pins
|
||||
pop x3 ;2
|
||||
pop YL ;2
|
||||
out USBDDR, x2 ;1 <-- release bus now
|
||||
out USBOUT, x1 ;1 set pullup state
|
||||
pop YH ;2
|
||||
rjmp txDoReturn ;2 [we want to jump to rxDoReturn, but this saves cycles]
|
||||
|
||||
|
||||
bitstuff4: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
rjmp didStuff4 ;2 jump back 2 cycles earlier
|
||||
bitstuff5: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
sec ;1 set carry so that brsh is not taken
|
||||
out USBOUT, x1 ;1 <-- out
|
||||
rjmp didStuff5 ;2 jump back 1 cycle earlier
|
||||
bitstuff6: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
rjmp didStuff6 ;2 jump back 3 cycles earlier and do out there
|
||||
bitstuff7: ;1 (for branch taken)
|
||||
eor x1, x4 ;1
|
||||
ldi x2, 0 ;1
|
||||
rjmp didStuff7 ;2 jump back 4 cycles earlier
|
||||
|
||||
; ######################## utility functions ########################
|
||||
;----------------------------------------------------------------------------
|
||||
; Utility functions
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __IAR_SYSTEMS_ASM__
|
||||
/* 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.
|
||||
* Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
|
||||
* Result is passed in r16/r17
|
||||
* In case of the "tiny" memory model, pointers are only 8 bit with no
|
||||
* padding. We therefore pass argument 1 as "16 bit unsigned".
|
||||
*/
|
||||
RTMODEL "__rt_version", "3"
|
||||
/* The line above will generate an error if cc calling conventions change.
|
||||
@ -756,3 +198,24 @@ usbCrc16Append:
|
||||
st ptr+, resCrcL
|
||||
st ptr+, resCrcH
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; Now include the clock rate specific code
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
#ifndef USB_CFG_CLOCK_KHZ
|
||||
# define USB_CFG_CLOCK_KHZ 12000
|
||||
#endif
|
||||
|
||||
#if USB_CFG_CLOCK_KHZ == 12000
|
||||
# include "usbdrvasm12.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
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: Proprietary, free under certain conditions. See Documentation.
|
||||
* This Revision: $Id: usbdrvasm.asm,v 1.1 2007-03-25 02:59:31 raph Exp $
|
||||
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: usbdrvasm.asm,v 1.2 2009-05-02 12:41:41 cvs Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user