summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
committerYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
commit990090a4cc9070837d31e66b58d40f0c3d038741 (patch)
treecf1b905082c364e9b223e0c5058566103138dae5
parent7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff)
Add usblib and utils
-rw-r--r--usblib/Makefile103
-rw-r--r--usblib/ccs/.ccsproject9
-rw-r--r--usblib/ccs/.cproject164
-rw-r--r--usblib/ccs/.project185
-rw-r--r--usblib/ccs/.settings/org.eclipse.cdt.codan.core.prefs3
-rw-r--r--usblib/ccs/Debug/usblib.libbin0 -> 2044400 bytes
-rw-r--r--usblib/ccs/macros.ini_initial1
-rw-r--r--usblib/device/usbdaudio.c1510
-rw-r--r--usblib/device/usbdaudio.h382
-rw-r--r--usblib/device/usbdbulk.c1562
-rw-r--r--usblib/device/usbdbulk.h300
-rw-r--r--usblib/device/usbdcdc.c3043
-rw-r--r--usblib/device/usbdcdc.h447
-rw-r--r--usblib/device/usbdcdesc.c643
-rw-r--r--usblib/device/usbdcomp.c1544
-rw-r--r--usblib/device/usbdcomp.h261
-rw-r--r--usblib/device/usbdconfig.c555
-rw-r--r--usblib/device/usbddfu-rt.c661
-rw-r--r--usblib/device/usbddfu-rt.h184
-rw-r--r--usblib/device/usbdenum.c3190
-rw-r--r--usblib/device/usbdevice.h232
-rw-r--r--usblib/device/usbdevicepriv.h248
-rw-r--r--usblib/device/usbdhandler.c85
-rw-r--r--usblib/device/usbdhid.c2502
-rw-r--r--usblib/device/usbdhid.h1102
-rw-r--r--usblib/device/usbdhidgamepad.c845
-rw-r--r--usblib/device/usbdhidgamepad.h274
-rw-r--r--usblib/device/usbdhidkeyb.c1321
-rw-r--r--usblib/device/usbdhidkeyb.h365
-rw-r--r--usblib/device/usbdhidmouse.c1008
-rw-r--r--usblib/device/usbdhidmouse.h299
-rw-r--r--usblib/device/usbdmsc.c2441
-rw-r--r--usblib/device/usbdmsc.h420
-rw-r--r--usblib/ewarm/Exe/usblib.abin0 -> 1276396 bytes
-rw-r--r--usblib/gcc/libusb.abin0 -> 183108 bytes
-rw-r--r--usblib/host/usbhaudio.c1557
-rw-r--r--usblib/host/usbhaudio.h163
-rw-r--r--usblib/host/usbhhid.c746
-rw-r--r--usblib/host/usbhhid.h166
-rw-r--r--usblib/host/usbhhidkeyboard.c752
-rw-r--r--usblib/host/usbhhidkeyboard.h89
-rw-r--r--usblib/host/usbhhidmouse.c452
-rw-r--r--usblib/host/usbhhidmouse.h81
-rw-r--r--usblib/host/usbhhub.c1522
-rw-r--r--usblib/host/usbhhub.h174
-rw-r--r--usblib/host/usbhmsc.c756
-rw-r--r--usblib/host/usbhmsc.h99
-rw-r--r--usblib/host/usbhost.h295
-rw-r--r--usblib/host/usbhostenum.c6284
-rw-r--r--usblib/host/usbhostpriv.h201
-rw-r--r--usblib/host/usbhscsi.c777
-rw-r--r--usblib/host/usbhscsi.h87
-rw-r--r--usblib/readme.txt21
-rw-r--r--usblib/rvmdk/usblib.libbin0 -> 3025636 bytes
-rw-r--r--usblib/usb-ids.h57
-rw-r--r--usblib/usbaudio.h718
-rw-r--r--usblib/usbbuffer.c1192
-rw-r--r--usblib/usbcdc.h947
-rw-r--r--usblib/usbdesc.c480
-rw-r--r--usblib/usbdfu.h504
-rw-r--r--usblib/usbdma.c1453
-rw-r--r--usblib/usbhid.h667
-rw-r--r--usblib/usbkeyboardmap.c145
-rw-r--r--usblib/usblib.ewp860
-rw-r--r--usblib/usblib.h1951
-rw-r--r--usblib/usblib.uvopt650
-rw-r--r--usblib/usblib.uvproj555
-rw-r--r--usblib/usblibpriv.h529
-rw-r--r--usblib/usbmode.c1180
-rw-r--r--usblib/usbmsc.h444
-rw-r--r--usblib/usbringbuf.c715
-rw-r--r--usblib/usbtick.c219
-rw-r--r--usblib/usbulpi.c176
-rw-r--r--usblib/usbulpi.h40
-rw-r--r--utils/cmdline.c193
-rw-r--r--utils/cmdline.h137
-rw-r--r--utils/cpu_usage.c206
-rw-r--r--utils/cpu_usage.h57
-rw-r--r--utils/flash_pb.c493
-rw-r--r--utils/flash_pb.h58
-rw-r--r--utils/fswrapper.c860
-rw-r--r--utils/fswrapper.h142
-rw-r--r--utils/isqrt.c118
-rw-r--r--utils/isqrt.h55
-rw-r--r--utils/locator.c342
-rw-r--r--utils/locator.h61
-rw-r--r--utils/lwiplib.c1399
-rw-r--r--utils/lwiplib.h121
-rw-r--r--utils/ptpdlib.c56
-rw-r--r--utils/ptpdlib.h55
-rw-r--r--utils/random.c169
-rw-r--r--utils/random.h56
-rw-r--r--utils/ringbuf.c712
-rw-r--r--utils/ringbuf.h105
-rw-r--r--utils/scheduler.c310
-rw-r--r--utils/scheduler.h140
-rw-r--r--utils/sine.c126
-rw-r--r--utils/sine.h85
-rw-r--r--utils/smbus.c5173
-rw-r--r--utils/smbus.h463
-rw-r--r--utils/softi2c.c1321
-rw-r--r--utils/softi2c.h195
-rw-r--r--utils/softssi.c1297
-rw-r--r--utils/softssi.h280
-rw-r--r--utils/softuart.c2591
-rw-r--r--utils/softuart.h375
-rw-r--r--utils/speexlib.c377
-rw-r--r--utils/speexlib.h63
-rw-r--r--utils/spi_flash.c2484
-rw-r--r--utils/spi_flash.h166
-rw-r--r--utils/swupdate.c355
-rw-r--r--utils/swupdate.h66
-rw-r--r--utils/tftp.c710
-rw-r--r--utils/tftp.h215
-rw-r--r--utils/uartstdio.c1720
-rw-r--r--utils/uartstdio.h86
-rw-r--r--utils/ustdlib.c1826
-rw-r--r--utils/ustdlib.h82
-rw-r--r--utils/wavfile.c291
-rw-r--r--utils/wavfile.h97
120 files changed, 79882 insertions, 0 deletions
diff --git a/usblib/Makefile b/usblib/Makefile
new file mode 100644
index 0000000..afd50ba
--- /dev/null
+++ b/usblib/Makefile
@@ -0,0 +1,103 @@
+#******************************************************************************
+#
+# Makefile - Rules for building the USB library.
+#
+# Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+# Software License Agreement
+#
+# Texas Instruments (TI) is supplying this software for use solely and
+# exclusively on TI's microcontroller products. The software is owned by
+# TI and/or its suppliers, and is protected under applicable copyright
+# laws. You may not combine this software with "viral" open-source
+# software in order to form a larger program.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+# NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+# NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+# CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+# DAMAGES, FOR ANY REASON WHATSOEVER.
+#
+# This is part of revision 2.1.0.12573 of the Tiva USB Library.
+#
+#******************************************************************************
+
+#
+# The base directory for TivaWare.
+#
+ROOT=..
+
+#
+# Include the common make definitions.
+#
+include ${ROOT}/makedefs
+
+#
+# Where to find source files that do not live in this directory.
+#
+VPATH=./device
+VPATH+=./host
+
+#
+# Where to find header files that do not live in the source directory.
+#
+IPATH=..
+
+#
+# The default rule, which causes the USB library to be built.
+#
+all: ${COMPILER}
+all: ${COMPILER}/libusb.a
+
+#
+# The rule to clean out all the build products.
+#
+clean:
+ @rm -rf ${COMPILER} ${wildcard *~}
+
+#
+# The rule to create the target directory.
+#
+${COMPILER}:
+ @mkdir -p ${COMPILER}
+
+#
+# Rules for building the USB library.
+#
+${COMPILER}/libusb.a: ${COMPILER}/usbbuffer.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdaudio.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdbulk.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdcdc.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdcdesc.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdcomp.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdconfig.o
+${COMPILER}/libusb.a: ${COMPILER}/usbddfu-rt.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdenum.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdesc.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdhandler.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdhid.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdhidgamepad.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdhidkeyb.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdhidmouse.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdma.o
+${COMPILER}/libusb.a: ${COMPILER}/usbdmsc.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhaudio.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhhid.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhhidkeyboard.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhhidmouse.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhhub.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhmsc.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhostenum.o
+${COMPILER}/libusb.a: ${COMPILER}/usbhscsi.o
+${COMPILER}/libusb.a: ${COMPILER}/usbkeyboardmap.o
+${COMPILER}/libusb.a: ${COMPILER}/usbmode.o
+${COMPILER}/libusb.a: ${COMPILER}/usbringbuf.o
+${COMPILER}/libusb.a: ${COMPILER}/usbtick.o
+${COMPILER}/libusb.a: ${COMPILER}/usbulpi.o
+
+#
+# Include the automatically generated dependency files.
+#
+ifneq (${MAKECMDGOALS},clean)
+-include ${wildcard ${COMPILER}/*.d} __dummy__
+endif
diff --git a/usblib/ccs/.ccsproject b/usblib/ccs/.ccsproject
new file mode 100644
index 0000000..b4eaafa
--- /dev/null
+++ b/usblib/ccs/.ccsproject
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<?ccsproject version="1.0"?>
+<projectOptions>
+ <deviceVariant value="Cortex M.TM4C1230C3PM"/>
+ <deviceFamily value="TMS470"/>
+ <deviceEndianness value="little"/>
+ <codegenToolVersion value="5.0.4"/>
+ <isElfFormat value="true"/>
+</projectOptions>
diff --git a/usblib/ccs/.cproject b/usblib/ccs/.cproject
new file mode 100644
index 0000000..d5a180a
--- /dev/null
+++ b/usblib/ccs/.cproject
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+ <storageModule moduleId="org.eclipse.cdt.core.settings">
+ <cconfiguration id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+ <macros>
+ <stringMacro name="SW_ROOT" type="VALUE_PATH_DIR" value="${PROJECT_ROOT}/../.."/>
+ </macros>
+ <externalSettings/>
+ <extensions>
+ <extension id="com.ti.ccstudio.binaryparser.CoffParser" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="com.ti.ccstudio.errorparser.CoffErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.LinkErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.AsmErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="lib" artifactName="${ProjName}" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224" name="Debug" parent="com.ti.ccstudio.buildDefinitions.TMS470.Debug">
+ <folderInfo id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224." name="/" resourcePath="">
+ <toolChain id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.libraryDebugToolchain.1199429182" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.libraryDebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug.517344320">
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1656348484" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
+ <listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=Cortex M.TM4C1230C3PM"/>
+ <listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little"/>
+ <listOptionValue builtIn="false" value="OUTPUT_FORMAT=ELF"/>
+ <listOptionValue builtIn="false" value="CCS_MBS_VERSION=5.1.0.01"/>
+ <listOptionValue builtIn="false" value="OUTPUT_TYPE=staticLibrary"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1071374229" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="5.0.4" valueType="string"/>
+ <targetPlatform id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformDebug.1526412577" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformDebug"/>
+ <builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderDebug.1762046893" name="GNU Make.Debug" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderDebug"/>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1251797066" name="ARM Compiler" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.812149092" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.7M4" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.2015628749" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.1495507101" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.eabi" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.1886829153" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.FPv4SPD16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL.296773954" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING.1719263867" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING" valueType="stringList">
+ <listOptionValue builtIn="false" value="225"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER.1222339691" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.2113959950" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.off" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH.1821809944" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${CG_TOOL_ROOT}/include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${SW_ROOT}&quot;"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN.1638962570" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.291209018" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL.187298390" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL.2" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC.604934158" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL.1446620616" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.462031813" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="ccs=&quot;ccs&quot;"/>
+ </option>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.813107964" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.124449644" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.999923136" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.212027145" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS"/>
+ </tool>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug.517344320" name="ARM Archiver" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE.1315708159" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE" value="&quot;${ProjName}.lib&quot;" valueType="string"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ <cconfiguration id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244" moduleId="org.eclipse.cdt.core.settings" name="Release">
+ <macros>
+ <stringMacro name="SW_ROOT" type="VALUE_PATH_DIR" value="${PROJECT_ROOT}/../.."/>
+ </macros>
+ <externalSettings/>
+ <extensions>
+ <extension id="com.ti.ccstudio.binaryparser.CoffParser" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="com.ti.ccstudio.errorparser.CoffErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.LinkErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.AsmErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="lib" artifactName="${ProjName}" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244" name="Release" parent="com.ti.ccstudio.buildDefinitions.TMS470.Release">
+ <folderInfo id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244." name="/" resourcePath="">
+ <toolChain id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.ReleaseToolchain.1043090827" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.ReleaseToolchain" targetTool="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease.472098384">
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1111383295" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
+ <listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=Cortex M.TM4C1230C3PM"/>
+ <listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little"/>
+ <listOptionValue builtIn="false" value="OUTPUT_FORMAT=ELF"/>
+ <listOptionValue builtIn="false" value="CCS_MBS_VERSION=5.1.0.01"/>
+ <listOptionValue builtIn="false" value="OUTPUT_TYPE=staticLibrary"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.88898150" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="5.0.4" valueType="string"/>
+ <targetPlatform id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformRelease.644864433" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformRelease"/>
+ <builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderRelease.1887536299" name="GNU Make.Release" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderRelease"/>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.764598937" name="ARM Compiler" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.718553667" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.7M4" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.851432476" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.1727423064" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.eabi" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.1008942853" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.FPv4SPD16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING.1359721383" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING" valueType="stringList">
+ <listOptionValue builtIn="false" value="225"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER.2078518258" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.1006078791" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.off" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH.1832633464" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${CG_TOOL_ROOT}/include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${SW_ROOT}&quot;"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN.1338574271" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.1604415284" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC.305169826" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL.1395139601" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.586555075" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="ccs=&quot;ccs&quot;"/>
+ </option>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.1682483173" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.1780668618" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.847380163" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.1792912495" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS"/>
+ </tool>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease.472098384" name="ARM Archiver" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE.2135546246" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE" value="&quot;${ProjName}.lib&quot;" valueType="string"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <project id="usblib.com.ti.ccstudio.buildDefinitions.TMS470.ProjectType.1894937210" name="ARM" projectType="com.ti.ccstudio.buildDefinitions.TMS470.ProjectType"/>
+ </storageModule>
+ <storageModule moduleId="scannerConfiguration">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244;com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.764598937;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.1682483173">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244;com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.764598937;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.1792912495">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224;com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1251797066;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.813107964">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224;com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1251797066;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.212027145">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224;com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1251797066;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.124449644">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244;com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.764598937;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.1780668618">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244;com.ti.ccstudio.buildDefinitions.TMS470.Release.1976680244.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.764598937;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.847380163">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224;com.ti.ccstudio.buildDefinitions.TMS470.Debug.688171224.;com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1251797066;com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.999923136">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.ti.ccstudio.project.core.CCSScannerDiscoveryProfile"/>
+ </scannerConfigBuildInfo>
+ </storageModule>
+</cproject>
diff --git a/usblib/ccs/.project b/usblib/ccs/.project
new file mode 100644
index 0000000..d9015db
--- /dev/null
+++ b/usblib/ccs/.project
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>usblib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.ti.ccstudio.core.ccsNature</nature>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ </natures>
+ <linkedResources>
+ <link>
+ <name>usbbuffer.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbbuffer.c</locationURI>
+ </link>
+ <link>
+ <name>usbdesc.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbdesc.c</locationURI>
+ </link>
+ <link>
+ <name>usbdma.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbdma.c</locationURI>
+ </link>
+ <link>
+ <name>usbkeyboardmap.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbkeyboardmap.c</locationURI>
+ </link>
+ <link>
+ <name>usbmode.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbmode.c</locationURI>
+ </link>
+ <link>
+ <name>usbringbuf.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbringbuf.c</locationURI>
+ </link>
+ <link>
+ <name>usbtick.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbtick.c</locationURI>
+ </link>
+ <link>
+ <name>usbulpi.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/usbulpi.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdaudio.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdaudio.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdbulk.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdbulk.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdcdc.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdcdc.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdcdesc.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdcdesc.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdcomp.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdcomp.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdconfig.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdconfig.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbddfu-rt.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbddfu-rt.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdenum.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdenum.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdhandler.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdhandler.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdhid.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdhid.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdhidgamepad.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdhidgamepad.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdhidkeyb.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdhidkeyb.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdhidmouse.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdhidmouse.c</locationURI>
+ </link>
+ <link>
+ <name>device/usbdmsc.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/device/usbdmsc.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhaudio.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhaudio.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhhid.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhhid.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhhidkeyboard.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhhidkeyboard.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhhidmouse.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhhidmouse.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhhub.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhhub.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhmsc.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhmsc.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhostenum.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhostenum.c</locationURI>
+ </link>
+ <link>
+ <name>host/usbhscsi.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/usblib/host/usbhscsi.c</locationURI>
+ </link>
+ </linkedResources>
+ <variableList>
+ <variable>
+ <name>SW_ROOT</name>
+ <value>$%7BPARENT-2-PROJECT_LOC%7D</value>
+ </variable>
+ </variableList>
+</projectDescription>
diff --git a/usblib/ccs/.settings/org.eclipse.cdt.codan.core.prefs b/usblib/ccs/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 0000000..98b6350
--- /dev/null
+++ b/usblib/ccs/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+inEditor=false
+onBuild=false
diff --git a/usblib/ccs/Debug/usblib.lib b/usblib/ccs/Debug/usblib.lib
new file mode 100644
index 0000000..95c0b66
--- /dev/null
+++ b/usblib/ccs/Debug/usblib.lib
Binary files differ
diff --git a/usblib/ccs/macros.ini_initial b/usblib/ccs/macros.ini_initial
new file mode 100644
index 0000000..08b716d
--- /dev/null
+++ b/usblib/ccs/macros.ini_initial
@@ -0,0 +1 @@
+SW_ROOT = ../..
diff --git a/usblib/device/usbdaudio.c b/usblib/device/usbdaudio.c
new file mode 100644
index 0000000..18c90b5
--- /dev/null
+++ b/usblib/device/usbdaudio.c
@@ -0,0 +1,1510 @@
+//*****************************************************************************
+//
+// usbdaudio.c - USB audio device class driver.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbaudio.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdaudio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup audio_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following are the USB audio descriptor identifiers.
+//
+//*****************************************************************************
+#define AUDIO_IN_TERMINAL_ID 1
+#define AUDIO_OUT_TERMINAL_ID 2
+#define AUDIO_CONTROL_ID 3
+
+//*****************************************************************************
+//
+// The following are the USB interface numbers for this audio device.
+//
+//*****************************************************************************
+#define AUDIO_INTERFACE_CONTROL 0
+#define AUDIO_INTERFACE_OUTPUT 1
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define ISOC_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Max size is (48000 samples/sec * 4 bytes/sample) * 0.001 seconds/frame.
+//
+//*****************************************************************************
+#define ISOC_OUT_EP_MAX_SIZE ((48000*4)/1000)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8AudioDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ 0, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ 0, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during USBDAudioInit).
+ USBShort(0), // Product ID (filled in during USBDAudioInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Audio class device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8AudioDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 2, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_BUS_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// This is the Interface Association Descriptor for the serial device used in
+// composite devices.
+//
+//*****************************************************************************
+uint8_t g_pui8IADAudioDescriptor[AUDIODESCRIPTOR_SIZE] =
+{
+
+ 8, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE_ASC, // Interface Association Type.
+ 0x0, // Default starting interface is 0.
+ 0x2, // Number of interfaces in this association.
+ USB_CLASS_AUDIO, // The device class for this association.
+ USB_SUBCLASS_UNDEFINED, // The device subclass for this association.
+ USB_PROTOCOL_UNDEFINED, // The protocol for this association.
+ 0 // The string index for this association.
+};
+
+const tConfigSection g_sIADAudioConfigSection =
+{
+ sizeof(g_pui8IADAudioDescriptor),
+ g_pui8IADAudioDescriptor
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8AudioControlInterface[CONTROLINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ AUDIO_INTERFACE_CONTROL, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 0, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_CONTROL, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Audio Header Descriptor.
+ //
+ 9, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_HEADER, // Descriptor sub-type is HEADER.
+ USBShort(0x0100), // Audio Device Class Specification Release
+ // Number in Binary-Coded Decimal.
+ // Total number of bytes in
+ // g_pui8AudioControlInterface
+ USBShort((9 + 9 + 12 + 13 + 9)),
+ 1, // Number of streaming interfaces.
+ 1, // Index of the first and only streaming
+ // interface.
+
+ //
+ // Audio Input Terminal Descriptor.
+ //
+ 12, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_IN_TERMINAL, // Descriptor sub-type is INPUT_TERMINAL.
+ AUDIO_IN_TERMINAL_ID, // Terminal ID for this interface.
+ // USB streaming interface.
+ USBShort(USB_TTYPE_STREAMING),
+ 0, // ID of the Output Terminal to which this
+ // Input Terminal is associated.
+ 2, // Number of logical output channels in the
+ // Terminal's output audio channel cluster.
+ USBShort((USB_CHANNEL_L | // Describes the spatial location of the
+ USB_CHANNEL_R)), // logical channels.
+ 0, // Channel Name string index.
+ 0, // Terminal Name string index.
+
+ //
+ // Audio Feature Unit Descriptor
+ //
+ 13, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_FEATURE_UNIT, // Descriptor sub-type is FEATURE_UNIT.
+ AUDIO_CONTROL_ID, // Unit ID for this interface.
+ AUDIO_IN_TERMINAL_ID, // ID of the Unit or Terminal to which this
+ // Feature Unit is connected.
+ 2, // Size in bytes of an element of the
+ // bmaControls() array that follows.
+ // Master Mute control.
+ USBShort(USB_ACONTROL_MUTE),
+ // Left channel volume control.
+ USBShort(USB_ACONTROL_VOLUME),
+ // Right channel volume control.
+ USBShort(USB_ACONTROL_VOLUME),
+ 0, // Feature unit string index.
+
+ //
+ // Audio Output Terminal Descriptor.
+ //
+ 9, // The size of this descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ACDSTYPE_OUT_TERMINAL, // Descriptor sub-type is INPUT_TERMINAL.
+ AUDIO_OUT_TERMINAL_ID, // Terminal ID for this interface.
+ // Output type is a generic speaker.
+ USBShort(USB_ATTYPE_SPEAKER),
+ AUDIO_IN_TERMINAL_ID, // ID of the input terminal to which this
+ // output terminal is connected.
+ AUDIO_CONTROL_ID, // ID of the feature unit that this output
+ // terminal is connected to.
+ 0, // Output terminal string index.
+
+};
+
+//*****************************************************************************
+//
+// The audio streaming interface descriptor. This describes the two valid
+// interfaces for this class. The first interface has no endpoints and is used
+// by host operating systems to put the device in idle mode, while the second
+// is used when the audio device is active.
+//
+//*****************************************************************************
+const uint8_t g_pui8AudioStreamInterface[STREAMINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ AUDIO_INTERFACE_OUTPUT, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 0, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_STREAMING, // The interface sub-class.
+ 0, // Unused must be 0.
+ 0, // The string index for this interface.
+
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 1, // The index for this interface.
+ 1, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_AUDIO, // The interface class
+ USB_ASC_AUDIO_STREAMING, // The interface sub-class.
+ 0, // Unused must be 0.
+ 0, // The string index for this interface.
+
+ //
+ // Class specific Audio Streaming Interface descriptor.
+ //
+ 7, // Size of the interface descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ASDSTYPE_GENERAL, // General information.
+ AUDIO_IN_TERMINAL_ID, // ID of the terminal to which this streaming
+ // interface is connected.
+ 1, // One frame delay.
+ USBShort(USB_ADF_PCM), //
+
+ //
+ // Format type Audio Streaming descriptor.
+ //
+ 11, // Size of the interface descriptor.
+ USB_DTYPE_CS_INTERFACE, // Interface descriptor is class specific.
+ USB_ASDSTYPE_FORMAT_TYPE, // Audio Streaming format type.
+ USB_AF_TYPE_TYPE_I, // Type I audio format type.
+ 2, // Two audio channels.
+ 2, // Two bytes per audio sub-frame.
+ 16, // 16 bits per sample.
+ 1, // One sample rate provided.
+ USB3Byte(48000), // Only 48000 sample rate supported.
+
+ //
+ // Endpoint Descriptor
+ //
+ 9, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ // OUT endpoint with address
+ // ISOC_OUT_ENDPOINT.
+ USB_EP_DESC_OUT | USBEPToIndex(ISOC_OUT_ENDPOINT),
+ USB_EP_ATTR_ISOC | // Endpoint is an adaptive isochronous data
+ USB_EP_ATTR_ISOC_ADAPT | // endpoint.
+ USB_EP_ATTR_USAGE_DATA,
+ USBShort(ISOC_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 1, // The polling interval for this endpoint.
+ 0, // Refresh is unused.
+ 0, // Synch endpoint address.
+
+ //
+ // Audio Streaming Isochronous Audio Data Endpoint Descriptor
+ //
+ 7, // The size of the descriptor.
+ USB_ACSDT_ENDPOINT, // Audio Class Specific Endpoint
+ // Descriptor.
+ USB_ASDSTYPE_GENERAL, // This is a general descriptor.
+ USB_EP_ATTR_ACG_SAMPLING, // Sampling frequency is supported.
+ USB_EP_LOCKDELAY_UNDEF, // Undefined lock delay units.
+ USBShort(0), // No lock delay.
+};
+
+//*****************************************************************************
+//
+// The audio device configuration descriptor is defined as three sections,
+// one containing just the 9 byte USB configuration descriptor. The second
+// holds the audio streaming interface and the third holds the audio control
+// interface.
+//
+//*****************************************************************************
+const tConfigSection g_sAudioConfigSection =
+{
+ sizeof(g_pui8AudioDescriptor),
+ g_pui8AudioDescriptor
+};
+
+const tConfigSection g_sAudioStreamInterfaceSection =
+{
+ sizeof(g_pui8AudioStreamInterface),
+ g_pui8AudioStreamInterface
+};
+
+const tConfigSection g_sAudioControlInterfaceSection =
+{
+ sizeof(g_pui8AudioControlInterface),
+ g_pui8AudioControlInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete audio device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psAudioSections[] =
+{
+ &g_sAudioConfigSection,
+ &g_sIADAudioConfigSection,
+ &g_sAudioControlInterfaceSection,
+ &g_sAudioStreamInterfaceSection
+};
+
+#define NUM_AUDIO_SECTIONS (sizeof(g_psAudioSections) / \
+ sizeof(g_psAudioSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sAudioConfigHeader =
+{
+ NUM_AUDIO_SECTIONS,
+ g_psAudioSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppAudioConfigDescriptors[] =
+{
+ &g_sAudioConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvAudioDevice);
+static void InterfaceChange(void *pvAudioDevice, uint8_t ui8Interface,
+ uint8_t ui8AlternateSetting);
+static void ConfigChangeHandler(void *pvAudioDevice, uint32_t ui32Value);
+static void DataReceived(void *pvAudioDevice, uint32_t ui32Info);
+static void HandleEndpoints(void *pvAudioDevice, uint32_t ui32Status);
+static void HandleRequests(void *pvAudioDevice, tUSBRequest *psUSBRequest);
+static void HandleDevice(void *pvAudioDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB Audio device.
+//
+//*****************************************************************************
+static const tCustomHandlers g_sAudioHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// This function is called to handle data being received back from the host so
+// that the application callback can be called when the new data is ready.
+//
+//*****************************************************************************
+static void
+DataReceived(void *pvAudioDevice, uint32_t ui32Info)
+{
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Make a copy of this pointer for ease of use in this function.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // If there is an update pending and the request was to set a current
+ // value then check which value was set.
+ //
+ if(psInst->ui16Update && (psInst->ui8Request == USB_AC_SET_CUR))
+ {
+ //
+ // Only handling interface requests.
+ //
+ if((psInst->ui16RequestType & USB_RTYPE_RECIPIENT_M) ==
+ USB_RTYPE_INTERFACE)
+ {
+ if(psInst->ui16Update == VOLUME_CONTROL)
+ {
+ //
+ // Inform the callback of the new volume.
+ //
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_VOLUME,
+ psInst->i16Volume, 0);
+ }
+ else if(psAudioDevice->sPrivateData.ui16Update == MUTE_CONTROL)
+ {
+ //
+ // Inform the callback of the new data.
+ //
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_MUTE,
+ psInst->ui8Mute, 0);
+ }
+ }
+ psInst->ui16Update = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the isochronous endpoint
+// for the audio device class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvAudioDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+ uint32_t ui32Size;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Read out the current endpoint status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // See if there is a receive interrupt pending.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Get the amount of data available in the FIFO.
+ //
+ ui32Size = USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Configure the next DMA transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ psInst->sBuffer.pvData, ui32Size);
+ }
+ else if((USBLibDMAChannelStatus(psInst->psDMAInstance,
+ psInst->ui8OUTDMA) ==
+ USBLIBSTATUS_DMA_COMPLETE))
+ {
+ USBEndpointDMADisable(USB0_BASE,
+ psInst->ui8OUTEndpoint, USB_EP_DEV_OUT);
+
+ //
+ // Acknowledge that the data was read, this will not cause a bus
+ // acknowledgment.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, psInst->ui8OUTEndpoint, 0);
+
+ //
+ // Inform the callback of the new data.
+ //
+ psInst->sBuffer.pfnCallback(psInst->sBuffer.pvData,
+ psInst->sBuffer.ui32Size,
+ USBD_AUDIO_EVENT_DATAOUT);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvAudioDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tAudioInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDAudioDevice *psAudioDevice;
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pui8Data[0] == AUDIO_INTERFACE_CONTROL)
+ {
+ psInst->ui8InterfaceControl = pui8Data[1];
+ }
+ else if(pui8Data[0] == AUDIO_INTERFACE_OUTPUT)
+ {
+ psInst->ui8InterfaceAudio = pui8Data[1];
+ }
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if((pui8Data[0] & USB_EP_DESC_IN) == 0)
+ {
+ //
+ // Extract the new endpoint number without the DIR bit.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8OUTDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8OUTDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8OUTEndpoint,
+ ISOC_OUT_EP_MAX_SIZE,
+ (USB_DMA_EP_RX |
+ USB_DMA_EP_TYPE_ISOC |
+ USB_DMA_EP_DEVICE));
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 16);
+ }
+ break;
+ }
+
+ //
+ // Handle class specific reconfiguring of the configuration descriptor
+ // once the composite class has built the full descriptor.
+ //
+ case USB_EVENT_COMP_CONFIG:
+ {
+ //
+ // This sets the bFirstInterface of the Interface Association
+ // descriptor to the first interface which is the control
+ // interface used by this instance.
+ //
+ pui8Data[2] = psInst->ui8InterfaceControl;
+
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvAudioDevice)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ psAudioDevice->pfnCallback(0, USB_EVENT_DISCONNECTED, 0, 0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// interface changes. This occurs when the audio device transitions between
+// being active and inactive. Interface AUDIO_INTERFACE_CONTROL is the
+// inactive interface that has no endpoints, while interface
+// AUDIO_INTERFACE_AUDIO has the single Isochronous OUT endpoint.
+//
+//*****************************************************************************
+static void
+InterfaceChange(void *pvAudioDevice, uint8_t ui8Interface,
+ uint8_t ui8AlternateSetting)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Check which interface to change into.
+ //
+ if(ui8AlternateSetting == 0)
+ {
+ //
+ // Alternate setting 0 is an inactive state.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_IDLE, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Alternate setting 1 is the active state.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ psAudioDevice->pfnCallback(0, USBD_AUDIO_EVENT_ACTIVE, 0, 0);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvAudioDevice, uint32_t ui32Value)
+{
+ const tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (const tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psAudioDevice->pfnCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psAudioDevice->pfnCallback(pvAudioDevice, USB_EVENT_CONNECTED, 0, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the audio class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psAudioDevice points to a structure containing parameters
+//! customizing the operation of the audio device.
+//!
+//! In order for an application to initialize the USB audio device class, it
+//! must first call this function with the a valid audio device class structure
+//! in the \e psAudioDevice parameter. This allows this function to initialize
+//! the USB controller and device code to be prepared to enumerate and function
+//! as a USB audio device.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the audio class.
+//!
+//! See the documentation on the tUSBDAudioDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return Returns 0 on failure or a non-zero void pointer on success.
+//
+//*****************************************************************************
+void *
+USBDAudioInit(uint32_t ui32Index, tUSBDAudioDevice *psAudioDevice)
+{
+ tConfigDescriptor *psConfigDesc;
+ tDeviceDescriptor *psDevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psAudioDevice);
+ ASSERT(psAudioDevice->ppui8StringDescriptors);
+
+ //
+ // Composite Init handles all initialization that is not specific to a
+ // multiple instance device.
+ //
+ USBDAudioCompositeInit(ui32Index, psAudioDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8AudioDeviceDescriptor;
+ psDevDesc->idVendor = psAudioDevice->ui16VID;
+ psDevDesc->idProduct = psAudioDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8AudioDescriptor;
+ psConfigDesc->bmAttributes = psAudioDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psAudioDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psAudioDevice->sPrivateData.sDevInfo,
+ (void *)psAudioDevice);
+
+ //
+ // Configure the DMA for the OUT endpoint.
+ //
+ psAudioDevice->sPrivateData.ui8OUTDMA =
+ USBLibDMAChannelAllocate(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTEndpoint,
+ ISOC_OUT_EP_MAX_SIZE,
+ USB_DMA_EP_RX | USB_DMA_EP_TYPE_ISOC |
+ USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTDMA, 32);
+ USBLibDMAArbSizeSet(psAudioDevice->sPrivateData.psDMAInstance,
+ psAudioDevice->sPrivateData.ui8OUTDMA, 16);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the audio class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! audio class device operation.
+//! \param psAudioDevice points to a structure containing parameters
+//! customizing the operation of the audio device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! In order for an application to initialize the USB audio device class, it
+//! must first call this function with the a valid audio device class structure
+//! in the \e psAudioDevice parameter. This allows this function to initialize
+//! the USB controller and device code to be prepared to enumerate and function
+//! as a USB audio device. When this audio device is part of a composite
+//! device, then the \e psCompEntry should point to the composite device entry
+//! to initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the audio class.
+//!
+//! See the documentation on the tUSBDAudioDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB audio APIs.
+//
+//*****************************************************************************
+void *
+USBDAudioCompositeInit(uint32_t ui32Index, tUSBDAudioDevice *psAudioDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tAudioInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psAudioDevice);
+ ASSERT(psAudioDevice->ppui8StringDescriptors);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+ psInst->ui32USBBase = USB0_BASE;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psAudioDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sAudioHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8AudioDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppAudioConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the HID device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // The Control interface is at index 0.
+ //
+ psInst->ui8InterfaceControl = AUDIO_INTERFACE_CONTROL;
+
+ //
+ // The Audio interface is at index 1.
+ //
+ psInst->ui8InterfaceAudio = AUDIO_INTERFACE_OUTPUT;
+
+ //
+ // Set the default Isochronous OUT endpoint.
+ //
+ psInst->ui8OUTEndpoint = ISOC_OUT_ENDPOINT;
+ psInst->ui8OUTDMA = 0;
+
+ //
+ // Set the initial buffer to null.
+ //
+ psInst->sBuffer.pvData = 0;
+
+ //
+ // Save the volume settings.
+ //
+ psInst->i16VolumeMax = psAudioDevice->i16VolumeMax;
+ psInst->i16VolumeMin = psAudioDevice->i16VolumeMin;
+ psInst->i16VolumeStep = psAudioDevice->i16VolumeStep;
+
+ //
+ // No update pending to any command.
+ //
+ psInst->ui16Update = 0;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psAudioDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psAudioDevice->ui32NumStringDescriptors;
+
+ //
+ // Get the DMA instance pointer.
+ //
+ psInst->psDMAInstance = USBLibDMAInit(0);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the audio device.
+//!
+//! \param pvAudioDevice is the pointer to the device instance structure as
+//! returned by USBDAudioInit().
+//!
+//! This function terminates audio interface for the instance supplied. This
+//! function should not be called if the audio device is part of a composite
+//! device and instead the USBDCompositeTerm() function should be called for
+//! the full composite device.
+//! Following this call, the \e pvAudioDevice instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDAudioTerm(void *pvAudioDevice)
+{
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvAudioDevice is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure to the type of request and
+// will respond to all commands that are understood by the class.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvAudioDevice, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Control, ui32Recipient, ui32Stall;
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ ASSERT(pvAudioDevice != 0);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Make sure to acknowledge that the data was read, this will not send and
+ // ACK that has already been done at this point. This just tells the
+ // hardware that the data was read.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // Don't stall by default.
+ //
+ ui32Stall = 0;
+
+ //
+ // Get the request type.
+ //
+ ui32Recipient = psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M;
+
+ //
+ // Save the request type and request value.
+ //
+ psInst->ui16RequestType = psUSBRequest->bmRequestType;
+ psInst->ui8Request = psUSBRequest->bRequest;
+
+ //
+ // Check if this is an endpoint request to the audio streaming endpoint.
+ //
+ if((ui32Recipient == USB_RTYPE_ENDPOINT) &&
+ (psUSBRequest->wIndex == USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ui8Request)
+ {
+ case USB_AC_SET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(psUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Retrieve the requested sample rate.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->ui32SampleRate,
+ 3);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = SAMPLING_FREQ_CONTROL;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ //
+ // Handle retrieving the sample rate.
+ //
+ if(psUSBRequest->wValue == SAMPLING_FREQ_CONTROL)
+ {
+ //
+ // Send back the current sample rate.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->ui32SampleRate,
+ 3);
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ break;
+ }
+ }
+ }
+ else if(ui32Recipient == USB_RTYPE_INTERFACE)
+ {
+ //
+ // Make sure the request was for the control interface.
+ //
+ if((uint8_t)psUSBRequest->wIndex != psInst->ui8InterfaceControl)
+ {
+ return;
+ }
+
+ //
+ // Extract the control value from the message.
+ //
+ ui32Control = psUSBRequest->wValue & USB_CS_CONTROL_M;
+
+ //
+ // Handle an audio control request to the feature control unit.
+ //
+ if((AUDIO_CONTROL_ID << 8) ==
+ (psUSBRequest->wIndex & USB_CS_CONTROL_M))
+ {
+ //
+ // Determine the type of request.
+ //
+ switch(psInst->ui8Request)
+ {
+ case USB_AC_GET_MAX:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the maximum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeMax,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_MIN:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the minimum volume setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeMin,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_RES:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Return the volume step setting.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeStep,
+ 2);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_GET_CUR:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Send back the current volume level.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->i16Volume,
+ 2);
+ }
+ else if(ui32Control == MUTE_CONTROL)
+ {
+ //
+ // Send back the current mute value.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)&psInst->ui8Mute, 1);
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_CUR:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume level.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->i16Volume,
+ 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = VOLUME_CONTROL;
+ }
+ else if(ui32Control == MUTE_CONTROL)
+ {
+ //
+ // Read the new mute setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->ui8Mute,
+ 1);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = MUTE_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ case USB_AC_SET_RES:
+ {
+ if(ui32Control == VOLUME_CONTROL)
+ {
+ //
+ // Read the new volume step setting.
+ //
+ USBDCDRequestDataEP0(0,
+ (uint8_t *)&psInst->i16VolumeStep, 2);
+
+ //
+ // Save what we are updating.
+ //
+ psInst->ui16Update = VOLUME_CONTROL;
+ }
+ else
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // Stall on unknown commands.
+ //
+ ui32Stall = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Stall on all unknown commands.
+ //
+ if(ui32Stall)
+ {
+ USBDCDStallEP0(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to supply buffers to the audio class to be filled
+//! from the USB host device.
+//!
+//! \param pvAudioDevice is the pointer to the device instance structure as
+//! returned by USBDAudioInit() or USBDAudioCompositeInit().
+//! \param pvBuffer is a pointer to the buffer to fill with audio data.
+//! \param ui32Size is the size in bytes of the buffer pointed to by the
+//! \e pvBuffer
+//! parameter.
+//! \param pfnCallback is a callback that will provide notification when this
+//! buffer has valid data.
+//!
+//! This function fills the buffer pointed to by the \e pvBuffer parameter with
+//! at most \e ui32Size one packet of data from the host controller. The
+//! \e ui32Size has a minimum value of \b ISOC_OUT_EP_MAX_SIZE since each USB
+//! packet can be at most \b ISOC_OUT_EP_MAX_SIZE bytes in size. Since the
+//! audio data may not be received in amounts that evenly fit in the buffer
+//! provided, the buffer may not be completely filled. The \e pfnCallback
+//! function will provide the amount of valid data that was actually stored in
+//! the buffer provided. The function will return zero if the buffer could be
+//! scheduled to be filled, otherwise the function will return a non-zero value
+//! if there was some reason that the buffer could not be added.
+//!
+//! \return Returns 0 to indicate success any other value indicates that the
+//! buffer will not be filled.
+//
+//*****************************************************************************
+int32_t
+USBAudioBufferOut(void *pvAudioDevice, void *pvBuffer, uint32_t ui32Size,
+ tUSBAudioBufferCallback pfnCallback)
+{
+ tAudioInstance *psInst;
+ tUSBDAudioDevice *psAudioDevice;
+
+ //
+ // Make sure we were not passed NULL pointers.
+ //
+ ASSERT(pvAudioDevice != 0);
+ ASSERT(pvBuffer != 0);
+
+ //
+ // Buffer must be at least one packet in size.
+ //
+ ASSERT(ui32Size >= ISOC_OUT_EP_MAX_SIZE);
+ ASSERT(pfnCallback);
+
+ //
+ // The audio device structure pointer.
+ //
+ psAudioDevice = (tUSBDAudioDevice *)pvAudioDevice;
+
+ //
+ // Create a pointer to the audio instance data.
+ //
+ psInst = &psAudioDevice->sPrivateData;
+
+ //
+ // Initialize the buffer instance.
+ //
+ psInst->sBuffer.pvData = pvBuffer;
+ psInst->sBuffer.ui32Size = ui32Size;
+ psInst->sBuffer.ui32NumBytes = 0;
+ psInst->sBuffer.pfnCallback = pfnCallback;
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/usblib/device/usbdaudio.h b/usblib/device/usbdaudio.h
new file mode 100644
index 0000000..e934914
--- /dev/null
+++ b/usblib/device/usbdaudio.h
@@ -0,0 +1,382 @@
+//*****************************************************************************
+//
+// usbdaudio.h - USB audio device class driver.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDAUDIO_H__
+#define __USBDAUDIO_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup audio_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+typedef void (* tUSBAudioBufferCallback)(void *pvBuffer, uint32_t ui32Param,
+ uint32_t ui32Event);
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// audio device class. The memory for this structure is pointed to by
+// the pi16PrivateData field in the tUSBDAudioDevice structure passed on
+// USBDAudioInit() and should not be modified by any code outside of the audio
+// device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The maximum volume expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeMax;
+
+ //
+ // The minimum volume expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeMin;
+
+ //
+ // The minimum volume step expressed as an 8.8 signed value.
+ //
+ int16_t i16VolumeStep;
+
+ struct
+ {
+ //
+ // Pointer to a buffer provided by caller.
+ //
+ void *pvData;
+
+ //
+ // Size of the data area provided in pvData in bytes.
+ //
+ uint32_t ui32Size;
+
+ //
+ // Number of valid bytes copied into the pvData area.
+ //
+ uint32_t ui32NumBytes;
+
+ //
+ // The buffer callback for this function.
+ //
+ tUSBAudioBufferCallback pfnCallback;
+ }
+ sBuffer;
+
+ //
+ // Pending request type.
+ //
+ uint16_t ui16RequestType;
+
+ //
+ // Pending request.
+ //
+ uint8_t ui8Request;
+
+ //
+ // Pending update value.
+ //
+ uint16_t ui16Update;
+
+ //
+ // Current Volume setting.
+ //
+ int16_t i16Volume;
+
+ //
+ // Current Mute setting.
+ //
+ uint8_t ui8Mute;
+
+ //
+ // Current Sample rate, this is not writable but the host will try.
+ //
+ uint32_t ui32SampleRate;
+
+ //
+ // The OUT endpoint in use by this instance.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The OUT endpoint DMA channel in use by this instance.
+ //
+ uint8_t ui8OUTDMA;
+
+ //
+ // The control interface number associated with this instance.
+ //
+ uint8_t ui8InterfaceControl;
+
+ //
+ // The audio interface number associated with this instance.
+ //
+ uint8_t ui8InterfaceAudio;
+
+ //
+ // A copy of the DMA instance data used with calls to USBLibDMA functions.
+ //
+ tUSBDMAInstance *psDMAInstance;
+}
+tAudioInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8IADAudioDescriptor array in bytes.
+//
+//*****************************************************************************
+#define AUDIODESCRIPTOR_SIZE (8)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8AudioControlInterface array in bytes.
+//
+//*****************************************************************************
+#define CONTROLINTERFACE_SIZE (52)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8AudioStreamInterface array in bytes.
+//
+//*****************************************************************************
+#define STREAMINTERFACE_SIZE (52)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Audio Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DAUDIO_SIZE (AUDIODESCRIPTOR_SIZE + \
+ CONTROLINTERFACE_SIZE + STREAMINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the device audio class.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ const char pcVendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ const char pcProduct[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ const char pcVersion[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the audio
+ //! device.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), Audio
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The maximum volume expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeMax;
+
+ //
+ //! The minimum volume expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeMin;
+
+ //
+ //! The minimum volume step expressed as an 8.8 signed value.
+ //
+ const int16_t i16VolumeStep;
+
+ //
+ //! The private instance data for the audio device.
+ //
+ tAudioInstance sPrivateData;
+}
+tUSBDAudioDevice;
+
+//*****************************************************************************
+//
+// Audio specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is connected but not active.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_IDLE (USBD_AUDIO_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is connected and is now
+//! active.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_ACTIVE (USBD_AUDIO_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that the device is returning a data buffer
+//! provided by the USBAudioBufferOut() function back to the application with
+//! valid audio data received from the USB host controller. The \e pvBuffer
+//! parameter holds the pointer to the buffer with the new audio data and
+//! the \e ui32Param value holds the amount of valid data in bytes that are
+//! contained in the \e pvBuffer parameter.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_DATAOUT (USBD_AUDIO_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that a volume change has occurred. The
+//! \e ui32Param value contains a signed 8.8 fixed point value that represents
+//! the current volume gain/attenuation in decibels(dB). The provided message
+//! handler should be prepared to handle negative and positive values with the
+//! value 0x8000 indicating maximum attenuation. The \e pvBuffer parameter
+//! should be ignored.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_VOLUME (USBD_AUDIO_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! This USB audio event indicates that a mute request has occurred. The
+//! \e ui32Param value will either be a 1 to indicate that the audio is now
+//! muted, and a value of 0 indicates that the audio has been unmuted.
+//
+//*****************************************************************************
+#define USBD_AUDIO_EVENT_MUTE (USBD_AUDIO_EVENT_BASE + 5)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDAudioInit(uint32_t ui32Index,
+ tUSBDAudioDevice *psAudioDevice);
+extern void *USBDAudioCompositeInit(uint32_t ui32Index,
+ tUSBDAudioDevice *psAudioDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDAudioTerm(void *pvAudioDevice);
+extern int32_t USBAudioBufferOut(void *pvAudioDevice, void *pvBuffer,
+ uint32_t ui32Size,
+ tUSBAudioBufferCallback pfnCallback);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/device/usbdbulk.c b/usblib/device/usbdbulk.c
new file mode 100644
index 0000000..1e4cf0b
--- /dev/null
+++ b/usblib/device/usbdbulk.c
@@ -0,0 +1,1562 @@
+//*****************************************************************************
+//
+// usbdbulk.c - USB bulk device class driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdbulk.h"
+#include "usblib/device/usbdcomp.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bulk_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+// Each deferred operation is defined as the bit number that should be set in
+// tBulkInstance->ui16DeferredOpFlags to indicate that the operation is
+// pending.
+//
+//*****************************************************************************
+#define BULK_DO_PACKET_RX 5
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.'
+//
+//*****************************************************************************
+#define DATA_IN_ENDPOINT USB_EP_1
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints used for bulk data
+// transmission and reception and the associated FIFO sizes to set aside
+// for each endpoint.
+//
+//*****************************************************************************
+#define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
+
+#define DATA_IN_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_OUT_EP_FIFO_SIZE)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8BulkDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_VEND_SPECIFIC, // USB Device Class
+ 0, // USB Device Sub-class
+ 0, // USB Device protocol
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Bulk device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8BulkDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8BulkInterface[BULKINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_VEND_SPECIFIC, // The interface class
+ 0, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The bulk configuration descriptor is defined as two sections, one
+// containing just the 9 byte USB configuration descriptor and the other
+// containing everything else that is sent to the host along with it.
+//
+//*****************************************************************************
+const tConfigSection g_sBulkConfigSection =
+{
+ sizeof(g_pui8BulkDescriptor),
+ g_pui8BulkDescriptor
+};
+
+const tConfigSection g_sBulkInterfaceSection =
+{
+ sizeof(g_pui8BulkInterface),
+ g_pui8BulkInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete bulk device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psBulkSections[] =
+{
+ &g_sBulkConfigSection,
+ &g_sBulkInterfaceSection
+};
+
+#define NUM_BULK_SECTIONS (sizeof(g_psBulkSections) / \
+ sizeof(g_psBulkSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sBulkConfigHeader =
+{
+ NUM_BULK_SECTIONS,
+ g_psBulkSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppBulkConfigDescriptors[] =
+{
+ &g_sBulkConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info);
+static void HandleDisconnect(void *pvBulkDevice);
+static void HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status);
+static void HandleSuspend(void *pvBulkDevice);
+static void HandleResume(void *pvBulkDevice);
+static void HandleDevice(void *pvBulkDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// Device event handler callbacks.
+//
+//*****************************************************************************
+const tCustomHandlers g_sBulkHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ 0,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psBulkDevice is the device instance whose endpoint is to be
+// processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the bulk OUT endpoint (in other words, whenever the
+// host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataFromHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ uint32_t ui32Size;
+ tBulkInstance *psInst;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client does not read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX,
+ true);
+
+ //
+ // How big is the packet we have just received?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE,
+ ui32Size, (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so allow the callback
+ // to handle it.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psBulkDevice is the device instance whose endpoint is to be
+// processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the bulk IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataToHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status)
+{
+ tBulkInstance *psInst;
+ uint32_t ui32EPStatus, ui32Size;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8INEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, psInst->ui8INEndpoint,
+ ui32EPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->iBulkTxState = eBulkStateIdle;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ui32Size = psInst->ui16LastTxSize;
+ psInst->ui16LastTxSize = 0;
+ psBulkDevice->pfnTxCallback(psBulkDevice->pvTxCBData,
+ USB_EVENT_TX_COMPLETE, ui32Size, (void *)0);
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status)
+{
+ tUSBDBulkDevice *psBulkDevice;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(psBulkDevice, ui32Status);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint)))
+ {
+ ProcessDataToHost(psBulkDevice, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info)
+{
+ tBulkInstance *psInst;
+ tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iBulkRxState = eBulkStateIdle;
+ psInst->iBulkTxState = eBulkStateIdle;
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvBulkDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tBulkInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDBulkDevice *psBulkDevice;
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB Bulk
+ // class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_SLEEP, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psBulkDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_LPM_ERROR, 0, (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvBulkDevice)
+{
+ tUSBDBulkDevice *psBulkDevice;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(psInst->bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psInst->bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvBulkDevice)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_SUSPEND, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvBulkDevice)
+{
+ const tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_RESUME, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param ui32Index is the index of the USB controller for which this tick
+// is being generated.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+BulkTickHandler(void *pvBulkDevice, uint32_t ui32TimemS)
+{
+ tBulkInstance *psInst;
+ uint32_t ui32Size;
+ tUSBDBulkDevice *psBulkDevice;
+
+ ASSERT(pvBulkDevice != 0);
+
+ //
+ // The bulk device structure pointer.
+ //
+ psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice;
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << BULK_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psBulkDevice points to a structure containing parameters customizing
+//! the operation of the bulk device.
+//!
+//! An application wishing to make use of a USB bulk communication channel
+//! must call this function to initialize the USB controller and attach the
+//! device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function will return the \e psBulkDevice
+//! pointer passed to it. This must be passed on all future calls to the
+//! device driver related to this device.
+//!
+//! The USBDBulk interface offers packet-based transmit and receive operation.
+//! If the application would rather use block based communication with
+//! transmit and receive buffers, USB buffers may be used above the bulk
+//! transmit and receive channels to offer this functionality.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDBulkPacketWrite() must send no more than 64 bytes of data at a
+//! time and may only be made when no other transmission is currently
+//! outstanding.
+//!
+//! Once a packet of data has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to
+//! inform it that another packet may be transmitted.
+//!
+//! Receive Operation:
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USBD_EVENT_RX_AVAILABLE. The application must then
+//! call USBDBulkPacketRead(), passing a buffer capable of holding 64 bytes, to
+//! retrieve the data and acknowledge reception to the USB host.
+//!
+//! \note The application must not make any calls to the low level USB Device
+//! API if interacting with USB via the USB bulk device class API. Doing so
+//! will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or void pointer that should be used with
+//! the remaining USB bulk class APSs.
+//
+//*****************************************************************************
+void *
+USBDBulkInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice)
+{
+ void *pvBulkDevice;
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psBulkDevice);
+
+ pvBulkDevice = USBDBulkCompositeInit(ui32Index, psBulkDevice, 0);
+
+ if(pvBulkDevice)
+ {
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8BulkDeviceDescriptor;
+ psDevDesc->idVendor = psBulkDevice->ui16VID;
+ psDevDesc->idProduct = psBulkDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8BulkDescriptor;
+ psConfigDesc->bmAttributes = psBulkDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psBulkDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psBulkDevice->sPrivateData.sDevInfo,
+ (void *)psBulkDevice);
+ }
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return(pvBulkDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes bulk device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for bulk device operation.
+//! \param psBulkDevice points to a structure containing parameters customizing
+//! the operation of the bulk device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDBulkInit() except that it is used for
+//! initializing an instance of the bulk device for use in a composite device.
+//! When this bulk device is part of a composite device, then the
+//! \e psCompEntry should point to the composite device entry to initialize.
+//! This is part of the array that is passed to the USBDCompositeInit()
+//! function.
+//!
+//! \return Returns zero on failure or a non-zero value that should be
+//! used with the remaining USB Bulk APIs.
+//
+//*****************************************************************************
+void *
+USBDBulkCompositeInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tBulkInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psBulkDevice);
+ ASSERT(psBulkDevice->ppui8StringDescriptors);
+ ASSERT(psBulkDevice->pfnRxCallback);
+ ASSERT(psBulkDevice->pfnTxCallback);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psBulkDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psBulkDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sBulkHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8BulkDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppBulkConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Set the basic state information for the class.
+ //
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iBulkRxState = eBulkStateUnconfigured;
+ psInst->iBulkTxState = eBulkStateUnconfigured;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->bConnected = false;
+
+ //
+ // Initialize the device info structure for the Bulk device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ui8INEndpoint = DATA_IN_ENDPOINT;
+ psInst->ui8OUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8Interface = 0;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psBulkDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psBulkDevice->ui32NumStringDescriptors;
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(BulkTickHandler, (void *)psBulkDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psBulkDevice);
+}
+
+//*****************************************************************************
+//
+//! Shut down the bulk device.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function terminates device operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the bulk device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvBulkDevice instance should not me used in any
+//! other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDBulkTerm(void *pvBulkDevice)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDBulkInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides
+//! in RAM. If this structure is in flash, callback pointer changes are not
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetRxCBData(void *pvBulkDevice, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData;
+ ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the transmit callback.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDBulkInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides
+//! in RAM. If this structure is in flash, callback pointer changes are not
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDBulkSetTxCBData(void *pvBulkDevice, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Set the callback pointer for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData;
+ ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a packet of data to the USB host via the bulk data interface.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast indicates whether more data is to be written before a packet
+//! should be scheduled for transmission. If \b true, the client will make
+//! a further call to this function. If \b false, no further call will be
+//! made and the driver should schedule transmission of a short packet.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB packet. If no transmission is currently ongoing,
+//! the data is immediately copied to the relevant USB endpoint FIFO for
+//! transmission. Whenever a USB packet is acknowledged by the host, a
+//! \b USB_EVENT_TX_COMPLETE event will be sent to the transmit channel
+//! callback indicating that more data can now be transmitted.
+//!
+//! The maximum value for \e ui32Length is 64 bytes (the maximum USB packet
+//! size for the bulk endpoints in use by the device). Attempts to send more
+//! data than this will result in a return code of 0 indicating that the data
+//! cannot be sent.
+//!
+//! The \e bLast parameter allows a client to make multiple calls to this
+//! function before scheduling transmission of the packet to the host. This
+//! can be helpful if, for example, constructing a packet on the fly or
+//! writing a packet which spans the wrap point in a ring buffer.
+//!
+//! \return Returns the number of bytes actually sent. At this level, this
+//! will either be the number of bytes passed (if less than or equal to the
+//! maximum packet size for the USB endpoint in use and no outstanding
+//! transmission ongoing) or 0 to indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkPacketWrite(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tBulkInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ui32Length > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->iBulkTxState != eBulkStateIdle))
+ {
+ //
+ // Either the packet was too big or we are in the middle of sending
+ // another packet. Return 0 to indicate that we can't send this data.
+ //
+ return(0);
+ }
+
+ //
+ // Copy the data into the USB endpoint FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8INEndpoint,
+ pi8Data, ui32Length);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->ui16LastTxSize += (uint16_t)ui32Length;
+
+ //
+ // If this is the last call for this packet, schedule transmission.
+ //
+ if(bLast)
+ {
+ //
+ // Send the packet to the host if we have received all the data we
+ // can expect for this packet.
+ //
+ psInst->iBulkTxState = eBulkStateWaitData;
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the bulk data
+//! interface.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to \e ui32Length bytes of data received from the USB
+//! host into the supplied application buffer. If the driver detects that the
+//! entire packet has been read, it is acknowledged to the host.
+//!
+//! The \e bLast parameter is ignored in this implementation since the end of
+//! a packet can be determined without relying upon the client to provide
+//! this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkPacketRead(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tBulkInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX,
+ false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function returns the maximum number of bytes that can be passed on a
+//! call to USBDBulkPacketWrite() and accepted for transmission. The value
+//! returned will be the maximum USB packet size (64) if no transmission is
+//! currently outstanding or 0 if a transmission is in progress.
+//!
+//! \return Returns the number of bytes available in the transmit buffer.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkTxPacketAvailable(void *pvBulkDevice)
+{
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iBulkTxState != eBulkStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(DATA_IN_EP_MAX_SIZE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvBulkDevice is the pointer to the device instance structure as
+//! returned by USBDBulkInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDBulkRxPacketAvailable(void *pvBulkDevice)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tBulkInstance *psInst;
+
+ ASSERT(pvBulkDevice);
+
+ //
+ // Get a pointer to the bulk device instance data pointer
+ //
+ psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvBulkDevice is the pointer to the bulk device instance structure.
+//! \param ui8Power indicates the current power status, either
+//! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus- or self-powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDBulkPowerStatusSet(void *pvBulkDevice, uint8_t ui8Power)
+{
+ ASSERT(pvBulkDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvBulkDevice is the pointer to the bulk device instance structure.
+//!
+//! When the bus is suspended, an application which supports remote wake up
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wake up signaling to the host. If the remote
+//! wake up feature has not been disabled by the host, this will cause the bus
+//! to resume operation within 20mS. If the host has disabled remote wake up,
+//! \b false will be returned to indicate that the wake up request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wake up is not disabled and the
+//! signaling was started or \b false if remote wake up is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDBulkRemoteWakeupRequest(void *pvBulkDevice)
+{
+ ASSERT(pvBulkDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdbulk.h b/usblib/device/usbdbulk.h
new file mode 100644
index 0000000..0f6887d
--- /dev/null
+++ b/usblib/device/usbdbulk.h
@@ -0,0 +1,300 @@
+//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for a generic bulk device.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDBULK_H__
+#define __USBDBULK_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bulk_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB Bulk example code and are here only to help with the application
+// allocating the correct amount of memory for the Bulk example device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Not configured.
+ //
+ eBulkStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eBulkStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eBulkStateWaitData,
+
+ //
+ // Waiting for client to process data.
+ //
+ eBulkStateWaitClient
+}
+tBulkState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// Bulk only example device. The memory for this structure is inlcluded in
+// the sPrivateData field in the tUSBDBulkDevice structure passed on
+// USBDBulkInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the bulk receive channel.
+ //
+ volatile tBulkState iBulkRxState;
+
+ //
+ // The state of the bulk transmit channel.
+ //
+ volatile tBulkState iBulkTxState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the last transmit.
+ //
+ uint16_t ui16LastTxSize;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+}
+tBulkInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8BulkInterface array in bytes.
+//
+//*****************************************************************************
+#define BULKINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Bulk Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DBULK_SIZE (BULKINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the bulk device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data receive channel.
+ //
+ const tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data transmit
+ //! channel.
+ //
+ const tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain pointers to the following string descriptors in this
+ //! order. Language descriptor, Manufacturer name string (language 1),
+ //! Product name string (language 1), Serial number string (language 1),
+ //! Interface description string (language 1) and Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the strings for indices 1 through 5
+ //! must be repeated for each of the other languages defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors array.
+ //! This must be 1 + (5 * number of supported languages).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! not be modified by any code outside the bulk class driver.
+ //
+ tBulkInstance sPrivateData;
+}
+tUSBDBulkDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDBulkInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice);
+extern void *USBDBulkCompositeInit(uint32_t ui32Index,
+ tUSBDBulkDevice *psBulkDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDBulkTerm(void *pvBulkInstance);
+extern void *USBDBulkSetRxCBData(void *pvBulkInstance, void *pvCBData);
+extern void *USBDBulkSetTxCBData(void *pvBulkInstance, void *pvCBData);
+extern uint32_t USBDBulkPacketWrite(void *pvBulkInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDBulkPacketRead(void *pvBulkInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDBulkTxPacketAvailable(void *pvBulkInstance);
+extern uint32_t USBDBulkRxPacketAvailable(void *pvBulkInstance);
+extern bool USBDBulkRemoteWakeupRequest(void *pvBulkInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+extern void USBDBulkPowerStatusSet(void *pvBulkInstance, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDBULK_H__
diff --git a/usblib/device/usbdcdc.c b/usblib/device/usbdcdc.c
new file mode 100644
index 0000000..a4dc73a
--- /dev/null
+++ b/usblib/device/usbdcdc.c
@@ -0,0 +1,3043 @@
+//*****************************************************************************
+//
+// usbdcdc.c - USB CDC ACM (serial) device class driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usbcdc.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdcomp.h"
+#include "usblib/device/usbdcdc.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cdc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Some assumptions and deviations from the CDC specification
+// ----------------------------------------------------------
+//
+// 1. Although the CDC specification indicates that the following requests
+// should be supported by ACM CDC devices, these don't seem relevant to a
+// virtual COM port implementation and are never seen when connecting to a
+// Windows host and running either Hyperterminal or TeraTerm. As a result,
+// this implementation does not support them and stalls endpoint 0 if they are
+// received.
+// - SEND_ENCAPSULATED_COMMAND
+// - GET_ENCAPSULATED_RESPONSE
+// - SET_COMM_FEATURE
+// - GET_COMM_FEATURE
+// - CLEAR_COMM_FEATURE
+//
+// 2. The CDC specification is very clear on the fact that an ACM device
+// should offer two interfaces - a control interface offering an interrupt IN
+// endpoint and a data interface offering bulk IN and OUT endpoints. Using
+// this descriptor configuration, however, Windows insists on enumerating the
+// device as two separate entities resulting in two virtual COM ports or one
+// COM port and an Unknown Device (depending upon INF contents) appearing
+// in Device Manager. This implementation, derived by experimentation and
+// examination of other virtual COM and CDC solutions, uses only a single
+// interface combining all three endpoints. This appears to satisfy
+// Windows2000, XP and Vista and operates as intended using the Hyperterminal
+// and TeraTerm terminal emulators. Your mileage may vary with other
+// (untested) operating systems!
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Size of the buffer to hold request-specific data read from the host. This
+// must be sized to accommodate the largest request structure that we intend
+// processing.
+//
+//*****************************************************************************
+#define MAX_REQUEST_DATA_SIZE sizeof(tLineCoding)
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+//
+//*****************************************************************************
+#define CDC_DO_SERIAL_STATE_CHANGE \
+ 0
+#define CDC_DO_SEND_BREAK 1
+#define CDC_DO_CLEAR_BREAK 2
+#define CDC_DO_LINE_CODING_CHANGE \
+ 3
+#define CDC_DO_LINE_STATE_CHANGE \
+ 4
+#define CDC_DO_PACKET_RX 5
+
+//*****************************************************************************
+//
+// The subset of deferred operations which result in the receive channel
+// being blocked.
+//
+//*****************************************************************************
+#define RX_BLOCK_OPS ((1 << CDC_DO_SEND_BREAK) | \
+ (1 << CDC_DO_LINE_CODING_CHANGE) | \
+ (1 << CDC_DO_LINE_STATE_CHANGE))
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define CONTROL_ENDPOINT USB_EP_1
+#define DATA_IN_ENDPOINT USB_EP_2
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// The following are the USB interface numbers for the CDC serial device.
+//
+//*****************************************************************************
+#define SERIAL_INTERFACE_CONTROL \
+ 0
+#define SERIAL_INTERFACE_DATA 1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints used for serial data
+// transmission and reception and the associated FIFO sizes to set aside
+// for each endpoint.
+//
+//*****************************************************************************
+#define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64
+#define CTL_IN_EP_FIFO_SIZE USB_FIFO_SZ_16
+
+#define DATA_IN_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define DATA_OUT_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE)
+#define CTL_IN_EP_MAX_SIZE USBFIFOSizeToBytes(CTL_IN_EP_FIFO_SIZE)
+
+//*****************************************************************************
+//
+// The collection of serial state flags indicating character errors.
+//
+//*****************************************************************************
+#define USB_CDC_SERIAL_ERRORS (USB_CDC_SERIAL_STATE_OVERRUN | \
+ USB_CDC_SERIAL_STATE_PARITY | \
+ USB_CDC_SERIAL_STATE_FRAMING)
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8CDCSerDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume high-speed - see USB 2.0 spec
+ // 9.2.6.6)
+ USB_CLASS_CDC, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ USB_CDC_PROTOCOL_NONE, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during
+ // USBDCDCInit).
+ USBShort(0), // Product ID (filled in during
+ // USBDCDCInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// CDC Serial configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8CDCSerDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(9), // The total size of this full structure,
+ // this will be patched so it is just set
+ // to the size of this structure.
+ 2, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+const tConfigSection g_sCDCSerConfigSection =
+{
+ sizeof(g_pui8CDCSerDescriptor),
+ g_pui8CDCSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the Interface Association Descriptor for the serial device used in
+// composite devices.
+//
+//*****************************************************************************
+uint8_t g_pui8IADSerDescriptor[SERDESCRIPTOR_SIZE] =
+{
+
+ 8, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE_ASC, // Interface Association Type.
+ 0x0, // Default starting interface is 0.
+ 0x2, // Number of interfaces in this
+ // association.
+ USB_CLASS_CDC, // The device class for this association.
+ USB_CDC_SUBCLASS_ABSTRACT_MODEL,
+ // The device subclass for this
+ // association.
+ USB_CDC_PROTOCOL_V25TER, // The protocol for this association.
+ 0 // The string index for this association.
+};
+
+const tConfigSection g_sIADSerConfigSection =
+{
+ sizeof(g_pui8IADSerDescriptor),
+ g_pui8IADSerDescriptor
+};
+
+//*****************************************************************************
+//
+// This is the control interface for the serial device.
+//
+//*****************************************************************************
+const uint8_t g_pui8CDCSerCommInterface[SERCOMMINTERFACE_SIZE] =
+{
+ //
+ // Communication Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ SERIAL_INTERFACE_CONTROL, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_CDC, // The interface class constant defined by
+ // USB-IF (spec 5.1.3).
+ USB_CDC_SUBCLASS_ABSTRACT_MODEL,
+ // The interface sub-class constant
+ // defined by USB-IF (spec 5.1.3).
+ USB_CDC_PROTOCOL_V25TER, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+
+ //
+ // Communication Class Interface Functional Descriptor - Header
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_HEADER, // Header functional descriptor
+ USBShort(0x110), // Complies with CDC version 1.1
+
+ //
+ // Communication Class Interface Functional Descriptor - ACM
+ //
+ 4, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_ABSTRACT_CTL_MGMT,
+ USB_CDC_ACM_SUPPORTS_LINE_PARAMS | USB_CDC_ACM_SUPPORTS_SEND_BREAK,
+
+ //
+ // Communication Class Interface Functional Descriptor - Unions
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_UNION,
+ SERIAL_INTERFACE_CONTROL,
+ SERIAL_INTERFACE_DATA, // Data interface number
+
+ //
+ // Communication Class Interface Functional Descriptor - Call Management
+ //
+ 5, // Size of the functional descriptor.
+ USB_CDC_CS_INTERFACE, // CDC interface descriptor
+ USB_CDC_FD_SUBTYPE_CALL_MGMT,
+ USB_CDC_CALL_MGMT_HANDLED,
+ SERIAL_INTERFACE_DATA, // Data interface number
+
+ //
+ // Endpoint Descriptor (interrupt, IN)
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(CONTROL_ENDPOINT),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(CTL_IN_EP_MAX_SIZE), // The maximum packet size.
+ 1 // The polling interval for this endpoint.
+};
+
+const tConfigSection g_sCDCSerCommInterfaceSection =
+{
+ sizeof(g_pui8CDCSerCommInterface),
+ g_pui8CDCSerCommInterface
+};
+
+//*****************************************************************************
+//
+// This is the Data interface for the serial device.
+//
+//*****************************************************************************
+const uint8_t g_pui8CDCSerDataInterface[SERDATAINTERFACE_SIZE] =
+{
+ //
+ // Communication Class Data Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ SERIAL_INTERFACE_DATA, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_CDC_DATA, // The interface class constant defined by
+ // USB-IF (spec 5.1.3).
+ 0, // The interface sub-class constant
+ // defined by USB-IF (spec 5.1.3).
+ USB_CDC_PROTOCOL_NONE, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+const tConfigSection g_sCDCSerDataInterfaceSection =
+{
+ sizeof(g_pui8CDCSerDataInterface),
+ g_pui8CDCSerDataInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete CDC ACM configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psCDCSerSections[] =
+{
+ &g_sCDCSerConfigSection,
+ &g_sCDCSerCommInterfaceSection,
+ &g_sCDCSerDataInterfaceSection,
+};
+
+#define NUM_CDCSER_SECTIONS (sizeof(g_psCDCSerSections) / \
+ sizeof(g_psCDCSerSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration. This is the root of the data
+// structure that defines all the bits and pieces that are pulled together to
+// generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sCDCSerConfigHeader =
+{
+ NUM_CDCSER_SECTIONS,
+ g_psCDCSerSections
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete CDC ACM configuration descriptor used in composite devices.
+// The only addition is the g_sIADSerConfigSection.
+//
+//*****************************************************************************
+const tConfigSection *g_psCDCCompSerSections[] =
+{
+ &g_sCDCSerConfigSection,
+ &g_sIADSerConfigSection,
+ &g_sCDCSerCommInterfaceSection,
+ &g_sCDCSerDataInterfaceSection,
+};
+
+#define NUM_COMP_CDCSER_SECTIONS (sizeof(g_psCDCCompSerSections) / \
+ sizeof(g_psCDCCompSerSections[0]))
+
+//*****************************************************************************
+//
+// The header for the composite configuration. This is the root of the data
+// structure that defines all the bits and pieces that are pulled together to
+// generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sCDCCompSerConfigHeader =
+{
+ NUM_COMP_CDCSER_SECTIONS,
+ g_psCDCCompSerSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor for the CDC serial class device.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppCDCSerConfigDescriptors[] =
+{
+ &g_sCDCSerConfigHeader
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor for the CDC serial class device used in a composite
+// device.
+//
+//*****************************************************************************
+const tConfigHeader * const g_pCDCCompSerConfigDescriptors[] =
+{
+ &g_sCDCCompSerConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleRequests(void *pvCDCDevice, tUSBRequest *pUSBRequest);
+static void HandleConfigChange(void *pvCDCDevice, uint32_t ui32Info);
+static void HandleEP0Data(void *pvCDCDevice, uint32_t ui32DataSize);
+static void HandleDisconnect(void *pvCDCDevice);
+static void HandleEndpoints(void *pvCDCDevice, uint32_t ui32Status);
+static void HandleSuspend(void *pvCDCDevice);
+static void HandleResume(void *pvCDCDevice);
+static void HandleDevice(void *pvCDCDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB serial device.
+//
+//*****************************************************************************
+const tCustomHandlers g_sCDCHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ HandleEP0Data,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler.
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// Determines whether or not a client has consumed all received data previously
+// passed to it.
+//
+//! \param psCDCDevice is the pointer to the device instance structure as returned
+//! by USBDCDCInit().
+//
+// This function is called to determine whether or not a device has consumed
+// all data previously passed to it via its receive callback.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+DeviceConsumedAllData(const tUSBDCDCDevice *psCDCDevice)
+{
+ uint32_t ui32Remaining;
+
+ //
+ // Send the device an event requesting that it tell us how many bytes
+ // of data it still has to process.
+ //
+ ui32Remaining = psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_DATA_REMAINING, 0, (void *)0);
+
+ //
+ // If any data remains to be processed, return false, else return true.
+ //
+ return(ui32Remaining ? false : true);
+}
+
+//*****************************************************************************
+//
+// Notifies the client that it should set or clear a break condition.
+//
+// \param psCDCDevice is the pointer to the device instance structure as returned
+// by USBDCDCInit().
+// \param bSend is \b true if a break condition is to be set or \b false if
+// it is to be cleared.
+//
+// This function is called to instruct the client to start or stop sending a
+// break condition on its serial transmit line.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static void
+SendBreak(tUSBDCDCDevice *psCDCDevice, bool bSend)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Set the break state flags as necessary. If we are turning the break on,
+ // set the flag to tell ourselves that we need to notify the client when
+ // it is time to turn it off again.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SEND_BREAK, false);
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_CLEAR_BREAK, bSend);
+
+ //
+ // Tell the client to start or stop sending the break.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ (bSend ? USBD_CDC_EVENT_SEND_BREAK :
+ USBD_CDC_EVENT_CLEAR_BREAK), 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a host request to set the serial communication
+// parameters.
+//
+// \param psCDCDevice is the device instance whose communication parameters are to
+// be set.
+//
+// This function is called to notify the client when the host requests a change
+// in the serial communication parameters (baud rate, parity, number of bits
+// per character and number of stop bits) to use.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SendLineCodingChange(tUSBDCDCDevice *psCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_LINE_CODING_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_SET_LINE_CODING, 0,
+ &(psInst->sLineCoding));
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a host request to set the RTS and DTR handshake line
+// states.
+//
+// \param psCDCDevice is the device instance whose break condition is to be set or
+// cleared.
+//
+// This function is called to notify the client when the host requests a change
+// in the state of one or other of the RTS and DTR handshake lines.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SendLineStateChange(tUSBDCDCDevice *psCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Clear the flag we use to tell ourselves that the line coding change has
+ // yet to be notified to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_LINE_STATE_CHANGE,
+ false);
+
+ //
+ // Tell the client to update their serial line coding parameters.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_SET_CONTROL_LINE_STATE,
+ psInst->ui16ControlLineState,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a break request if no data remains to be processed.
+//
+// \param psCDCDevice is the device instance that is to be commanded to send a
+// break condition.
+//
+// This function is called when the host requests that the device set a break
+// condition on the serial transmit line. If no data received from the host
+// remains to be processed, the break request is passed to the control
+// callback. If data is outstanding, the call is ignored (with the operation
+// being retried on the next timer tick).
+//
+// \return Returns \b true if the break notification was sent, \b false
+// otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendBreak(tUSBDCDCDevice *psCDCDevice, uint16_t ui16Duration)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the break request on to the client since no data remains to be
+ // consumed.
+ //
+ SendBreak(psCDCDevice, (ui16Duration ? true : false));
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a request to change the serial line parameters if no
+// data remains to be processed.
+//
+// \param psCDCDevice is the device instance whose line coding parameters are to
+// be changed.
+//
+// This function is called when the host requests that the device change the
+// serial line coding parameters. If no data received from the host remains
+// to be processed, the request is passed to the control callback. If data is
+// outstanding, the call is ignored (with the operation being retried on the
+// next timer tick).
+//
+// \return Returns \b true if the notification was sent, \b false otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendLineCodingChange(tUSBDCDCDevice *psCDCDevice)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineCodingChange(psCDCDevice);
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a request to change the handshake line states if no
+// data remains to be processed.
+//
+// \param psCDCDevice is the device instance whose handshake line states are to
+// be changed.
+//
+// This function is called when the host requests that the device change the
+// state of one or other of the RTS or DTR handshake lines. If no data
+// received from the host remains to be processed, the request is passed to
+// the control callback. If data is outstanding, the call is ignored (with
+// the operation being retried on the next timer tick).
+//
+// \return Returns \b true if the notification was sent, \b false otherwise.
+//
+//*****************************************************************************
+static bool
+CheckAndSendLineStateChange(tUSBDCDCDevice *psCDCDevice)
+{
+ bool bCanSend;
+
+ //
+ // Has the client consumed all data received from the host yet?
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Can we send the break request?
+ //
+ if(bCanSend)
+ {
+ //
+ // Pass the request on to the client since no data remains to be
+ // consumed.
+ //
+ SendLineStateChange(psCDCDevice);
+ }
+
+ //
+ // Tell the caller whether or not we sent the notification.
+ //
+ return(bCanSend);
+}
+
+//*****************************************************************************
+//
+// Notifies the client of a change in the serial line state.
+//
+// \param psInst is the instance whose serial state is to be reported.
+//
+// This function is called to send the current serial state information to
+// the host via the the interrupt IN endpoint. This notification informs the
+// host of problems or conditions such as parity errors, breaks received,
+// framing errors, etc.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+SendSerialState(tUSBDCDCDevice *psCDCDevice)
+{
+ tUSBRequest sRequest;
+ uint16_t ui16SerialState;
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Remember that we are in the middle of sending a notification.
+ //
+ psInst->iCDCInterruptState = eCDCStateWaitData;
+
+ //
+ // Clear the flag we use to indicate that a send is required.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ false);
+ //
+ // Take a snapshot of the serial state.
+ //
+ ui16SerialState = psInst->ui16SerialState;
+
+ //
+ // Build the request we will use to send the notification.
+ //
+ sRequest.bmRequestType = (USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE);
+ sRequest.bRequest = USB_CDC_NOTIFY_SERIAL_STATE;
+ sRequest.wValue = 0;
+ sRequest.wIndex = 0;
+ sRequest.wLength = USB_CDC_NOTIFY_SERIAL_STATE_SIZE;
+
+ //
+ // Write the request structure to the USB FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ (uint8_t *)&sRequest,
+ sizeof(tUSBRequest));
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ (uint8_t *)&ui16SerialState,
+ USB_CDC_NOTIFY_SERIAL_STATE_SIZE);
+
+ //
+ // Did we correctly write the data to the endpoint FIFO?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // We put the data into the FIFO so now schedule it to be
+ // sent.
+ //
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // If an error occurred, mark the endpoint as idle (to prevent possible
+ // lockup) and return an error.
+ //
+ if(i32Retcode == -1)
+ {
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ return(false);
+ }
+ else
+ {
+ //
+ // Everything went fine. Clear the error bits that we just notified
+ // and return true.
+ //
+ psInst->ui16SerialState &= ~(ui16SerialState & USB_CDC_SERIAL_ERRORS);
+ return(true);
+ }
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the bulk OUT endpoint (in other words, whenever the
+// host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessDataFromHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tCDCSerInstance *psInst;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client doesn't read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be notified later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_PACKET_RX,
+ true);
+
+ //
+ // Is the receive channel currently blocked?
+ //
+ if(!psInst->bControlBlocked && !psInst->bRxBlocked)
+ {
+ //
+ // How big is the packet we have just been received?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData, USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to interrupt messages sent to the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the interrupt IN endpoint (in other words, whenever a notification has
+// been transmitted to the USB host).
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessNotificationToHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ //
+ // Assume all will go well until we have reason to believe otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8ControlEndpoint, ui32EPStatus);
+
+ //
+ // Did the state change while we were waiting for the previous notification
+ // to complete?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_SERIAL_STATE_CHANGE))
+ {
+ //
+ // The state changed while we were waiting so we need to schedule
+ // another notification immediately.
+ //
+ bRetcode = SendSerialState(psCDCDevice);
+ }
+ else
+ {
+ //
+ // Our last notification completed and we did not have any new
+ // notifications to make so the interrupt channel is now idle again.
+ //
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ }
+
+ //
+ // Tell the caller how things went.
+ //
+ return(bRetcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psCDCDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the bulk IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessDataToHost(tUSBDCDCDevice *psCDCDevice, uint32_t ui32Status)
+{
+ tCDCSerInstance *psInst;
+ uint32_t ui32EPStatus, ui32Size;
+ bool bSentFullPacket;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint, ui32EPStatus);
+
+ //
+ // Our last transmission completed. Clear our state back to idle and
+ // see if we need to send any more data.
+ //
+ psInst->iCDCTxState = eCDCStateIdle;
+
+ //
+ // If this notification is not as a result of sending a zero-length packet,
+ // call back to the client to let it know we sent the last thing it passed
+ // us.
+ //
+ if(psInst->ui16LastTxSize)
+ {
+ //
+ // Have we just sent a 64 byte packet?
+ //
+ bSentFullPacket = (psInst->ui16LastTxSize == DATA_IN_EP_MAX_SIZE) ?
+ true : false;
+
+ //
+ // Notify the client that the last transmission completed.
+ //
+ ui32Size = (uint32_t)psInst->ui16LastTxSize;
+ psInst->ui16LastTxSize = 0;
+ psCDCDevice->pfnTxCallback(psCDCDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
+ ui32Size, (void *)0);
+
+ //
+ // If we had previously sent a full packet and the callback didn't
+ // schedule a new transmission, send a zero length packet to indicate
+ // the end of the transfer.
+ //
+ if(bSentFullPacket && !psInst->ui16LastTxSize)
+ {
+ //
+ // We can expect another transmit complete notification after doing
+ // this.
+ //
+ psInst->iCDCTxState = eCDCStateWaitData;
+
+ //
+ // Send the zero-length packet.
+ //
+ MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvCDCDevice, uint32_t ui32Status)
+{
+ tUSBDCDCDevice *psCDCDeviceInst;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psCDCDeviceInst = pvCDCDevice;
+ psInst = &psCDCDeviceInst->sPrivateData;
+
+ //
+ // Handler for the interrupt IN notification endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8ControlEndpoint)))
+ {
+ //
+ // We have sent an interrupt notification to the host.
+ //
+ ProcessNotificationToHost(psCDCDeviceInst, ui32Status);
+ }
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8BulkOUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(psCDCDeviceInst, ui32Status);
+ }
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8BulkINEndpoint)))
+ {
+ ProcessDataToHost(psCDCDeviceInst, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvCDCDevice, uint32_t ui32Info)
+{
+ tCDCSerInstance *psInst;
+ tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iCDCInterruptState = eCDCStateIdle;
+ psInst->iCDCRequestState = eCDCStateIdle;
+ psInst->iCDCRxState = eCDCStateIdle;
+ psInst->iCDCTxState = eCDCStateIdle;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(!psInst->bConnected)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// USB data received callback.
+//
+// This function is called by the USB stack whenever any data requested from
+// EP0 is received.
+//
+//*****************************************************************************
+static void
+HandleEP0Data(void *pvCDCDevice, uint32_t ui32DataSize)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ui32DataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->iCDCRequestState != eCDCStateWaitData)
+ {
+ return;
+ }
+
+ //
+ // Process the data received. This will be a request-specific data
+ // block associated with the last request received.
+ //
+ switch (psInst->ui8PendingRequest)
+ {
+ //
+ // We just got the line coding structure. Make sure the client has
+ // read all outstanding data then pass it back to initiate a change
+ // in the line state.
+ //
+ case USB_CDC_SET_LINE_CODING:
+ {
+ if(ui32DataSize != sizeof(tLineCoding))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Set the flag telling us that we need to send a line coding
+ // notification to the client.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_LINE_CODING_CHANGE, true);
+
+ //
+ // See if we can send the notification immediately.
+ //
+ bRetcode = CheckAndSendLineCodingChange(psCDCDevice);
+
+ //
+ // If we could not send the line coding change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+ }
+ break;
+ }
+
+ //
+ // Oops - we seem to be waiting on a request which has not yet been
+ // coded here. Flag the error and stall EP0 anyway (even though
+ // this would indicate a coding error).
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ ASSERT(0);
+ break;
+ }
+ }
+
+ //
+ // All is well. Set the state back to IDLE.
+ //
+ psInst->iCDCRequestState = eCDCStateIdle;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvCDCDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tCDCSerInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDCDCDevice *psCDCDevice;
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the appropriate interface number.
+ //
+ if(pui8Data[0] == SERIAL_INTERFACE_CONTROL)
+ {
+ psInst->ui8InterfaceControl = pui8Data[1];
+ }
+ else if(pui8Data[0] == SERIAL_INTERFACE_DATA)
+ {
+ psInst->ui8InterfaceData = pui8Data[1];
+ }
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ //
+ // Determine which IN endpoint to modify.
+ //
+ if((pui8Data[0] & 0x7f) == USBEPToIndex(CONTROL_ENDPOINT))
+ {
+ psInst->ui8ControlEndpoint =
+ IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ psInst->ui8BulkINEndpoint =
+ IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8BulkOUTEndpoint =
+ IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+
+ //
+ // Handle class specific reconfiguring of the configuration descriptor
+ // once the composite class has built the full descriptor.
+ //
+ case USB_EVENT_COMP_CONFIG:
+ {
+ //
+ // This sets the bFirstInterface of the Interface Association
+ // descriptor to the first interface which is the control
+ // interface used by this instance.
+ //
+ pui8Data[2] = psInst->ui8InterfaceControl;
+
+ //
+ // This sets the bMasterInterface of the Union descriptor to the
+ // Control interface and the bSlaveInterface of the Union
+ // Descriptor to the Data interface used by this instance.
+ //
+ pui8Data[29] = psInst->ui8InterfaceControl;
+ pui8Data[30] = psInst->ui8InterfaceData;
+
+ //
+ // This sets the bDataInterface of the Union descriptor to the
+ // Data interface used by this instance.
+ pui8Data[35] = psInst->ui8InterfaceData;
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psCDCDevice->pfnControlCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// USB non-standard request callback.
+//
+// This function is called by the USB stack whenever any non-standard request
+// is made to the device. The handler should process any requests that it
+// supports or stall EP0 in any unsupported cases.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvCDCDevice, tUSBRequest *pUSBRequest)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ bool bRetcode;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Only handle requests meant for this interface.
+ //
+ if(pUSBRequest->wIndex != psInst->ui8InterfaceControl)
+ {
+ return;
+ }
+
+ //
+ // Handle each of the requests that we expect from the host.
+ //
+ switch(pUSBRequest->bRequest)
+ {
+ case USB_CDC_SEND_ENCAPSULATED_COMMAND:
+ {
+ //
+ // This implementation makes use of no communication protocol so
+ // this request is meaningless. We stall endpoint 0 if we receive
+ // it.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_GET_ENCAPSULATED_RESPONSE:
+ {
+ //
+ // This implementation makes use of no communication protocol so
+ // this request is meaningless. We stall endpoint 0 if we receive
+ // it.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_SET_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_GET_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ case USB_CDC_CLEAR_COMM_FEATURE:
+ {
+ //
+ // This request is apparently required by an ACM device but does
+ // not appear relevant to a virtual COM port and is never used by
+ // Windows (or, at least, is not seen when using Hyperterminal or
+ // TeraTerm via a Windows virtual COM port). We stall endpoint 0
+ // to indicate that we do not support the request.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ //
+ // Set the serial communication parameters.
+ //
+ case USB_CDC_SET_LINE_CODING:
+ {
+ //
+ // Remember the request we are processing.
+ //
+ psInst->ui8PendingRequest = USB_CDC_SET_LINE_CODING;
+
+ //
+ // Set the state to indicate we are waiting for data.
+ //
+ psInst->iCDCRequestState = eCDCStateWaitData;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, (uint8_t *)&psInst->sLineCoding,
+ sizeof(tLineCoding));
+
+ //
+ // ACK what we have already received. We must do this after
+ // requesting the data or we get into a race condition where the
+ // data may return before we have set the stack state appropriately
+ // to receive it.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ break;
+ }
+
+ //
+ // Return the serial communication parameters.
+ //
+ case USB_CDC_GET_LINE_CODING:
+ {
+ tLineCoding sLineCoding;
+
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Ask the client for the current line coding.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USBD_CDC_EVENT_GET_LINE_CODING, 0,
+ &sLineCoding);
+
+ //
+ // Send the line coding information back to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&sLineCoding, sizeof(tLineCoding));
+
+ break;
+ }
+
+ case USB_CDC_SET_CONTROL_LINE_STATE:
+ {
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Set the handshake lines as required.
+ //
+ psInst->ui16ControlLineState = pUSBRequest->wValue;
+
+ //
+ // Remember that we are due to notify the client of a line
+ // state change.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_LINE_STATE_CHANGE, true);
+
+ //
+ // See if we can notify now.
+ //
+ bRetcode = CheckAndSendLineStateChange(psCDCDevice);
+
+ //
+ // If we could not send the line state change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+
+ break;
+ }
+
+ case USB_CDC_SEND_BREAK:
+ {
+ //
+ // ACK what we have already received
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+
+ //
+ // Keep a copy of the requested break duration.
+ //
+ psInst->ui16BreakDuration = pUSBRequest->wValue;
+
+ //
+ // Remember that we need to send a break request.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_SEND_BREAK, true);
+
+ //
+ // Send the break request if all outstanding receive data has been
+ // processed.
+ //
+ bRetcode = CheckAndSendBreak(psCDCDevice, pUSBRequest->wValue);
+
+ //
+ // If we could not send the line coding change request to the
+ // client, block reception of more data from the host until
+ // previous data is processed and we send the change request.
+ //
+ if(!bRetcode)
+ {
+ psInst->bRxBlocked = true;
+ }
+
+ break;
+ }
+
+ //
+ // These are valid CDC requests but not ones that an ACM device should
+ // receive.
+ //
+ case USB_CDC_SET_AUX_LINE_STATE:
+ case USB_CDC_SET_HOOK_STATE:
+ case USB_CDC_PULSE_SETUP:
+ case USB_CDC_SEND_PULSE:
+ case USB_CDC_SET_PULSE_TIME:
+ case USB_CDC_RING_AUX_JACK:
+ case USB_CDC_SET_RINGER_PARMS:
+ case USB_CDC_GET_RINGER_PARMS:
+ case USB_CDC_SET_OPERATION_PARMS:
+ case USB_CDC_GET_OPERATION_PARMS:
+ case USB_CDC_SET_LINE_PARMS:
+ case USB_CDC_GET_LINE_PARMS:
+ case USB_CDC_DIAL_DIGITS:
+ case USB_CDC_SET_UNIT_PARAMETER:
+ case USB_CDC_GET_UNIT_PARAMETER:
+ case USB_CDC_CLEAR_UNIT_PARAMETER:
+ case USB_CDC_GET_PROFILE:
+ case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
+ case USB_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
+ case USB_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
+ case USB_CDC_SET_ETHERNET_PACKET_FILTER:
+ case USB_CDC_GET_ETHERNET_STATISTIC:
+ case USB_CDC_SET_ATM_DATA_FORMAT:
+ case USB_CDC_GET_ATM_DEVICE_STATISTICS:
+ case USB_CDC_SET_ATM_DEFAULT_VC:
+ case USB_CDC_GET_ATM_VC_STATISTICS:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ default:
+ {
+ //
+ // This request is not part of the CDC specification.
+ //
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvCDCDevice)
+{
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // If we are not currently connected and we have a control callback,
+ // let the client know we are open for business.
+ //
+ if(psInst->bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psInst->bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvCDCDevice)
+{
+ const tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (const tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_SUSPEND, 0, (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvCDCDevice)
+{
+ tUSBDCDCDevice *psCDCDevice;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Pass the event on to the client.
+ //
+ psCDCDevice->pfnControlCallback(psCDCDevice->pvControlCBData,
+ USB_EVENT_RESUME, 0, (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param ui32Index is the index of the USB controller for which this tick
+// is being generated.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+CDCTickHandler(void *pvCDCDevice, uint32_t ui32TimemS)
+{
+ bool bCanSend;
+ tUSBDCDCDevice *psCDCDevice;
+ tCDCSerInstance *psInst;
+ uint32_t ui32Size;
+
+ ASSERT(pvCDCDevice != 0);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psCDCDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Is there any outstanding operation that we should try to perform?
+ //
+ if(psInst->ui16DeferredOpFlags)
+ {
+ //
+ // Yes - we have at least one deferred operation pending. First check
+ // to see if it is time to turn off a break condition.
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_CLEAR_BREAK))
+ {
+ //
+ // Will our break timer expire this time?
+ //
+ if(psInst->ui16BreakDuration <= ui32TimemS)
+ {
+ //
+ // Yes - turn off the break condition.
+ //
+ SendBreak(psCDCDevice, false);
+ }
+ else
+ {
+ //
+ // We have not timed out yet. Decrement the break timer.
+ //
+ psInst->ui16BreakDuration -= (uint16_t)ui32TimemS;
+ }
+ }
+
+ // Now check to see if the client has any data remaining to be
+ // processed. This information is needed by the remaining deferred
+ // operations which are waiting for the receive pipe to be emptied
+ // before they can be carried out.
+ //
+ bCanSend = DeviceConsumedAllData(psCDCDevice);
+
+ //
+ // Has all outstanding data been consumed?
+ //
+ if(bCanSend)
+ {
+ //
+ // Yes - go ahead and notify the client of the various things
+ // it has been asked to do while we waited for data to be
+ // consumed.
+ //
+
+ //
+ // Do we need to start sending a break condition?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_SEND_BREAK))
+ {
+ SendBreak(psCDCDevice, true);
+ }
+
+ //
+ // Do we need to set the RTS/DTR states?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_LINE_STATE_CHANGE))
+ {
+ SendLineStateChange(psCDCDevice);
+ }
+
+ //
+ // Do we need to change the line coding parameters?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_LINE_CODING_CHANGE))
+ {
+ SendLineCodingChange(psCDCDevice);
+ }
+
+ //
+ // NOTE: We do not need to handle CDC_DO_SERIAL_STATE_CHANGE here
+ // since this is handled in the transmission complete notification
+ // for the control IN endpoint (ProcessNotificationToHost()).
+ //
+
+ //
+ // If all the deferred operations which caused the receive channel
+ // to be blocked are now handled, we can unblock receive and handle
+ // any packet that is currently waiting to be received.
+ //
+ if(!(psInst->ui16DeferredOpFlags & RX_BLOCK_OPS))
+ {
+ //
+ // We can remove the receive block.
+ //
+ psInst->bRxBlocked = false;
+ }
+ }
+
+ //
+ // Is the receive channel unblocked?
+ //
+ if(!psInst->bRxBlocked)
+ {
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << CDC_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ // Tell the client that there is a packet waiting for it.
+ //
+ psCDCDevice->pfnRxCallback(psCDCDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ }
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes CDC device operation when used with a composite device.
+//!
+//! \param ui32Index is the index of the USB controller in use.
+//! \param psCDCDevice points to a structure containing parameters customizing
+//! the operation of the CDC device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDCDCInit() except that it is used for
+//! initializing an instance of the serial device for use in a composite
+//! device. When this CDC serial device is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB CDC APIs.
+//
+//*****************************************************************************
+void *
+USBDCDCCompositeInit(uint32_t ui32Index, tUSBDCDCDevice *psCDCDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tCDCSerInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psCDCDevice);
+ ASSERT(psCDCDevice->pfnControlCallback);
+ ASSERT(psCDCDevice->pfnRxCallback);
+ ASSERT(psCDCDevice->pfnTxCallback);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psCDCDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sCDCHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CDCSerDeviceDescriptor;
+
+ //
+ // The CDC serial configuration is different for composite devices and
+ // stand alone devices.
+ //
+ if(psCompEntry == 0)
+ {
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppCDCSerConfigDescriptors;
+ }
+ else
+ {
+ psInst->sDevInfo.ppsConfigDescriptors = g_pCDCCompSerConfigDescriptors;
+ }
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Set the default endpoint and interface assignments.
+ //
+ psInst->ui8BulkINEndpoint = DATA_IN_ENDPOINT;
+ psInst->ui8BulkOUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8InterfaceControl = SERIAL_INTERFACE_CONTROL;
+ psInst->ui8InterfaceData = SERIAL_INTERFACE_DATA;
+
+ //
+ // By default do not use the interrupt control endpoint. The single
+ // instance CDC serial device will turn this on in USBDCDCInit();
+ //
+ psInst->ui8ControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iCDCRxState = eCDCStateUnconfigured;
+ psInst->iCDCTxState = eCDCStateUnconfigured;
+ psInst->iCDCInterruptState = eCDCStateUnconfigured;
+ psInst->iCDCRequestState = eCDCStateUnconfigured;
+ psInst->ui8PendingRequest = 0;
+ psInst->ui16BreakDuration = 0;
+ psInst->ui16SerialState = 0;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->ui16ControlLineState = 0;
+ psInst->bRxBlocked = false;
+ psInst->bControlBlocked = false;
+ psInst->bConnected = false;
+
+ //
+ // Initialize the device info structure for the serial device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psCDCDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psCDCDevice->ui32NumStringDescriptors;
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(CDCTickHandler, (void *)psCDCDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psCDCDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes CDC device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for CDC device operation.
+//! \param psCDCDevice points to a structure containing parameters customizing
+//! the operation of the CDC device.
+//!
+//! An application wishing to make use of a USB CDC communication channel and
+//! appear as a virtual serial port on the host system must call this function
+//! to initialize the USB controller and attach the device to the USB bus.
+//! This function performs all required USB initialization.
+//!
+//! The value returned by this function is the \e psCDCDevice pointer passed
+//! to it if successful. This pointer must be passed to all later calls to the
+//! CDC class driver to identify the device instance.
+//!
+//! The USB CDC device class driver offers packet-based transmit and receive
+//! operation. If the application would rather use block based communication
+//! with transmit and receive buffers, USB buffers on the transmit and receive
+//! channels may be used to offer this functionality.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDCDCPacketWrite() must send no more than 64 bytes of data at a
+//! time and may only be made when no other transmission is currently
+//! outstanding.
+//!
+//! Once a packet of data has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to
+//! inform it that another packet may be transmitted.
+//!
+//! Receive Operation:
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USB_EVENT_RX_AVAILABLE. The application must then
+//! call USBDCDCPacketRead(), passing a buffer capable of holding the received
+//! packet to retrieve the data and acknowledge reception to the USB host. The
+//! size of the received packet may be queried by calling
+//! USBDCDCRxPacketAvailable().
+//!
+//! \note The application must not make any calls to the low level USB Device
+//! API if interacting with USB via the CDC device class API. Doing so
+//! will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the psCDCDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDCDCInit(uint32_t ui32Index, tUSBDCDCDevice *psCDCDevice)
+{
+ void *pvRet;
+ tCDCSerInstance *psInst;
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Initialize the internal state for this class.
+ //
+ pvRet = USBDCDCCompositeInit(ui32Index, psCDCDevice, 0);
+
+ if(pvRet)
+ {
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8CDCSerDeviceDescriptor;
+ psDevDesc->idVendor = psCDCDevice->ui16VID;
+ psDevDesc->idProduct = psCDCDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psConfigDesc = (tConfigDescriptor *)g_pui8CDCSerDescriptor;
+ psConfigDesc->bmAttributes = psCDCDevice->ui8PwrAttributes;
+ psConfigDesc->bMaxPower = (uint8_t)(psCDCDevice->ui16MaxPowermA / 2);
+
+ //
+ // Create an instance pointer to the private data area.
+ //
+ psInst = &psCDCDevice->sPrivateData;
+
+ //
+ // Enable the default interrupt control endpoint if this class is not
+ // being used in a composite device.
+ //
+ psInst->ui8ControlEndpoint = CONTROL_ENDPOINT;
+
+ //
+ // Use the configuration descriptor with the interrupt control
+ // endpoint.
+ //
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppCDCSerConfigDescriptors;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the CDC device on the bus.
+ //
+ USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psCDCDevice);
+ }
+
+ return(pvRet);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the CDC device instance.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function terminates CDC operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the CDC device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvCDCDevice instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCTerm(void *pvCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer for the control callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the control channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnControlCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback pointer changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's control callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetControlCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback pointer for the control channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvControlCBData;
+ psBulkDevice->pvControlCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the receive channel callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetRxCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvRxCBData;
+ psBulkDevice->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data parameter for the transmit callback.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDCDCInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the psCDCDevice structure passed to USBDCDCInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDCDCSetTxCBData(void *pvCDCDevice, void *pvCBData)
+{
+ tUSBDCDCDevice *psBulkDevice;
+ void *pvOldValue;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // The CDC device structure pointer.
+ //
+ psBulkDevice = (tUSBDCDCDevice *)pvCDCDevice;
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = psBulkDevice->pvTxCBData;
+ psBulkDevice->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback pointer.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a packet of data to the USB host via the CDC data interface.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast indicates whether more data is to be written before a packet
+//! should be scheduled for transmission. If \b true, the client will make
+//! a further call to this function. If \b false, no further call will be
+//! made and the driver should schedule transmission of a short packet.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB packet. If no transmission is currently ongoing
+//! the data is immediately copied to the relevant USB endpoint FIFO. If the
+//! \e bLast parameter is \b true, the newly written packet is then scheduled
+//! for transmission. Whenever a USB packet is acknowledged by the host, a
+//! \b USB_EVENT_TX_COMPLETE event will be sent to the application transmit
+//! callback indicating that more data can now be transmitted.
+//!
+//! The maximum value for \e ui32Length is 64 bytes (the maximum USB packet
+//! size for the bulk endpoints in use by CDC). Attempts to send more data
+//! than this will result in a return code of 0 indicating that the data cannot
+//! be sent.
+//!
+//! \return Returns the number of bytes actually sent. At this level, this
+//! will either be the number of bytes passed (if less than or equal to the
+//! maximum packet size for the USB endpoint in use and no outstanding
+//! transmission ongoing) or 0 to indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCPacketWrite(void *pvCDCDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Can we send the data provided?
+ //
+ if((ui32Length > DATA_IN_EP_MAX_SIZE) ||
+ (psInst->iCDCTxState != eCDCStateIdle))
+ {
+ //
+ // Either the packet was too big or we are in the middle of sending
+ // another packet. Return 0 to indicate that we can't send this data.
+ //
+ return(0);
+ }
+
+ //
+ // Copy the data into the USB endpoint FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint, pi8Data,
+ ui32Length);
+
+ //
+ // Did we copy the data successfully?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // Remember how many bytes we sent.
+ //
+ psInst->ui16LastTxSize += (uint16_t)ui32Length;
+
+ //
+ // If this is the last call for this packet, schedule transmission.
+ //
+ if(bLast)
+ {
+ //
+ // Send the packet to the host if we have received all the data we
+ // can expect for this packet.
+ //
+ psInst->iCDCTxState = eCDCStateWaitData;
+ i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase,
+ psInst->ui8BulkINEndpoint,
+ USB_TRANS_IN);
+ }
+ }
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the CDC data
+//! interface.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by \e pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to ui32Length bytes of data received from the USB
+//! host into the supplied application buffer.
+//!
+//! \note The \e bLast parameter is ignored in this implementation since the
+//! end of a packet can be determined without relying upon the client to
+//! provide this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCPacketRead(void *pvCDCDevice, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tCDCSerInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // If receive is currently blocked or the buffer we were passed is
+ // (potentially) too small, set the flag telling us that we have a
+ // packet waiting but return 0.
+ //
+ if(psInst->bRxBlocked || psInst->bControlBlocked)
+ {
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_PACKET_RX,
+ true);
+ return(0);
+ }
+ else
+ {
+ //
+ // It is OK to receive the new packet. How many bytes are
+ // available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint,
+ true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ CDC_DO_PACKET_RX, false);
+
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function returns the maximum number of bytes that can be passed on a
+//! call to USBDCDCPacketWrite() and accepted for transmission. The value
+//! returned will be the maximum USB packet size if no transmission is
+//! currently outstanding or 0 if a transmission is in progress.
+//!
+//! \return Returns the number of bytes available in the transmit buffer.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCTxPacketAvailable(void *pvCDCDevice)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iCDCTxState != eCDCStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(DATA_IN_EP_MAX_SIZE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDCDCRxPacketAvailable(void *pvCDCDevice)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // If receive is currently blocked, return 0.
+ //
+ if(psInst->bRxBlocked || psInst->bControlBlocked)
+ {
+ return(0);
+ }
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8BulkOUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Informs the CDC module of changes in the serial control line states or
+//! receive error conditions.
+//!
+//! \param pvCDCDevice is the pointer to the device instance structure as
+//! returned by USBDCDCInit().
+//! \param ui16State indicates the states of the various control lines and
+//! any receive errors detected. Bit definitions are as for the USB CDC
+//! SerialState asynchronous notification and are defined in header file
+//! usbcdc.h.
+//!
+//! The application should call this function whenever the state of any of
+//! the incoming RS232 handshake signals changes or in response to a receive
+//! error or break condition. The \e ui16State parameter is the ORed
+//! combination of the following flags with each flag indicating the presence
+//! of that condition.
+//!
+//! - USB_CDC_SERIAL_STATE_OVERRUN
+//! - USB_CDC_SERIAL_STATE_PARITY
+//! - USB_CDC_SERIAL_STATE_FRAMING
+//! - USB_CDC_SERIAL_STATE_RING_SIGNAL
+//! - USB_CDC_SERIAL_STATE_BREAK
+//! - USB_CDC_SERIAL_STATE_TXCARRIER
+//! - USB_CDC_SERIAL_STATE_RXCARRIER
+//!
+//! This function should be called only when the state of any flag changes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCSerialStateChange(void *pvCDCDevice, uint16_t ui16State)
+{
+ tCDCSerInstance *psInst;
+
+ ASSERT(pvCDCDevice);
+
+ //
+ // Get a pointer to the CDC device instance data pointer
+ //
+ psInst = &((tUSBDCDCDevice *)pvCDCDevice)->sPrivateData;
+
+ //
+ // Add the newly reported state bits to the current collection. We do this
+ // in case two state changes occur back-to-back before the first has been
+ // notified. There are two distinct types of signals that we report here
+ // and we deal with them differently:
+ //
+ // 1. Errors (overrun, parity, framing error) are ORed together so that
+ // any reported error is sent on the next notification.
+ // 2. Signal line states (RI, break, TX carrier, RX carrier) always
+ // report the last state notified to us. The implementation here will
+ // send an interrupt showing the last state but, if two state changes
+ // occur very quickly, the host may receive a notification containing
+ // the same state that was last reported (in other words, a short pulse
+ // will be lost). It would be possible to reduce the likelihood of
+ // this happening by building a queue of state changes and sending
+ // these in order but you are left with exactly the same problem if the
+ // queue fills up. For now, therefore, we run the risk of missing very
+ // short pulses on the "steady-state" signal lines.
+ //
+ psInst->ui16SerialState |= (ui16State & USB_CDC_SERIAL_ERRORS);
+ psInst->ui16SerialState &= ~USB_CDC_SERIAL_ERRORS;
+ psInst->ui16SerialState |= (ui16State & ~USB_CDC_SERIAL_ERRORS);
+
+ //
+ // Set the flag indicating that a serial state change is to be sent.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, CDC_DO_SERIAL_STATE_CHANGE,
+ true);
+
+ //
+ // Can we send the state change immediately?
+ //
+ if(psInst->iCDCInterruptState == eCDCStateIdle)
+ {
+ //
+ // The interrupt channel is free so send the notification immediately.
+ // If we can't do this, the tick timer will catch this next time
+ // round.
+ //
+ psInst->iCDCInterruptState = eCDCStateWaitData;
+ SendSerialState(pvCDCDevice);
+ }
+
+ return;
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvCDCDevice is the pointer to the CDC device instance structure.
+//! \param ui8Power indicates the current power status, either \b
+//! USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus- or self-powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDCPowerStatusSet(void *pvCDCDevice, uint8_t ui8Power)
+{
+ ASSERT(pvCDCDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wakeup to resume communication when in suspended state.
+//!
+//! \param pvCDCDevice is the pointer to the CDC device instance structure.
+//!
+//! When the bus is suspended, an application which supports remote wakeup
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wakeup signaling to the host. If the remote
+//! wakeup feature has not been disabled by the host, this will cause the bus
+//! to resume operation within 20mS. If the host has disabled remote wakeup,
+//! \b false will be returned to indicate that the wakeup request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wakeup is not disabled and the
+//! signaling was started or \b false if remote wakeup is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDCDCRemoteWakeupRequest(void *pvCDCDevice)
+{
+ ASSERT(pvCDCDevice);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdcdc.h b/usblib/device/usbdcdc.h
new file mode 100644
index 0000000..dc96086
--- /dev/null
+++ b/usblib/device/usbdcdc.h
@@ -0,0 +1,447 @@
+//*****************************************************************************
+//
+// usbdcdc.h - USBLib support for generic CDC ACM (serial) device.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDCDC_H__
+#define __USBDCDC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cdc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB CDC Serial code and are here only to help with the application
+// allocating the correct amount of memory for the CDC Serial device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eCDCStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eCDCStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eCDCStateWaitData,
+
+ //
+ // Waiting for client to process data.
+ //
+ eCDCStateWaitClient
+}
+tCDCState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// CDC Serial device. The memory for this structure is allocated in the
+// tUSBDCDCDevice structure passed on USBDCDCInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the serial receive state.
+ //
+ volatile tCDCState iCDCRxState;
+
+ //
+ // The state of the serial transmit state.
+ //
+ volatile tCDCState iCDCTxState;
+
+ //
+ // The state of the serial request state.
+ //
+ volatile tCDCState iCDCRequestState;
+
+ //
+ // The state of the serial interrupt state.
+ //
+ volatile tCDCState iCDCInterruptState;
+
+ //
+ // The current pending request.
+ //
+ volatile uint8_t ui8PendingRequest;
+
+ //
+ // The current break duration used during send break requests.
+ //
+ uint16_t ui16BreakDuration;
+
+ //
+ // The current line control state for the serial port.
+ //
+ uint16_t ui16ControlLineState;
+
+ //
+ // The general serial state.
+ //
+ uint16_t ui16SerialState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the last transmit.
+ //
+ uint16_t ui16LastTxSize;
+
+ //
+ // The current serial line coding.
+ //
+ tLineCoding sLineCoding;
+
+ //
+ // Serial port receive is blocked.
+ //
+ volatile bool bRxBlocked;
+
+ //
+ // Serial control port is blocked.
+ //
+ volatile bool bControlBlocked;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // The control endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8ControlEndpoint;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8BulkINEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8BulkOUTEndpoint;
+
+ //
+ // The interface number for the control interface, this is modified in
+ // composite devices.
+ //
+ uint8_t ui8InterfaceControl;
+
+ //
+ // The interface number for the data interface, this is modified in
+ // composite devices.
+ //
+ uint8_t ui8InterfaceData;
+}
+tCDCSerInstance;
+
+//*****************************************************************************
+//
+// The following defines are used when working with composite devices.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8IADSerDescriptor array in bytes.
+//
+//*****************************************************************************
+#define SERDESCRIPTOR_SIZE (8)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8CDCSerCommInterface array in bytes.
+//
+//*****************************************************************************
+#define SERCOMMINTERFACE_SIZE (35)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8CDCSerDataInterface array in bytes.
+//
+//*****************************************************************************
+#define SERDATAINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Serial CDC Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DCDC_SIZE (SERDESCRIPTOR_SIZE + SERCOMMINTERFACE_SIZE + \
+ SERDATAINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+// CDC-specific events These events are provided to the application in the
+// \e ui32Msg parameter of the tUSBCallback function.
+//
+//*****************************************************************************
+
+//
+//! The host requests that the device send a BREAK condition on its
+//! serial communication channel. The BREAK should remain active until
+//! a USBD_CDC_EVENT_CLEAR_BREAK event is received.
+//
+#define USBD_CDC_EVENT_SEND_BREAK (USBD_CDC_EVENT_BASE + 0)
+
+//
+//! The host requests that the device stop sending a BREAK condition on its
+//! serial communication channel.
+//
+#define USBD_CDC_EVENT_CLEAR_BREAK (USBD_CDC_EVENT_BASE + 1)
+
+//
+//! The host requests that the device set the RS232 signaling lines to
+//! a particular state. The ui32MsgValue parameter contains the RTS and
+//! DTR control line states as defined in table 51 of the USB CDC class
+//! definition and is a combination of the following values:
+//!
+//! (RTS) USB_CDC_DEACTIVATE_CARRIER or USB_CDC_ACTIVATE_CARRIER
+//! (DTR) USB_CDC_DTE_NOT_PRESENT or USB_CDC_DTE_PRESENT
+//
+#define USBD_CDC_EVENT_SET_CONTROL_LINE_STATE (USBD_CDC_EVENT_BASE + 2)
+
+//
+//! The host requests that the device set the RS232 communication
+//! parameters. The pvMsgData parameter points to a tLineCoding structure
+//! defining the required number of bits per character, parity mode,
+//! number of stop bits and the baud rate.
+//
+#define USBD_CDC_EVENT_SET_LINE_CODING (USBD_CDC_EVENT_BASE + 3)
+
+//
+//! The host is querying the current RS232 communication parameters. The
+//! pvMsgData parameter points to a tLineCoding structure that the
+//! application must fill with the current settings prior to returning
+//! from the callback.
+//
+#define USBD_CDC_EVENT_GET_LINE_CODING (USBD_CDC_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the CDC device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of all asynchronous control events related to the
+ //! operation of the device.
+ //
+ const tUSBCallback pfnControlCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the control channel callback,
+ //! pfnControlCallback.
+ //
+ void *pvControlCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data receive channel.
+ //
+ const tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events related to the device's data transmit
+ //! channel.
+ //
+ const tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),
+ //! Control interface description string (language 1), Configuration
+ //! description string (language 1).
+ //!
+ //! If supporting more than 1 language, the strings for indices 1 through 5
+ //! must be repeated for each of the other languages defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + (5 * number of supported languages).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory
+ //! must remain accessible for as long as the CDC device is in use and
+ //! must not be modified by any code outside the CDC class driver.
+ //
+ tCDCSerInstance sPrivateData;
+}
+tUSBDCDCDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDCDCCompositeInit(uint32_t ui32Index,
+ tUSBDCDCDevice *psCDCDevice,
+ tCompositeEntry *psCompEntry);
+extern void *USBDCDCInit(uint32_t ui32Index,
+ tUSBDCDCDevice *psCDCDevice);
+extern void USBDCDCTerm(void *pvCDCDevice);
+extern void *USBDCDCSetControlCBData(void *pvCDCDevice, void *pvCBData);
+extern void *USBDCDCSetRxCBData(void *pvCDCDevice, void *pvCBData);
+extern void *USBDCDCSetTxCBData(void *pvCDCDevice, void *pvCBData);
+extern uint32_t USBDCDCPacketWrite(void *pvCDCDevice, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDCDCPacketRead(void *pvCDCDevice, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDCDCTxPacketAvailable(void *pvCDCDevice);
+extern uint32_t USBDCDCRxPacketAvailable(void *pvCDCDevice);
+extern void USBDCDCSerialStateChange(void *pvCDCDevice, uint16_t ui16State);
+extern bool USBDCDCRemoteWakeupRequest(void *pvCDCDevice);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDCDCPowerStatusSet(void *pvCDCDevice, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDCDC_H__
diff --git a/usblib/device/usbdcdesc.c b/usblib/device/usbdcdesc.c
new file mode 100644
index 0000000..6260d42
--- /dev/null
+++ b/usblib/device/usbdcdesc.c
@@ -0,0 +1,643 @@
+//*****************************************************************************
+//
+// usbcdesc.c - Config descriptor parsing functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+
+//*****************************************************************************
+//
+// The functions in this file mirror the descriptor parsing APIs available
+// in usblib.h but parse configuration descriptors defined in terms of a list
+// of sections rather than as a single block of descriptor data.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Walk to the next descriptor after the supplied one within a section-based
+//! config descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor which contains \e pi16Desc.
+//! \param pui32Sec points to a variable containing the section within
+//! \e psConfig which contains \e pi16Desc.
+//! \param pi16Desc points to the descriptor that we want to step past.
+//!
+//! This function walks forward one descriptor within a configuration
+//! descriptor. The value returned is a pointer to the header of the next
+//! descriptor after the descriptor supplied in \e pi16Desc. If the next
+//! descriptor is in the next section, \e *pui32Sec will be incremented
+//! accordingly.
+//!
+//! \return Returns a pointer to the next descriptor in the configuration
+//! descriptor.
+//
+//*****************************************************************************
+static tDescriptorHeader *
+NextConfigDescGet(const tConfigHeader *psConfig, uint32_t *pui32Sec,
+ tDescriptorHeader *psDesc)
+{
+ //
+ // Determine where the next descriptor after the supplied one should be
+ // assuming it is within the current section.
+ //
+ psDesc = NEXT_USB_DESCRIPTOR(psDesc);
+
+ //
+ // Did we run off the end of the section?
+ //
+ if((uint8_t *)psDesc >= (psConfig->psSections[*pui32Sec]->pui8Data +
+ psConfig->psSections[*pui32Sec]->ui16Size))
+ {
+ //
+ // Yes - move to the next section.
+ //
+ (*pui32Sec)++;
+
+ //
+ // Are we still within the configuration descriptor?
+ //
+ if(*pui32Sec < psConfig->ui8NumSections)
+ {
+ //
+ // Yes - the new descriptor is at the start of the new section.
+ //
+ psDesc =
+ (tDescriptorHeader *)psConfig->psSections[*pui32Sec]->pui8Data;
+ }
+ else
+ {
+ //
+ // No - we ran off the end of the descriptor so return NULL.
+ //
+ psDesc = (tDescriptorHeader *)0;
+ }
+ }
+
+ //
+ // Return the new descriptor pointer.
+ //
+ return(psDesc);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Returns a pointer to the n-th interface descriptor in a configuration
+//! descriptor with the supplied interface number.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor to search.
+//! \param ui8InterfaceNumber is the interface number of the descriptor to
+//! query.
+//! \param ui32Index is the zero based index of the descriptor.
+//! \param pui32Section points to storage which is written with the index
+//! of the section containing the returned descriptor.
+//!
+//! This function returns a pointer to the n-th interface descriptor in the
+//! supplied configuration which has the requested interface number. It may be
+//! used by a client to retrieve the descriptors for each alternate setting
+//! of a given interface within the configuration passed.
+//!
+//! \return Returns a pointer to the n-th interface descriptor with interface
+//! number as specified or NULL of this descriptor does not exist.
+//
+//*****************************************************************************
+static tInterfaceDescriptor *
+ConfigAlternateInterfaceGet(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber, uint32_t ui32Index,
+ uint32_t *pui32Section)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32Count, ui32Sec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data;
+ ui32Count = 0;
+ ui32Sec = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(psDescCheck)
+ {
+ //
+ // Does this descriptor match the type passed (if a specific type
+ // has been specified)?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // This is an interface descriptor for interface
+ // ui8InterfaceNumber. Determine if this is the n-th one we have
+ // found and, if so, return its pointer.
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Found it - return the pointer and section number.
+ //
+ *pui32Section = ui32Sec;
+ return((tInterfaceDescriptor *)psDescCheck);
+ }
+
+ //
+ // Increment our count of matching descriptors found and go back
+ // to look for another since we have not yet reached the n-th
+ // match.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck);
+ }
+
+ //
+ // If we drop out the end of the loop, we did not find the requested
+ // descriptor so return NULL.
+ //
+ return((tInterfaceDescriptor *)0);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the total length of a configuration descriptor defined in terms
+//! of a collection of concatenated sections.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor whose size is to be determined.
+//!
+//! \return Returns the number of bytes in the configuration descriptor will
+//! result from concatenating the required sections.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigDescGetSize(const tConfigHeader *psConfig)
+{
+ uint32_t ui32Loop, ui32Len;
+
+ ui32Len = 0;
+
+ //
+ // Determine the size of the whole descriptor by adding the sizes of
+ // each section which will be concatenated to produce it.
+ //
+ for(ui32Loop = 0; ui32Loop < psConfig->ui8NumSections; ui32Loop++)
+ {
+ ui32Len += psConfig->psSections[ui32Loop]->ui16Size;
+ }
+
+ return(ui32Len);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the number of individual descriptors of a particular type within
+//! a supplied configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Type identifies the type of descriptor that is to be counted.
+//! If the value is \b USB_DESC_ANY, the function returns the total number of
+//! descriptors regardless of type.
+//!
+//! This function can be used to count the number of descriptors of a
+//! particular type within a configuration descriptor. The caller can provide
+//! a specific type value which the function matches against the second byte
+//! of each descriptor or, alternatively, can specify \b USB_DESC_ANY to have
+//! the function count all descriptors regardless of their type.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetNum(), searches through a single, contiguous
+//! block of data to perform the same enumeration.
+//!
+//! \return Returns the number of descriptors found in the supplied block of
+//! data.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigDescGetNum(const tConfigHeader *psConfig, uint32_t ui32Type)
+{
+ uint32_t ui32Section, ui32NumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ui32NumDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the configuration descriptor. Note that this
+ // assumes each section contains only whole descriptors!
+ //
+ for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections;
+ ui32Section++)
+ {
+ ui32NumDescs += USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size, ui32Type);
+ }
+
+ return(ui32NumDescs);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Finds the n-th descriptor of a particular type within the supplied
+//! configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Type identifies the type of descriptor that is to be found. If
+//! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th
+//! descriptor regardless of type.
+//! \param ui32Index is the zero based index of the descriptor whose pointer is
+//! to be returned. For example, passing value 1 in \e ui32Index returns the
+//! second matching descriptor.
+//! \param pui32Section points to storage which will receive the section index
+//! containing the requested descriptor.
+//!
+//! Return a pointer to the n-th descriptor of a particular type found in the
+//! configuration descriptor passed.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGet(), searches through a single, contiguous
+//! block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the header of the required descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tDescriptorHeader *
+USBDCDConfigDescGet(const tConfigHeader *psConfig, uint32_t ui32Type,
+ uint32_t ui32Index, uint32_t *pui32Section)
+{
+ uint32_t ui32Section, ui32TotalDescs, ui32NumDescs;
+
+ //
+ // Initialize our counts.
+ //
+ ui32TotalDescs = 0;
+
+ //
+ // Determine the number of descriptors of the given type in each of the
+ // sections comprising the configuration descriptor. This allows us to
+ // determine which section contains the descriptor we are being asked for.
+ //
+ for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections;
+ ui32Section++)
+ {
+ //
+ // How many descriptors of the requested type exist in this section?
+ //
+ ui32NumDescs = USBDescGetNum(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size, ui32Type);
+
+ //
+ // Does this section contain the descriptor whose index we are looking
+ // for?
+ //
+ if((ui32TotalDescs + ui32NumDescs) > ui32Index)
+ {
+ //
+ // We know the requested descriptor exists in the current
+ // block so write the section number to the caller's storage.
+ //
+ *pui32Section = ui32Section;
+
+ //
+ // Now find the actual descriptor requested and return its pointer.
+ //
+ return(USBDescGet(
+ (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data,
+ psConfig->psSections[ui32Section]->ui16Size,
+ ui32Type, ui32Index - ui32TotalDescs));
+ }
+
+ //
+ // We have not found the required descriptor yet. Update our running
+ // count of the number of type matches found so far then move on to
+ // the next section.
+ //
+ ui32TotalDescs += ui32NumDescs;
+ }
+
+ //
+ // If we drop out of the loop, we can't find the requested descriptor
+ // so return NULL.
+ //
+ return((tDescriptorHeader *)0);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Determines the number of different alternate configurations for a given
+//! interface within a configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui8InterfaceNumber is the interface number for which the number of
+//! alternate configurations is to be counted.
+//!
+//! This function can be used to count the number of alternate settings for a
+//! specific interface within a configuration.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetNumAlternateInterfaces(), searches through
+//! a single, contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns the number of alternate versions of the specified interface
+//! or 0 if the interface number supplied cannot be found in the configuration
+//! descriptor.
+//
+//*****************************************************************************
+uint32_t
+USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32Count, ui32Sec;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data;
+ ui32Sec = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(psDescCheck)
+ {
+ //
+ // Is this an interface descriptor with the required interface number?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // Yes - increment our count.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck);
+ }
+
+ //
+ // Return the descriptor count to the caller.
+ //
+ return(ui32Count);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Returns a pointer to the n-th interface descriptor in a configuration
+//! descriptor that applies to the supplied alternate setting number.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32Index is the zero based index of the interface that is to be
+//! found. If \e ui32Alt is set to a value other than \b USB_DESC_ANY, this
+//! is equivalent to the interface number being searched for.
+//! \param ui32Alt is the alternate setting number which is to be
+//! searched for. If this value is \b USB_DESC_ANY, the alternate setting
+//! is ignored and all interface descriptors are considered in the search.
+//! \param pui32Section points to storage which will receive the index of the
+//! config descriptor section which contains the requested interface
+//! descriptor.
+//!
+//! Return a pointer to the n-th interface descriptor found in the supplied
+//! configuration descriptor. If \e ui32Alt is not \b USB_DESC_ANY, only
+//! interface descriptors which are part of the supplied alternate setting are
+//! considered in the search otherwise all interface descriptors are
+//! considered.
+//!
+//! Note that, although alternate settings can be applied on an interface-by-
+//! interface basis, the number of interfaces offered is fixed for a given
+//! config descriptor. Hence, this function will correctly find the unique
+//! interface descriptor for that interface's alternate setting number \e
+//! ui32Alt if \e ui32Index is set to the required interface number and
+//! \e ui32Alt is set to a valid alternate setting number for that interface.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetInterface(), searches through a single,
+//! contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the required interface descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tInterfaceDescriptor *
+USBDCDConfigGetInterface(const tConfigHeader *psConfig, uint32_t ui32Index,
+ uint32_t ui32Alt, uint32_t *pui32Section)
+{
+ //
+ // If we are being told to ignore the alternate configuration, this boils
+ // down to a very simple query.
+ //
+ if(ui32Alt == USB_DESC_ANY)
+ {
+ //
+ // Return the ui32Index-th interface descriptor we find in the
+ // configuration descriptor.
+ //
+ return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig,
+ USB_DTYPE_INTERFACE,
+ ui32Index,
+ pui32Section));
+ }
+ else
+ {
+ //
+ // In this case, a specific alternate setting number is required.
+ // Given that interface numbers are zero based indices, we can
+ // pass the supplied ui32Index parameter directly as the interface
+ // number to USBDescGetAlternateInterface() to retrieve the requested
+ // interface descriptor pointer.
+ //
+ return(ConfigAlternateInterfaceGet(psConfig, ui32Index, ui32Alt,
+ pui32Section));
+ }
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Return a pointer to the n-th endpoint descriptor in a particular interface
+//! within a configuration descriptor.
+//!
+//! \param psConfig points to the header structure for the configuration
+//! descriptor that is to be searched.
+//! \param ui32InterfaceNumber is the interface number whose endpoint is to be
+//! found.
+//! \param ui32AltCfg is the alternate setting number which is to be searched
+//! for. This must be a valid alternate setting number for the requested
+//! interface.
+//! \param ui32Index is the zero based index of the endpoint that is to be
+//! found within the appropriate alternate setting for the interface.
+//!
+//! Return a pointer to the n-th endpoint descriptor found in the supplied
+//! interface descriptor. If the \e ui32Index parameter is invalid (greater
+//! than or equal to the bNumEndpoints field of the interface descriptor) or
+//! the endpoint descriptor cannot be found, the function will return NULL.
+//!
+//! The search performed by this function traverses through the list of
+//! sections comprising the configuration descriptor. Note that the similar
+//! top-level function, USBDescGetInterfaceEndpoint(), searches through a
+//! single, contiguous block of data to perform the same enumeration.
+//!
+//! \return Returns a pointer to the requested endpoint descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tEndpointDescriptor *
+USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
+ uint32_t ui32InterfaceNumber,
+ uint32_t ui32AltCfg, uint32_t ui32Index)
+{
+ tInterfaceDescriptor *psInterface;
+ tDescriptorHeader *psEndpoint;
+ uint32_t ui32Section, ui32Count;
+
+ //
+ // Find the requested interface descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ui32InterfaceNumber,
+ ui32AltCfg, &ui32Section);
+
+ //
+ // Did we find the requested interface?
+ //
+ if(psInterface)
+ {
+ //
+ // Is the index passed valid?
+ //
+ if(ui32Index >= psInterface->bNumEndpoints)
+ {
+ //
+ // It's out of bounds so return a NULL.
+ //
+ return((tEndpointDescriptor *)0);
+ }
+ else
+ {
+ //
+ // Endpoint index is valid so find the descriptor. We start from
+ // the interface descriptor and look for following endpoint
+ // descriptors.
+ //
+ ui32Count = 0;
+ psEndpoint = (tDescriptorHeader *)psInterface;
+
+ while(psEndpoint)
+ {
+ if(psEndpoint->bDescriptorType == USB_DTYPE_ENDPOINT)
+ {
+ //
+ // We found an endpoint descriptor. Have we reached the
+ // one we want?
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Yes - return the descriptor pointer to the caller.
+ //
+ return((tEndpointDescriptor *)psEndpoint);
+ }
+
+ //
+ // Move on to look for the next endpoint.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move to the next descriptor.
+ //
+ psEndpoint = NextConfigDescGet(psConfig, &ui32Section,
+ psEndpoint);
+ }
+ }
+ }
+
+ //
+ // We could not find the requested interface or we got to the end of the
+ // descriptor without finding the requested endpoint.
+ //
+ return((tEndpointDescriptor *)0);
+
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdcomp.c b/usblib/device/usbdcomp.c
new file mode 100644
index 0000000..727ed42
--- /dev/null
+++ b/usblib/device/usbdcomp.c
@@ -0,0 +1,1544 @@
+//****************************************************************************
+//
+// usbdcomp.c - USB composite device class driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usb-ids.h"
+#include "usblib/usbcdc.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdcdc.h"
+#include "usblib/device/usbdcomp.h"
+
+//****************************************************************************
+//
+//! \addtogroup composite_device_class_api
+//! @{
+//
+//****************************************************************************
+
+//****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//****************************************************************************
+static uint8_t g_pui8CompDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_MISC, // USB Device Class (spec 5.1.1)
+ USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1)
+ USB_MISC_PROTOCOL_IAD, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during USBDCompositeInit).
+ USBShort(0), // Product ID (filled in during USBDCompositeInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//****************************************************************************
+//
+// Composite class device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//****************************************************************************
+static const uint8_t g_pui8CompConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(0), // The total size of this full structure.
+ 0, // The number of interfaces in this
+ // configuration, this will be filled by
+ // the class as it discovers all classes
+ // supported.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_BUS_PWR, // .
+ 250, // The maximum power in 2mA increments.
+};
+
+//****************************************************************************
+//
+// Byte offsets used to access various fields in our index/interface/endpoint
+// lookup table (tUSBDCompositeDevice.pui32DeviceWorkspace). This workspace
+// contains one 4 byte entry per device. The LSB is the device index, next byte
+// is the number of the first interface not within this device, next byte is
+// the number of the first IN endpoint not within this device and the final
+// byte is the number of the first OUT endpoint not within this device. Using
+// this simple table we can reasonably quickly cross-reference index with
+// interface and endpoint numbers.
+//
+//****************************************************************************
+#define LOOKUP_INDEX_BYTE 0
+#define LOOKUP_INTERFACE_BYTE 1
+#define LOOKUP_IN_END_BYTE 2
+#define LOOKUP_OUT_END_BYTE 3
+
+//****************************************************************************
+//
+// A marker used to indicate an invalid index into the device table.
+//
+//****************************************************************************
+#define INVALID_DEVICE_INDEX 0xFFFFFFFF
+
+//****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//****************************************************************************
+static void HandleDisconnect(void *pvCompositeInstance);
+static void InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+static void ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value);
+static void DataSent(void *pvCompositeInstance, uint32_t ui32Info);
+static void DataReceived(void *pvCompositeInstance, uint32_t ui32Info);
+static void HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status);
+static void HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+static void SuspendHandler(void *pvCompositeInstance);
+static void ResumeHandler(void *pvCompositeInstance);
+static void ResetHandler(void *pvCompositeInstance);
+static void HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData);
+static void GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest);
+
+//****************************************************************************
+//
+// Configuration Descriptor.
+//
+//****************************************************************************
+tConfigHeader *g_ppCompConfigDescriptors[1];
+
+//****************************************************************************
+//
+// The device information structure for the USB Composite device.
+//
+//****************************************************************************
+const tCustomHandlers g_sCompHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ GetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ InterfaceChange,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ DataSent,
+
+ //
+ // ResetHandler
+ //
+ ResetHandler,
+
+ //
+ // SuspendHandler
+ //
+ SuspendHandler,
+
+ //
+ // ResumeHandler
+ //
+ ResumeHandler,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // DeviceHandler
+ //
+ HandleDevice,
+};
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device interface number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this interface or INVALID_DEVICE_INDEX if no
+// device contains the passed interface number.
+//
+//****************************************************************************
+static uint32_t
+InterfaceToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Interface)
+{
+ uint32_t ui32Loop;
+ uint32_t ui32Lookup;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up value from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (8 * LOOKUP_INTERFACE_BYTE)) & 0xff;
+
+ //
+ // If the desired interface number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Interface < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid interface number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+//****************************************************************************
+//
+// Use the lookup table from the field pui32DeviceWorkspace in the
+// tUSBDCompositeDevice structure to determine which device to call given a
+// particular composite device endpoint number.
+//
+// The returned value is the index into psDevice->tCompositeEntry indicating
+// the device which contains this endpoint or INVALID_DEVICE_INDEX if no
+// device contains the passed endpoint number.
+//
+//****************************************************************************
+static uint32_t
+EndpointToIndex(tUSBDCompositeDevice *psDevice, uint32_t ui32Endpoint,
+ bool bInEndpoint)
+{
+ uint32_t ui32Loop, ui32EndpointByte, ui32Lookup;
+
+ //
+ // Are we considering an IN or OUT endpoint?
+ //
+ ui32EndpointByte = bInEndpoint ? LOOKUP_IN_END_BYTE : LOOKUP_OUT_END_BYTE;
+
+ //
+ // Check each lookup entry in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psDevice->ui32NumDevices; ui32Loop++)
+ {
+ //
+ // Get the look up byte from the device.
+ //
+ ui32Lookup = psDevice->psDevices[ui32Loop].ui32DeviceWorkspace;
+ ui32Lookup = (ui32Lookup >> (ui32EndpointByte * 8)) & 0xff;
+
+ //
+ // If the desired endpoint number is lower than the value in the
+ // current lookup table entry, we have found the desired device so
+ // return its index.
+ //
+ if(ui32Endpoint < ui32Lookup)
+ {
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we get here, an invalid endpoint number was passed so return a
+ // marker to indicate this.
+ //
+ return(INVALID_DEVICE_INDEX);
+}
+
+
+//****************************************************************************
+//
+// This function will check if any device classes need a get descriptor
+// handler called.
+//
+//****************************************************************************
+static void
+GetDescriptor(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the composite device pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific descriptors,
+ // you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a GetDescriptor callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnGetDescriptor)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnGetDescriptor(
+ psCompDevice->psDevices[ui32Idx].pvInstance, psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an suspend handler
+// called.
+//
+//****************************************************************************
+static void
+SuspendHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_SUSPEND,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnSuspendHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnSuspendHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an resume handler
+// called.
+//
+//****************************************************************************
+static void
+ResumeHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has resumed.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance, USB_EVENT_RESUME,
+ 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResumeHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResumeHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an reset handler
+// called.
+//
+//****************************************************************************
+static void
+ResetHandler(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+ void *pvDeviceInst;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been connected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_CONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+ pvDeviceInst = psCompDevice->psDevices[ui32Idx].pvInstance;
+
+ if(psDeviceInfo->psCallbacks->pfnResetHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnResetHandler(pvDeviceInst);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being set to the host so that the
+// application callback can be called when the data has been transferred.
+//
+//****************************************************************************
+static void
+DataSent(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataSent)
+ {
+ psDeviceInfo->psCallbacks->pfnDataSent(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called to handle data being received back from the host so
+// that the application callback can be called when the new data is ready.
+//
+//****************************************************************************
+static void
+DataReceived(void *pvCompositeInstance, uint32_t ui32Info)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Pass this notification on to the device which last handled a
+ // transaction on endpoint 0 (assuming we know who that was).
+ //
+ ui32Idx = psCompDevice->sPrivateData.ui32EP0Owner;
+
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDataReceived)
+ {
+ psDeviceInfo->psCallbacks->pfnDataReceived(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Info);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function will check if any device classes need an endpoint handler
+// called.
+//
+//****************************************************************************
+static void
+HandleEndpoints(void *pvCompositeInstance, uint32_t ui32Status)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Call each of the endpoint handlers. This may seem odd since we should
+ // only call the handler whose endpoint needs service. Unfortunately, if
+ // the device class driver is using uDMA, we have no way of knowing which
+ // handler to call (since ui32Status will be 0). Since the handlers are
+ // set up to ignore any callback that is not for them, this is safe.
+ //
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnEndpointHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnEndpointHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Status);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvCompositeInstance, uint32_t ui32Request,
+ void *pvRequestData)
+{
+ uint32_t ui32Idx;
+ tUSBDCompositeDevice *psCompDevice;
+ const tDeviceInfo *psDeviceInfo;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDeviceHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Request,
+ pvRequestData);
+ }
+ }
+
+ if(psCompDevice->pfnCallback)
+ {
+ switch(ui32Request)
+ {
+ case USB_EVENT_LPM_RESUME:
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_SLEEP, 0,
+ (void *)0);
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psCompDevice->pfnCallback(0, USB_EVENT_LPM_ERROR, 0,
+ (void *)0);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//****************************************************************************
+static void
+HandleDisconnect(void *pvCompositeInstance)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Inform the application that the device has been disconnected.
+ //
+ if(psCompDevice->pfnCallback)
+ {
+ psCompDevice->pfnCallback(pvCompositeInstance,
+ USB_EVENT_DISCONNECTED, 0, 0);
+ }
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnDisconnectHandler)
+ {
+ psDeviceInfo->psCallbacks->pfnDisconnectHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// interface changes. It will be passed on to the device classes if they have
+// a handler for this function.
+//
+//****************************************************************************
+static void
+InterfaceChange(void *pvCompositeInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnInterfaceChange)
+ {
+ psDeviceInfo->psCallbacks->pfnInterfaceChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ ui8InterfaceNum, ui8AlternateSetting);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes. It will be passed on to the device classes if they
+// have a handler for this function.
+//
+//****************************************************************************
+static void
+ConfigChangeHandler(void *pvCompositeInstance, uint32_t ui32Value)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ ASSERT(pvCompositeInstance != 0);
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ for(ui32Idx = 0; ui32Idx < psCompDevice->ui32NumDevices; ui32Idx++)
+ {
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ if(psDeviceInfo->psCallbacks->pfnConfigChange)
+ {
+ psDeviceInfo->psCallbacks->pfnConfigChange(
+ psCompDevice->psDevices[ui32Idx].pvInstance, ui32Value);
+ }
+ }
+}
+
+//****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvCompositeInstance
+// \param psUSBRequest points to the request received.
+//
+// This call will be passed on to the device classes if they have a handler
+// for this function.
+//
+// \return None.
+//
+//****************************************************************************
+static void
+HandleRequests(void *pvCompositeInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Idx;
+ const tDeviceInfo *psDeviceInfo;
+ tUSBDCompositeDevice *psCompDevice;
+
+ //
+ // Create the device instance pointer.
+ //
+ psCompDevice = (tUSBDCompositeDevice *)pvCompositeInstance;
+
+ //
+ // Determine which device this request is intended for. We have to be
+ // careful here to send this to the callback for the correct device
+ // depending upon whether it is a request sent to the device, the interface
+ // or the endpoint.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ case USB_RTYPE_INTERFACE:
+ {
+ ui32Idx = InterfaceToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0xFF));
+ break;
+ }
+
+ case USB_RTYPE_ENDPOINT:
+ {
+ ui32Idx = EndpointToIndex(psCompDevice,
+ (psUSBRequest->wIndex & 0x0F),
+ (psUSBRequest->wIndex & 0x80) ? true : false);
+ break;
+ }
+
+ //
+ // Requests sent to the device or any other recipient can't be
+ // handled here since we have no way of telling where they are
+ // supposed to be handled. As a result, we just stall them.
+ //
+ // If your composite device has some device-specific requests that need
+ // to be handled at the device (rather than interface or endpoint)
+ // level, you should add code here to handle them.
+ //
+ case USB_RTYPE_DEVICE:
+ case USB_RTYPE_OTHER:
+ default:
+ {
+ ui32Idx = INVALID_DEVICE_INDEX;
+ break;
+ }
+ }
+
+ //
+ // Did we find a device class to pass the request to?
+ //
+ if(ui32Idx != INVALID_DEVICE_INDEX)
+ {
+ //
+ // Get a pointer to the individual device instance.
+ //
+ psDeviceInfo = psCompDevice->psDevices[ui32Idx].psDevInfo;
+
+ //
+ // Does this device have a RequestHandler callback?
+ //
+ if(psDeviceInfo->psCallbacks->pfnRequestHandler)
+ {
+ //
+ // Remember this device index so that we can correctly route any
+ // data notification callbacks to it.
+ //
+ psCompDevice->sPrivateData.ui32EP0Owner = ui32Idx;
+
+ //
+ // Yes - call the device to retrieve the descriptor.
+ //
+ psDeviceInfo->psCallbacks->pfnRequestHandler(
+ psCompDevice->psDevices[ui32Idx].pvInstance,
+ psUSBRequest);
+ }
+ else
+ {
+ //
+ // Oops - we can't satisfy the request so stall EP0 to indicate
+ // an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+ }
+ else
+ {
+ //
+ // We are unable to satisfy the descriptor request so stall EP0 to
+ // indicate an error.
+ //
+ USBDCDStallEP0(USBBaseToIndex(
+ psCompDevice->sPrivateData.ui32USBBase));
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending interface number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeIfaceChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_IFACE_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function handles sending endpoint number changes to device instances.
+//
+//****************************************************************************
+static void
+CompositeEPChange(tCompositeEntry *psCompDevice, uint8_t ui8Old,
+ uint8_t ui8New)
+{
+ uint8_t pui8Interfaces[2];
+
+ if(psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler)
+ {
+ //
+ // Create the data to pass to the device handler.
+ //
+ pui8Interfaces[0] = ui8Old;
+ pui8Interfaces[1] = ui8New;
+
+ ui8New--;
+
+ //
+ // Call the device handler to inform the class of the interface number
+ // change.
+ //
+ psCompDevice->psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->pvInstance, USB_EVENT_COMP_EP_CHANGE,
+ (void *)pui8Interfaces);
+ }
+}
+
+//****************************************************************************
+//
+// This function merges the configuration descriptors into a single multiple
+// instance device.
+//
+//****************************************************************************
+uint32_t
+BuildCompositeDescriptor(tUSBDCompositeDevice *psCompDevice)
+{
+ uint32_t ui32Idx, ui32Offset, ui32CPIdx, ui32FixINT, ui32Dev;
+ uint16_t ui16TotalLength, ui16Bytes;
+ uint8_t ui8Interface, ui8INEndpoint, ui8OUTEndpoint;
+ uint8_t *pui8Data, *pui8Config;
+ const tConfigHeader *psConfigHeader;
+ tDescriptorHeader *psHeader;
+ const uint8_t *pui8Descriptor;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ const tDeviceInfo *psDevice;
+
+ //
+ // Save the number of devices to look through.
+ //
+ ui32Dev = 0;
+ ui32Idx = 0;
+ ui8Interface = 0;
+ ui8INEndpoint = 1;
+ ui8OUTEndpoint = 1;
+ ui32Offset = 0;
+ ui32FixINT = 0;
+
+ //
+ // This puts the first section pointer in the first entry in the list
+ // of sections.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0] =
+ &psCompDevice->sPrivateData.psCompSections[0];
+
+ //
+ // Put the pointer to this instances configuration descriptor into the
+ // front of the list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[0]->pui8Data =
+ (uint8_t *)&psCompDevice->sPrivateData.sConfigDescriptor;
+
+ psCompDevice->sPrivateData.ppsCompSections[0]->ui16Size =
+ psCompDevice->sPrivateData.sConfigDescriptor.bLength;
+
+ //
+ // The configuration descriptor is 9 bytes so initialize the total length
+ // to 9 bytes.
+ //
+ ui16TotalLength = 9;
+
+ //
+ // Copy the section pointer into the section array for the composite
+ // device. This is awkward but is required given the definition
+ // of the structures.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1] =
+ &psCompDevice->sPrivateData.psCompSections[1];
+
+ //
+ // Copy the pointer to the application supplied space into the section
+ // list.
+ //
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = 0;
+ psCompDevice->sPrivateData.ppsCompSections[1]->pui8Data =
+ psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Create a local pointer to the data that is used to copy data from
+ // the other devices into the composite descriptor.
+ //
+ pui8Data = psCompDevice->sPrivateData.pui8Data;
+
+ //
+ // Consider each device in turn.
+ //
+ while(ui32Dev < psCompDevice->ui32NumDevices)
+ {
+ //
+ // Save the current starting address of this descriptor.
+ //
+ pui8Config = pui8Data + ui32Offset;
+
+ //
+ // Create a local pointer to the configuration header.
+ //
+ psDevice = psCompDevice->psDevices[ui32Dev].psDevInfo;
+ psConfigHeader = psDevice->ppsConfigDescriptors[0];
+
+ //
+ // Loop through each of the sections in this device's configuration
+ // descriptor.
+ //
+ for(ui32Idx = 0; ui32Idx < psConfigHeader->ui8NumSections; ui32Idx++)
+ {
+ //
+ // Initialize the local offset in this descriptor. We include
+ // a special case here to ignore the initial 9 byte configuration
+ // descriptor since this has already been handled.
+ //
+ if(ui32Idx)
+ {
+ //
+ // This is not the first section so we handle everything in
+ // it.
+ //
+ ui16Bytes = 0;
+ }
+ else
+ {
+ //
+ // This is the first section for this device so skip the 9
+ // byte configuration descriptor since we've already handled
+ // this.
+ //
+ ui16Bytes = 9;
+
+ //
+ // If this section includes only the configuration descriptor,
+ // skip it entirely.
+ //
+ if(psConfigHeader->psSections[ui32Idx]->ui16Size <= ui16Bytes)
+ {
+ continue;
+ }
+ }
+
+ //
+ // Get a pointer to the configuration descriptor.
+ //
+ pui8Descriptor = psConfigHeader->psSections[ui32Idx]->pui8Data;
+
+ //
+ // Bounds check the allocated space and return if there is not
+ // enough space.
+ //
+ if(ui32Offset > psCompDevice->sPrivateData.ui32DataSize)
+ {
+ return(1);
+ }
+
+ //
+ // Copy the descriptor from the device into the descriptor list.
+ //
+ for(ui32CPIdx = 0;
+ ui32CPIdx < psConfigHeader->psSections[ui32Idx]->ui16Size;
+ ui32CPIdx++)
+ {
+ pui8Data[ui32CPIdx + ui32Offset] = pui8Descriptor[ui32CPIdx];
+ }
+
+ //
+ // Read out the descriptors in this section.
+ //
+ while(ui16Bytes < psConfigHeader->psSections[ui32Idx]->ui16Size)
+ {
+ //
+ // Create a descriptor header pointer.
+ //
+ psHeader = (tDescriptorHeader *)&pui8Data[ui32Offset +
+ ui16Bytes];
+
+ //
+ // Check for interface descriptors and modify the numbering to
+ // match the composite device.
+ //
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // See if this is an alternate setting or the initial
+ // setting.
+ //
+ if(psInterface->bAlternateSetting != 0)
+ {
+ //
+ // If this is an alternate setting then use the
+ // previous interface number because the current one
+ // has already been incremented.
+ //
+ psInterface->bInterfaceNumber = ui8Interface - 1;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeIfaceChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psInterface->bInterfaceNumber,
+ ui8Interface);
+ //
+ // This was the non-alternate setting so save the
+ // value and move to the next interface number.
+ //
+ psInterface->bInterfaceNumber = ui8Interface;
+
+ //
+ // No strings allowed on interface descriptors for
+ // composite devices.
+ //
+ psInterface->iInterface = 0;
+
+ ui8Interface++;
+ }
+ }
+ //
+ // Check for endpoint descriptors and modify the numbering to
+ // match the composite device.
+ //
+ else if(psHeader->bDescriptorType == USB_DTYPE_ENDPOINT)
+ {
+ psEndpoint = (tEndpointDescriptor *)psHeader;
+
+ //
+ // Check if this is an IN or OUT endpoint.
+ //
+ if(psEndpoint->bEndpointAddress & USB_RTYPE_DIR_IN)
+ {
+ //
+ // Check if this is the special Fixed Interrupt class
+ // and this is the interrupt endpoint.
+ //
+ if(((psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT) &&
+ (psCompDevice->ui16PID == USB_PID_COMP_SERIAL))
+ {
+ //
+ // Check if the Fixed Interrupt endpoint has been
+ // set yet.
+ //
+ if(ui32FixINT == 0)
+ {
+ //
+ // Allocate the fixed interrupt endpoint and
+ // save its number.
+ //
+ ui32FixINT = ui8INEndpoint++;
+ }
+
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui32FixINT);
+
+ psEndpoint->bEndpointAddress = ui32FixINT |
+ USB_RTYPE_DIR_IN;
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(
+ &psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8INEndpoint);
+
+ psEndpoint->bEndpointAddress = ui8INEndpoint++ |
+ USB_RTYPE_DIR_IN;
+ }
+ }
+ else
+ {
+ //
+ // Notify the class that it's interface number has
+ // changed.
+ //
+ CompositeEPChange(&psCompDevice->psDevices[ui32Dev],
+ psEndpoint->bEndpointAddress,
+ ui8OUTEndpoint);
+ psEndpoint->bEndpointAddress = ui8OUTEndpoint++;
+ }
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui16Bytes += psHeader->bLength;
+ }
+
+ ui32Offset += psConfigHeader->psSections[ui32Idx]->ui16Size;
+
+ ui16TotalLength += ui16Bytes;
+ }
+
+ //
+ // Allow the device class to make adjustments to the configuration
+ // descriptor.
+ //
+ psCompDevice->psDevices[ui32Dev].psDevInfo->psCallbacks->pfnDeviceHandler(
+ psCompDevice->psDevices[ui32Dev].pvInstance,
+ USB_EVENT_COMP_CONFIG, (void *)pui8Config);
+
+ //
+ // Add an entry into the device workspace array to allow us to quickly
+ // map interface and endpoint numbers to device instances later.
+ //
+ psCompDevice->psDevices[ui32Dev].ui32DeviceWorkspace =
+ (ui32Dev << (LOOKUP_INDEX_BYTE * 8)) |
+ (ui8Interface << (LOOKUP_INTERFACE_BYTE * 8)) |
+ (ui8OUTEndpoint << (LOOKUP_OUT_END_BYTE * 8)) |
+ (ui8INEndpoint << (LOOKUP_IN_END_BYTE * 8));
+
+ //
+ // Move on to the next device.
+ //
+ ui32Dev++;
+ }
+
+ //
+ // Modify the configuration descriptor to match the number of interfaces
+ // and the new total size.
+ //
+ psCompDevice->sPrivateData.sCompConfigHeader.ui8NumSections = 2;
+ psCompDevice->sPrivateData.ppsCompSections[1]->ui16Size = ui32Offset;
+ psCompDevice->sPrivateData.sConfigDescriptor.bNumInterfaces =
+ ui8Interface;
+ psCompDevice->sPrivateData.sConfigDescriptor.wTotalLength =
+ ui16TotalLength;
+
+
+ return(0);
+}
+
+//****************************************************************************
+//
+//! This function should be called once for the composite class device to
+//! initialize basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! composite device operation.
+//! \param psDevice points to a structure containing parameters customizing
+//! the operation of the composite device.
+//! \param ui32Size is the size in bytes of the data pointed to by the
+//! \e pui8Data parameter.
+//! \param pui8Data is the data area that the composite class can use to build
+//! up descriptors.
+//!
+//! In order for an application to initialize the USB composite device class,
+//! it must first call this function with the a valid composite device class
+//! structure in the \e psDevice parameter. This allows this function to
+//! initialize the USB controller and device code to be prepared to enumerate
+//! and function as a USB composite device. The \e ui32Size and \e pui8Data
+//! parameters should be large enough to hold all of the class instances
+//! passed in via the \e psDevice structure. This is typically the full size
+//! of the configuration descriptor for a device minus its configuration
+//! header(9 bytes).
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the composite class.
+//!
+//! See the documentation on the tUSBDCompositeDevice structure for more
+//! information on how to properly fill the structure members.
+//!
+//! \return This function returns 0 on failure or a non-zero void pointer on
+//! success.
+//
+//****************************************************************************
+void *
+USBDCompositeInit(uint32_t ui32Index, tUSBDCompositeDevice *psDevice,
+ uint32_t ui32Size, uint8_t *pui8Data)
+{
+ tCompositeInstance *psInst;
+ int32_t i32Idx;
+ uint8_t *pui8Temp;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDevice);
+ ASSERT(psDevice->ppui8StringDescriptors);
+
+ //
+ // Initialize the work space in the passed instance structure.
+ //
+ psInst = &psDevice->sPrivateData;
+ psInst->ui32DataSize = ui32Size;
+ psInst->pui8Data = pui8Data;
+
+ //
+ // Save the base address of the USB controller.
+ //
+ psInst->ui32USBBase = USBIndexToBase(ui32Index);
+
+ //
+ // No device is currently transferring data on EP0.
+ //
+ psInst->ui32EP0Owner = INVALID_DEVICE_INDEX;
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sCompHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8CompDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors =
+ (const tConfigHeader * const *)g_ppCompConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the composite device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ g_ppCompConfigDescriptors[0] = &psInst->sCompConfigHeader;
+ g_ppCompConfigDescriptors[0]->ui8NumSections = 0;
+ g_ppCompConfigDescriptors[0]->psSections =
+ (const tConfigSection * const *)psDevice->sPrivateData.ppsCompSections;
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sConfigDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompConfigDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompConfigDescriptor[i32Idx];
+ }
+
+ //
+ // Create a byte pointer to use with the copy.
+ //
+ pui8Temp = (uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Copy the default configuration descriptor into the instance data.
+ //
+ for(i32Idx = 0; i32Idx < g_pui8CompDeviceDescriptor[0]; i32Idx++)
+ {
+ pui8Temp[i32Idx] = g_pui8CompDeviceDescriptor[i32Idx];
+ }
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psInst->sDeviceDescriptor.idVendor = psDevice->ui16VID;
+ psInst->sDeviceDescriptor.idProduct = psDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ psInst->sConfigDescriptor.bmAttributes = psDevice->ui8PwrAttributes;
+ psInst->sConfigDescriptor.bMaxPower =
+ (uint8_t)(psDevice->ui16MaxPowermA>>1);
+
+ psInst->sDevInfo.pui8DeviceDescriptor =
+ (const uint8_t *)&psInst->sDeviceDescriptor;
+
+ //
+ // Plug in the client's string table to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psDevice->ui32NumStringDescriptors;
+
+ //
+ // Enable Clocking to the USB controller so that changes to the USB
+ // controller can be made in the BuildCompositeDescriptor() function.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Create the combined descriptors.
+ //
+ if(BuildCompositeDescriptor(psDevice))
+ {
+ return(0);
+ }
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psInst->sDevInfo, (void *)psDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went
+ // well.
+ //
+ return((void *)psDevice);
+}
+
+//****************************************************************************
+//
+//! Shuts down the composite device.
+//!
+//! \param pvCompositeInstance is the pointer to the device instance structure
+//! as returned by USBDCompositeInit().
+//!
+//! This function terminates composite device interface for the instance
+//! not me supplied. Following this call, the \e pvCompositeInstance instance
+//! should not be used in any other calls.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+USBDCompositeTerm(void *pvCompositeInstance)
+{
+ ASSERT(pvCompositeInstance != 0);
+
+}
+
+//****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//****************************************************************************
+
diff --git a/usblib/device/usbdcomp.h b/usblib/device/usbdcomp.h
new file mode 100644
index 0000000..e064193
--- /dev/null
+++ b/usblib/device/usbdcomp.h
@@ -0,0 +1,261 @@
+//*****************************************************************************
+//
+// usbdcomp.h - USB composite device class driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDCOMP_H__
+#define __USBDCOMP_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup composite_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//
+// Defines a single entry in a table of device types supported by the composite
+// device.
+//
+typedef struct
+{
+ //
+ // This is set internally by the composite class so it can be left
+ // uninitialized by the application.
+ //
+ const tDeviceInfo *psDeviceInfo;
+
+ //
+ // This should be the header to the configuration header for a class.
+ //
+ const tConfigHeader *psConfigHeader;
+
+ //
+ // The offset to this devices interface, filled in by the composite class.
+ //
+ uint8_t ui8IfaceOffset;
+}
+tUSBDCompositeEntry;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// composite device class. The memory for this structure is included in
+// the sPrivateData field in the tUSBDCompositeDevice structure passed on
+// USBDCompositeInit() and should not be modified by any code outside of the
+// composite device code.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Saves which USB controller is in use.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device information pointer.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // This is the configuration descriptor for this instance.
+ //
+ tConfigDescriptor sConfigDescriptor;
+
+ //
+ // This is the device descriptor for this instance.
+ //
+ tDeviceDescriptor sDeviceDescriptor;
+
+ //
+ // The configuration header for this instance.
+ //
+ tConfigHeader sCompConfigHeader;
+
+ //
+ // These are the configuration sections that will be built from the
+ // Configuration Descriptor header and the descriptors from the devices
+ // that are part of this composite device.
+ //
+ tConfigSection psCompSections[2];
+ tConfigSection *ppsCompSections[2];
+
+ //
+ // The size and pointer to the data used by the instance.
+ //
+ uint32_t ui32DataSize;
+ uint8_t *pui8Data;
+
+ //
+ // The current "owner" of endpoint 0. This is used to track the device
+ // class which is currently transferring data on EP0.
+ //
+ uint32_t ui32EP0Owner;
+}
+tCompositeInstance;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the composite device class.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in mA.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of events relating to the operation of the composite
+ //! device.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), Composite
+ //! device interface description string (language 1), Configuration
+ //! description string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be 1 + ((5 + (number of strings)) *
+ //! (number of languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The number of devices in the psDevices array.
+ //
+ const uint32_t ui32NumDevices;
+
+ //
+ //! This application supplied array holds the the top level device class
+ //! information as well as the Instance data for that class.
+ //
+ tCompositeEntry * const psDevices;
+
+ //
+ //! The private data for this device instance. This memory must remain
+ //! accessible for as long as the composite device is in use and must
+ //! not be modified by any code outside the composite class driver.
+ //
+ tCompositeInstance sPrivateData;
+}
+tUSBDCompositeDevice;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// Composite specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDCompositeInit(uint32_t ui32Index,
+ tUSBDCompositeDevice *psCompDevice,
+ uint32_t ui32Size, uint8_t *pui8Data);
+extern void USBDCompositeTerm(void *pvInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/device/usbdconfig.c b/usblib/device/usbdconfig.c
new file mode 100644
index 0000000..0a100cc
--- /dev/null
+++ b/usblib/device/usbdconfig.c
@@ -0,0 +1,555 @@
+//*****************************************************************************
+//
+// usbdconfig.c - High level USB device configuration function.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Structure used in compiling FIFO size and endpoint properties from a
+// configuration descriptor.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint32_t pui32Size[2];
+}
+tUSBEndpointInfo;
+
+//*****************************************************************************
+//
+// Indices used when accessing the tUSBEndpointInfo structure.
+//
+//*****************************************************************************
+#define EP_INFO_IN 0
+#define EP_INFO_OUT 1
+
+//*****************************************************************************
+//
+// Given a maximum packet size and the user's FIFO scaling requirements,
+// determine the flags to use to configure the endpoint FIFO and the number
+// of bytes of FIFO space occupied.
+//
+//*****************************************************************************
+static uint32_t
+GetEndpointFIFOSize(uint32_t ui32MaxPktSize, uint32_t *pupBytesUsed)
+{
+ uint32_t ui32Loop, ui32FIFOSize;
+
+ //
+ // Now we need to find the nearest supported size that accommodates the
+ // requested size. Step through each of the supported sizes until we
+ // find one that will do.
+ //
+ for(ui32Loop = USB_FIFO_SZ_8; ui32Loop <= USB_FIFO_SZ_2048; ui32Loop++)
+ {
+ //
+ // How many bytes does this FIFO value represent?
+ //
+ ui32FIFOSize = USBFIFOSizeToBytes(ui32Loop);
+
+ //
+ // Is this large enough to hold one packet.
+ //
+ if(ui32FIFOSize >= ui32MaxPktSize)
+ {
+ //
+ // Return the FIFO size setting and the USB_FIFO_SZ_ value.
+ //
+ *pupBytesUsed = ui32FIFOSize;
+
+ return(ui32Loop);
+ }
+ }
+
+ //
+ // If we drop out, we can't support the FIFO size requested. Signal a
+ // problem by returning 0 in the pBytesUsed
+ //
+ *pupBytesUsed = 0;
+
+ return(USB_FIFO_SZ_8);
+}
+
+//*****************************************************************************
+//
+// Translate a USB endpoint descriptor into the values we need to pass to the
+// USBDevEndpointConfigSet() API.
+//
+//*****************************************************************************
+static void
+GetEPDescriptorType(tEndpointDescriptor *psEndpoint, uint32_t *pui32EPIndex,
+ uint32_t *pui32MaxPktSize, uint32_t *pui32Flags)
+{
+ //
+ // Get the endpoint index.
+ //
+ *pui32EPIndex = psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+
+ //
+ // Extract the maximum packet size.
+ //
+ *pui32MaxPktSize = psEndpoint->wMaxPacketSize & USB_EP_MAX_PACKET_COUNT_M;
+
+ //
+ // Is this an IN or an OUT endpoint?
+ //
+ *pui32Flags = (psEndpoint->bEndpointAddress & USB_EP_DESC_IN) ?
+ USB_EP_DEV_IN : USB_EP_DEV_OUT;
+
+ //
+ // Set the endpoint mode.
+ //
+ switch(psEndpoint->bmAttributes & USB_EP_ATTR_TYPE_M)
+ {
+ case USB_EP_ATTR_CONTROL:
+ {
+ *pui32Flags |= USB_EP_MODE_CTRL;
+ break;
+ }
+ case USB_EP_ATTR_BULK:
+ {
+ *pui32Flags |= USB_EP_MODE_BULK;
+ break;
+ }
+ case USB_EP_ATTR_INT:
+ {
+ *pui32Flags |= USB_EP_MODE_INT;
+ break;
+ }
+ case USB_EP_ATTR_ISOC:
+ {
+ *pui32Flags |= USB_EP_MODE_ISOC;
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Configure the USB controller appropriately for the device whose
+//! configuration descriptor is passed.
+//!
+//! \param psDevInst is a pointer to the device instance being configured.
+//! \param psConfig is a pointer to the configuration descriptor that the
+//! USB controller is to be set up to support.
+//!
+//! This function may be used to initialize a USB controller to operate as
+//! the device whose configuration descriptor is passed. The function
+//! enables the USB controller, partitions the FIFO appropriately and
+//! configures each endpoint required by the configuration. If the supplied
+//! configuration supports multiple alternate settings for any interface,
+//! the USB FIFO is set up assuming the worst case use (largest packet size
+//! for a given endpoint in any alternate setting using that endpoint) to
+//! allow for on-the-fly alternate setting changes later. On return from this
+//! function, the USB controller is configured for correct operation of
+//! the default configuration of the device described by the descriptor passed.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+USBDeviceConfig(tDCDInstance *psDevInst, const tConfigHeader *psConfig)
+{
+ uint32_t ui32Loop, ui32Count, ui32NumInterfaces, ui32EpIndex, ui32EpType,
+ ui32MaxPkt, ui32NumEndpoints, ui32Flags, ui32BytesUsed,
+ ui32Section;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+ tUSBEndpointInfo psEPInfo[NUM_USB_EP - 1];
+
+ //
+ // A valid device instance is required.
+ //
+ ASSERT(psDevInst != 0);
+
+ //
+ // Catch bad pointers in a debug build.
+ //
+ ASSERT(psConfig);
+
+ //
+ // Clear out our endpoint info.
+ //
+ for(ui32Loop = 0; ui32Loop < (NUM_USB_EP - 1); ui32Loop++)
+ {
+ psEPInfo[ui32Loop].pui32Size[EP_INFO_IN] = 0;
+ psEPInfo[ui32Loop].pui32Size[EP_INFO_OUT] = 0;
+ }
+
+ //
+ // How many (total) endpoints does this configuration describe?
+ //
+ ui32NumEndpoints = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_ENDPOINT);
+
+ //
+ // How many interfaces are included?
+ //
+ ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_INTERFACE);
+
+ //
+ // Look at each endpoint and determine the largest max packet size for
+ // each endpoint. This will determine how we partition the USB FIFO.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumEndpoints; ui32Loop++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = (tEndpointDescriptor *)USBDCDConfigDescGet(
+ psConfig, USB_DTYPE_ENDPOINT, ui32Loop,
+ &ui32Section);
+
+ //
+ // Extract the endpoint number and whether it is an IN or OUT
+ // endpoint.
+ //
+ ui32EpIndex = (uint32_t)
+ psEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+ ui32EpType = (psEndpoint->bEndpointAddress & USB_EP_DESC_IN) ?
+ EP_INFO_IN : EP_INFO_OUT;
+
+ //
+ // Make sure the endpoint number is valid for our controller. If not,
+ // return false to indicate an error. Note that 0 is invalid since
+ // you shouldn't reference endpoint 0 in the config descriptor.
+ //
+ if((ui32EpIndex >= NUM_USB_EP) || (ui32EpIndex == 0))
+ {
+ return(false);
+ }
+
+ //
+ // Does this endpoint have a max packet size requirement larger than
+ // any previous use we have seen?
+ //
+ if(psEndpoint->wMaxPacketSize >
+ psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType])
+ {
+ //
+ // Yes - remember the new maximum packet size.
+ //
+ psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType] =
+ psEndpoint->wMaxPacketSize;
+ }
+ }
+
+ //
+ // At this point, we have determined the maximum packet size required
+ // for each endpoint by any possible alternate setting of any interface
+ // in this configuration. Now determine the endpoint settings required
+ // for the interface setting we are actually going to use.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumInterfaces; ui32Loop++)
+ {
+ //
+ // Get the next interface descriptor in the configuration descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ui32Loop,
+ USB_DESC_ANY, &ui32Section);
+
+ //
+ // Is this the default interface (bAlternateSetting set to 0)?
+ //
+ if(psInterface && (psInterface->bAlternateSetting == 0))
+ {
+ //
+ // This is an interface we are interested in so gather the
+ // information on its endpoints.
+ //
+ ui32NumEndpoints = (uint32_t)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in this interface and configure
+ // it appropriately.
+ //
+ for(ui32Count = 0; ui32Count < ui32NumEndpoints; ui32Count++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ui32Count);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ui32EpIndex, &ui32MaxPkt,
+ &ui32Flags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ui32EpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ IndexToUSBEP(ui32EpIndex),
+ ui32MaxPkt, ui32Flags);
+ }
+ }
+ }
+ }
+
+ //
+ // At this point, we have configured all the endpoints that are to be
+ // used by this configuration's alternate setting 0. Now we go on and
+ // partition the FIFO based on the maximum packet size information we
+ // extracted earlier. Endpoint 0 is automatically configured to use the
+ // first MAX_PACKET_SIZE_EP0 bytes of the FIFO so we start from there.
+ //
+ ui32Count = MAX_PACKET_SIZE_EP0;
+ for(ui32Loop = 1; ui32Loop < NUM_USB_EP; ui32Loop++)
+ {
+ //
+ // Configure the IN endpoint at this index if it is referred to
+ // anywhere.
+ //
+ if(psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_IN])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ui32MaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_IN],
+ &ui32BytesUsed);
+
+ //
+ // The FIFO space could not be allocated.
+ //
+ if(ui32BytesUsed == 0)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, IndexToUSBEP(ui32Loop), ui32Count,
+ ui32MaxPkt, USB_EP_DEV_IN);
+ ui32Count += ui32BytesUsed;
+ }
+
+ //
+ // Configure the OUT endpoint at this index.
+ //
+ if(psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_OUT])
+ {
+ //
+ // What FIFO size flag do we use for this endpoint?
+ //
+ ui32MaxPkt = GetEndpointFIFOSize(
+ psEPInfo[ui32Loop - 1].pui32Size[EP_INFO_OUT],
+ &ui32BytesUsed);
+
+ //
+ // The FIFO space could not be allocated.
+ //
+ if(ui32BytesUsed == 0)
+ {
+ return(false);
+ }
+
+ //
+ // Now actually configure the FIFO for this endpoint.
+ //
+ USBFIFOConfigSet(USB0_BASE, IndexToUSBEP(ui32Loop), ui32Count,
+ ui32MaxPkt, USB_EP_DEV_OUT);
+ ui32Count += ui32BytesUsed;
+ }
+
+ }
+
+ //
+ // If we get to the end, all is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+//! Configure the affected USB endpoints appropriately for one alternate
+//! interface setting.
+//!
+//! \param psDevInst is a pointer to the device instance being configured.
+//! \param psConfig is a pointer to the configuration descriptor that contains
+//! the interface whose alternate settings is to be configured.
+//! \param ui8InterfaceNum is the number of the interface whose alternate
+//! setting is to be configured. This number corresponds to the
+//! bInterfaceNumber field in the desired interface descriptor.
+//! \param ui8AlternateSetting is the alternate setting number for the desired
+//! interface. This number corresponds to the bAlternateSetting field in the
+//! desired interface descriptor.
+//!
+//! This function may be used to reconfigure the endpoints of an interface
+//! for operation in one of the interface's alternate settings. Note that this
+//! function assumes that the endpoint FIFO settings will not need to change
+//! and only the endpoint mode is changed. This assumption is valid if the
+//! USB controller was initialized using a previous call to USBDCDConfig().
+//!
+//! In reconfiguring the interface endpoints, any additional configuration
+//! bits set in the endpoint configuration other than the direction (\b
+//! USB_EP_DEV_IN or \b USB_EP_DEV_OUT) and mode (\b USB_EP_MODE_MASK) are
+//! preserved.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+USBDeviceConfigAlternate(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting)
+{
+ uint32_t ui32NumInterfaces, ui32NumEndpoints, ui32Loop, ui32Count,
+ ui32MaxPkt, ui32Flags, ui32Section, ui32EpIndex;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *psEndpoint;
+
+ //
+ // How many interfaces are included in the descriptor?
+ //
+ ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig,
+ USB_DTYPE_INTERFACE);
+
+ //
+ // Find the interface descriptor for the supplied interface and alternate
+ // setting numbers.
+ //
+
+ for(ui32Loop = 0; ui32Loop < ui32NumInterfaces; ui32Loop++)
+ {
+ //
+ // Get the next interface descriptor in the configuration descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ui32Loop,
+ USB_DESC_ANY, &ui32Section);
+
+ //
+ // Is this the default interface (bAlternateSetting set to 0)?
+ //
+ if(psInterface &&
+ (psInterface->bInterfaceNumber == ui8InterfaceNum) &&
+ (psInterface->bAlternateSetting == ui8AlternateSetting))
+ {
+ //
+ // This is an interface we are interested in and the descriptor
+ // representing the alternate setting we want so go ahead and
+ // reconfigure the endpoints.
+ //
+
+ //
+ // How many endpoints does this interface have?
+ //
+ ui32NumEndpoints = (uint32_t)psInterface->bNumEndpoints;
+
+ //
+ // Walk through each endpoint in turn.
+ //
+ for(ui32Count = 0; ui32Count < ui32NumEndpoints; ui32Count++)
+ {
+ //
+ // Get a pointer to the endpoint descriptor.
+ //
+ psEndpoint = USBDCDConfigGetInterfaceEndpoint(psConfig,
+ psInterface->bInterfaceNumber,
+ psInterface->bAlternateSetting,
+ ui32Count);
+
+ //
+ // Make sure we got a good pointer.
+ //
+ if(psEndpoint)
+ {
+ //
+ // Determine maximum packet size and flags from the
+ // endpoint descriptor.
+ //
+ GetEPDescriptorType(psEndpoint, &ui32EpIndex, &ui32MaxPkt,
+ &ui32Flags);
+
+ //
+ // Make sure no-one is trying to configure endpoint 0.
+ //
+ if(!ui32EpIndex)
+ {
+ return(false);
+ }
+
+ //
+ // Set the endpoint configuration.
+ //
+ USBDevEndpointConfigSet(USB0_BASE,
+ IndexToUSBEP(ui32EpIndex),
+ ui32MaxPkt, ui32Flags);
+ }
+ }
+
+ //
+ // At this point, we have reconfigured the desired interface so
+ // return indicating all is well.
+ //
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbddfu-rt.c b/usblib/device/usbddfu-rt.c
new file mode 100644
index 0000000..24adb26
--- /dev/null
+++ b/usblib/device/usbddfu-rt.c
@@ -0,0 +1,661 @@
+//*****************************************************************************
+//
+// usbddfu-rt.c - USB Device Firmware Update runtime device class driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_nvic.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/systick.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbdfu.h"
+#include "usblib/usb-ids.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbddfu-rt.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup dfu_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// DFU Device Descriptor. This is a dummy structure since runtime DFU must be
+// a part of a composite device and cannot be instantiated on its own.
+//
+//*****************************************************************************
+const uint8_t g_pui8DFUDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_VEND_SPECIFIC, // USB Device Class
+ 0, // USB Device Sub-class
+ 0, // USB Device protocol
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0), // Device Release Number BCD.
+ 0, // Manufacturer string identifier.
+ 0, // Product string identifier.
+ 0, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// DFU device runtime configuration descriptor. This is also a dummy structure
+// since the primary device class configuration will be used when DFU is added
+// to the composite device.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(27), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The DFU runtime interface descriptor.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUInterface[DFUINTERFACE_SIZE] =
+{
+ //
+ // Interface descriptor for runtime DFU operation.
+ //
+ 9, // Length of this descriptor.
+ USB_DTYPE_INTERFACE, // This is an interface descriptor.
+ 0, // Interface number .
+ 0, // Alternate setting number.
+ 0, // Number of endpoints (only endpoint 0
+ // used)
+ USB_CLASS_APP_SPECIFIC, // Application specific interface class
+ USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass
+ USB_DFU_RUNTIME_PROTOCOL, // DFU runtime protocol
+ 0, // No string descriptor for this interface.
+};
+
+//*****************************************************************************
+//
+// The DFU functional descriptor.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUFunctionalDesc[DFUFUNCTIONALDESC_SIZE] =
+{
+ //
+ // Device Firmware Upgrade functional descriptor.
+ //
+ 9, // Length of this descriptor.
+ USB_DFU_FUNC_DESCRIPTOR_TYPE, // DFU Functional descriptor type
+ (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes.
+ DFU_ATTR_CAN_UPLOAD |
+ DFU_ATTR_WILL_DETACH |
+ DFU_ATTR_MANIFEST_TOLERANT),
+ USBShort(0xFFFF), // Detach timeout (set to maximum).
+ USBShort(DFU_TRANSFER_SIZE), // Transfer size 1KB.
+ USBShort(0x0110) // DFU Version 1.1
+};
+
+//*****************************************************************************
+//
+// The DFU runtime configuration descriptor is defined as two sections.
+// These sections are:
+//
+// 1. The 9 byte configuration descriptor.
+// 2. The interface descriptor + DFU functional descriptor.
+//
+//*****************************************************************************
+const tConfigSection g_sDFUConfigSection =
+{
+ sizeof(g_pui8DFUConfigDescriptor),
+ g_pui8DFUConfigDescriptor
+};
+
+const tConfigSection g_sDFUInterfaceSection =
+{
+ sizeof(g_pui8DFUInterface),
+ g_pui8DFUInterface
+};
+
+const tConfigSection g_sDFUFunctionalDescSection =
+{
+ sizeof(g_pui8DFUFunctionalDesc),
+ g_pui8DFUFunctionalDesc
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete DFU runtime configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psDFUSections[] =
+{
+ &g_sDFUConfigSection,
+ &g_sDFUInterfaceSection,
+ &g_sDFUFunctionalDescSection
+};
+
+#define NUM_DFU_SECTIONS (sizeof(g_psDFUSections) / \
+ sizeof(g_psDFUSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+tConfigHeader g_sDFUConfigHeader =
+{
+ NUM_DFU_SECTIONS,
+ g_psDFUSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsDFUConfigDescriptors[] =
+{
+ &g_sDFUConfigHeader
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvDFUInstance, tUSBRequest *psUSBRequest);
+static void HandleRequest(void *pvDFUInstance, tUSBRequest *psUSBRequest);
+static void HandleDevice(void *pvDFUInstance, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB DFU devices.
+//
+//*****************************************************************************
+static const tCustomHandlers g_sDFUHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ HandleGetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequest,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ 0,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ //
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ 0,
+
+ //
+ // EndpointHandler
+ //
+ 0,
+
+ //
+ // Device handler.
+ //
+ HandleDevice,
+};
+
+//*****************************************************************************
+//
+// Device instance specific handler. This callback received notifications of
+// events related to handling interface, endpoint and string identifiers when
+// a device is part of a composite device. In this case, the only resource we
+// need which may be renumbered is the DFU runtime interface.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvDFUInstance, uint32_t ui32Request, void *pvRequestData)
+{
+ tDFUInstance *psInst;
+ uint8_t *pui8Data;
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &((tUSBDDFUDevice *)pvDFUInstance)->sPrivateData;
+
+ //
+ // Get a byte pointer to the data.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ //
+ // Which request event have we been passed?
+ //
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ //
+ // Save the change to the interface number.
+ //
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // We are not interested in any other event.
+ //
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a request for a
+// non-standard descriptor is received.
+//
+// \param pvDFUInstance is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure and determines which
+// descriptor is being requested. Assuming the descriptor can be found, it is
+// scheduled for transmission via endpoint zero. If the descriptor cannot be
+// found, the endpoint is stalled to indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleGetDescriptor(void *pvDFUInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Size;
+
+ ASSERT(pvDFUInstance != 0);
+
+ //
+ // Which type of class descriptor are we being asked for? We only support
+ // 1 type - the DFU functional descriptor.
+ //
+ if(((psUSBRequest->wValue >> 8) == USB_DFU_FUNC_DESCRIPTOR_TYPE) &&
+ ((psUSBRequest->wValue & 0xFF) == 0))
+ {
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if((uint16_t)g_pui8DFUFunctionalDesc[0] > psUSBRequest->wLength)
+ {
+ ui32Size = (uint32_t)psUSBRequest->wLength;
+ }
+ else
+ {
+ ui32Size = (uint32_t)g_pui8DFUFunctionalDesc[0];
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, g_pui8DFUFunctionalDesc, ui32Size);
+ }
+ else
+ {
+ //
+ // This was an unknown or invalid request so stall.
+ //
+ USBDCDStallEP0(0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvDFUInstance is the instance data for this HID device.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure. Assuming the request is
+// understood, it is handled and any required response generated. If the
+// request cannot be handled by this device class, endpoint zero is stalled to
+// indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleRequest(void *pvDFUInstance, tUSBRequest *psUSBRequest)
+{
+ tDFUInstance *psInst;
+ tUSBDDFUDevice *psDevice;
+
+ ASSERT(pvDFUInstance != 0);
+
+ //
+ // Get a pointer to the DFU device structure
+ //
+ psDevice = pvDFUInstance;
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &psDevice->sPrivateData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(psUSBRequest->wIndex != psInst->ui8Interface)
+ {
+ return;
+ }
+
+ //
+ // Determine the type of request.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // We have been asked to detach. In this case, we call back to the
+ // application telling it to tidy up and re-enter the boot loader. We
+ // rely upon it doing this on our behalf since this must be done from a
+ // non-interrupt context and this call is most likely in interrupt
+ // context.
+ //
+ case USBD_DFU_REQUEST_DETACH:
+ {
+ //
+ // Tell the application it's time to reenter the boot loader.
+ //
+ psDevice->pfnCallback(psDevice->pvCBData, USBD_DFU_EVENT_DETACH,
+ 0, (void *)0);
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes DFU device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for DFU runtime device operation.
+//! \param psDFUDevice points to a structure containing parameters customizing
+//! the operation of the DFU device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! The \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB DFU APIs.
+//
+//*****************************************************************************
+void *
+USBDDFUCompositeInit(uint32_t ui32Index, tUSBDDFUDevice *psDFUDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tDFUInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDFUDevice);
+ ASSERT(psCompEntry != 0);
+
+ //
+ // Get a pointer to the DFU device instance data pointer
+ //
+ psInst = &psDFUDevice->sPrivateData;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psDFUDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sDFUHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8DFUDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppsDFUConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->ui8Interface = 0;
+
+ //
+ // Initialize the device info structure for the DFU device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psDFUDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the DFU device.
+//!
+//! \param pvDFUInstance is the pointer to the device instance structure as
+//! returned by USBDDFUCompositeInit().
+//!
+//! This function terminates DFU operation for the instance supplied and
+//! removes the device from the USB bus.
+//!
+//! Following this call, the \e pvDFUInstance instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDDFUCompositeTerm(void *pvDFUInstance)
+{
+ tDFUInstance *psInst;
+
+ ASSERT(pvDFUInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &((tUSBDDFUDevice *)pvDFUInstance)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(0);
+
+ psInst->ui32USBBase = 0;
+}
+
+//*****************************************************************************
+//
+//! Removes the current USB device from the bus and transfers control to the
+//! DFU boot loader.
+//!
+//! This function should be called from the application's main loop (i.e. not
+//! in interrupt context) following a callback to the USB DFU callback function
+//! notifying the application of a DETACH request from the host. The function
+//! will prepare the system to switch to DFU mode and transfer control to the
+//! boot loader in preparation for a firmware upgrade from the host.
+//!
+//! The application must ensure that it has completed all necessary shutdown
+//! activities (saved any required data, etc.) before making this call since
+//! the function will not return.
+//!
+//! \return This function does not return.
+//
+//*****************************************************************************
+void
+USBDDFUUpdateBegin(void)
+{
+ //
+ // Terminate the USB device and take us off the bus.
+ //
+ USBDCDTerm(0);
+
+ //
+ // Disable all interrupts.
+ //
+ MAP_IntMasterDisable();
+
+ //
+ // We must make sure we turn off SysTick and its interrupt
+ // before entering the boot loader!
+ //
+ MAP_SysTickIntDisable();
+ MAP_SysTickDisable();
+
+ //
+ // Disable all processor interrupts. Instead of disabling them
+ // one at a time, a direct write to NVIC is done to disable all
+ // peripheral interrupts.
+ //
+ HWREG(NVIC_DIS0) = 0xffffffff;
+ HWREG(NVIC_DIS1) = 0xffffffff;
+
+ //
+ // Reset the USB peripheral
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+ MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Wait for about a second.
+ //
+ MAP_SysCtlDelay(MAP_SysCtlClockGet() / 3);
+
+ //
+ // Re-enable interrupts at the NVIC level.
+ //
+ MAP_IntMasterEnable();
+
+ //
+ // Return control to the boot loader. This is a call to the SVC
+ // handler in the boot loader.
+ //
+ (*((void (*)(void))(*(uint32_t *)0x2c)))();
+
+ //
+ // Should never get here, but just in case.
+ //
+ while(1)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbddfu-rt.h b/usblib/device/usbddfu-rt.h
new file mode 100644
index 0000000..c344207
--- /dev/null
+++ b/usblib/device/usbddfu-rt.h
@@ -0,0 +1,184 @@
+//*****************************************************************************
+//
+// usbddfu-rt.h - Definitions used by runtime DFU class devices.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDDFURT_H__
+#define __USBDDFURT_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup dfu_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8DFUInterface array in bytes.
+//
+//*****************************************************************************
+#define DFUINTERFACE_SIZE (9)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8DFUFunctionalDesc array in bytes.
+//
+//*****************************************************************************
+#define DFUFUNCTIONALDESC_SIZE (9)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the DFU runtime device. This does not
+//! include the configuration descriptor which is automatically ignored by the
+//! composite device class.
+//!
+//! This label is used to compute the value which will be passed to the
+//! USBDCompositeInit function in the ui32Size parameter.
+//
+//*****************************************************************************
+#define COMPOSITE_DDFU_SIZE (DFUINTERFACE_SIZE + DFUFUNCTIONALDESC_SIZE)
+
+//*****************************************************************************
+//
+//! This value is passed to the client via the callback function provided in
+//! the tUSBDDFUDevice structure and indicates that the host has sent a DETACH
+//! request to the DFU interface. This request indicates that the device detach
+//! from the USB bus and reattach in DFU mode in preparation for a firmware
+//! upgrade. Currently, this is the only event that the DFU runtime class
+//! reports to the client.
+//!
+//! When this event is received, the client should call USBDDFUUpdateBegin()
+//! from a non-interrupt context at its earliest opportunity.
+//
+//*****************************************************************************
+#define USBD_DFU_EVENT_DETACH (USBD_DFU_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for
+// DFU devices. The memory for this structure is included in the
+// sPrivateData field in the tUSBDDFUDevice structure passed in the
+// USBDDFUCompositeInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The DFU class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+
+ //
+ // The connection status of the device.
+ //
+ bool bConnected;
+}
+tDFUInstance;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the DFU device. Note that, unlike all other devices, this structure does
+//! not contain any fields which configure the device descriptor sent back to
+//! the host. The DFU runtime device class must be used as part of a composite
+//! device since all it provides is the capability to signal the device to
+//! switch into DFU mode in preparation for a firmware upgrade. Creating a
+//! device with nothing but DFU runtime mode capability is rather pointless
+//! so this is not supported.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of DETACH requests.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which will be sent as the first
+ //! parameter in all calls made to the pfnCallback function.
+ //
+ void * const pvCBData;
+
+ //
+ //! The private instance data for this device class. This
+ //! memory must remain accessible for as long as the DFU device is in use
+ //! and must not be modified by any code outside the DFU class driver.
+ //
+ tDFUInstance sPrivateData;
+}
+tUSBDDFUDevice;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDDFUCompositeInit(uint32_t ui32Index,
+ tUSBDDFUDevice *psDFUDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDDFUCompositeTerm(void *pvDFUInstance);
+extern void USBDDFUUpdateBegin(void);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDDFURT_H__
diff --git a/usblib/device/usbdenum.c b/usblib/device/usbdenum.c
new file mode 100644
index 0000000..94e4cce
--- /dev/null
+++ b/usblib/device/usbdenum.c
@@ -0,0 +1,3190 @@
+//*****************************************************************************
+//
+// usbenum.c - Enumeration code to handle all endpoint zero traffic.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbulpi.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+// External prototypes.
+//
+//*****************************************************************************
+extern tUSBMode g_iUSBMode;
+
+//*****************************************************************************
+//
+// Local functions prototypes.
+//
+//*****************************************************************************
+static void USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDGetConfiguration(void *pvInstance,
+ tUSBRequest *psUSBRequest);
+static void USBDSetConfiguration(void *pvInstance,
+ tUSBRequest *psUSBRequest);
+static void USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest);
+static void USBDEP0StateTx(uint32_t ui32Index);
+static void USBDEP0StateTxConfig(uint32_t ui32Index);
+static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
+ uint16_t ui16Index);
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Indices into the ppui8Halt array to select the IN or OUT endpoint group.
+//
+//*****************************************************************************
+#define HALT_EP_IN 0
+#define HALT_EP_OUT 1
+
+//*****************************************************************************
+//
+// Define the max packet size for endpoint zero.
+//
+//*****************************************************************************
+#define EP0_MAX_PACKET_SIZE 64
+
+//*****************************************************************************
+//
+// This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a
+// device address change is pending.
+//
+//*****************************************************************************
+#define DEV_ADDR_PENDING 0x80000000
+
+//*****************************************************************************
+//
+// This label defines the default configuration number to use after a bus
+// reset. This may be overridden by calling USBDCDSetDefaultConfiguration()
+// during processing of the device reset handler if required.
+//
+//*****************************************************************************
+#define DEFAULT_CONFIG_ID 1
+
+//*****************************************************************************
+//
+// This label defines the number of milliseconds that the remote wake up signal
+// must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
+// states that "the remote wake up device must hold the resume signaling for at
+// least 1ms but for no more than 15ms" so 10mS seems a reasonable choice.
+//
+//*****************************************************************************
+#define REMOTE_WAKEUP_PULSE_MS 10
+
+//*****************************************************************************
+//
+// This label defines the number of milliseconds between the point where we
+// assert the remote wake up signal and calling the client back to tell it that
+// bus operation has been resumed. This value is based on the timings provided
+// in section 7.1.7.7 of the USB 2.0 specification which indicates that the
+// host (which takes over resume signaling when the device's initial signal is
+// detected) must hold the resume signaling for at least 20mS.
+//
+//*****************************************************************************
+#define REMOTE_WAKEUP_READY_MS 20
+
+//*****************************************************************************
+//
+// The LPM states.
+//
+//*****************************************************************************
+#define USBLIB_LPM_STATE_DISABLED 0x00000000
+#define USBLIB_LPM_STATE_AWAKE 0x00000001
+#define USBLIB_LPM_STATE_SLEEP 0x00000002
+
+//*****************************************************************************
+//
+// The buffer for reading data coming into EP0
+//
+//*****************************************************************************
+static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
+
+//*****************************************************************************
+//
+// This is 480000000/60000000 or a PLL Divide of 8.
+//
+//*****************************************************************************
+static uint32_t g_ui32PLLDiv = 8;
+
+//*****************************************************************************
+//
+// Holds the ULPI configuration.
+//
+//*****************************************************************************
+static uint32_t g_ui32ULPISupport;
+
+//*****************************************************************************
+//
+// This is the instance data for the USB controller itself and not a USB
+// device class.
+//
+//*****************************************************************************
+tDCDInstance g_psDCDInst[1];
+
+//*****************************************************************************
+//
+// This is the currently active class in use by USBLib. There is only one
+// of these per USB controller and no device has more than one controller.
+//
+//*****************************************************************************
+tDeviceInfo *g_ppsDevInfo[1];
+
+//*****************************************************************************
+//
+// Function table to handle standard requests.
+//
+//*****************************************************************************
+static const tStdRequest g_psUSBDStdRequests[] =
+{
+ USBDGetStatus,
+ USBDClearFeature,
+ 0,
+ USBDSetFeature,
+ 0,
+ USBDSetAddress,
+ USBDGetDescriptor,
+ USBDSetDescriptor,
+ USBDGetConfiguration,
+ USBDSetConfiguration,
+ USBDGetInterface,
+ USBDSetInterface,
+ USBDSyncFrame
+};
+
+//*****************************************************************************
+//
+// Functions accessible by USBLIB clients.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Initialize an instance of the tDeviceInfo structure.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized.
+//! \param psDeviceInfo is a pointer to the tDeviceInfo structure that needs
+//! to be initialized.
+//!
+//! This function must be called by a USB device class
+//! instance to initialize the basic tDeviceInfo required for all USB device
+//! class modules. This is typically called in the initialization routine for
+//! USB device class. For example in usbdaudio.c that supports USB device
+//! audio classes, this function is called in the USBDAudioCompositeInit()
+//! function which is used for both composite and non-composites instances of
+//! the USB audio class.
+//!
+//! \note This function should not be called directly by applications.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDDeviceInfoInit(uint32_t ui32Index, tDeviceInfo *psDeviceInfo)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDeviceInfo != 0);
+
+ //
+ // Save the USB interrupt number.
+ //
+ g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C129;
+ }
+
+ //
+ // Disable LPM support by default.
+ //
+ g_psDCDInst[0].ui32LPMState = 0;
+
+ //
+ // Initialize a couple of fields in the device state structure.
+ //
+ g_psDCDInst[0].ui32Configuration = DEFAULT_CONFIG_ID;
+ g_psDCDInst[0].ui32DefaultConfiguration = DEFAULT_CONFIG_ID;
+
+ g_psDCDInst[0].iEP0State = eUSBStateIdle;
+
+ //
+ // Default to the state where remote wake up is disabled.
+ //
+ g_psDCDInst[0].ui8Status = 0;
+ g_psDCDInst[0].bRemoteWakeup = false;
+
+ //
+ // Determine the self- or bus-powered state based on the flags the
+ // user provided.
+ //
+ g_psDCDInst[0].bPwrSrcSet = false;
+}
+
+//*****************************************************************************
+//
+//! Initialize the USB library device control driver for a given hardware
+//! controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized.
+//! \param psDevice is a pointer to a structure containing information that
+//! the USB library requires to support operation of this application's
+//! device. The structure contains event handler callbacks and pointers to the
+//! various standard descriptors that the device wishes to publish to the
+//! host.
+//! \param pvDCDCBData is the callback data for any device callbacks.
+//!
+//! This function must be called by a device class which wishes to operate
+//! as a USB device and is not typically called by an application. This
+//! function initializes the USB device control driver for the given
+//! controller and saves the device information for future use. Prior to
+//! returning from this function, the device is connected to the USB bus.
+//! Following return, the caller can expect to receive a callback to the
+//! supplied <tt>pfnResetHandler</tt> function when a host connects to the
+//! device. The \e pvDCDCBData contains a pointer to data that is returned
+//! with the DCD calls back to the function in the psDevice->psCallbacks()
+//! functions.
+//!
+//! The device information structure passed in \e psDevice must remain
+//! unchanged between this call and any matching call to USBDCDTerm() because
+//! it is not copied by the USB library.
+//!
+//! The USBStackModeSet() function can be called with eUSBModeForceDevice in
+//! order to cause the USB library to force the USB operating mode to a device
+//! controller. This allows the application to used the USBVBUS and USBID pins
+//! as GPIOs on devices that support forcing OTG to operate as a device only
+//! controller. By default the USB library will assume that the USBVBUS and
+//! USBID pins are configured as USB pins and not GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDInit(uint32_t ui32Index, tDeviceInfo *psDevice, void *pvDCDCBData)
+{
+ const tConfigHeader *psHdr;
+ const tConfigDescriptor *psDesc;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psDevice != 0);
+
+ g_ppsDevInfo[0] = psDevice;
+ g_psDCDInst[0].pvCBData = pvDCDCBData;
+
+ //
+ // Initialize the Device Info structure for a USB device instance.
+ //
+ USBDCDDeviceInfoInit(ui32Index, psDevice);
+
+ //
+ // Should not call this if the stack is in host mode.
+ //
+ ASSERT(g_iUSBMode != eUSBModeHost);
+ ASSERT(g_iUSBMode != eUSBModeForceHost);
+
+ //
+ // Default to device mode if no mode was set.
+ //
+ if(g_iUSBMode == eUSBModeNone)
+ {
+ g_iUSBMode = eUSBModeDevice;
+ }
+
+ //
+ // Only do hardware update if the stack is in not in OTG mode.
+ //
+ if(g_iUSBMode != eUSBModeOTG)
+ {
+ //
+ // Reset the USB controller.
+ //
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Set the PLL to USB clock divider.
+ //
+ USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_INTERNAL);
+
+ //
+ // Configure ULPI support.
+ //
+ if(g_ui32ULPISupport != USBLIB_FEATURE_ULPI_NONE)
+ {
+ USBULPIEnable(USB0_BASE);
+
+ if(g_ui32ULPISupport & USBLIB_FEATURE_ULPI_HS)
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_HS);
+ }
+ else
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_FS);
+ }
+ }
+ else
+ {
+ USBULPIDisable(USB0_BASE);
+ }
+
+ //
+ // Force device mode if requested.
+ //
+ if(g_iUSBMode == eUSBModeForceDevice)
+ {
+ MAP_USBDevMode(USB0_BASE);
+ }
+ else if(g_iUSBMode == eUSBModeDevice)
+ {
+ //
+ // To run in active device mode the OTG signals must be active.
+ // This allows disconnect to be detected by the controller.
+ //
+ MAP_USBOTGMode(USB0_BASE);
+ }
+
+ //
+ // In all other cases, set the mode to device this function should not
+ // be called in OTG mode.
+ //
+ g_iUSBMode = eUSBModeDevice;
+
+ //
+ // Enable or disable LPM functionality.
+ //
+ if(g_psDCDInst[0].ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ //
+ // Enable full LPM support and all LPM related interrupts.
+ // USB_INTLPM_ERROR is not enabled since there is no response to
+ // this interrupt.
+ //
+ USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_EN);
+ USBLPMIntEnable(USB0_BASE, USB_INTLPM_RESUME | USB_INTLPM_ERROR |
+ USB_INTLPM_ACK | USB_INTLPM_NYET);
+ USBDevLPMEnable(USB0_BASE);
+
+ //
+ // Awake by default.
+ //
+ g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
+ }
+ else
+ {
+ USBDevLPMDisable(USB0_BASE);
+ USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_NONE);
+ g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_DISABLED;
+ }
+ }
+
+ //
+ // Initialize the USB DMA interface.
+ //
+ g_psDCDInst[0].psDMAInstance = USBLibDMAInit(0);
+
+ //
+ // Initialize the USB tick module.
+ //
+ InternalUSBTickInit();
+
+ //
+ // Get a pointer to the default configuration descriptor.
+ //
+ psHdr = psDevice->ppsConfigDescriptors[
+ g_psDCDInst[0].ui32DefaultConfiguration - 1];
+ psDesc = (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
+
+ if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) == USB_CONF_ATTR_SELF_PWR)
+ {
+ g_psDCDInst[0].ui8Status |= USB_STATUS_SELF_PWR;
+ }
+ else
+ {
+ g_psDCDInst[0].ui8Status &= ~USB_STATUS_SELF_PWR;
+ }
+
+ //
+ // Only do hardware update if the stack is not in OTG mode.
+ //
+ if(g_iUSBMode != eUSBModeOTG)
+ {
+ //
+ // Get the current interrupt status.to clear all pending USB
+ // interrupts.
+ //
+ MAP_USBIntStatusControl(USB0_BASE);
+ MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Enable USB Interrupts.
+ //
+ MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
+ USB_INTCTRL_DISCONNECT |
+ USB_INTCTRL_RESUME |
+ USB_INTCTRL_SUSPEND |
+ USB_INTCTRL_SOF);
+ MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Attach the device using the soft connect.
+ //
+ MAP_USBDevConnect(USB0_BASE);
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_psDCDInst[0].ui32IntNum);
+ }
+}
+
+//*****************************************************************************
+//
+//! Free the USB library device control driver for a given hardware controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! freed.
+//!
+//! This function should be called by an application if it no longer requires
+//! the use of a given USB controller to support its operation as a USB device.
+//! It frees the controller for use by another client.
+//!
+//! It is the caller's responsibility to remove its device from the USB bus
+//! prior to calling this function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDTerm(uint32_t ui32Index)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Disable the USB interrupts.
+ //
+ OS_INT_DISABLE(g_psDCDInst[0].ui32IntNum);
+
+ //
+ // Reset the tick handlers so that they can be reconfigured when and if
+ // USBDCDInit() is called.
+ //
+ InternalUSBTickReset();
+
+ //
+ // No active device.
+ //
+ g_ppsDevInfo[0] = 0;
+
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Detach the device using the soft connect.
+ //
+ MAP_USBDevDisconnect(USB0_BASE);
+
+ //
+ // Clear any pending interrupts.
+ //
+ MAP_USBIntStatusControl(USB0_BASE);
+ MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Turn off USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLDisable();
+
+ //
+ // Disable the USB peripheral
+ //
+ MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
+}
+
+//*****************************************************************************
+//
+//! This function starts the request for data from the host on endpoint zero.
+//!
+//! \param ui32Index is the index of the USB controller from which the data
+//! is being requested.
+//! \param pui8Data is a pointer to the buffer to fill with data from the USB
+//! host.
+//! \param ui32Size is the size of the buffer or data to return from the USB
+//! host.
+//!
+//! This function handles retrieving data from the host when a custom command
+//! has been issued on endpoint zero. If the application needs notification
+//! when the data has been received,
+//! <tt>psCallbacks->pfnDataReceived()</tt> in the tDeviceInfo structure
+//! must contain valid function pointer. In nearly all cases this is necessary
+//! because the caller of this function would likely need to know that the data
+//! requested was received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDRequestDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Enter the RX state on end point 0.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateRx;
+
+ //
+ // Save the pointer to the data.
+ //
+ g_psDCDInst[0].pui8EP0Data = pui8Data;
+
+ //
+ // Location to save the current number of bytes received.
+ //
+ g_psDCDInst[0].ui32OUTDataSize = ui32Size;
+
+ //
+ // Bytes remaining to be received.
+ //
+ g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
+}
+
+//*****************************************************************************
+//
+//! This function requests transfer of data to the host on endpoint zero.
+//!
+//! \param ui32Index is the index of the USB controller which is to be used to
+//! send the data.
+//! \param pui8Data is a pointer to the buffer to send via endpoint zero.
+//! \param ui32Size is the amount of data to send in bytes.
+//!
+//! This function handles sending data to the host when a custom command is
+//! issued or non-standard descriptor has been requested on endpoint zero. If
+//! the application needs notification when this is complete,
+//! <tt>psCallbacks->pfnDataSent</tt> in the tDeviceInfo structure must
+//! contain a valid function pointer. This callback could be used to free up
+//! the buffer passed into this function in the \e pui8Data parameter. The
+//! contents of the \e pui8Data buffer must remain unchanged until the
+//! <tt>pfnDataSent</tt> callback is received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDSendDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_psDCDInst[0].pui8EP0Data = pui8Data;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
+
+ //
+ // Save the total size of the data sent.
+ //
+ g_psDCDInst[0].ui32OUTDataSize = ui32Size;
+
+ //
+ // Now in the transmit data state.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+//! This function sets the default configuration for the device.
+//!
+//! \param ui32Index is the index of the USB controller whose default
+//! configuration is to be set.
+//! \param ui32DefaultConfig is the configuration identifier (byte 6 of the
+//! standard configuration descriptor) which is to be presented to the host
+//! as the default configuration in cases where the configuration descriptor is
+//! queried prior to any specific configuration being set.
+//!
+//! This function allows a device to override the default configuration
+//! descriptor that will be returned to a host whenever it is queried prior
+//! to a specific configuration having been set. The parameter passed must
+//! equal one of the configuration identifiers found in the
+//! <tt>ppsConfigDescriptors</tt> array for the device.
+//!
+//! If this function is not called, the USB library will return the first
+//! configuration in the <tt>ppsConfigDescriptors</tt> array as the default
+//! configuration.
+//!
+//! \note The USB device stack assumes that the configuration IDs (byte 6 of
+//! the configuration descriptor, <tt>bConfigurationValue</tt>) stored within
+//! the configuration descriptor array, <tt>ppsConfigDescriptors</tt>,
+//! are equal to the array index + 1. In other words, the first entry in the
+//! array must contain a descriptor with <tt>bConfigurationValue</tt> 1, the
+//! second must have <tt>bConfigurationValue</tt> 2 and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDSetDefaultConfiguration(uint32_t ui32Index, uint32_t ui32DefaultConfig)
+{
+ ASSERT(ui32Index == 0);
+
+ g_psDCDInst[0].ui32DefaultConfiguration = ui32DefaultConfig;
+}
+
+//*****************************************************************************
+//
+//! This function generates a stall condition on endpoint zero.
+//!
+//! \param ui32Index is the index of the USB controller whose endpoint zero is
+//! to be stalled.
+//!
+//! This function is typically called to signal an error condition to the host
+//! when an unsupported request is received by the device. It should be
+//! called from within the callback itself (in interrupt context) and not
+//! deferred until later since it affects the operation of the endpoint zero
+//! state machine in the USB library.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDStallEP0(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Stall the endpoint in question.
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, USB_EP_0, USB_EP_DEV_OUT);
+
+ //
+ // Enter the stalled state.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateStall;
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the library.
+//!
+//! \param ui32Index is the index of the USB controller whose device power
+//! status is being reported.
+//! \param ui8Power indicates the current power status, either
+//! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus- or self-powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the library to allow correct responses to be provided when
+//! the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDCDPowerStatusSet(uint32_t ui32Index, uint8_t ui8Power)
+{
+ //
+ // Check for valid parameters.
+ //
+ ASSERT((ui8Power == USB_STATUS_BUS_PWR) ||
+ (ui8Power == USB_STATUS_SELF_PWR));
+ ASSERT(ui32Index == 0);
+
+ //
+ // Update the device status with the new power status flag.
+ //
+ g_psDCDInst[0].bPwrSrcSet = true;
+ g_psDCDInst[0].ui8Status &= ~USB_STATUS_PWR_M;
+ g_psDCDInst[0].ui8Status |= ui8Power;
+}
+#endif
+
+//*****************************************************************************
+//
+//! This function is used to enable/disable features of the USB library.
+//!
+//! \param ui32Index is the index of the USB controller whose device power
+//! status is being reported.
+//! \param ui32Feature indicates which feature is being changed.
+//! \param pvFeature holds the data that controls the feature request.
+//!
+//! Applications can change the support levels of some USB library features by
+//! calling this function to enable/disable certain features. This function
+//! should normally be called before class initialization functions since the
+//! settings need to be in place before enumeration starts. This allows the
+//! USB library to properly respond to all enumeration requests. The
+//! \e ui32Feature value is one of the \b USBLIB_FEATURE_* defines which
+//! controls the type of request being made. The \e pvFeature is a feature
+//! specific data structure that is determined by the value passed in the
+//! \e ui32Feature parameter.
+//!
+//! \return Returns \b true if the feature was successfully changed and returns
+//! \b false if the feature was not able to be changed or is not supported.
+//
+//*****************************************************************************
+bool
+USBDCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
+{
+ bool bRetCode;
+ tLPMFeature *psLPMFeature;
+
+ bRetCode = true;
+
+ switch(ui32Feature)
+ {
+ case USBLIB_FEATURE_LPM:
+ {
+ //
+ // Save the LPM setting.
+ //
+ psLPMFeature = (tLPMFeature *)pvFeature;
+
+ if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ g_psDCDInst[0].ui32Features |= USBLIB_FEATURE_LPM_EN;
+ }
+ else
+ {
+ g_psDCDInst[0].ui32Features &= ~USBLIB_FEATURE_LPM_EN;
+ }
+
+ break;
+ }
+ case USBLIB_FEATURE_USBPLL:
+ {
+ //
+ // If the PLL rate is not evenly divisible by 60MHz then
+ // do not set it.
+ //
+ if((*(uint32_t *)pvFeature % 60000000) != 0)
+ {
+ bRetCode = false;
+ }
+ else
+ {
+ //
+ // Save the new PLL rate.
+ //
+ g_ui32PLLDiv = (*(uint32_t *)pvFeature / 60000000);
+ }
+ break;
+ }
+ case USBLIB_FEATURE_USBULPI:
+ {
+ //
+ // Save the ULPI support level.
+ //
+ g_ui32ULPISupport = *(uint32_t *)pvFeature;
+
+ break;
+ }
+ case USBLIB_FEATURE_POWER:
+ {
+ //
+ // Update the device status with the new power status flag.
+ //
+ g_psDCDInst[0].bPwrSrcSet = true;
+ g_psDCDInst[0].ui8Status &= ~USBLIB_FEATURE_POWER_SELF;
+ g_psDCDInst[0].ui8Status |= (uint8_t)(*(uint32_t *)pvFeature);
+
+ break;
+ }
+ default:
+ {
+ bRetCode = false;
+ break;
+ }
+ }
+ return(bRetCode);
+}
+
+//*****************************************************************************
+//
+//! Requests an LPM remote wake up to resume communication when in an LPM sleep
+//! state.
+//!
+//! \param ui32Index is the index of the USB controller that will request
+//! a bus wake up.
+//!
+//! When the host controller puts the device into an LPM sleep state, the
+//! device can call this function to initiate LPM remote wake up signaling to
+//! the host. If the remote wake up feature has been enabled by the host, this
+//! will cause the host to respond to the LPM remote wake request and resume
+//! normal operation. If the host has disabled remote wake up, \b false is
+//! returned to indicate that the wake up request was not successful.
+//!
+//! \return Returns \b true if the remote wake up request has been sent or
+//!\b false if LPM remote wake up is disabled.
+//
+//*****************************************************************************
+bool
+USBDCDRemoteWakeLPM(uint32_t ui32Index)
+{
+ if(USBLPMRemoteWakeEnabled(USB0_BASE))
+ {
+ USBDevLPMRemoteWake(USB0_BASE);
+ return(true);
+ }
+ return(false);
+}
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param ui32Index is the index of the USB controller that will request
+//! a bus wake up.
+//!
+//! When the bus is suspended, an application which supports remote wake up
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wake up signaling to the host. If the remote
+//! wake up feature has not been disabled by the host, this will cause the bus
+//! to resume operation within 20mS. If the host has disabled remote wake up,
+//! \b false will be returned to indicate that the wake up request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wake up is not disabled and the
+//! signaling was started or \b false if remote wake up is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDCDRemoteWakeupRequest(uint32_t ui32Index)
+{
+ //
+ // Check for parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Is remote wake up signaling currently enabled?
+ //
+ if(g_psDCDInst[0].ui8Status & USB_STATUS_REMOTE_WAKE)
+ {
+ //
+ // The host has not disabled remote wake up. Are we still in the
+ // middle of a previous wake up sequence?
+ //
+ if(!g_psDCDInst[0].bRemoteWakeup)
+ {
+ //
+ // No - we are not in the middle of a wake up sequence so start
+ // one here.
+ //
+ g_psDCDInst[0].ui8RemoteWakeupCount = 0;
+ g_psDCDInst[0].bRemoteWakeup = true;
+ MAP_USBHostResume(USB0_BASE, true);
+ return(true);
+ }
+ }
+
+ //
+ // If we drop through to here, signaling was not initiated so return
+ // false.
+ return(false);
+}
+
+//*****************************************************************************
+//
+// Internal Functions, not to be called by applications
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This internal function is called on the SOF interrupt to process any
+// outstanding remote wake up requests.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDeviceResumeTickHandler(tDCDInstance *psDevInst)
+{
+ if(g_psDCDInst[0].bRemoteWakeup)
+ {
+ //
+ // Increment the millisecond counter we use to time the resume
+ // signaling.
+ //
+ g_psDCDInst[0].ui8RemoteWakeupCount++;
+
+ //
+ // Have we reached the 10mS mark? If so, we need to turn the signaling
+ // off again.
+ //
+ if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_PULSE_MS)
+ {
+ MAP_USBHostResume(USB0_BASE, false);
+ }
+
+ //
+ // Have we reached the point at which we can tell the client that the
+ // bus has resumed? The controller does not give us an interrupt if we
+ // initiated the wake up signaling so we just wait until 20mS have
+ // passed then tell the client all is well.
+ //
+ if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_READY_MS)
+ {
+ //
+ // We are now finished with the remote wake up signaling.
+ //
+ g_psDCDInst[0].bRemoteWakeup = false;
+
+ //
+ // If the client has registered a resume callback, call it. In the
+ // case of a remote wake up request, we do not get a resume
+ // interrupt from the controller so we need to fake it here.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(
+ g_psDCDInst[0].pvCBData);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function reads a request data packet and dispatches it to
+// either a standard request handler or the registered device request
+// callback depending upon the request type.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDReadAndDispatchRequest(uint32_t ui32Index)
+{
+ uint32_t ui32Size;
+ tUSBRequest *psRequest;
+
+ //
+ // Cast the buffer to a request structure.
+ //
+ psRequest = (tUSBRequest *)g_pui8DataBufferIn;
+
+ //
+ // Set the buffer size.
+ //
+ ui32Size = EP0_MAX_PACKET_SIZE;
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0, g_pui8DataBufferIn,
+ &ui32Size);
+
+ //
+ // If there was a null setup packet then just return.
+ //
+ if(!ui32Size)
+ {
+ return;
+ }
+
+ //
+ // See if this is a standard request or not.
+ //
+ if((psRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
+ {
+ //
+ // Since this is not a standard request, see if there is
+ // an external handler present.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler(
+ g_psDCDInst[0].pvCBData,
+ psRequest);
+ }
+ else
+ {
+ //
+ // If there is no handler then stall this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ }
+ else
+ {
+ //
+ // Assure that the jump table is not out of bounds.
+ //
+ if((psRequest->bRequest <
+ (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) &&
+ (g_psUSBDStdRequests[psRequest->bRequest] != 0))
+ {
+ //
+ // Jump table to the appropriate handler.
+ //
+ g_psUSBDStdRequests[psRequest->bRequest](&g_psDCDInst[0],
+ psRequest);
+ }
+ else
+ {
+ //
+ // If there is no handler then stall this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This is interrupt handler for endpoint zero.
+//
+// This function handles all interrupts on endpoint zero in order to maintain
+// the state needed for the control endpoint on endpoint zero. In order to
+// successfully enumerate and handle all USB standard requests, all requests
+// on endpoint zero must pass through this function. The endpoint has the
+// following states: \b eUSBStateIdle, \b eUSBStateTx, \b eUSBStateRx,
+// \b eUSBStateStall, and \b eUSBStateStatus. In the \b eUSBStateIdle
+// state the USB controller has not received the start of a request, and once
+// it does receive the data for the request it will either enter the
+// \b eUSBStateTx, \b eUSBStateRx, or \b eUSBStateStall depending on the
+// command. If the controller enters the \b eUSBStateTx or \b eUSBStateRx
+// then once all data has been sent or received, it must pass through the
+// \b eUSBStateStatus state to allow the host to acknowledge completion of
+// the request. The \b eUSBStateStall is entered from \b eUSBStateIdle in
+// the event that the USB request was not valid. Both the \b eUSBStateStall
+// and \b eUSBStateStatus are transitional states that return to the
+// \b eUSBStateIdle state.
+//
+// \return None.
+//
+// eUSBStateIdle -*--> eUSBStateTx -*-> eUSBStateStatus -*->eUSBStateIdle
+// | | |
+// |--> eUSBStateRx |
+// | |
+// |--> eUSBStateStall ---------->--------
+//
+// ----------------------------------------------------------------
+// | Current State | State 0 | State 1 |
+// | --------------------|-------------------|----------------------
+// | eUSBStateIdle | eUSBStateTx/RX | eUSBStateStall |
+// | eUSBStateTx | eUSBStateStatus | |
+// | eUSBStateRx | eUSBStateStatus | |
+// | eUSBStateStatus | eUSBStateIdle | |
+// | eUSBStateStall | eUSBStateIdle | |
+// ----------------------------------------------------------------
+//
+//*****************************************************************************
+void
+USBDeviceEnumHandler(tDCDInstance *pDevInstance)
+{
+ uint32_t ui32EPStatus, ui32DataSize;
+
+ //
+ // Get the end point 0 status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
+
+ switch(pDevInstance->iEP0State)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // eUSBStateTx or eUSBStateRx back to eUSBStateIdle.
+ //
+ case eUSBStateStatus:
+ {
+ //
+ // Just go back to the idle state.
+ //
+ pDevInstance->iEP0State = eUSBStateIdle;
+
+ //
+ // If there is a pending address change then set the address.
+ //
+ if(pDevInstance->ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ //
+ // Clear the pending address change and set the address.
+ //
+ pDevInstance->ui32DevAddress &= ~DEV_ADDR_PENDING;
+ MAP_USBDevAddrSet(USB0_BASE, pDevInstance->ui32DevAddress);
+ }
+
+ //
+ // If a new packet is already pending, we need to read it
+ // and handle whatever request it contains.
+ //
+ if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
+ {
+ //
+ // Process the newly arrived packet.
+ //
+ USBDReadAndDispatchRequest(0);
+ }
+ break;
+ }
+
+ //
+ // In the IDLE state the code is waiting to receive data from the host.
+ //
+ case eUSBStateIdle:
+ {
+ //
+ // Is there a packet waiting for us?
+ //
+ if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
+ {
+ //
+ // Yes - process it.
+ //
+ USBDReadAndDispatchRequest(0);
+ }
+ break;
+ }
+
+ //
+ // Data is still being sent to the host so handle this in the
+ // EP0StateTx() function.
+ //
+ case eUSBStateTx:
+ {
+ USBDEP0StateTx(0);
+ break;
+ }
+
+ //
+ // We are still in the middle of sending the configuration descriptor
+ // so handle this in the EP0StateTxConfig() function.
+ //
+ case eUSBStateTxConfig:
+ {
+ USBDEP0StateTxConfig(0);
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint zero.
+ //
+ case eUSBStateRx:
+ {
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ if(pDevInstance->ui32EP0DataRemain > EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Don't send more than EP0_MAX_PACKET_SIZE bytes.
+ //
+ ui32DataSize = EP0_MAX_PACKET_SIZE;
+ }
+ else
+ {
+ //
+ // There was space so send the remaining bytes.
+ //
+ ui32DataSize = pDevInstance->ui32EP0DataRemain;
+ }
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0,
+ pDevInstance->pui8EP0Data, &ui32DataSize);
+
+ //
+ // If there we not more that EP0_MAX_PACKET_SIZE or more bytes
+ // remaining then this transfer is complete. If there were exactly
+ // EP0_MAX_PACKET_SIZE remaining then there still needs to be
+ // null packet sent before this is complete.
+ //
+ if(pDevInstance->ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Return to the idle state.
+ //
+ pDevInstance->iEP0State = eUSBStateStatus;
+
+ //
+ // If there is a receive callback then call it.
+ //
+ if((g_ppsDevInfo[0]->psCallbacks->pfnDataReceived) &&
+ (pDevInstance->ui32OUTDataSize != 0))
+ {
+ //
+ // Call the custom receive handler to handle the data
+ // that was received.
+ //
+ g_ppsDevInfo[0]->psCallbacks->pfnDataReceived(
+ g_psDCDInst[0].pvCBData,
+ pDevInstance->ui32OUTDataSize);
+
+ //
+ // Indicate that there is no longer any data being waited
+ // on.
+ //
+ pDevInstance->ui32OUTDataSize = 0;
+ }
+
+ //
+ // Need to ACK the data on end point 0 in this case and set the
+ // data end as this is the last of the data.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+ }
+ else
+ {
+ //
+ // Need to ACK the data on end point 0 in this case
+ // without setting data end because more data is coming.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+ }
+
+ //
+ // Advance the pointer.
+ //
+ pDevInstance->pui8EP0Data += ui32DataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ pDevInstance->ui32EP0DataRemain -= ui32DataSize;
+
+ break;
+ }
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case eUSBStateStall:
+ {
+ //
+ // If we sent a stall then acknowledge this interrupt.
+ //
+ if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
+ {
+ //
+ // Clear the Setup End condition.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, USB_EP_0,
+ USB_DEV_EP0_SENT_STALL);
+
+ //
+ // Reset the global end point 0 state to IDLE.
+ //
+ pDevInstance->iEP0State = eUSBStateIdle;
+
+ }
+ break;
+ }
+ //
+ // Halt on an unknown state, but only in DEBUG mode builds.
+ //
+ default:
+ {
+ ASSERT(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles bus reset notifications.
+//
+// This function is called from the low level USB interrupt handler whenever
+// a bus reset is detected. It performs tidy-up as required and resets the
+// configuration back to defaults in preparation for descriptor queries from
+// the host.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDeviceEnumResetHandler(tDCDInstance *pDevInstance)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Disable remote wake up signaling (as per USB 2.0 spec 9.1.1.6).
+ //
+ pDevInstance->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+ pDevInstance->bRemoteWakeup = false;
+
+ //
+ // Call the device dependent code to indicate a bus reset has occurred.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnResetHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnResetHandler(g_psDCDInst[0].pvCBData);
+ }
+
+ //
+ // Reset the default configuration identifier and alternate function
+ // selections.
+ //
+ pDevInstance->ui32Configuration = pDevInstance->ui32DefaultConfiguration;
+
+ for(ui32Loop = 0; ui32Loop < USB_MAX_INTERFACES_PER_DEVICE; ui32Loop++)
+ {
+ pDevInstance->pui8AltSetting[ui32Loop] = (uint8_t)0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_STATUS standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the request type and endpoint number if endpoint
+// status is requested.
+//
+// This function handles responses to a Get Status request from the host
+// controller. A status request can be for the device, an interface or an
+// endpoint. If any other type of request is made this function will cause
+// a stall condition to indicate that the command is not supported. The
+// \e psUSBRequest structure holds the type of the request in the
+// bmRequestType field. If the type indicates that this is a request for an
+// endpoint's status, then the wIndex field holds the endpoint number.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ uint16_t ui16Data, ui16Index;
+ uint32_t ui32Dir;
+ tDCDInstance *psUSBControl;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 without setting last data as there
+ // will be a data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // Determine what type of status was requested.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This was a Device Status request.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Return the current status for the device.
+ //
+ ui16Data = (uint16_t)psUSBControl->ui8Status;
+
+ break;
+ }
+
+ //
+ // This was a Interface status request.
+ //
+ case USB_RTYPE_INTERFACE:
+ {
+ //
+ // Interface status always returns 0.
+ //
+ ui16Data = (uint16_t)0;
+
+ break;
+ }
+
+ //
+ // This was an endpoint status request.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ //
+ // Which endpoint are we dealing with?
+ //
+ ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Check if this was a valid endpoint request.
+ //
+ if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ return;
+ }
+ else
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
+ USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
+
+ //
+ // Get the current halt status for this endpoint.
+ //
+ ui16Data =
+ (uint16_t)psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1];
+ }
+ break;
+ }
+
+ //
+ // This was an unknown request.
+ //
+ default:
+ {
+ //
+ // Anything else causes a stall condition to indicate that the
+ // command was not supported.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+
+ //
+ // Send the two byte status response.
+ //
+ psUSBControl->ui32EP0DataRemain = 2;
+ psUSBControl->pui8EP0Data = (uint8_t *)&ui16Data;
+
+ //
+ // Send the response.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the CLEAR_FEATURE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the options for the Clear Feature USB request.
+//
+// This function handles device or endpoint clear feature requests. The
+// \e psUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. The device can only
+// clear the Remote Wake feature. This device request should only be made if
+// the descriptor indicates that Remote Wake is implemented by the device.
+// Endpoints can only clear a halt on a given endpoint. If any other
+// requests are made, then the device will stall the request to indicate to
+// the host that the command was not supported.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ tDCDInstance *psUSBControl;
+ uint32_t ui32Dir;
+ uint16_t ui16Index;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Determine what type of status was requested.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a clear feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is can be cleared by this function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
+ {
+ //
+ // Clear the remote wake up state.
+ //
+ psUSBControl->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+ }
+ else
+ {
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This is a clear feature request at the endpoint level.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ //
+ // Which endpoint are we dealing with?
+ //
+ ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Not a valid endpoint.
+ //
+ if((ui16Index == 0) || (ui16Index > NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Only the halt feature is supported.
+ //
+ if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
+ USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
+
+ //
+ // Clear the halt condition on this endpoint.
+ //
+ psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 0;
+
+ if(ui32Dir == HALT_EP_IN)
+ {
+ MAP_USBDevEndpointStallClear(USB0_BASE,
+ IndexToUSBEP(ui16Index),
+ USB_EP_DEV_IN);
+ }
+ else
+ {
+ MAP_USBDevEndpointStallClear(USB0_BASE,
+ IndexToUSBEP(ui16Index),
+ USB_EP_DEV_OUT);
+ }
+ }
+ else
+ {
+ //
+ // If any other feature is requested, this is an error.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_FEATURE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the feature in the wValue field of the USB
+// request.
+//
+// This function handles device or endpoint set feature requests. The
+// \e psUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. The device can only
+// set the Remote Wake feature. This device request should only be made if the
+// descriptor indicates that Remote Wake is implemented by the device.
+// Endpoint requests can only issue a halt on a given endpoint. If any other
+// requests are made, then the device will stall the request to indicate to the
+// host that the command was not supported.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ tDCDInstance *psUSBControl;
+ uint16_t ui16Index;
+ uint32_t ui32Dir;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Determine what type of status was requested.
+ //
+ switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a set feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is the only feature that can be set by this
+ // function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
+ {
+ //
+ // Set the remote wake up state.
+ //
+ psUSBControl->ui8Status |= USB_STATUS_REMOTE_WAKE;
+ }
+ else
+ {
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This is a set feature request at the endpoint level.
+ //
+ case USB_RTYPE_ENDPOINT:
+ {
+ //
+ // Which endpoint are we dealing with?
+ //
+ ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
+
+ //
+ // Not a valid endpoint?
+ //
+ if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
+ {
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Only the Halt feature can be set.
+ //
+ if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
+ {
+ //
+ // Are we dealing with an IN or OUT endpoint?
+ //
+ ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
+ USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
+
+ //
+ // Clear the halt condition on this endpoint.
+ //
+ psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 1;
+ }
+ else
+ {
+ //
+ // No other requests are supported.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_ADDRESS standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the new address to use in the wValue field of the
+// USB request.
+//
+// This function is called to handle the change of address request from the
+// host controller. This can only start the sequence as the host must
+// acknowledge that the device has changed address. Thus this function sets
+// the address change as pending until the status phase of the request has
+// been completed successfully. This prevents the devices address from
+// changing and not properly responding to the status phase.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ tDCDInstance *psUSBControl;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Save the device address as we cannot change address until the status
+ // phase is complete.
+ //
+ psUSBControl->ui32DevAddress = psUSBRequest->wValue | DEV_ADDR_PENDING;
+
+ //
+ // Transition directly to the status state since there is no data phase
+ // for this request.
+ //
+ psUSBControl->iEP0State = eUSBStateStatus;
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_DESCRIPTOR standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function will return most of the descriptors requested by the host
+// controller. The descriptor specified by \e
+// pvInstance->psInfo->pui8DeviceDescriptor will be returned when the device
+// descriptor is requested. If a request for a specific configuration
+// descriptor is made, then the appropriate descriptor from the \e
+// g_pConfigDescriptors will be returned. When a request for a string
+// descriptor is made, the appropriate string from the
+// \e pvInstance->psInfo->pStringDescriptors will be returned. If the
+// \e pvInstance->psInfo->psCallbacks->GetDescriptor is specified it will be
+// called to handle the request. In this case it must call the
+// USBDCDSendDataEP0() function to send the data to the host controller. If
+// the callback is not specified, and the descriptor request is not for a
+// device, configuration, or string descriptor then this function will stall
+// the request to indicate that the request was not supported by the device.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ bool bConfig;
+ tDCDInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+ const tConfigHeader *psConfig;
+ const tDeviceDescriptor *psDeviceDesc;
+ uint8_t ui8Index;
+ int32_t i32Index;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+ psDevice = g_ppsDevInfo[0];
+
+ //
+ // Need to ACK the data on end point 0 without setting last data as there
+ // will be a data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // Assume we are not sending the configuration descriptor until we
+ // determine otherwise.
+ //
+ bConfig = false;
+
+ //
+ // Which descriptor are we being asked for?
+ //
+ switch(psUSBRequest->wValue >> 8)
+ {
+ //
+ // This request was for a device descriptor.
+ //
+ case USB_DTYPE_DEVICE:
+ {
+ //
+ // Return the externally provided device descriptor.
+ //
+ psUSBControl->pui8EP0Data =
+ (uint8_t *)psDevice->pui8DeviceDescriptor;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ psUSBControl->ui32EP0DataRemain =
+ psDevice->pui8DeviceDescriptor[0];
+
+ break;
+ }
+
+ //
+ // This request was for a configuration descriptor.
+ //
+ case USB_DTYPE_CONFIGURATION:
+ {
+ //
+ // Which configuration are we being asked for?
+ //
+ ui8Index = (uint8_t)(psUSBRequest->wValue & 0xFF);
+
+ //
+ // Is this valid?
+ //
+ psDeviceDesc =
+ (const tDeviceDescriptor *)psDevice->pui8DeviceDescriptor;
+
+ if(ui8Index >= psDeviceDesc->bNumConfigurations)
+ {
+ //
+ // This is an invalid configuration index. Stall EP0 to
+ // indicate a request error.
+ //
+ USBDCDStallEP0(0);
+ psUSBControl->pui8EP0Data = 0;
+ psUSBControl->ui32EP0DataRemain = 0;
+ }
+ else
+ {
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ psConfig = psDevice->ppsConfigDescriptors[ui8Index];
+
+ //
+ // Start by sending data from the beginning of the first
+ // descriptor.
+ //
+ psUSBControl->ui8ConfigSection = 0;
+ psUSBControl->ui16SectionOffset = 0;
+ psUSBControl->pui8EP0Data =
+ (uint8_t *)psConfig->psSections[0]->pui8Data;
+
+ //
+ // Determine the total size of the configuration descriptor
+ // by counting the sizes of the sections comprising it.
+ //
+ psUSBControl->ui32EP0DataRemain =
+ USBDCDConfigDescGetSize(psConfig);
+
+ //
+ // Remember that we need to send the configuration descriptor
+ // and which descriptor we need to send.
+ //
+ psUSBControl->ui8ConfigIndex = ui8Index;
+
+ bConfig = true;
+ }
+ break;
+ }
+
+ //
+ // This request was for a string descriptor.
+ //
+ case USB_DTYPE_STRING:
+ {
+ //
+ // Determine the correct descriptor index based on the requested
+ // language ID and index.
+ //
+ i32Index = USBDStringIndexFromRequest(psUSBRequest->wIndex,
+ psUSBRequest->wValue & 0xFF);
+
+ //
+ // If the mapping function returned -1 then stall the request to
+ // indicate that the request was not valid.
+ //
+ if(i32Index == -1)
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ psUSBControl->pui8EP0Data =
+ (uint8_t *)psDevice->ppui8StringDescriptors[i32Index];
+
+ //
+ // The total size of a string descriptor is in byte 0.
+ //
+ psUSBControl->ui32EP0DataRemain =
+ psDevice->ppui8StringDescriptors[i32Index][0];
+
+ break;
+ }
+
+ //
+ // Any other request is not handled by the default enumeration handler
+ // so see if it needs to be passed on to another handler.
+ //
+ default:
+ {
+ //
+ // If there is a handler for requests that are not handled then
+ // call it.
+ //
+ if(psDevice->psCallbacks->pfnGetDescriptor)
+ {
+ psDevice->psCallbacks->pfnGetDescriptor(g_psDCDInst[0].pvCBData,
+ psUSBRequest);
+ }
+ else
+ {
+ //
+ // Whatever this was this handler does not understand it so
+ // just stall the request.
+ //
+ USBDCDStallEP0(0);
+ }
+
+ return;
+ }
+ }
+
+ //
+ // If this request has data to send, then send it.
+ //
+ if(psUSBControl->pui8EP0Data)
+ {
+ //
+ // If there is more data to send than is requested then just
+ // send the requested amount of data.
+ //
+ if(psUSBControl->ui32EP0DataRemain > psUSBRequest->wLength)
+ {
+ psUSBControl->ui32EP0DataRemain = psUSBRequest->wLength;
+ }
+
+ //
+ // Now in the transmit data state. Be careful to call the correct
+ // function since we need to handle the configuration descriptor
+ // differently from the others.
+ //
+ if(!bConfig)
+ {
+ USBDEP0StateTx(0);
+ }
+ else
+ {
+ USBDEP0StateTxConfig(0);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function determines which string descriptor to send to satisfy a
+// request for a given index and language.
+//
+// \param ui16Lang is the requested string language ID.
+// \param ui16Index is the requested string descriptor index.
+//
+// When a string descriptor is requested, the host provides a language ID and
+// index to identify the string ("give me string number 5 in French"). This
+// function maps these two parameters to an index within our device's string
+// descriptor array which is arranged as multiple groups of strings with
+// one group for each language advertised via string descriptor 0.
+//
+// We assume that there are an equal number of strings per language and
+// that the first descriptor is the language descriptor and use this fact to
+// perform the mapping.
+//
+// \return The index of the string descriptor to return or -1 if the string
+// could not be found.
+//
+//*****************************************************************************
+static int32_t
+USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index)
+{
+ tString0Descriptor *pLang;
+ uint32_t ui32NumLangs, ui32NumStringi16PerLang, ui32Loop;
+
+ //
+ // Make sure we have a string table at all.
+ //
+ if((g_ppsDevInfo[0] == 0) ||
+ (g_ppsDevInfo[0]->ppui8StringDescriptors == 0))
+ {
+ return(-1);
+ }
+
+ //
+ // First look for the trivial case where descriptor 0 is being
+ // requested. This is the special case since descriptor 0 contains the
+ // language codes supported by the device.
+ //
+ if(ui16Index == 0)
+ {
+ return(0);
+ }
+
+ //
+ // How many languages does this device support? This is determined by
+ // looking at the length of the first descriptor in the string table,
+ // subtracting 2 for the header and dividing by two (the size of each
+ // language code).
+ //
+ ui32NumLangs =
+ (g_ppsDevInfo[0]->ppui8StringDescriptors[0][0] - 2) / 2;
+
+ //
+ // We assume that the table includes the same number of strings for each
+ // supported language. We know the number of entries in the string table,
+ // so how many are there for each language? This may seem an odd way to
+ // do this (why not just have the application tell us in the device info
+ // structure?) but it's needed since we didn't want to change the API
+ // after the first release which did not support multiple languages.
+ //
+ ui32NumStringi16PerLang =
+ ((g_ppsDevInfo[0]->ui32NumStringDescriptors - 1) /ui32NumLangs);
+
+ //
+ // Just to be sure, make sure that the calculation indicates an equal
+ // number of strings per language. We expect the string table to contain
+ // (1 + (strings_per_language * languages)) entries.
+ //
+ if((1 + (ui32NumStringi16PerLang * ui32NumLangs)) !=
+ g_ppsDevInfo[0]->ui32NumStringDescriptors)
+ {
+ return(-1);
+ }
+
+ //
+ // Now determine which language we are looking for. It is assumed that
+ // the order of the groups of strings per language in the table is the
+ // same as the order of the language IDs listed in the first descriptor.
+ //
+ pLang = (tString0Descriptor *)
+ (g_ppsDevInfo[0]->ppui8StringDescriptors[0]);
+
+ //
+ // Look through the supported languages looking for the one we were asked
+ // for.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++)
+ {
+ //
+ // Have we found the requested language?
+ //
+ if(pLang->wLANGID[ui32Loop] == ui16Lang)
+ {
+ //
+ // Yes - calculate the index of the descriptor to send.
+ //
+ return((ui32NumStringi16PerLang * ui32Loop) + ui16Index);
+ }
+ }
+
+ //
+ // If we drop out of the loop, the requested language was not found so
+ // return -1 to indicate the error.
+ //
+ return(-1);
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_DESCRIPTOR standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function currently is not supported and will respond with a Stall
+// to indicate that this command is not supported by the device.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ //
+ // Need to ACK the data on end point 0 without setting last data as there
+ // will be a data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // This function is not handled by default.
+ //
+ USBDCDStallEP0(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_CONFIGURATION standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function responds to a host request to return the current
+// configuration of the USB device. The function will send the configuration
+// response to the host and return. This value will either be 0 or the last
+// value received from a call to SetConfiguration().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ uint8_t ui8Value;
+ tDCDInstance *psUSBControl;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 without setting last data as there
+ // will be a data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = 0;
+ }
+ else
+ {
+ ui8Value = (uint8_t)psUSBControl->ui32Configuration;
+ }
+
+ psUSBControl->ui32EP0DataRemain = 1;
+ psUSBControl->pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_CONFIGURATION standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function responds to a host request to change the current
+// configuration of the USB device. The actual configuration number is taken
+// from the structure passed in via \e psUSBRequest. This number should be one
+// of the configurations that was specified in the descriptors. If the
+// \e ConfigChange callback is specified in \e pvInstance->psInfo->psCallbacks->
+// it will be called so that the application can respond to a change in
+// configuration.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ tDCDInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+ const tConfigHeader *psHdr;
+ const tConfigDescriptor *psDesc;
+
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+ psDevice = g_ppsDevInfo[0];
+
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Cannot set the configuration to one that does not exist so check the
+ // enumeration structure to see how many valid configurations are present.
+ //
+ if(psUSBRequest->wValue > psDevice->pui8DeviceDescriptor[17])
+ {
+ //
+ // The passed configuration number is not valid. Stall the endpoint to
+ // signal the error to the host.
+ //
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // Save the configuration.
+ //
+ psUSBControl->ui32Configuration = psUSBRequest->wValue;
+
+ //
+ // If passed a configuration other than 0 (which tells us that we are
+ // not currently configured), configure the endpoints (other than EP0)
+ // appropriately.
+ //
+ if(psUSBControl->ui32Configuration)
+ {
+ //
+ // Get a pointer to the configuration descriptor. This will always
+ // be the first section in the current configuration.
+ //
+ psHdr = psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1];
+ psDesc =
+ (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
+
+ //
+ // Remember the new self- or bus-powered state if the user has not
+ // already called us to tell us the state to report.
+ //
+ if(!psUSBControl->bPwrSrcSet)
+ {
+ if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) ==
+ USB_CONF_ATTR_SELF_PWR)
+ {
+ psUSBControl->ui8Status |= USB_STATUS_SELF_PWR;
+ }
+ else
+ {
+ psUSBControl->ui8Status &= ~USB_STATUS_SELF_PWR;
+ }
+ }
+
+ //
+ // Configure endpoints for the new configuration.
+ //
+ USBDeviceConfig(psUSBControl,
+ psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1]);
+ }
+
+ //
+ // If there is a configuration change callback then call it.
+ //
+ if(psDevice->psCallbacks->pfnConfigChange)
+ {
+ psDevice->psCallbacks->pfnConfigChange(g_psDCDInst[0].pvCBData,
+ psUSBControl->ui32Configuration);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_INTERFACE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function is called when the host controller request the current
+// interface that is in use by the device. This simply returns the value set
+// by the last call to SetInterface().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ uint8_t ui8Value;
+ tDCDInstance *psUSBControl;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+
+ //
+ // Need to ACK the data on end point 0 without setting last data as there
+ // will be a data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = (uint8_t)0;
+ }
+ else
+ {
+ //
+ // Is the interface number valid?
+ //
+ if(psUSBRequest->wIndex < USB_MAX_INTERFACES_PER_DEVICE)
+ {
+ //
+ // Read the current alternate setting for the required interface.
+ //
+ ui8Value = psUSBControl->pui8AltSetting[psUSBRequest->wIndex];
+ }
+ else
+ {
+ //
+ // An invalid interface number was specified.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+ }
+
+ //
+ // Send the single byte response.
+ //
+ psUSBControl->ui32EP0DataRemain = 1;
+ psUSBControl->pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_INTERFACE standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This function is called when a standard request for changing the interface
+// is received from the host controller. If this is a valid request the
+// function will call the function specified by the InterfaceChange in the
+// \e pvInstance->psInfo->psCallbacks->variable to notify the application that
+// the interface has changed and will pass it the new alternate interface
+// number.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ const tConfigHeader *psConfig;
+ tInterfaceDescriptor *psInterface;
+ uint32_t ui32Loop, ui32Section, ui32NumInterfaces;
+ uint8_t ui8Interface;
+ bool bRetcode;
+ tDCDInstance *psUSBControl;
+ tDeviceInfo *psDevice;
+
+ ASSERT(psUSBRequest != 0);
+ ASSERT(pvInstance != 0);
+
+ //
+ // Create the device information pointer.
+ //
+ psUSBControl = (tDCDInstance *)pvInstance;
+ psDevice = g_ppsDevInfo[0];
+
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Use the current configuration.
+ //
+ psConfig =
+ psDevice->ppsConfigDescriptors[psUSBControl->ui32Configuration - 1];
+
+ //
+ // How many interfaces are included in the descriptor?
+ //
+ ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig, USB_DTYPE_INTERFACE);
+
+ //
+ // Find the interface descriptor for the supplied interface and alternate
+ // setting numbers.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumInterfaces; ui32Loop++)
+ {
+ //
+ // Get the next interface descriptor in the configuration descriptor.
+ //
+ psInterface = USBDCDConfigGetInterface(psConfig, ui32Loop,
+ USB_DESC_ANY, &ui32Section);
+
+ //
+ // Is this the required interface with the correct alternate setting?
+ //
+ if(psInterface &&
+ (psInterface->bInterfaceNumber == psUSBRequest->wIndex) &&
+ (psInterface->bAlternateSetting == psUSBRequest->wValue))
+ {
+ ui8Interface = psInterface->bInterfaceNumber;
+
+ //
+ // Make sure we don't write outside the bounds of the
+ // pui8AltSetting array (in a debug build, anyway, since this
+ // indicates an error in the device descriptor).
+ //
+ ASSERT(ui8Interface < USB_MAX_INTERFACES_PER_DEVICE);
+
+ //
+ // This is the correct interface descriptor so save the
+ // setting.
+ //
+ psUSBControl->pui8AltSetting[ui8Interface] =
+ psInterface->bAlternateSetting;
+
+ //
+ // Reconfigure the endpoints to match the requirements of the
+ // new alternate setting for the interface.
+ //
+ bRetcode = USBDeviceConfigAlternate(psUSBControl, psConfig,
+ ui8Interface,
+ psInterface->bAlternateSetting);
+
+ //
+ // If there is a callback then notify the application of the
+ // change to the alternate interface.
+ //
+ if(bRetcode && psDevice->psCallbacks->pfnInterfaceChange)
+ {
+ psDevice->psCallbacks->pfnInterfaceChange(
+ g_psDCDInst[0].pvCBData,
+ psUSBRequest->wIndex,
+ psUSBRequest->wValue);
+ }
+
+ //
+ // All done.
+ //
+ return;
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find an interface descriptor
+ // matching the requested number and alternate setting or there was an
+ // error while trying to set up for the new alternate setting.
+ //
+ USBDCDStallEP0(0);
+}
+
+//*****************************************************************************
+//
+// This function handles the SYNC_FRAME standard USB request.
+//
+// \param pvInstance is the USB device controller instance data.
+// \param psUSBRequest holds the data for this request.
+//
+// This is currently a stub function that will stall indicating that the
+// command is not supported.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest)
+{
+ //
+ // Need to ACK the data on end point 0 with last data set as this has no
+ // data phase.
+ //
+ MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Not handled yet so stall this request.
+ //
+ USBDCDStallEP0(0);
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending data on endpoint zero.
+//
+// \param ui32Index is the index of the USB controller which is to be
+// initialized.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTx(uint32_t ui32Index)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateTx;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
+ {
+ ui32NumBytes = EP0_MAX_PACKET_SIZE;
+ }
+
+ //
+ // Save the pointer so that it can be passed to the USBEndpointDataPut()
+ // function.
+ //
+ pui8Data = (uint8_t *)g_psDCDInst[0].pui8EP0Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
+ g_psDCDInst[0].pui8EP0Data += ui32NumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32NumBytes);
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // There is more data to send or exactly 64 bytes were sent, this
+ // means that there is either more data coming or a null packet needs
+ // to be sent to complete the transaction.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
+ }
+ else
+ {
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateStatus;
+
+ //
+ // Send the last bit of data.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
+
+ //
+ // If there is a sent callback then call it.
+ //
+ if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
+ (g_psDCDInst[0].ui32OUTDataSize != 0))
+ {
+ //
+ // Call the custom handler.
+ //
+ g_ppsDevInfo[0]->psCallbacks->pfnDataSent(
+ g_psDCDInst[0].pvCBData,
+ g_psDCDInst[0].ui32OUTDataSize);
+
+ //
+ // There is no longer any data pending to be sent.
+ //
+ g_psDCDInst[0].ui32OUTDataSize = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending the configuration descriptor on
+// endpoint zero.
+//
+// \param ui32Index is the index of the USB controller.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTxConfig(uint32_t ui32Index)
+{
+ uint32_t ui32NumBytes, ui32SecBytes, ui32ToSend;
+ uint8_t *pui8Data;
+ tConfigDescriptor sConfDesc;
+ const tConfigHeader *psConfig;
+ const tConfigSection *psSection;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateTxConfig;
+
+ //
+ // Find the current configuration descriptor definition.
+ //
+ psConfig = g_ppsDevInfo[0]->ppsConfigDescriptors[
+ g_psDCDInst[0].ui8ConfigIndex];
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
+ {
+ ui32NumBytes = EP0_MAX_PACKET_SIZE;
+ }
+
+ //
+ // If this is the first call, we need to fix up the total length of the
+ // configuration descriptor. This has already been determined and set in
+ // g_sUSBDeviceState.ui32EP0DataRemain.
+ //
+ if((g_psDCDInst[0].ui16SectionOffset == 0) &&
+ (g_psDCDInst[0].ui8ConfigSection == 0))
+ {
+ //
+ // Copy the USB configuration descriptor from the beginning of the
+ // first section of the current configuration.
+ //
+ sConfDesc = *(tConfigDescriptor *)g_psDCDInst[0].pui8EP0Data;
+
+ //
+ // Update the total size.
+ //
+ sConfDesc.wTotalLength = (uint16_t)USBDCDConfigDescGetSize(psConfig);
+
+ //
+ // Write the descriptor to the USB FIFO.
+ //
+ ui32ToSend = (ui32NumBytes < sizeof(tConfigDescriptor)) ? ui32NumBytes:
+ sizeof(tConfigDescriptor);
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (uint8_t *)&sConfDesc,
+ ui32ToSend);
+
+ //
+ // Did we reach the end of the first section?
+ //
+ if(psConfig->psSections[0]->ui16Size == ui32ToSend)
+ {
+ //
+ // Update our tracking indices to point to the start of the next
+ // section.
+ //
+ g_psDCDInst[0].ui16SectionOffset = 0;
+ g_psDCDInst[0].ui8ConfigSection = 1;
+ }
+ else
+ {
+ //
+ // Note that we have sent the first few bytes of the descriptor.
+ //
+ g_psDCDInst[0].ui16SectionOffset = (uint8_t)ui32ToSend;
+ }
+
+ //
+ // How many bytes do we have remaining to send on this iteration?
+ //
+ ui32ToSend = ui32NumBytes - ui32ToSend;
+ }
+ else
+ {
+ //
+ // Set the number of bytes we still have to send on this call.
+ //
+ ui32ToSend = ui32NumBytes;
+ }
+
+ //
+ // Add the relevant number of bytes to the USB FIFO
+ //
+ while(ui32ToSend)
+ {
+ //
+ // Get a pointer to the current configuration section.
+ //
+ psSection = psConfig->psSections[g_psDCDInst[0].ui8ConfigSection];
+
+ //
+ // Calculate bytes are available in the current configuration section.
+ //
+ ui32SecBytes = (uint32_t)(psSection->ui16Size -
+ g_psDCDInst[0].ui16SectionOffset);
+
+ //
+ // Save the pointer so that it can be passed to the
+ // USBEndpointDataPut() function.
+ //
+ pui8Data = (uint8_t *)psSection->pui8Data +
+ g_psDCDInst[0].ui16SectionOffset;
+
+ //
+ // Are there more bytes in this section that we still have to send?
+ //
+ if(ui32SecBytes > ui32ToSend)
+ {
+ //
+ // Yes - send only the remaining bytes in the transfer.
+ //
+ ui32SecBytes = ui32ToSend;
+ }
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32SecBytes);
+
+ //
+ // Fix up our pointers for the next iteration.
+ //
+ ui32ToSend -= ui32SecBytes;
+ g_psDCDInst[0].ui16SectionOffset += (uint8_t)ui32SecBytes;
+
+ //
+ // Have we reached the end of a section?
+ //
+ if(g_psDCDInst[0].ui16SectionOffset == psSection->ui16Size)
+ {
+ //
+ // Yes - move to the next one.
+ //
+ g_psDCDInst[0].ui8ConfigSection++;
+ g_psDCDInst[0].ui16SectionOffset = 0;
+ }
+ }
+
+ //
+ // Fix up the number of bytes remaining to be sent and the start pointer.
+ //
+ g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
+
+ //
+ // If we ran out of bytes in the configuration section, bail and just
+ // send out what we have.
+ //
+ if(psConfig->ui8NumSections <= g_psDCDInst[0].ui8ConfigSection)
+ {
+ g_psDCDInst[0].ui32EP0DataRemain = 0;
+ }
+
+ //
+ // If there is no more data don't keep looking or ui8ConfigSection might
+ // overrun the available space.
+ //
+ if(g_psDCDInst[0].ui32EP0DataRemain != 0)
+ {
+ pui8Data =(uint8_t *)
+ psConfig->psSections[g_psDCDInst[0].ui8ConfigSection]->pui8Data;
+ ui32ToSend = g_psDCDInst[0].ui16SectionOffset;
+ g_psDCDInst[0].pui8EP0Data = (pui8Data + ui32ToSend);
+ }
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // There is more data to send or exactly 64 bytes were sent, this
+ // means that there is either more data coming or a null packet needs
+ // to be sent to complete the transaction.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
+ }
+ else
+ {
+ //
+ // Send the last bit of data.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
+
+ //
+ // If there is a sent callback then call it.
+ //
+ if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
+ (g_psDCDInst[0].ui32OUTDataSize != 0))
+ {
+ //
+ // Call the custom handler.
+ //
+ g_ppsDevInfo[0]->psCallbacks->pfnDataSent(g_psDCDInst[0].pvCBData,
+ g_psDCDInst[0].ui32OUTDataSize);
+
+ //
+ // There is no longer any data pending to be sent.
+ //
+ g_psDCDInst[0].ui32OUTDataSize = 0;
+ }
+
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_psDCDInst[0].iEP0State = eUSBStateStatus;
+ }
+}
+
+//*****************************************************************************
+//
+// The internal USB device interrupt handler.
+//
+// \param ui32Index is the USB controller associated with this interrupt.
+// \param ui32Status is the current interrupt status as read via a call to
+// USBIntStatusControl().
+//
+// This function is called from either \e USB0DualModeIntHandler() or
+// \e USB0DeviceIntHandler() to process USB interrupts when in device mode.
+// This handler will branch the interrupt off to the appropriate application or
+// stack handlers depending on the current status of the USB controller.
+//
+// The two-tiered structure for the interrupt handler ensures that it is
+// possible to use the same handler code in both device and OTG modes and
+// means that host code can be excluded from applications that only require
+// support for USB device mode operation.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDeviceIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status)
+{
+ static uint32_t ui32SOFDivide = 0;
+ void *pvInstance;
+ uint32_t ui32DMAIntStatus;
+ uint32_t ui32LPMStatus;
+
+ //
+ // If device initialization has not been performed then just disconnect
+ // from the USB bus and return from the handler.
+ //
+ if(g_ppsDevInfo[0] == 0)
+ {
+ MAP_USBDevDisconnect(USB0_BASE);
+ return;
+ }
+
+ pvInstance = g_psDCDInst[0].pvCBData;
+
+ //
+ // Received a reset from the host.
+ //
+ if(ui32Status & USB_INTCTRL_RESET)
+ {
+ USBDeviceEnumResetHandler(&g_psDCDInst[0]);
+ }
+
+ //
+ // Suspend was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_SUSPEND)
+ {
+ //
+ // Call the SuspendHandler() if it was specified.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler(pvInstance);
+ }
+ }
+
+ //
+ // Resume was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_RESUME)
+ {
+ //
+ // Call the ResumeHandler() if it was specified.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(pvInstance);
+ }
+ }
+
+ //
+ // USB device was disconnected.
+ //
+ if(ui32Status & USB_INTCTRL_DISCONNECT)
+ {
+ //
+ // Call the DisconnectHandler() if it was specified.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler(pvInstance);
+ }
+ }
+
+ //
+ // Start of Frame was received.
+ //
+ if(ui32Status & USB_INTCTRL_SOF)
+ {
+ //
+ // Increment the global Start of Frame counter.
+ //
+ g_ui32USBSOFCount++;
+
+ //
+ // Increment our SOF divider.
+ //
+ ui32SOFDivide++;
+
+ //
+ // Handle resume signaling if required.
+ //
+ USBDeviceResumeTickHandler(&g_psDCDInst[0]);
+
+ //
+ // Have we counted enough SOFs to allow us to call the tick function?
+ //
+ if(ui32SOFDivide == USB_SOF_TICK_DIVIDE)
+ {
+ //
+ // Yes - reset the divider and call the SOF tick handler.
+ //
+ ui32SOFDivide = 0;
+ InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
+ }
+ }
+
+ //
+ // Handle LPM interrupts.
+ //
+ ui32LPMStatus = USBLPMIntStatus(USB0_BASE);
+
+ //
+ // The host LPM resume request has been acknowledged, allow the device
+ // class to handle the sleep state.
+ //
+ if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_SLEEP) &&
+ ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
+ USB_INTLPM_RESUME))
+ {
+ //
+ // Notify the class of the wake from LPM L1.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
+ USB_EVENT_LPM_RESUME,
+ (void *)0);
+ }
+
+ //
+ // Now back in the awake state.
+ //
+ g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
+
+ //
+ // Enable receiving of LPM packet.
+ //
+ USBDevLPMEnable(USB0_BASE);
+ }
+ //
+ // The host LPM sleep request has been acknowledged, allow the device
+ // class to handle the sleep state.
+ //
+ else if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_AWAKE) &&
+ ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
+ USB_INTLPM_ACK))
+ {
+ if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
+ USB_EVENT_LPM_SLEEP,
+ (void *)0);
+ }
+
+ //
+ // Now back in the sleep state.
+ //
+ g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_SLEEP;
+ }
+ else if(ui32LPMStatus & USB_INTLPM_NYET)
+ {
+ //
+ // The device has held off the sleep state because LPM
+ // responses are disabled.
+ //
+ if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
+ USB_EVENT_LPM_ERROR,
+ (void *)0);
+ }
+ }
+
+ //
+ // Get the controller interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Handle end point 0 interrupts.
+ //
+ if(ui32Status & USB_INTEP_0)
+ {
+ USBDeviceEnumHandler(&g_psDCDInst[0]);
+ ui32Status &= ~USB_INTEP_0;
+ }
+
+ //
+ // Check to see if any DMA transfers are pending
+ //
+ ui32DMAIntStatus = USBLibDMAIntStatus(g_psDCDInst[0].psDMAInstance);
+
+ if(ui32DMAIntStatus)
+ {
+ //
+ // Handle any DMA interrupt processing.
+ //
+ USBLibDMAIntHandler(g_psDCDInst[0].psDMAInstance, ui32DMAIntStatus);
+ }
+
+ //
+ // Because there is no way to detect if a uDMA interrupt has occurred,
+ // check for an endpoint callback and call it if it is available.
+ //
+ if((g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler) &&
+ ((ui32Status != 0) || (ui32DMAIntStatus != 0)))
+ {
+ g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler(pvInstance, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdevice.h b/usblib/device/usbdevice.h
new file mode 100644
index 0000000..d4df6a6
--- /dev/null
+++ b/usblib/device/usbdevice.h
@@ -0,0 +1,232 @@
+//*****************************************************************************
+//
+// usbdevice.h - types and definitions used during USB enumeration.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDEVICE_H__
+#define __USBDEVICE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The maximum number of independent interfaces that any single device
+//! implementation can support. Independent interfaces means interface
+//! descriptors with different \e bInterfaceNumber values - several interface
+//! descriptors offering different alternative settings but the same interface
+//! number count as a single interface.
+//
+//*****************************************************************************
+#define USB_MAX_INTERFACES_PER_DEVICE 8
+
+#include "usbdevicepriv.h"
+
+//*****************************************************************************
+//
+//! This structure is passed to the USB library on a call to USBDCDInit and
+//! provides the library with information about the device that the
+//! application is implementing. It contains functions pointers for the
+//! various USB event handlers and pointers to each of the standard device
+//! descriptors.
+//
+//*****************************************************************************
+struct tDeviceInfo
+{
+ //
+ //! A pointer to a structure containing pointers to event handler functions
+ //! provided by the client to support the operation of this device.
+ //
+ const tCustomHandlers * psCallbacks;
+
+ //
+ //! A pointer to the device descriptor for this device.
+ //
+ const uint8_t *pui8DeviceDescriptor;
+
+ //
+ //! A pointer to an array of configuration descriptor pointers. Each entry
+ //! in the array corresponds to one configuration that the device may be
+ //! set to use by the USB host. The number of entries in the array must
+ //! match the bNumConfigurations value in the device descriptor
+ //! array, \e pui8DeviceDescriptor.
+ //
+ const tConfigHeader * const *ppsConfigDescriptors;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must be arranged as follows:
+ //!
+ //! [0] - Standard descriptor containing supported language codes.
+ //!
+ //! [1] - String 1 for the first language listed in descriptor 0.
+ //!
+ //! [2] - String 2 for the first language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [n] - String n for the first language listed in descriptor 0.
+ //!
+ //! [n+1] - String 1 for the second language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [2n] - String n for the second language listed in descriptor 0.
+ //!
+ //! [2n+1]- String 1 for the third language listed in descriptor 0.
+ //!
+ //! ...
+ //!
+ //! [3n] - String n for the third language listed in descriptor 0.
+ //!
+ //! and so on.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The total number of descriptors provided in the ppStringDescriptors
+ //! array.
+ //
+ uint32_t ui32NumStringDescriptors;
+};
+
+//*****************************************************************************
+//
+//! This type is used by an application to describe and instance of a device
+//! and an instance data pointer for that class. The psDevice pointer should
+//! be a pointer to a valid device class to include in the composite device.
+//! The pvInstance pointer should be a pointer to an instance pointer for the
+//! device in the psDevice pointer.
+//!
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This is the top level device information structure.
+ //
+ const tDeviceInfo *psDevInfo;
+
+ //
+ //! This is the instance data for the device structure.
+ //
+ void *pvInstance;
+
+ //
+ //! A per-device workspace used by the composite device.
+ //
+ uint32_t ui32DeviceWorkspace;
+}
+tCompositeEntry;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public APIs offered by the USB library device control driver.
+//
+//*****************************************************************************
+extern void USBDCDInit(uint32_t ui32Index, tDeviceInfo *psDevice,
+ void *pvDCDCBData);
+extern void USBDCDTerm(uint32_t ui32Index);
+extern void USBDCDStallEP0(uint32_t ui32Index);
+extern void USBDCDRequestDataEP0(uint32_t ui32Index, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern void USBDCDSendDataEP0(uint32_t ui32Index, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern void USBDCDSetDefaultConfiguration(uint32_t ui32Index,
+ uint32_t ui32DefaultConfig);
+extern uint32_t USBDCDConfigDescGetSize(const tConfigHeader *psConfig);
+extern uint32_t USBDCDConfigDescGetNum(const tConfigHeader *psConfig,
+ uint32_t ui32Type);
+extern tDescriptorHeader *USBDCDConfigDescGet(const tConfigHeader *psConfig,
+ uint32_t ui32Type,
+ uint32_t ui32Index,
+ uint32_t *pui32Section);
+extern uint32_t
+ USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNumber);
+extern tInterfaceDescriptor *
+ USBDCDConfigGetInterface(const tConfigHeader *psConfig,
+ uint32_t ui32Index, uint32_t ui32AltCfg,
+ uint32_t *pui32Section);
+extern tEndpointDescriptor *
+ USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
+ uint32_t ui32InterfaceNumber,
+ uint32_t ui32AltCfg,
+ uint32_t ui32Index);
+extern bool USBDCDRemoteWakeupRequest(uint32_t ui32Index);
+extern bool USBDCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature);
+extern bool USBDCDRemoteWakeLPM(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// Device mode interrupt handler for controller index 0.
+//
+//*****************************************************************************
+extern void USB0DeviceIntHandler(void);
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDCDPowerStatusSet(uint32_t ui32Index, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBENUM_H__
diff --git a/usblib/device/usbdevicepriv.h b/usblib/device/usbdevicepriv.h
new file mode 100644
index 0000000..4eef230
--- /dev/null
+++ b/usblib/device/usbdevicepriv.h
@@ -0,0 +1,248 @@
+//*****************************************************************************
+//
+// usbdevicepriv.h - Private header file used to share internal variables and
+// function prototypes between the various device-related
+// modules in the USB library. This header MUST NOT be
+// used by application code.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDEVICEPRIV_H__
+#define __USBDEVICEPRIV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The states for endpoint zero during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint zero.
+ //
+ eUSBStateIdle,
+
+ //
+ // The USB device is sending data back to the host due to an IN request.
+ //
+ eUSBStateTx,
+
+ //
+ // The USB device is sending the configuration descriptor back to the host
+ // due to an IN request.
+ //
+ eUSBStateTxConfig,
+
+ //
+ // The USB device is receiving data from the host due to an OUT
+ // request from the host.
+ //
+ eUSBStateRx,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ eUSBStateStatus,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ eUSBStateStall
+}
+tEP0State;
+
+typedef struct tDeviceInfo tDeviceInfo;
+
+//*****************************************************************************
+//
+// The USB controller device information.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The current state of endpoint zero.
+ //
+ volatile tEP0State iEP0State;
+
+ //
+ // The devices current address, this also has a change pending bit in the
+ // MSB of this value specified by DEV_ADDR_PENDING.
+ //
+ volatile uint32_t ui32DevAddress;
+
+ //
+ // This holds the current active configuration for this device.
+ //
+ uint32_t ui32Configuration;
+
+ //
+ // This holds the configuration id that will take effect after a reset.
+ //
+ uint32_t ui32DefaultConfiguration;
+
+ //
+ // This holds the current alternate interface for this device.
+ //
+ uint8_t pui8AltSetting[USB_MAX_INTERFACES_PER_DEVICE];
+
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint zero.
+ //
+ uint8_t *pui8EP0Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_sUSBDeviceState.pui8EP0Data data buffer.
+ //
+ volatile uint32_t ui32EP0DataRemain;
+
+ //
+ // The amount of data being sent/received due to a custom request.
+ //
+ uint32_t ui32OUTDataSize;
+
+ //
+ // Holds the current device status.
+ //
+ uint8_t ui8Status;
+
+ //
+ // Holds the endpoint status for the HALT condition. This array is sized
+ // to hold halt status for all IN and OUT endpoints.
+ //
+ uint8_t ppui8Halt[2][USBLIB_NUM_EP - 1];
+
+ //
+ // Holds the configuration descriptor section number currently being sent
+ // to the host.
+ //
+ uint8_t ui8ConfigSection;
+
+ //
+ // Holds the offset within the configuration descriptor section currently
+ // being sent to the host.
+ //
+ uint16_t ui16SectionOffset;
+
+ //
+ // Holds the index of the configuration that we are currently sending back
+ // to the host.
+ //
+ uint8_t ui8ConfigIndex;
+
+ //
+ // This flag is set to true if the client has called USBDPowerStatusSet()
+ // and tells the USB library not to try to determine the current power
+ // status from the configuration descriptor.
+ //
+ bool bPwrSrcSet;
+
+ //
+ // This flag indicates whether or not remote wake up signaling is in
+ // progress.
+ //
+ bool bRemoteWakeup;
+
+ //
+ // During remote wake up signaling, this counter is used to track the
+ // number of milliseconds since the signaling was initiated.
+ //
+ uint8_t ui8RemoteWakeupCount;
+
+ //
+ // The DMA instance information for this USB controller.
+ //
+ tUSBDMAInstance *psDMAInstance;
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+
+ //
+ // Pointer to the device supplied call back data.
+ //
+ void *pvCBData;
+
+ //
+ // This holds the state of the LPM support for the device.
+ //
+ uint32_t ui32LPMState;
+
+ //
+ // Device feature flags.
+ //
+ uint32_t ui32Features;
+}
+tDCDInstance;
+
+extern tDCDInstance g_psDCDInst[];
+extern tDeviceInfo *g_ppsDevInfo[];
+
+//*****************************************************************************
+//
+// Device enumeration functions provided by device/usbenum.c and called from
+// the interrupt handler in device/usbhandler.c
+//
+//*****************************************************************************
+extern bool USBDeviceConfig(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig);
+extern bool USBDeviceConfigAlternate(tDCDInstance *psDevInst,
+ const tConfigHeader *psConfig,
+ uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+
+extern void USBDCDDeviceInfoInit(uint32_t ui32Index, tDeviceInfo *psDevice);
+
+//*****************************************************************************
+//
+// Macro access function to device information.
+//
+//*****************************************************************************
+#define DCDGetDMAInstance(psDevInfo) (&(psDevInfo->psDCDInst->sDMAInstance))
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDEVICEPRIV_H__
diff --git a/usblib/device/usbdhandler.c b/usblib/device/usbdhandler.c
new file mode 100644
index 0000000..751cc44
--- /dev/null
+++ b/usblib/device/usbdhandler.c
@@ -0,0 +1,85 @@
+//*****************************************************************************
+//
+// usbhandler.c - General USB handling routines.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdevicepriv.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The USB device interrupt handler.
+//!
+//! This the main USB interrupt handler entry point for use in USB device
+//! applications. This top-level handler will branch the interrupt off to the
+//! appropriate application or stack handlers depending on the current status
+//! of the USB controller.
+//!
+//! Applications which operate purely as USB devices (rather than dual mode
+//! applications which can operate in either device or host mode at different
+//! times) must ensure that a pointer to this function is installed in the
+//! interrupt vector table entry for the USB0 interrupt. For dual mode
+//! operation, the vector should be set to point to \e USB0DualModeIntHandler()
+//! instead.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0DeviceIntHandler(void)
+{
+ uint32_t ui32Status;
+
+ //
+ // Get the controller interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusControl(USB0_BASE);
+
+ //
+ // Call the internal handler.
+ //
+ USBDeviceIntHandlerInternal(0, ui32Status);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhid.c b/usblib/device/usbdhid.c
new file mode 100644
index 0000000..c708f62
--- /dev/null
+++ b/usblib/device/usbdhid.c
@@ -0,0 +1,2502 @@
+//*****************************************************************************
+//
+// usbdhid.c - USB HID device class driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// Marker used to indicate that a given HID descriptor cannot be found in the
+// client-supplied list.
+//
+//*****************************************************************************
+#define HID_NOT_FOUND 0xFFFFFFFF
+
+//*****************************************************************************
+//
+// Flags that may appear in ui16DeferredOpFlags to indicate some operation that
+// has been requested but could not be processed at the time it was received.
+// Each deferred operation is defined as the bit number that should be set in
+// tHIDInstance->ui16DeferredOpFlags to indicate that the operation is pending.
+//
+//*****************************************************************************
+#define HID_DO_PACKET_RX 5
+#define HID_DO_SEND_IDLE_REPORT 6
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define INT_IN_ENDPOINT USB_EP_3
+#define INT_OUT_ENDPOINT USB_EP_3
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8HIDDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_DEVICE, // USB Device Class
+ 0, // USB Device Sub-class
+ USB_HID_PROTOCOL_NONE, // USB Device protocol
+ USBDHID_MAX_PACKET, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (VID).
+ USBShort(0), // Product ID (PID).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Forward references for device handler callbacks
+//
+//*****************************************************************************
+static void HandleGetDescriptor(void *pvHIDInstance, tUSBRequest *psUSBRequest);
+static void HandleRequest(void *pvHIDInstance, tUSBRequest *psUSBRequest);
+static void HandleConfigChange(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleEP0DataReceived(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleEP0DataSent(void *pvHIDInstance, uint32_t ui32Info);
+static void HandleReset(void *pvHIDInstance);
+static void HandleSuspend(void *pvHIDInstance);
+static void HandleResume(void *pvHIDInstance);
+static void HandleDisconnect(void *pvHIDInstance);
+static void HandleEndpoints(void *pvHIDInstance, uint32_t ui32Status);
+static void HandleDevice(void *pvHIDInstance, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB HID devices.
+//
+//*****************************************************************************
+const tCustomHandlers g_sHIDHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ HandleGetDescriptor,
+
+ //
+ // RequestHandler
+ //
+ HandleRequest,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ HandleConfigChange,
+
+ //
+ // DataReceived
+ //
+ HandleEP0DataReceived,
+
+ //
+ // DataSentCallback
+ //
+ HandleEP0DataSent,
+
+ //
+ // ResetHandler
+ //
+ HandleReset,
+
+ //
+ // SuspendHandler
+ //
+ HandleSuspend,
+
+ //
+ // ResumeHandler
+ //
+ HandleResume,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler.
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+// Set or clear deferred operation flags in an "atomic" manner.
+//
+// \param pui16DeferredOp points to the flags variable which is to be modified.
+// \param ui16Bit indicates which bit number is to be set or cleared.
+// \param bSet indicates the state that the flag must be set to. If \b true,
+// the flag is set, if \b false, the flag is cleared.
+//
+// This function safely sets or clears a bit in a flag variable. The operation
+// makes use of bitbanding to ensure that the operation is atomic (no read-
+// modify-write is required).
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit,
+ bool bSet)
+{
+ //
+ // Set the flag bit to 1 or 0 using a bitband access.
+ //
+ HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0;
+}
+
+//*****************************************************************************
+//
+// This function is called to clear the counter used to keep track of the time
+// elapsed since a given report was last sent.
+//
+// \param psHIDDevice points to the HID device structure whose report timer is
+// to be cleared.
+// \param ui8ReportID is the first byte of the report to be sent. If this
+// device offers more than one input report, this value is used to find the
+// relevant report timer structure in the psHIDDevice structure.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearReportTimer(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID)
+{
+ uint32_t ui32Loop;
+
+ if(psHIDDevice->ui8NumInputReports > 1)
+ {
+ //
+ // We have more than 1 input report so the report must begin with a
+ // byte containing the report ID. Scan the table we were provided
+ // when the device was initialized to find the entry for this report.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports;
+ ui32Loop++)
+ {
+ if(psHIDDevice->psReportIdle[ui32Loop].ui8ReportID == ui8ReportID)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ ui32Loop = 0;
+ }
+
+ //
+ // If we drop out of the loop with an index less than ui8NumInputReports,
+ // we found the relevant report so clear its timer.
+ //
+ if(ui32Loop < psHIDDevice->ui8NumInputReports)
+ {
+ psHIDDevice->psReportIdle[ui32Loop].ui32TimeSinceReportmS = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called to clear the idle period timers for each input
+// report supported by the device.
+//
+// \param psHIDDevice points to the HID device structure whose timers are to be
+// cleared.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ClearIdleTimers(const tUSBDHIDDevice *psHIDDevice)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Clear the "time till next report" counters for each input report.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS =
+ psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS * 4;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called periodically to allow us to process the report idle
+// timers.
+//
+// \param psHIDDevice points to the HID device structure whose timers are to be
+// updated.
+// \param ui32ElapsedmS indicates the number of milliseconds that have elapsed
+// since the last call to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ProcessIdleTimers(const tUSBDHIDDevice *psHIDDevice, uint32_t ui32ElapsedmS)
+{
+ uint32_t ui32Loop, ui32SizeReport;
+ void *pvReport;
+ tHIDInstance *psInst;
+ bool bDeferred;
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)psHIDDevice)->sPrivateData;
+
+ //
+ // We have not had to defer any report transmissions yet.
+ //
+ bDeferred = false;
+
+ //
+ // Look at each of the input report idle timers in turn.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ //
+ // Update the time since the last report was sent.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui32TimeSinceReportmS +=
+ ui32ElapsedmS;
+
+ //
+ // Is this timer running?
+ //
+ if(psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS)
+ {
+ //
+ // Yes - is it about to expire?
+ //
+ if(psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS <=
+ ui32ElapsedmS)
+ {
+ //
+ // The timer is about to expire. Can we send a report right
+ // now?
+ //
+ if((psInst->iHIDTxState == eHIDStateIdle) &&
+ (psInst->bSendInProgress == false))
+ {
+ //
+ // We can send a report so send a message to the
+ // application to retrieve its latest report for
+ // transmission to the host.
+ //
+ ui32SizeReport = psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_IDLE_TIMEOUT,
+ psHIDDevice->psReportIdle[ui32Loop].ui8ReportID,
+ &pvReport);
+
+ //
+ // Schedule the report for transmission.
+ //
+ USBDHIDReportWrite((void *)psHIDDevice, pvReport,
+ ui32SizeReport, true);
+
+ //
+ // Reload the timer for the next period.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS =
+ psHIDDevice->psReportIdle[ui32Loop].ui8Duration4mS * 4;
+ }
+ else
+ {
+ //
+ // We can't send the report straight away so flag it for
+ // transmission as soon as the previous transmission ends.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS = 0;
+ bDeferred = true;
+ }
+ }
+ else
+ {
+ //
+ // The timer is not about to expire. Update the time till the
+ // next report transmission.
+ //
+ psHIDDevice->psReportIdle[ui32Loop].ui16TimeTillNextmS -=
+ ui32ElapsedmS;
+ }
+ }
+ }
+
+ //
+ // If we had to defer transmission of any report, remember this so that we
+ // will process it as soon as possible.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, HID_DO_SEND_IDLE_REPORT,
+ bDeferred);
+}
+
+static void
+SetIdleTimeout(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID,
+ uint8_t ui8Timeout4mS)
+{
+ uint32_t ui32Loop;
+ bool bReportNeeded;
+ tHIDReportIdle *psIdle;
+
+ //
+ // Remember that we have not found any report that needs to be sent
+ // immediately.
+ //
+ bReportNeeded = false;
+
+ //
+ // Search through all the input reports looking for ones that fit the
+ // requirements.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psIdle = &psHIDDevice->psReportIdle[ui32Loop];
+
+ //
+ // If the report ID passed matches the report ID in the idle timer
+ // control structure or we were passed a report ID of zero, which
+ // indicates that all timers are to be set...
+ //
+ if(!ui8ReportID || (ui8ReportID == psIdle->ui8ReportID))
+ {
+ //
+ // Save the new duration for the idle timer.
+ //
+ psIdle->ui8Duration4mS = ui8Timeout4mS;
+
+ //
+ // Are we enabling the idle timer? If so, fix up the time until it
+ // needs to fire.
+ //
+ if(ui8Timeout4mS)
+ {
+ //
+ // Determine what the timeout is for this report given the time
+ // since the last report of this type was sent.
+ //
+ if(psIdle->ui32TimeSinceReportmS >=
+ ((uint32_t)ui8Timeout4mS * 4))
+ {
+ psIdle->ui16TimeTillNextmS = 0;
+ bReportNeeded = true;
+ }
+ else
+ {
+ psIdle->ui16TimeTillNextmS =
+ (((uint16_t)ui8Timeout4mS * 4) -
+ psIdle->ui32TimeSinceReportmS);
+ }
+ }
+ }
+ }
+
+ //
+ // If we get to here and bReportNeeded is true, this means we need to
+ // send back at least one of the input reports as soon as possible. Try
+ // to do this immediately.
+ //
+ if(bReportNeeded)
+ {
+ ProcessIdleTimers(psHIDDevice, 0);
+ }
+}
+
+//*****************************************************************************
+//
+// Find the idle timeout for a given HID input report.
+//
+// \param psHIDDevice points to the HID device whose report idle timeout is to
+// be found.
+// \param ui8ReportID identifies the report whose timeout is requested. If 0,
+// the timeout for the first report is returns, regardless of its ID (or
+// whether it has one).
+//
+// This function returns the current idle timeout for a given HID input report.
+// The value returned is expressed in terms of 4mS intervals. Convert to
+// milliseconds by multiplying by 4. If the return value is 0, this indicates
+// that an infinite timeout is currently set and the device will not send the
+// report unless a state change occurs.
+//
+// \return Returns the current idle timeout for the given report.
+//
+//*****************************************************************************
+static uint32_t
+GetIdleTimeout(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8ReportID)
+{
+ uint32_t ui32Loop;
+ tHIDReportIdle *psIdle;
+
+ //
+ // Search through all the input reports looking for ones that fit the
+ // requirements.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->ui8NumInputReports; ui32Loop++)
+ {
+ psIdle = &psHIDDevice->psReportIdle[ui32Loop];
+
+ //
+ // If the report ID passed matches the report ID in the idle timer
+ // control structure or we were passed a report ID of zero, which
+ // indicates that all timers are to be set...
+ //
+ if(!ui8ReportID || (ui8ReportID == psIdle->ui8ReportID))
+ {
+ //
+ // We found a report matching the required ID or we were not passed
+ // an ID and we are looking at the first report information.
+ //
+ return((uint32_t)psIdle->ui8Duration4mS);
+ }
+ }
+
+ //
+ // If we drop out, the report could not be found so we need to indicate
+ // an error.
+ //
+ return(HID_NOT_FOUND);
+}
+
+//*****************************************************************************
+//
+// Find the n-th HID class descriptor of a given type in the client-provided
+// descriptor table.
+//
+// \param psHIDDevice points to the HID device which is to be searched for the
+// required class descriptor.
+// \param ui8Type is the type of class descriptor being requested. This will
+// be either USB_HID_DTYPE_REPORT or USB_HID_DTYPE_PHYSICAL.
+// \param ui32Index is the zero-based index of the descriptor that is being
+// requested.
+//
+// This function parses the supplied HID descriptor to find the index into the
+// sClassDescriptor array that corresponds to the requested descriptor. If
+// a descriptor with the requested index does not exist, HID_NOT_FOUND will be
+// returned unless the request is for a physical descriptor and at least one
+// such descriptor exists. In this case, the index returned will be for the
+// last physical descriptor (as required by the HID spec 7.1.1).
+//
+// \return Returns the index of the descriptor within the sClassDescriptor
+// of the tHIDDevice structure if found or HID_NOT_FOUND otherwise.
+//
+//*****************************************************************************
+static uint32_t
+FindHIDDescriptor(const tUSBDHIDDevice *psHIDDevice, uint8_t ui8Type,
+ uint32_t ui32Index, uint32_t *pui32Len)
+{
+ bool bFoundType;
+ uint32_t ui32Loop, ui32Count, ui32LastFound;
+ const tHIDClassDescriptorInfo *psDesc;
+
+ //
+ // Remember that we have not found any descriptor with a matching type yet.
+ //
+ bFoundType = false;
+ ui32Count = 0;
+ ui32LastFound = 0;
+
+ //
+ // Walk through all the class descriptors looking for the one which
+ // matches the requested index and type.
+ //
+ for(ui32Loop = 0; ui32Loop < psHIDDevice->psHIDDescriptor->bNumDescriptors;
+ ui32Loop++)
+ {
+ psDesc = &(psHIDDevice->psHIDDescriptor->sClassDescriptor[ui32Loop]);
+ if(psDesc->bDescriptorType == ui8Type)
+ {
+ //
+ // We found a descriptor of the correct type. Is this the
+ // correct index?
+ //
+ bFoundType = true;
+
+ //
+ // Is this the descriptor we are looking for?
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Yes - we found it so return the index and size to the
+ // caller.
+ //
+ *pui32Len = (uint32_t)psDesc->wDescriptorLength;
+ return(ui32Loop);
+ }
+ else
+ {
+ //
+ // Update our count and keep looking. Remember where we were
+ // when we found this descriptor in case we need to return the
+ // last physical descriptor.
+ //
+ ui32Count++;
+ ui32LastFound = ui32Loop;
+ }
+ }
+ }
+
+ //
+ // If we drop out, we did not find the requested descriptor. Now handle
+ // the special case of a physical descriptor - if we found any physical
+ // descriptors, return the last one.
+ //
+ if((ui8Type == USB_HID_DTYPE_PHYSICAL) && bFoundType)
+ {
+ //
+ // Get the length of the last descriptor we found.
+ //
+ psDesc =
+ &(psHIDDevice->psHIDDescriptor->sClassDescriptor[ui32LastFound]);
+ *pui32Len = (uint32_t)psDesc->wDescriptorLength;
+
+ //
+ // Return the index to the caller.
+ //
+ return(ui32LastFound);
+ }
+ else
+ {
+ //
+ // We could not find the descriptor so return an appropriate error.
+ //
+ return(HID_NOT_FOUND);
+ }
+}
+
+//*****************************************************************************
+//
+// Schedule transmission of the next packet forming part of an input report.
+//
+// \param psHIDInst points to the HID device instance whose input report is to
+// be sent.
+//
+// This function is called to transmit the next packet of an input report
+// passed to the driver via a call to USBDHIDReportWrite. If any data remains
+// to be sent, a USB packet is written to the FIFO and scheduled for
+// transmission to the host. The function ensures that reports are sent as
+// a sequence of full packets followed by either a single int16_t packet or a
+// packet with no data to indicate the end of the transaction.
+//
+//*****************************************************************************
+static int32_t
+ScheduleReportTransmission(tHIDInstance *psHIDInst)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+ int32_t i32Retcode;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = (uint32_t)(psHIDInst->ui16InReportSize -
+ psHIDInst->ui16InReportIndex);
+
+ //
+ // Limit individual transfers to the maximum packet size for the endpoint.
+ //
+ if(ui32NumBytes > USBDHID_MAX_PACKET)
+ {
+ ui32NumBytes = USBDHID_MAX_PACKET;
+ }
+
+ //
+ // Where are we sending this data from?
+ //
+ pui8Data = psHIDInst->pui8InReportData + psHIDInst->ui16InReportIndex;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ i32Retcode = MAP_USBEndpointDataPut(psHIDInst->ui32USBBase,
+ psHIDInst->ui8INEndpoint,
+ pui8Data, ui32NumBytes);
+
+ if(i32Retcode != -1)
+ {
+ //
+ // Update the count and index ready for the next time round.
+ //
+ psHIDInst->ui16InReportIndex += ui32NumBytes;
+
+ //
+ // Send out the current data.
+ //
+ i32Retcode = MAP_USBEndpointDataSend(psHIDInst->ui32USBBase,
+ psHIDInst->ui8INEndpoint,
+ USB_TRANS_IN);
+ }
+
+ //
+ // Tell the caller how we got on.
+ //
+ return(i32Retcode);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data received from the host.
+//
+// \param psHIDDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts signaling
+// the arrival of data on the interrupt OUT endpoint (in other words, whenever
+// the host has sent us a packet of data). We inform the client that a packet
+// is available and, on return, check to see if the packet has been read. If
+// not, we schedule another notification to the client for a later time.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataFromHost(tUSBDHIDDevice *psHIDDevice, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tHIDInstance *psInst;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Has a packet been received?
+ //
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Set the flag we use to indicate that a packet read is pending. This
+ // will be cleared if the packet is read. If the client does not read
+ // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
+ // the event will be signaled later during tick processing.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, HID_DO_PACKET_RX,
+ true);
+
+ //
+ // How big is the packet we have just been sent?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // The receive channel is not blocked so let the caller know
+ // that a packet is waiting. The parameters are set to indicate
+ // that the packet has not been read from the hardware FIFO yet.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // No packet was received. Some error must have been reported. Check
+ // and pass this on to the client if necessary.
+ //
+ if(ui32EPStatus & USB_RX_ERROR_FLAGS)
+ {
+ //
+ // This is an error we report to the client so...
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_ERROR,
+ (ui32EPStatus & USB_RX_ERROR_FLAGS),
+ (void *)0);
+ }
+ return(false);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Receives notifications related to data sent to the host.
+//
+// \param psHIDDevice is the device instance whose endpoint is to be processed.
+// \param ui32Status is the USB interrupt status that caused this function to
+// be called.
+//
+// This function is called from HandleEndpoints for all interrupts originating
+// from the interrupt IN endpoint (in other words, whenever data has been
+// transmitted to the USB host). We examine the cause of the interrupt and,
+// if due to completion of a transmission, notify the client.
+//
+// \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+static bool
+ProcessDataToHost(tUSBDHIDDevice *psHIDDevice, uint32_t ui32Status)
+{
+ tHIDInstance *psInst;
+ uint32_t ui32EPStatus;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8INEndpoint);
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, psInst->ui8INEndpoint,
+ ui32EPStatus);
+
+ //
+ // Our last packet was transmitted successfully. Is there any more data to
+ // send or have we finished sending the whole report? We know we finished
+ // if the ui16InReportIndex has reached the ui16InReportSize value.
+ //
+ if(psInst->ui16InReportSize == psInst->ui16InReportIndex)
+ {
+ //
+ // We finished sending the last report so are idle once again.
+ //
+ psInst->iHIDTxState = eHIDStateIdle;
+
+ //
+ // Notify the client that the report transmission completed.
+ //
+ psHIDDevice->pfnTxCallback(psHIDDevice->pvTxCBData,
+ USB_EVENT_TX_COMPLETE,
+ psInst->ui16InReportSize, (void *)0);
+
+ //
+ // Do we have any reports to send as a result of idle timer timeouts?
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << HID_DO_SEND_IDLE_REPORT))
+ {
+ //
+ // Yes - send reports for any timers that expired recently.
+ //
+ ProcessIdleTimers(psHIDDevice, 0);
+ }
+ }
+ else
+ {
+ //
+ // There must be more data or a zero length packet waiting to be sent
+ // so go ahead and do this.
+ //
+ ScheduleReportTransmission(psInst);
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack for any activity involving one of our endpoints
+// other than EP0. This function is a fan out that merely directs the call to
+// the correct handler depending upon the endpoint and transaction direction
+// signaled in ui32Status.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvHIDInstance, uint32_t ui32Status)
+{
+ tUSBDHIDDevice *psHIDInst;
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psHIDInst = (tUSBDHIDDevice *)pvHIDInstance;
+ psInst = &psHIDInst->sPrivateData;
+
+ //
+ // Handler for the interrupt OUT data endpoint.
+ //
+ if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint)))
+ {
+ //
+ // Data is being sent to us from the host.
+ //
+ ProcessDataFromHost(pvHIDInstance, ui32Status);
+ }
+
+ //
+ // Handler for the interrupt IN data endpoint.
+ //
+ if(ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint)))
+ {
+ ProcessDataToHost(pvHIDInstance, ui32Status);
+ }
+}
+
+//*****************************************************************************
+//
+// Called by the USB stack whenever a configuration change occurs.
+//
+//*****************************************************************************
+static void
+HandleConfigChange(void *pvHIDInstance, uint32_t ui32Info)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Set all our endpoints to idle state.
+ //
+ psInst->iHIDRxState = eHIDStateIdle;
+ psInst->iHIDTxState = eHIDStateIdle;
+
+ //
+ // If we are not currently connected let the client know we are open for
+ // business.
+ //
+ if(!psInst->bConnected)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Clear the idle timers for each input report.
+ //
+ ClearIdleTimers(psHIDDevice);
+
+ //
+ // Remember that we are connected.
+ //
+ psInst->bConnected = true;
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvHIDInstance, uint32_t ui32Request, void *pvRequestData)
+{
+ tHIDInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDHIDDevice *psHIDDevice;
+
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Create the int8_t array used by the events supported by the USB CDC
+ // serial class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+ }
+ else
+ {
+ //
+ // Extract the new endpoint number.
+ //
+ psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_RESUME, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_SLEEP, 0, (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psHIDDevice->pfnRxCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_LPM_ERROR, 0, (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvHIDInstance)
+{
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // If we are not currently connected so let the client know we are open
+ // for business.
+ //
+ if(psHIDDevice->sPrivateData.bConnected)
+ {
+ //
+ // Pass the disconnected event to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+ }
+
+ //
+ // Remember that we are no longer connected.
+ //
+ psHIDDevice->sPrivateData.bConnected = false;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a request for a
+// non-standard descriptor is received.
+//
+// \param pvHIDInstance is the instance data for this request.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure and determines which
+// descriptor is being requested. Assuming the descriptor can be found, it is
+// scheduled for transmission via endpoint zero. If the descriptor cannot be
+// found, the endpoint is stalled to indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleGetDescriptor(void *pvHIDInstance, tUSBRequest *psUSBRequest)
+{
+ uint32_t ui32Size, ui32Desc;
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Which type of class descriptor are we being asked for?
+ //
+ switch(psUSBRequest->wValue >> 8)
+ {
+ //
+ // This is a request for a HID report or physical descriptor.
+ //
+ case USB_HID_DTYPE_REPORT:
+ case USB_HID_DTYPE_PHYSICAL:
+ {
+ //
+ // Find the index to the descriptor that is being queried.
+ //
+ ui32Size = 0;
+ ui32Desc = FindHIDDescriptor(psHIDDevice,
+ psUSBRequest->wValue >> 8,
+ psUSBRequest->wValue & 0xFF,
+ &ui32Size);
+
+ //
+ // Did we find the descriptor?
+ //
+ if(ui32Desc == HID_NOT_FOUND)
+ {
+ //
+ // No - stall the endpoint and return.
+ //
+ USBDCDStallEP0(0);
+ return;
+ }
+
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if(ui32Size > psUSBRequest->wLength)
+ {
+ ui32Size = psUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0,
+ (uint8_t *)psHIDDevice->ppui8ClassDescriptors[ui32Desc],
+ ui32Size);
+
+ break;
+ }
+
+ //
+ // This is a request for the HID descriptor (as found in the
+ // configuration descriptor following the relevant interface).
+ //
+ case USB_HID_DTYPE_HID:
+ {
+ //
+ // How big is the HID descriptor?
+ //
+ ui32Size = (uint32_t)psHIDDevice->psHIDDescriptor->bLength;
+
+ //
+ // If there is more data to send than the host requested then just
+ // send the requested amount of data.
+ //
+ if(ui32Size > psUSBRequest->wLength)
+ {
+ ui32Size = psUSBRequest->wLength;
+ }
+
+ //
+ // Send the data via endpoint 0.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)psHIDDevice->psHIDDescriptor,
+ ui32Size);
+ break;
+ }
+
+ //
+ // This was an unknown request so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvHIDInstance is the instance data for this HID device.
+// \param psUSBRequest points to the request received.
+//
+// This call parses the provided request structure. Assuming the request is
+// understood, it is handled and any required response generated. If the
+// request cannot be handled by this device class, endpoint zero is stalled to
+// indicate an error to the host.
+//
+//*****************************************************************************
+static void
+HandleRequest(void *pvHIDInstance, tUSBRequest *psUSBRequest)
+{
+ tHIDInstance *psInst;
+ uint8_t ui8Protocol;
+ uint32_t ui32Size, ui32Timeout;
+ uint8_t *pui8Report;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Make sure the request was for this interface.
+ //
+ if(psUSBRequest->wIndex != psInst->ui8Interface)
+ {
+ return;
+ }
+
+ //
+ // Determine the type of request.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // A Set Report request is received from the host when it sends an
+ // Output report via endpoint 0.
+ //
+ case USBREQ_SET_REPORT:
+ {
+ //
+ // Ask the application for a buffer large enough to hold the
+ // report we are to be sent.
+ //
+ psInst->ui16OutReportSize = psUSBRequest->wLength;
+ psInst->pui8OutReportData =
+ (uint8_t *)psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT_BUFFER,
+ psUSBRequest->wValue,
+ (void *)(uint32_t)(psUSBRequest->wLength));
+
+ //
+ // Did the client provide us a buffer?
+ //
+ if(!psInst->pui8OutReportData)
+ {
+ //
+ // The application could not provide us a buffer so stall the
+ // request.
+ //
+ USBDCDStallEP0(0);
+ }
+ else
+ {
+ //
+ // The client provided us a buffer to read the report into
+ // so request the data from the host.
+ //
+
+ //
+ // Set the state to indicate we are waiting for data.
+ //
+ psInst->iHIDRxState = eHIDStateWaitData;
+
+ //
+ // Now read the payload of the request. We handle the actual
+ // operation in the data callback once this data is received.
+ //
+ USBDCDRequestDataEP0(0, psInst->pui8OutReportData,
+ (uint32_t)psUSBRequest->wLength);
+
+ //
+ // Need to ACK the data on end point 0 in this case. Do this
+ // after requesting the data to prevent race conditions that
+ // occur if you acknowledge before setting up to receive the
+ // request data.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, false);
+ }
+
+ break;
+ }
+
+ //
+ // A Get Report request is used by the host to poll a device for its
+ // current state.
+ //
+ case USBREQ_GET_REPORT:
+ {
+ //
+ // Get the latest report from the application.
+ //
+ ui32Size = psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_GET_REPORT,
+ psUSBRequest->wValue, &pui8Report);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // ..then send back the requested report.
+ //
+ psInst->bGetRequestPending = true;
+ USBDCDSendDataEP0(0, pui8Report, ui32Size);
+
+ break;
+ }
+
+ //
+ // A set IDLE request has been made. This indicates to us how often a
+ // given report should be sent back to the host in the absence of any
+ // change in state of the device.
+ //
+ case USBREQ_SET_IDLE:
+ {
+ //
+ // Set the idle timeout for the requested report(s).
+ //
+ SetIdleTimeout(psHIDDevice, psUSBRequest->wValue & 0xFF,
+ (psUSBRequest->wValue >> 8) & 0xFF);
+
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ break;
+ }
+
+ //
+ // A get IDLE request has been made. This request queries the current
+ // idle timeout for a given report.
+ //
+ case USBREQ_GET_IDLE:
+ {
+ //
+ // Determine the timeout for the requested report.
+ //
+ ui32Timeout = GetIdleTimeout(psHIDDevice, psUSBRequest->wValue);
+
+ if(ui32Timeout != HID_NOT_FOUND)
+ {
+ //
+ // Need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui32Timeout, 1);
+ }
+ else
+ {
+ //
+ // The report ID was not found so stall the endpoint.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // Set either boot or report protocol for reports sent from the device.
+ // This is only supported by devices in the boot subclass.
+ //
+ case USBREQ_SET_PROTOCOL:
+ {
+ if(psHIDDevice->ui8Subclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_SET_PROTOCOL,
+ psUSBRequest->wValue,
+ (void *)0);
+ }
+ else
+ {
+ //
+ // This is not a boot subclass device so stall the endpoint to
+ // show that we don't support this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // Inform the host of the protocol, boot or report, that is currently
+ // in use. This is only supported by devices in the boot subclass.
+ //
+ case USBREQ_GET_PROTOCOL:
+ {
+ if(psHIDDevice->ui8Subclass == USB_HID_SCLASS_BOOT)
+ {
+ //
+ // We need to ACK the data on end point 0 in this case.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase, USB_EP_0, true);
+
+ //
+ // We are a boot subclass device so pass this on to the
+ // application callback to get the answer.
+ //
+ ui8Protocol = (uint8_t)psHIDDevice->pfnRxCallback(
+ psHIDDevice->pvRxCBData, USBD_HID_EVENT_GET_PROTOCOL, 0,
+ (void *)0);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8Protocol, 1);
+ }
+ else
+ {
+ //
+ // This is not a boot subclass device so stall the endpoint to
+ // show that we don't support this request.
+ //
+ USBDCDStallEP0(0);
+ }
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the data requested
+// on endpoint zero is received.
+//
+//*****************************************************************************
+static void
+HandleEP0DataReceived(void *pvHIDInstance, uint32_t ui32DataSize)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // If we were not passed any data, just return.
+ //
+ if(ui32DataSize == 0)
+ {
+ return;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Make sure we are actually expecting something.
+ //
+ if(psInst->iHIDRxState != eHIDStateWaitData)
+ {
+ return;
+ }
+
+ //
+ // Change the endpoint state back to idle now that we have been passed
+ // the data we were waiting for.
+ //
+ psInst->iHIDRxState = eHIDStateIdle;
+
+ //
+ // The only things we ever request via endpoint zero are reports sent to
+ // us via a Set_Report request. Pass the newly received report on to
+ // the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_SET_REPORT,
+ psInst->ui16OutReportSize,
+ psInst->pui8OutReportData);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the data sent on
+// endpoint zero is received and acknowledged by the host.
+//
+//*****************************************************************************
+static void
+HandleEP0DataSent(void *pvHIDInstance, uint32_t ui32Info)
+{
+ tHIDInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Which device are we dealing with?
+ //
+ psHIDDevice = pvHIDInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // If we just sent a report in response to a Get_Report request, send an
+ // event to the application telling it that the transmission completed.
+ //
+ if(psInst->bGetRequestPending)
+ {
+ //
+ // Clear the flag now that we are sending the application callback.
+ //
+ psInst->bGetRequestPending = false;
+
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USBD_HID_EVENT_REPORT_SENT, 0, (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// reset. If we are currently connected, send a disconnect event at this
+// point.
+//
+//*****************************************************************************
+static void
+HandleReset(void *pvHIDInstance)
+{
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Merely call the disconnect handler. This causes a disconnect message to
+ // be sent to the client if we think we are currently connected.
+ //
+ HandleDisconnect(pvHIDInstance);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is put into
+// suspend state.
+//
+//*****************************************************************************
+static void
+HandleSuspend(void *pvHIDInstance)
+{
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (const tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData, USB_EVENT_SUSPEND, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the bus is taken
+// out of suspend state.
+//
+//*****************************************************************************
+static void
+HandleResume(void *pvHIDInstance)
+{
+ const tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (const tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData, USB_EVENT_RESUME, 0,
+ (void *)0);
+}
+
+//*****************************************************************************
+//
+// This function is called periodically and provides us with a time reference
+// and method of implementing delayed or time-dependent operations.
+//
+// \param pvHIDInstance is the instance data for this request.
+// \param ui32TimemS is the elapsed time in milliseconds since the last call
+// to this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HIDTickHandler(void *pvHIDInstance, uint32_t ui32TimemS)
+{
+ tHIDInstance *psInst;
+ uint32_t ui32Size;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvHIDInstance != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psHIDDevice = (tUSBDHIDDevice *)pvHIDInstance;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // If we are connected, process our idle timers.
+ //
+ if(psInst->bConnected)
+ {
+ ProcessIdleTimers(psHIDDevice, ui32TimemS);
+ }
+
+ //
+ // Do we have a deferred receive waiting
+ //
+ if(psInst->ui16DeferredOpFlags & (1 << HID_DO_PACKET_RX))
+ {
+ //
+ // Yes - how big is the waiting packet?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Tell the client that there is a packet waiting for it.
+ //
+ psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Size,
+ (void *)0);
+ }
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psHIDDevice points to a structure containing parameters customizing
+//! the operation of the HID device.
+//!
+//! An application wishing to offer a USB HID interface to a host system
+//! must call this function to initialize the USB controller and attach the
+//! device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function will return the \e psHIDDevice
+//! pointer passed to it. This must be passed on all future calls from the
+//! application to the HID device class driver.
+//!
+//! The USB HID device class API offers the application a report-based transmit
+//! interface for Input reports. Output reports may be received via the
+//! control endpoint or via a dedicated Interrupt OUT endpoint. If using the
+//! dedicated endpoint, report data is delivered to the application packet-by-
+//! packet. If the application uses reports longer than \b USBDHID_MAX_PACKET
+//! bytes and would rather receive full reports, it may use a USB buffer above
+//! the receive channel to allow full reports to be read.
+//!
+//! Transmit Operation:
+//!
+//! Calls to USBDHIDReportWrite() pass complete reports to the driver for
+//! transmission. These will be transmitted to the host using as many USB
+//! packets as are necessary to complete the transmission.
+//!
+//! Once a full Input report has been acknowledged by the USB host, a
+//! \b USB_EVENT_TX_COMPLETE event is sent to the application transmit callback
+//! to inform it that another report may be transmitted.
+//!
+//! Receive Operation (when using a dedicated interrupt OUT endpoint):
+//!
+//! An incoming USB data packet will result in a call to the application
+//! callback with event \b USB_EVENT_RX_AVAILABLE. The application must then
+//! call USBDHIDPacketRead(), passing a buffer capable of holding the received
+//! packet. The size of the packet may be determined by calling function
+//! USBDHIDRxPacketAvailable() prior to reading the packet.
+//!
+//! Receive Operation (when not using a dedicated OUT endpoint):
+//!
+//! If no dedicated OUT endpoint is used, Output and Feature reports are sent
+//! from the host using the control endpoint, endpoint zero. When such a
+//! report is received, \b USBD_HID_EVENT_GET_REPORT_BUFFER is sent to the
+//! application which must respond with a buffer large enough to hold the
+//! report. The device class driver will then copy the received report into
+//! the supplied buffer before sending \b USBD_HID_EVENT_SET_REPORT to indicate
+//! that the report is now available.
+//!
+//! \note The application must not make any calls to the low level USB device
+//! interface if interacting with USB via the USB HID device class API. Doing
+//! so will cause unpredictable (though almost certainly unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the \e psHIDDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice)
+{
+ tDeviceDescriptor *pi16DevDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psHIDDevice);
+ ASSERT(psHIDDevice->ppui8StringDescriptors);
+ ASSERT(psHIDDevice->pfnRxCallback);
+ ASSERT(psHIDDevice->pfnTxCallback);
+ ASSERT(psHIDDevice->ppui8ClassDescriptors);
+ ASSERT(psHIDDevice->psHIDDescriptor);
+ ASSERT((psHIDDevice->ui8NumInputReports == 0) || psHIDDevice->psReportIdle);
+
+ USBDHIDCompositeInit(ui32Index, psHIDDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ pi16DevDesc = (tDeviceDescriptor *)psHIDDevice->sPrivateData.sDevInfo.pui8DeviceDescriptor;
+ pi16DevDesc->idVendor = psHIDDevice->ui16VID;
+ pi16DevDesc->idProduct = psHIDDevice->ui16PID;
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the HID device on the bus.
+ //
+ USBDCDInit(ui32Index, &psHIDDevice->sPrivateData.sDevInfo,
+ (void *)psHIDDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID device operation.
+//! \param psHIDDevice points to a structure containing parameters customizing
+//! the operation of the HID device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! USB HID device classes call this function to initialize the lower level
+//! HID interface in the USB controller. If this HID device device is part of
+//! a composite device, then the \e psCompEntry should point to the composite
+//! device entry to initialize. This is part of the array that is passed to
+//! the USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDCompositeInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDInstance *psInst;
+ tEndpointDescriptor *psEndpoint;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psHIDDevice);
+ ASSERT(psHIDDevice->ppsConfigDescriptor);
+ ASSERT(psHIDDevice->ppui8StringDescriptors);
+ ASSERT(psHIDDevice->pfnRxCallback);
+ ASSERT(psHIDDevice->pfnTxCallback);
+ ASSERT(psHIDDevice->ppui8ClassDescriptors);
+ ASSERT(psHIDDevice->psHIDDescriptor);
+ ASSERT((psHIDDevice->ui8NumInputReports == 0) || psHIDDevice->psReportIdle);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psHIDDevice->sPrivateData;
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sHIDHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8HIDDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = psHIDDevice->ppsConfigDescriptor;
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psHIDDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psHIDDevice->ui32NumStringDescriptors;
+
+ //
+ // Default the endpoints zero before looking for them in the configuration
+ // descriptor.
+ //
+ psInst->ui8Interface = 0;
+ psInst->ui8INEndpoint = 0;
+ psInst->ui8OUTEndpoint = 0;
+
+ //
+ // Get the first endpoint descriptor on interface 0.
+ //
+ psEndpoint =
+ USBDCDConfigGetInterfaceEndpoint(psHIDDevice->ppsConfigDescriptor[0],
+ psInst->ui8Interface, 0, 0);
+
+ if(psEndpoint)
+ {
+ if(psEndpoint->bEndpointAddress & 0x80)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ else
+ {
+ psInst->ui8OUTEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ }
+
+ //
+ // Get the second endpoint descriptor on interface 0.
+ //
+ psEndpoint =
+ USBDCDConfigGetInterfaceEndpoint(psHIDDevice->ppsConfigDescriptor[0],
+ psInst->ui8Interface, 0, 1);
+ if(psEndpoint)
+ {
+ if(psEndpoint->bEndpointAddress & 0x80)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ else
+ {
+ psInst->ui8OUTEndpoint = IndexToUSBEP(psEndpoint->bEndpointAddress);
+ }
+ }
+
+ //
+ // Must have at least an IN endpoint.
+ //
+ if(psInst->ui8INEndpoint == 0)
+ {
+ return((void *)0);
+ }
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psHIDDevice;
+ }
+
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->iHIDRxState = eHIDStateUnconfigured;
+ psInst->iHIDTxState = eHIDStateUnconfigured;
+ psInst->ui16DeferredOpFlags = 0;
+ psInst->bConnected = false;
+ psInst->bGetRequestPending = false;
+ psInst->bSendInProgress = false;
+ psInst->ui16InReportIndex = 0;
+ psInst->ui16InReportSize = 0;
+ psInst->pui8InReportData = (uint8_t *)0;
+ psInst->ui16OutReportSize = 0;
+ psInst->pui8OutReportData = (uint8_t *)0;
+
+ //
+ // Initialize the device info structure for the HID device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Initialize the input report idle timers if any input reports exist.
+ //
+ ClearIdleTimers(psHIDDevice);
+
+ //
+ // Initialize the USB tick module, this will prevent it from being
+ // initialized later in the call to USBDCDInit();
+ //
+ InternalUSBTickInit();
+
+ //
+ // Register our tick handler (this must be done after USBDCDInit).
+ //
+ InternalUSBRegisterTickHandler(HIDTickHandler, (void *)psHIDDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID device.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function terminates HID operation for the instance supplied and
+//! removes the device from the USB bus. This function should not be called
+//! if the HID device is part of a composite device and instead the
+//! USBDCompositeTerm() function should be called for the full composite
+//! device.
+//!
+//! Following this call, the \e pvHIDInstance instance should not me used in
+//! any other calls.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDTerm(void *pvHIDInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get a pointer to our instance data.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Terminate the requested instance.
+ //
+ USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase));
+
+ psInst->ui32USBBase = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the receive channel
+//! callback.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the receive channel callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnRxCallback function
+//! passed on USBDHIDInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the pvHIDInstance structure passed to USBDHIDInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback pointer that was being used for
+//! this instance's receive callback.
+//
+//*****************************************************************************
+void *
+USBDHIDSetRxCBData(void *pvHIDInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Set the callback data for the receive channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvHIDInstance)->pvRxCBData;
+ ((tUSBDHIDDevice *)pvHIDInstance)->pvRxCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific data pointer for the transmit callback.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the transmit channel callback function.
+//!
+//! The client uses this function to change the callback data pointer passed in
+//! the first parameter on all callbacks to the \e pfnTxCallback function
+//! passed on USBDHIDInit().
+//!
+//! If a client wants to make runtime changes in the callback data, it must
+//! ensure that the pvHIDInstance structure passed to USBDHIDInit() resides in
+//! RAM. If this structure is in flash, callback data changes will not be
+//! possible.
+//!
+//! \return Returns the previous callback data pointer that was being used for
+//! this instance's transmit callback.
+//
+//*****************************************************************************
+void *
+USBDHIDSetTxCBData(void *pvHIDInstance, void *pvCBData)
+{
+ void *pvOldValue;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Set the callback data for the transmit channel after remembering the
+ // previous value.
+ //
+ pvOldValue = ((tUSBDHIDDevice *)pvHIDInstance)->pvTxCBData;
+ ((tUSBDHIDDevice *)pvHIDInstance)->pvTxCBData = pvCBData;
+
+ //
+ // Return the previous callback data value.
+ //
+ return(pvOldValue);
+}
+
+//*****************************************************************************
+//
+//! Transmits a HID device report to the USB host via the HID interrupt IN
+//! endpoint.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pi8Data points to the first byte of data which is to be transmitted.
+//! \param ui32Length is the number of bytes of data to transmit.
+//! \param bLast is ignored in this implementation. This parameter is required
+//! to ensure compatibility with other device class drivers and USB buffers.
+//!
+//! This function schedules the supplied data for transmission to the USB
+//! host in a single USB transaction using as many packets as it takes to send
+//! all the data in the report. If no transmission is currently ongoing,
+//! the first packet of data is immediately copied to the relevant USB endpoint
+//! FIFO for transmission. Whenever all the report data has been acknowledged
+//! by the host, a \b USB_EVENT_TX_COMPLETE event will be sent to the
+//! application transmit callback indicating that another report can now be
+//! transmitted.
+//!
+//! The caller must ensure that the data pointed to by \e pui8Data remains
+//! accessible and unaltered until the \b USB_EVENT_TX_COMPLETE is received.
+//!
+//! \return Returns the number of bytes actually scheduled for transmission.
+//! At this level, this will either be the number of bytes passed or 0 to
+//! indicate a failure.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDReportWrite(void *pvHIDInstance, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ tHIDInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Set a flag indicating that we are currently in the process of sending
+ // a packet.
+ //
+ psInst->bSendInProgress = true;
+
+ //
+ // Can we send the data provided?
+ //
+ if(psInst->iHIDTxState != eHIDStateIdle)
+ {
+ //
+ // We are in the middle of sending another report. Return 0 to
+ // indicate that we can't send this report until the previous one
+ // finishes.
+ //
+ psInst->bSendInProgress = false;
+ return(0);
+ }
+
+ //
+ // Clear the elapsed time since this report was last sent.
+ //
+ if(ui32Length)
+ {
+ ClearReportTimer(pvHIDInstance, *pi8Data);
+ }
+
+ //
+ // Keep track of the whereabouts of the report so that we can send it in
+ // multiple packets if necessary.
+ //
+ psInst->pui8InReportData = pi8Data;
+ psInst->ui16InReportIndex = 0;
+ psInst->ui16InReportSize = ui32Length;
+
+ //
+ // Schedule transmission of the first packet of the report.
+ //
+ psInst->iHIDTxState = eHIDStateWaitData;
+ i32Retcode = ScheduleReportTransmission(psInst);
+
+ //
+ // Clear the flag we use to indicate that we are in the midst of sending
+ // a packet.
+ //
+ psInst->bSendInProgress = false;
+
+ //
+ // Did an error occur while trying to send the data?
+ //
+ if(i32Retcode != -1)
+ {
+ //
+ // No - tell the caller we sent all the bytes provided.
+ //
+ return(ui32Length);
+ }
+ else
+ {
+ //
+ // Yes - tell the caller we could not send the data.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Reads a packet of data received from the USB host via the interrupt OUT
+//! endpoint (if in use).
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//! \param pi8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by pi8Data.
+//! \param bLast indicates whether the client will make a further call to
+//! read additional data from the packet.
+//!
+//! This function reads up to \e ui32Length bytes of data received from the USB
+//! host into the supplied application buffer. If the driver detects that the
+//! entire packet has been read, it is acknowledged to the host.
+//!
+//! The \e bLast parameter is ignored in this implementation since the end of
+//! a packet can be determined without relying upon the client to provide
+//! this information.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDPacketRead(void *pvHIDInstance, uint8_t *pi8Data, uint32_t ui32Length,
+ bool bLast)
+{
+ uint32_t ui32EPStatus, ui32Count, ui32Pkt;
+ tHIDInstance *psInst;
+ int32_t i32Retcode;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // How many bytes are available for us to receive?
+ //
+ ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ //
+ // Get as much data as we can.
+ //
+ ui32Count = ui32Length;
+ i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ pi8Data, &ui32Count);
+
+ //
+ // Did we read the last of the packet data?
+ //
+ if(ui32Count == ui32Pkt)
+ {
+ //
+ // Clear the endpoint status so that we know no packet is
+ // waiting.
+ //
+ MAP_USBDevEndpointStatusClear(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+
+ //
+ // Acknowledge the data, thus freeing the host to send the
+ // next packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, true);
+
+ //
+ // Clear the flag we set to indicate that a packet read is
+ // pending.
+ //
+ SetDeferredOpFlag(&psInst->ui16DeferredOpFlags,
+ HID_DO_PACKET_RX, false);
+ }
+
+ //
+ // If all went well, tell the caller how many bytes they got.
+ //
+ if(i32Retcode != -1)
+ {
+ return(ui32Count);
+ }
+ }
+
+ //
+ // No packet was available or an error occurred while reading so tell
+ // the caller no bytes were returned.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the transmit buffer.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function indicates to the caller whether or not it is safe to send a
+//! new report using a call to USBDHIDReportWrite(). The value returned will
+//! be the maximum USB packet size (\b USBDHID_MAX_PACKET) if no transmission
+//! is currently outstanding or 0 if a transmission is in progress. Since the
+//! function USBDHIDReportWrite() can accept full reports longer than a single
+//! USB packet, the caller should be aware that the returned value from this
+//! class driver, unlike others, does not indicate the maximum size of report
+//! that can be written but is merely an indication that another report can be
+//! written.
+//!
+//! \return Returns 0 if an outgoing report is still being transmitted or
+//! \b USBDHID_MAX_PACKET if no transmission is currently in progress.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDTxPacketAvailable(void *pvHIDInstance)
+{
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Do we have a packet transmission currently ongoing?
+ //
+ if(psInst->iHIDTxState != eHIDStateIdle)
+ {
+ //
+ // We are not ready to receive a new packet so return 0.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // We can receive a packet so return the max packet size for the
+ // relevant endpoint.
+ //
+ return(USBDHID_MAX_PACKET);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a packet is available and, if so, the size of the
+//! buffer required to read it.
+//!
+//! \param pvHIDInstance is the pointer to the device instance structure as
+//! returned by USBDHIDInit().
+//!
+//! This function may be used to determine if a received packet remains to be
+//! read and allows the application to determine the buffer size needed to
+//! read the data.
+//!
+//! \return Returns 0 if no received packet remains unprocessed or the
+//! size of the packet if a packet is waiting to be read.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDRxPacketAvailable(void *pvHIDInstance)
+{
+ uint32_t ui32EPStatus, ui32Size;
+ tHIDInstance *psInst;
+
+ ASSERT(pvHIDInstance);
+
+ //
+ // Get our instance data pointer
+ //
+ psInst = &((tUSBDHIDDevice *)pvHIDInstance)->sPrivateData;
+
+ //
+ // Does the relevant endpoint FIFO have a packet waiting for us?
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+ if(ui32EPStatus & USB_DEV_RX_PKT_RDY)
+ {
+ //
+ // Yes - a packet is waiting. How big is it?
+ //
+ ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint);
+
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // There is no packet waiting to be received.
+ //
+ return(0);
+ }
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvHIDInstance is the pointer to the HID device instance structure.
+//! \param ui8Power indicates the current power status, either
+//! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus- or self-powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDPowerStatusSet(void *pvHIDInstance, uint8_t ui8Power)
+{
+ ASSERT(pvHIDInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDCDPowerStatusSet(0, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvHIDInstance is the pointer to the HID device instance structure.
+//!
+//! When the bus is suspended, an application which supports remote wake up
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wake up signaling to the host. If the remote
+//! wake up feature has not been disabled by the host, this will cause the bus
+//! to resume operation within 20mS. If the host has disabled remote wake up,
+//! \b false will be returned to indicate that the wake up request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wake up is not disabled and the
+//! signaling was started or \b false if remote wake up is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDHIDRemoteWakeupRequest(void *pvHIDInstance)
+{
+ ASSERT(pvHIDInstance);
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDCDRemoteWakeupRequest(0));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhid.h b/usblib/device/usbdhid.h
new file mode 100644
index 0000000..14830fa
--- /dev/null
+++ b/usblib/device/usbdhid.h
@@ -0,0 +1,1102 @@
+//*****************************************************************************
+//
+// usbdhid.h - Definitions used by HID class devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHID_H__
+#define __USBDHID_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDInterface array in bytes.
+//
+//*****************************************************************************
+#define HIDINTERFACE_SIZE (9)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDInEndpoint array in bytes.
+//
+//*****************************************************************************
+#define HIDINENDPOINT_SIZE (7)
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8HIDOutEndpoint array in bytes.
+//
+//*****************************************************************************
+#define HIDOUTENDPOINT_SIZE (7)
+
+//*****************************************************************************
+//
+// This is the size of the tHIDDescriptor in bytes.
+//
+//*****************************************************************************
+#define HIDDESCRIPTOR_SIZE (9)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB HID Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//*****************************************************************************
+#define COMPOSITE_DHID_SIZE (HIDINTERFACE_SIZE + HIDINENDPOINT_SIZE + \
+ HIDOUTENDPOINT_SIZE + HIDDESCRIPTOR_SIZE)
+
+//*****************************************************************************
+//
+// Macros used to create the static Report Descriptors.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Page entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Page value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Page entry
+//! into a HID report structure. These are defined by the USB HID
+//! specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsagePage(ui8Value) 0x05, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Page entries in HID report
+//! descriptors when a vendor-specific value is to be used.
+//!
+//! \param ui16Value is the Usage Page value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Page entry
+//! into a HID report structure. These are defined by the USB HID
+//! specification. Vendor-specific values must lie in the range 0xFF00 to
+//! 0xFFFF inclusive.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsagePageVendor(ui16Value) 0x06, ((ui16Value) & 0xFF), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage entries in HID report descriptors.
+//!
+//! \param ui8Value is the Usage value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage entry into
+//! a HID report structure. These are defined by the USB HID specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Usage(ui8Value) 0x09, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding vendor-specific Usage entries in HID
+//! report descriptors.
+//!
+//! \param ui16Value is the vendor-specific Usage value in the range 0xFF00 to
+//! 0xFFFF.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage entry into
+//! a HID report structure. These are defined by the USB HID specification.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageVendor(ui16Value) 0x0A, ((ui16Value) & 0xFF), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Minimum entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Minimum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Minimum
+//! entry into a HID report structure. This is the first or minimum value
+//! associated with a usage value.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageMinimum(ui8Value) 0x19, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Usage Maximum entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the Usage Maximum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Usage Maximum
+//! entry into a HID report structure. This is the last or maximum value
+//! associated with a usage value.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UsageMaximum(ui8Value) 0x29, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the Logical Minimum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Logical Minimum
+//! entry into a HID report structure. This is the actual minimum value for a
+//! range of values associated with a field.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define LogicalMinimum(i8Value) 0x15, ((i8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Logical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the Logical Maximum value.
+//!
+//! This macro takes a value and prepares it to be placed as a Logical Maximum
+//! entry into a HID report structure. This is the actual maximum value for a
+//! range of values associated with a field.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define LogicalMaximum(i8Value) 0x25, ((i8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Minimum entries in HID report
+//! descriptors.
+//!
+//! \param i16Value is the Physical Minimum value. It is a signed, 16 bit
+//! number.
+//!
+//! This macro takes a value and prepares it to be placed as a Physical Minimum
+//! entry into a HID report structure. This is value is used in conversion of
+//! the control logical value, as returned to the host in the relevant report,
+//! to a physical measurement in the appropriate units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define PhysicalMinimum(i16Value) \
+ 0x36, ((i16Value) & 0xFF), \
+ (((i16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Physical Maximum entries in HID report
+//! descriptors.
+//!
+//! \param i16Value is the Physical Maximum value. It is a signed, 16 bit
+//! number.
+//!
+//! This macro takes a value and prepares it to be placed as a Physical Maximum
+//! entry into a HID report structure. This is value is used in conversion of
+//! the control logical value, as returned to the host in the relevant report,
+//! to a physical measurement in the appropriate units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define PhysicalMaximum(i16Value) \
+ 0x46, ((i16Value) & 0xFF), \
+ (((i16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Collection entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the type of Collection.
+//!
+//! This macro takes a value and prepares it to be placed as a Collection
+//! entry into a HID report structure. This is the type of values that are
+//! being grouped together, for instance input, output or features can be
+//! grouped together as a collection.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Collection(ui8Value) 0xa1, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding End Collection entries in HID report
+//! descriptors.
+//!
+//! This macro can be used to place an End Collection entry into a HID report
+//! structure. This is a tag to indicate that a collection of entries has
+//! ended in the HID report structure. This terminates a previous Collection()
+//! entry.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define EndCollection 0xc0
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report Count entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the number of items in a report item.
+//!
+//! This macro takes a value and prepares it to be placed as a Report Count
+//! entry into a HID report structure. This is number of entries of Report
+//! Size for a given item.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportCount(ui8Value) 0x95, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report ID entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the identifier prefix for the current report.
+//!
+//! This macro takes a value and prepares it to be placed as a Report ID
+//! entry into a HID report structure. This value is used as a 1 byte prefix
+//! for the report it is contained within.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportID(ui8Value) 0x85, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Report Size entries in HID report
+//! descriptors.
+//!
+//! \param ui8Value is the size, in bits, of items in a report item.
+//!
+//! This macro takes a value and prepares it to be placed as a Report Size
+//! entry into a HID report structure. This is size in bits of the entries of
+//! of a report entry. The Report Count specifies how many entries of Report
+//! Size are in a given item. These can be individual bits or bit fields.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define ReportSize(ui8Value) 0x75, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of input report
+//! items. Note that if the USB_HID_INPUT_BITF flag is required, the Input2
+//! macro (which uses a 2 byte version of the Input item tag) must be used
+//! instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as an Input entry
+//! into a HID report structure. This specifies the type of an input item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of input for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Input(ui8Value) 0x81, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Input entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of input report
+//! items. Note that this macro uses a version of the Input item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If USB_HID_INPUT_BITF (bit 8) is not required, the Input macro
+//! may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as an Input entry
+//! into a HID report structure. This specifies the type of an input item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of input for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Input2(ui16Value) 0x82, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of feature report
+//! items. Note that if the \b USB_HID_FEATURE_BITF flag is required, the
+//! Feature2 macro (which uses a 2 byte version of the Feature item tag) must
+//! be used instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as a Feature entry
+//! into a HID report structure. This specifies the type of a feature item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of feature for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Feature(ui8Value) 0xB1, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Feature entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of feature report
+//! items. Note that this macro uses a version of the Feature item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If \b USB_HID_FEATURE_BITF (bit 8) is not required, the Feature
+//! macro may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as a Feature entry
+//! into a HID report structure. This specifies the type of a feature item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of feature for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Feature2(ui16Value) 0xB2, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param ui8Value is bit mask to specify the type of a set of output report
+//! items. Note that if the \b USB_HID_OUTPUT_BITF flag is required, the
+//! Output2 macro (which uses a 2 byte version of the Output item tag) must be
+//! used instead of this macro.
+//!
+//! This macro takes a value and prepares it to be placed as an Output entry
+//! into a HID report structure. This specifies the type of an output item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of output for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Output(ui8Value) 0x91, ((ui8Value) & 0xff)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Output entries in HID report descriptors.
+//!
+//! \param ui16Value is bit mask to specify the type of a set of output report
+//! items. Note that this macro uses a version of the Output item tag with a
+//! two byte payload and allows any of the 8 possible data bits for the tag to
+//! be used. If \b USB_HID_OUTPUT_BITF is not required, the Output macro
+//! may be used instead.
+//!
+//! This macro takes a value and prepares it to be placed as an Output entry
+//! into a HID report structure. This specifies the type of an output item in
+//! a report structure. These refer to a bit mask of flags that indicate the
+//! type of output for a set of items.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Output2(ui16Value) 0x92, ((ui16Value) & 0xff), \
+ (((ui16Value) >> 8) & 0xFF)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit Exponent entries in HID report
+//! descriptors.
+//!
+//! \param i8Value is the required exponent in the range [-8, 7].
+//!
+//! This macro takes a value and prepares it to be placed as a Unit Exponent
+//! entry into a HID report structure. This is the exponent applied to
+//! PhysicalMinimum and PhysicalMaximum when scaling and converting control
+//! values to "real" units.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define UnitExponent(i8Value) 0x55, ((i8Value) & 0x0f)
+
+//*****************************************************************************
+//
+//! This is a macro to assist adding Unit entries for uncommon units in HID
+//! report descriptors.
+//!
+//! \param ui32Value is the definition of the unit required as defined in
+//! section 6.2.2.7 of the USB HID device class definition document.
+//!
+//! This macro takes a value and prepares it to be placed as a Unit entry into
+//! a HID report structure. Note that individual macros are defined for common
+//! units and this macro is intended for use when a complex or uncommon unit
+//! is needed. It allows entry of a 5 nibble unit definition into the report
+//! descriptor.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define Unit(ui32Value) 0x67, (ui32Value) & 0x0f), \
+ (((ui32Value) >> 8) & 0xFF), \
+ (((ui32Value) >> 16) & 0xFF), \
+ (((ui32Value) >> 24) & 0xFF)
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for centimeters into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitDistance_cm 0x66, 0x11, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for inches into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitDistance_i 0x66, 0x13, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for degrees into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitRotation_deg 0x66, 0x14, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for radians into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitRotation_rad 0x66, 0x12, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for grams into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitMass_g 0x66, 0x01, 0x01
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for seconds into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitTime_s 0x66, 0x01, 0x10
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for temperature in Kelvin into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitTemp_K 0x67, 0x01, 0x00, 0x01, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for temperature in Fahrenheit into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitTemp_F 0x67, 0x03, 0x00, 0x01, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for velocity in cm/s into a report
+//! descriptor.
+//!
+//*****************************************************************************
+#define UnitVelocitySI 0x66, 0x11, 0xF0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for momentum in (grams * cm)/s into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitMomentumSI 0x66, 0x11, 0xF1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for acceleration in cm/s**2 into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitAccelerationSI 0x66, 0x11, 0xE0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for force in (cm * grams)/s**2 into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitForceSI 0x66, 0x11, 0xE1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for energy in (grams * cm^2)/(s^2) into a
+//! report descriptor.
+//!
+//*****************************************************************************
+#define UnitEnergySI 0x66, 0x21, 0xE1
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for angular acceleration in degrees/(s^2)
+//! into a report descriptor.
+//!
+//*****************************************************************************
+#define UnitAngAccelerationSI 0x66, 0x12, 0xE0
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for voltage into a a report descriptor.
+//!
+//*****************************************************************************
+#define UnitVoltage 0x67, 0x21, 0xD1, 0xF0, 0x00
+
+//*****************************************************************************
+//
+//! This macro inserts a Unit entry for voltage into a a report descriptor.
+//!
+//*****************************************************************************
+#define UnitCurrent_A 0x67, 0x01, 0x00, 0x10, 0x00
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID code and are here only to help with the application
+// allocating the correct amount of memory for the HID device code.
+//
+//*****************************************************************************
+#define USBDHID_MAX_PACKET 64
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the device can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eHIDStateUnconfigured,
+
+ //
+ // No outstanding transaction remains to be completed.
+ //
+ eHIDStateIdle,
+
+ //
+ // Waiting on completion of a send or receive transaction.
+ //
+ eHIDStateWaitData
+}
+tHIDState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for
+// HID devices. The memory for this structure is included in the
+// sPrivateData field in the tUSBDHIDDevice structure passed in the
+// USBDHIDInit() function.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // The state of the HID receive channel.
+ //
+ volatile tHIDState iHIDRxState;
+
+ //
+ // The state of the HID transmit channel.
+ //
+ volatile tHIDState iHIDTxState;
+
+ //
+ // State of any pending operations that could not be handled immediately
+ // upon receipt.
+ //
+ volatile uint16_t ui16DeferredOpFlags;
+
+ //
+ // Size of the HID IN report.
+ //
+ uint16_t ui16InReportSize;
+
+ //
+ // .
+ //
+ uint16_t ui16InReportIndex;
+
+ //
+ // Size of the HID OUT report.
+ //
+ uint16_t ui16OutReportSize;
+
+ //
+ // Pointer to the current HID IN report data.
+ //
+ uint8_t *pui8InReportData;
+
+ //
+ // Pointer to the current HID OUT report data.
+ //
+ uint8_t *pui8OutReportData;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // Whether an IN transaction is in process.
+ //
+ volatile bool bSendInProgress;
+
+ //
+ // An HID request transaction is in process(Endpoint 0).
+ //
+ bool bGetRequestPending;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+}
+tHIDInstance;
+
+//*****************************************************************************
+//
+//! The structure used to track idle time for reports. An array of these
+//! structures is passed to the HID device class driver during USBDHIDInit and
+//! is used to track automatic resending of each report (if not disabled by
+//! the host).
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The idle duration for the report expressed in units of 4mS. 0
+ //! indicates infinite and informs the class driver not to send the report
+ //! unless a state change occurs.
+ //
+ uint8_t ui8Duration4mS;
+
+ //
+ //! The ID of the report which this structure applies to. This is the
+ //! report ID as specified using a ReportID tag in the report descriptor
+ //! rather than the index of the report in the HID class descriptor array.
+ //! If only a single Input report is supported and, thus, no ReportID tag
+ //! is present, this field should be set to 0.
+ //
+ uint8_t ui8ReportID;
+
+ //
+ //! The number of milliseconds before we need to send a copy of a given
+ //! report back to the host. This field is updated by the HID driver and
+ //! used to time sending of \b USBD_HID_EVENT_IDLE_TIMEOUT.
+ //
+ uint16_t ui16TimeTillNextmS;
+
+ //
+ //! The number of milliseconds that have passed since the last time this
+ //! report was sent. The HID class driver needs to track this since
+ //! Set_Idle requests are required to take effect as if issued immediately
+ //! after the last transmission of the report to which they refer.
+ //
+ uint32_t ui32TimeSinceReportmS;
+}
+tHIDReportIdle;
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the HID device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ uint8_t ui8PwrAttributes;
+
+ //
+ //! The interface subclass to publish to the server for this HID device.
+ //
+ uint8_t ui8Subclass;
+
+ //
+ //! The interface protocol to publish to the server for this HID device.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ //! The number of Input reports that this device supports. This field
+ //! must equal the number of reports published in the HID class descriptors
+ //! for the device and also the number of entries in the array whose first
+ //! element is pointed to by field \e pi16ReportIdle below.
+ //
+ uint8_t ui8NumInputReports;
+
+ //
+ //! A pointer to the first element in an array of structures used to track
+ //! idle time for each Input report. When USBDHIDInit() is called, the
+ //! ui8Duration4mS and ui8ReportID fields of each of these array members
+ //! should be initialized to indicate the default idle timeout for each
+ //! input report. This array must be in RAM since the HID device class
+ //! driver updates values in it in response to requests from the host
+ //! and to track elapsed time. The number of elements in the array must
+ //! match the number supplied in the ui8NumInputReports field above.
+ //
+ tHIDReportIdle *psReportIdle;
+
+ //! A pointer to the callback function which is called to notify
+ //! the application of general events, events related to report transfers
+ //! on endpoint zero and events related to reception of Output and Feature
+ //! reports via the (optional) interrupt OUT endpoint.
+ //
+ tUSBCallback pfnRxCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the receive channel callback,
+ //! pfnRxCallback.
+ //
+ void *pvRxCBData;
+
+ //
+ //! A pointer to the callback function which is called to notify
+ //! the application of events related to transmission of Input reports
+ //! via the interrupt IN endpoint.
+ //
+ tUSBCallback pfnTxCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the transmit channel callback,
+ //! pfnTxCallback.
+ //
+ void *pvTxCBData;
+
+ //
+ //! If set to true, this field indicates that the device should use a
+ //! dedicated interrupt OUT endpoint to receive reports from the host. In
+ //! this case, reports from the host are passed to the application via the
+ //! receive callback using \b USB_EVENT_RX_AVAILABLE events. If false,
+ //! reports from the host are received via endpoint zero and passed to the
+ //! application via \b USBD_HID_EVENT_REPORT_SENT events.
+ //
+ bool bUseOutEndpoint;
+
+ //
+ //! The HID descriptor that the device is to publish (following the
+ //! standard interface descriptor and prior to the endpoint descriptors for
+ //! the interface).
+ //
+ const tHIDDescriptor *psHIDDescriptor;
+
+ //
+ //! The HID class descriptors offered by the device are defined in an
+ //! array of byte pointers and this field points to that array. The
+ //! order and number of elements in the array must match the associated
+ //! information provided in the HID descriptor in field by
+ //! \e pi16HIDDescriptor.
+ //
+ const uint8_t * const *ppui8ClassDescriptors;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1), (optionally) First HID device-specific string
+ //! (language 1), (optionally) Second HID device-specific string (language
+ //! 1), etc.
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //! The number of HID device-specific strings is dependent upon the content
+ //! of the report descriptor passed to the interface and is, thus,
+ //! application controlled.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ uint32_t ui32NumStringDescriptors;
+
+ //
+ // ! The configuration descriptor for this HID device.
+ //
+ const tConfigHeader * const *ppsConfigDescriptor;
+
+ //
+ //! The private instance data for this device instance. This
+ //! memory must remain accessible for as long as the HID device is in
+ //! use and must not be modified by any code outside the HID class driver.
+ //
+ tHIDInstance sPrivateData;
+}
+tUSBDHIDDevice;
+
+//*****************************************************************************
+//
+// HID-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the host is requesting a particular report be
+//! returned via endpoint 0, the control endpoint. The ui32MsgValue parameter
+//! contains the requested report type in the high byte and report ID in the
+//! low byte (as passed in the wValue field of the USB request structure).
+//! The pvMsgData parameter contains a pointer which must be written with the
+//! address of the first byte of the requested report. The callback must
+//! return the size in bytes of the report pointed to by *pvMsgData. The
+//! memory returned in response to this event must remain unaltered until
+//! \b USBD_HID_EVENT_REPORT_SENT is sent.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_REPORT \
+ (USBD_HID_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This event indicates that a report previously requested via a
+//! \b USBD_HID_EVENT_GET_REPORT has been successfully transmitted to the host.
+//! The application may now free or reuse the report memory passed on the
+//! previous event. Although this would seem to be an event that would be
+//! passed to the transmit channel callback, it is actually passed to the
+//! receive channel callback. This ensures that all events related to the
+//! request and transmission of reports via endpoint zero can be handled in
+//! a single function.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_REPORT_SENT \
+ (USBD_HID_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This event indicates that the host has sent a Set_Report request to
+//! the device and requests that the device provide a buffer into which the
+//! report can be written. The ui32MsgValue parameter contains the received
+//! report type in the high byte and report ID in the low byte (as passed in
+//! the wValue field of the USB request structure). The pvMsgData parameter
+//! contains the length of buffer requested. Note that this is the actual
+//! length value cast to a "void *" type and not a pointer in this case.
+//! The callback must return a pointer to a suitable buffer (cast to the
+//! standard "uint32_t" return type for the callback).
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_REPORT_BUFFER \
+ (USBD_HID_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+//! This event indicates that the host has sent the device a report via
+//! endpoint 0, the control endpoint. The ui32MsgValue field indicates the
+//! size of the report and pvMsgData points to the first byte of the report.
+//! The report buffer was previously returned in response to an
+//! earlier \b USBD_HID_EVENT_GET_REPORT_BUFFER callback. The HID device class
+//! driver does not access the memory pointed to by pvMsgData after this
+//! callback is made so the application is free to reuse or free it at this
+//! point.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_SET_REPORT \
+ (USBD_HID_EVENT_BASE + 3)
+
+//*****************************************************************************
+//
+//! This event is sent in response to a Get_Protocol request from the host.
+//! The callback should provide the current protocol via the return code,
+//! \b USB_HID_PROTOCOL_BOOT or \b USB_HID_PROTOCOL_REPORT.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_GET_PROTOCOL \
+ (USBD_HID_EVENT_BASE + 4)
+
+//*****************************************************************************
+//
+//! This event is sent in response to a Set_Protocol request from the host.
+//! The ui32MsgData value contains the requested protocol,
+//! \b USB_HID_PROTOCOL_BOOT or \b USB_HID_PROTOCOL_REPORT.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_SET_PROTOCOL \
+ (USBD_HID_EVENT_BASE + 5)
+
+//*****************************************************************************
+//
+//! This event indicates to an application that a report idle timeout has
+//! occurred and requests a pointer to the report that must be sent back to
+//! the host. The ui32MsgData value contains the requested report ID and
+//! pvMsgData contains a pointer that must be written with a pointer to the
+//! report data that is to be sent. The callback must return the number of
+//! bytes in the report pointed to by *pvMsgData.
+//
+//*****************************************************************************
+#define USBD_HID_EVENT_IDLE_TIMEOUT \
+ (USBD_HID_EVENT_BASE + 6)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDInit(uint32_t ui32Index, tUSBDHIDDevice *psHIDDevice);
+extern void *USBDHIDCompositeInit(uint32_t ui32Index,
+ tUSBDHIDDevice *psDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDTerm(void *pvHIDInstance);
+extern void *USBDHIDSetRxCBData(void *pvHIDInstance, void *pvCBData);
+extern void *USBDHIDSetTxCBData(void *pvHIDInstance, void *pvCBData);
+extern uint32_t USBDHIDReportWrite(void *pvHIDInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDHIDPacketRead(void *pvHIDInstance, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+extern uint32_t USBDHIDTxPacketAvailable(void *pvHIDInstance);
+extern uint32_t USBDHIDRxPacketAvailable(void *pvHIDInstance);
+extern bool USBDHIDRemoteWakeupRequest(void *pvHIDInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following APIs are deprecated.
+//
+//*****************************************************************************
+#ifndef DEPRECATED
+
+//
+// Use USBDCDFeatureSet() or USBHCDFeatureSet() with \b USBLIB_FEATURE_POWER
+// configuration option.
+//
+extern void USBDHIDPowerStatusSet(void *pvHIDInstance, uint8_t ui8Power);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHID_H__
diff --git a/usblib/device/usbdhidgamepad.c b/usblib/device/usbdhidgamepad.c
new file mode 100644
index 0000000..a0945cc
--- /dev/null
+++ b/usblib/device/usbdhidgamepad.c
@@ -0,0 +1,845 @@
+//*****************************************************************************
+//
+// usbdhidgame.c - USB HID Gamepad device class driver
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidgamepad.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_gamepad_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+//*****************************************************************************
+static uint8_t g_pui8GameDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(24), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Self Powered.
+ 0, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// This is the HID interface descriptor for the gamepad device.
+//
+//*****************************************************************************
+static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ 0, // The interface sub-class.
+ 0, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+//*****************************************************************************
+//
+// This is the HID IN endpoint descriptor for the gamepad device.
+//
+//*****************************************************************************
+static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 1, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The following is the HID report structure definition that is passed back
+// to the host.
+//
+//*****************************************************************************
+static const uint8_t g_pui8GameReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_JOYSTICK),
+ Collection(USB_HID_APPLICATION),
+ //
+ // The axis for the controller.
+ //
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage (USB_HID_POINTER),
+ Collection (USB_HID_PHYSICAL),
+
+ //
+ // The X, Y and Z values which are specified as 8-bit absolute
+ // position values.
+ //
+ Usage (USB_HID_X),
+ Usage (USB_HID_Y),
+ Usage (USB_HID_Z),
+
+ //
+ // 3 8-bit absolute values.
+ //
+ ReportSize(8),
+ ReportCount(3),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ //
+ // The 8 buttons.
+ //
+ UsagePage(USB_HID_BUTTONS),
+ UsageMinimum(1),
+ UsageMaximum(8),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+ PhysicalMinimum(0),
+ PhysicalMaximum(1),
+
+ //
+ // 8 - 1 bit values for the buttons.
+ //
+ ReportSize(1),
+ ReportCount(8),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ EndCollection,
+ EndCollection
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the gamepad device.
+//
+//*****************************************************************************
+static tHIDDescriptor g_sGameHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8GameReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four sections.
+// These sections are:
+//
+// 1. The 9 byte configuration descriptor.
+// 2. The interface descriptor.
+// 3. The HID report and physical descriptors, provided by the application
+// or the default can be used.
+// 4. The mandatory interrupt IN endpoint descriptor.
+//
+//*****************************************************************************
+static const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8GameDescriptor),
+ g_pui8GameDescriptor
+};
+
+static const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+static const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+static tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sGameHIDDescriptor),
+ (const uint8_t *)&g_sGameHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+static const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+};
+
+#define NUM_HID_SECTIONS ((sizeof(g_psHIDSections) / \
+ sizeof(tConfigSection *)))
+
+//*****************************************************************************
+//
+// The header for the single configuration supported. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+static tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+static const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the gamepad class there is only a
+// single report descriptor.
+//
+//*****************************************************************************
+static const uint8_t *g_ppui8GameClassDescriptors[] =
+{
+ g_pui8GameReportDescriptor
+};
+
+//*****************************************************************************
+//
+// HID gamepad transmit channel event handler function.
+//
+// \param pvGameDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to the HID gamepad device structure
+// of the type tUSBDHIDGamepadDevice.
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the lower level HID device class driver to inform
+// the application of particular asynchronous events related to report events
+// related to using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDGamepadTxHandler(void *pvGameDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDGamepadDevice *psGamepad;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvGameDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psGamepad = (tUSBDHIDGamepadDevice *)pvGameDevice;
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // The last transmission is complete so return to the idle state.
+ //
+ psInst->iState = eHIDGamepadStateIdle;
+
+ //
+ // Pass the event on to the application.
+ //
+ psGamepad->pfnCallback(psGamepad->pvCBData, USB_EVENT_TX_COMPLETE,
+ ui32MsgData, (void *)0);
+
+ break;
+ }
+
+ //
+ // Ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Main HID device class event receive handler function.
+//
+// \param pvGameDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to the HID gamepad device structure
+// of the type tUSBDHIDGamepadDevice.
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the lower level HID device class driver to inform
+// the application of particular asynchronous events related to operation of
+// the gamepad HID device.
+//
+// \note This function also receive all generic events as well such as
+// \b USB_EVENT_CONNECTED and USB_EVENT_DISCONNECTED.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDGamepadRxHandler(void *pvGamepad, uint32_t ui32Event, uint32_t ui32MsgData,
+ void *pvMsgData)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDGamepadDevice *psGamepad;
+ uint32_t ui32Ret;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvGamepad);
+
+ //
+ // Return zero by default.
+ //
+ ui32Ret = 0;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psGamepad = (tUSBDHIDGamepadDevice *)pvGamepad;
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch(ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Now in the idle state.
+ //
+ psInst->iState = eHIDGamepadStateIdle;
+
+ //
+ // Pass the information on to the application.
+ //
+ psGamepad->pfnCallback(psGamepad->pvCBData, USB_EVENT_CONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Pass the information on to the application.
+ //
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData,
+ USB_EVENT_DISCONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // This handles the Set Idle command.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ {
+ //
+ // Give the pointer to the idle report structure.
+ //
+ *(void **)pvMsgData = (void *)&psInst->sReportIdle;
+
+ ui32Ret = sizeof(psInst->sReportIdle);
+
+ break;
+ }
+
+ //
+ // The host is polling for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // If this is an IN request then pass the request on to the
+ // application. All other requests are ignored.
+ //
+ if(ui32MsgData == USB_HID_REPORT_IN)
+ {
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData,
+ USBD_HID_EVENT_GET_REPORT, 0,
+ pvMsgData);
+ }
+
+ break;
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // Pass these events to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ ui32Ret = psGamepad->pfnCallback(psGamepad->pvCBData, ui32Event,
+ ui32MsgData, pvMsgData);
+
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request which
+ // is not supported for gamepads.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID gamepad device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller that is to be
+//! initialized for HID gamepad device operation.
+//! \param psGamepad points to a structure containing parameters
+//! customizing the operation of the HID gamepad device.
+//!
+//! An application that enables a USB HID gamepad interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! gamepad device to the USB bus. This function performs all required USB
+//! initialization, and the device is ready for operation on the function
+//! return.
+//!
+//! On successful completion, this function returns the modified \e psGamepad
+//! pointer passed to it or returns a NULL pointer if there was a problem.
+//! This pointer must be passed on all future calls to the HID gamepad device
+//! driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED, after which calls can be made to
+//! USBDHIDGamepadSendReport() to report changes to the gamepad interface to
+//! the USB host when it requests them.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID gamepad device class
+//! API.
+//!
+//! \return Returns NULL on failure or the \e psGamepad pointer on success.
+//
+//*****************************************************************************
+tUSBDHIDGamepadDevice *
+USBDHIDGamepadInit(uint32_t ui32Index, tUSBDHIDGamepadDevice *psGamepad)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check basic parameter validity.
+ //
+ ASSERT(psGamepad);
+ ASSERT(psGamepad->ppui8StringDescriptors);
+ ASSERT(psGamepad->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDGamepadCompositeInit(ui32Index, psGamepad, 0);
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8GameDescriptor;
+ pConfigDesc->bmAttributes = psGamepad->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psGamepad->ui16MaxPowermA / 2);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // gamepad.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return(psGamepad);
+ }
+ else
+ {
+ return((tUSBDHIDGamepadDevice *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID gamepad device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller that is to be
+//! initialized for HID gamepad device operation.
+//! \param psGamepad points to a structure containing parameters
+//! customizing the operation of the HID gamepad device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDGamepadInit() except that it is used
+//! for initializing an instance of the HID gamepad device for use in a
+//! composite device. If this HID gamepad is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This entry is part of the array that is passed to the
+//! USBDCompositeInit() function to start up and complete configuration of a
+//! composite USB device.
+//!
+//! \return Returns NULL on failure or the \e psGamepad value that should be
+//! used with the remaining USB HID gamepad APIs.
+//
+//*****************************************************************************
+tUSBDHIDGamepadDevice *
+USBDHIDGamepadCompositeInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psGamepad,
+ tCompositeEntry *psCompEntry)
+{
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psGamepad);
+ ASSERT(psGamepad->ppui8StringDescriptors);
+ ASSERT(psGamepad->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psGamepad->sPrivateData;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psGamepad->ui16PID;
+ psHIDDevice->ui16VID = psGamepad->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psGamepad->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psGamepad->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = 0;
+ psHIDDevice->ui8Protocol = 0;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+ psInst->sReportIdle.ui8Duration4mS = 125;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psHIDDevice->pfnTxCallback = HIDGamepadTxHandler;
+ psHIDDevice->pvRxCBData = (void *)psGamepad;
+ psHIDDevice->pfnRxCallback = HIDGamepadRxHandler;
+ psHIDDevice->pvTxCBData = (void *)psGamepad;
+ psHIDDevice->bUseOutEndpoint = false,
+ psHIDDevice->psHIDDescriptor = &g_sGameHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_ppui8GameClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors = psGamepad->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psGamepad->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ //
+ // If there was an override for the report descriptor then use it.
+ //
+ if(psGamepad->pui8ReportDescriptor)
+ {
+ //
+ // Save the report descriptor in the list of report descriptors.
+ //
+ g_ppui8GameClassDescriptors[0] = psGamepad->pui8ReportDescriptor;
+
+ //
+ // Override the report descriptor size.
+ //
+ g_sGameHIDDescriptor.sClassDescriptor[0].wDescriptorLength =
+ psGamepad->ui32ReportSize;
+ }
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a gamepad.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Schedules a report to be sent once the host requests more data.
+//!
+//! \param psHIDGamepad is the structure pointer that is returned from the
+//! USBDHIDGamepadCompositeInit() or USBDHIDGamepadInit() functions.
+//! \param pvReport is the data to send to the host.
+//! \param ui32Size is the number of bytes in the \e pvReport buffer.
+//!
+//! This call is made by an application to schedule data to be sent to the
+//! host when the host requests an update from the device. The application
+//! must then wait for a \b USB_EVENT_TX_COMPLETE event in the function
+//! provided in the \e pfnCallback pointer in the tUSBDHIDGamepadDevice
+//! structure before being able to send more data with this function. The
+//! pointer passed in the \e pvReport can be updated once this call returns as
+//! the data has been copied from the buffer. The function returns
+//! \b USBDGAMEPAD_SUCCESS if the transmission was successfully scheduled or
+//! \b USBDGAMEPAD_TX_ERROR if the report could not be sent at this time.
+//! If the call is made before the device is connected or ready to communicate
+//! with the host, then the function can return \b USBDGAMEPAD_NOT_CONFIGURED.
+//!
+//! \return The function returns one of the \b USBDGAMEPAD_* values.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDGamepadSendReport(tUSBDHIDGamepadDevice *psHIDGamepad, void *pvReport,
+ uint32_t ui32Size)
+{
+ uint32_t ui32Retcode, ui32Count;
+ tUSBDGamepadInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDGamepad->sPrivateData;
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(psInst->iState == eHIDGamepadStateNotConnected)
+ {
+ return(USBDGAMEPAD_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->iState = eHIDGamepadStateSending;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice, pvReport, ui32Size,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(ui32Count == 0)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ ui32Retcode = USBDGAMEPAD_TX_ERROR;
+ }
+ else
+ {
+ ui32Retcode = USBDGAMEPAD_SUCCESS;
+ }
+ }
+ else
+ {
+ ui32Retcode = USBDGAMEPAD_TX_ERROR;
+ }
+
+ //
+ // Return the relevant error code to the caller.
+ //
+ return(ui32Retcode);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID gamepad device.
+//!
+//! \param psGamepad is the pointer to the device instance structure
+//! as returned by USBDHIDGamepadInit() or USBDHIDGamepadCompositeInit().
+//!
+//! This function terminates HID gamepad operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e psGamepad instance may not me used in any other call to the HID
+//! gamepad device other than to reinitialize by calling USBDHIDGamepadInit()
+//! or USBDHIDGamepadCompositeInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDGamepadTerm(tUSBDHIDGamepadDevice *psGamepad)
+{
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(psGamepad);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psGamepad->sPrivateData.sHIDDevice;
+
+ //
+ // Mark the device as no longer connected.
+ //
+ psGamepad->sPrivateData.iState = eHIDGamepadStateNotConnected;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidgamepad.h b/usblib/device/usbdhidgamepad.h
new file mode 100644
index 0000000..3610680
--- /dev/null
+++ b/usblib/device/usbdhidgamepad.h
@@ -0,0 +1,274 @@
+//*****************************************************************************
+//
+// usbdhidgame.h - The header information for using the USB libraries game pad
+// device class.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDGAME_H__
+#define __USBDHIDGAME_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_gamepad_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the game pad can be in during
+// normal operation. This should not be used by applications and is only
+// here for memory allocation purposes.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Not yet configured.
+ //
+ eHIDGamepadStateNotConnected,
+
+ //
+ // Nothing to transmit and not waiting on data to be sent.
+ //
+ eHIDGamepadStateIdle,
+
+ //
+ // Waiting on data to be sent.
+ //
+ eHIDGamepadStateSending
+}
+tGamepadState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This is the structure for an instance of a USB game pad device. This should
+// not be used by applications and is only here for memory allocation purposes.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+
+ //
+ // The current state of the game pad device.
+ //
+ tGamepadState iState;
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+} tUSBDGamepadInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID game device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wake up. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function that is called to notify
+ //! the application of general events. This pointer must point to a valid
+ //! function.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer that is sent as the first parameter in all
+ //! calls made to the pfnCallback gamedevice callback function.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order:
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array, which must be (1 + (5 * (number of languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! Optional report descriptor if the application wants to use a custom
+ //! descriptor.
+ //
+ const uint8_t *pui8ReportDescriptor;
+
+ //
+ //! The size of the optional report descriptor define in
+ //! pui8ReportDescriptor.
+ //
+ const uint32_t ui32ReportSize;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the game device is in use and
+ //! must not be modified by any code outside the HID game device driver.
+ //
+ tUSBDGamepadInstance sPrivateData;
+}
+tUSBDHIDGamepadDevice;
+
+//*****************************************************************************
+//
+//! The USBDHIDGamepadSendReport() call successfully scheduled the report.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_SUCCESS 0
+
+//*****************************************************************************
+//
+//! The USBDHIDGamepadSendReport() function could not send the report at this
+//! time.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_TX_ERROR 1
+
+//*****************************************************************************
+//
+//! The device is not currently configured and cannot perform any operations.
+//
+//*****************************************************************************
+#define USBDGAMEPAD_NOT_CONFIGURED \
+ 2
+
+//*****************************************************************************
+//
+//! This structure is the default packed report structure that is sent to the
+//! host. The application can provide its own structure if the default report
+//! descriptor is overridden by the application. This structure or an
+//! application-defined structure is passed to the USBDHIDGamepadSendReport
+//! function to send gamepad updates to the host.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8XPos;
+
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8YPos;
+
+ //
+ //! Signed 8-bit value (-128 to 127).
+ //
+ int8_t i8ZPos;
+
+ //
+ //! 8-bit button mapping with button 1 in the LSB.
+ //
+ uint8_t ui8Buttons;
+}
+PACKED tGamepadReport;
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern tUSBDHIDGamepadDevice *USBDHIDGamepadInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psHIDGamepad);
+extern tUSBDHIDGamepadDevice *USBDHIDGamepadCompositeInit(uint32_t ui32Index,
+ tUSBDHIDGamepadDevice *psHIDGamepad,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDGamepadTerm(tUSBDHIDGamepadDevice *psCompEntry);
+
+extern uint32_t USBDHIDGamepadSendReport(tUSBDHIDGamepadDevice *psHIDGamepad,
+ void *pvReport, uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/device/usbdhidkeyb.c b/usblib/device/usbdhidkeyb.c
new file mode 100644
index 0000000..619714c
--- /dev/null
+++ b/usblib/device/usbdhidkeyb.c
@@ -0,0 +1,1321 @@
+//*****************************************************************************
+//
+// usbdhidkeyb.c - USB HID Keyboard device class driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidkeyb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_keyboard_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8KeybDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(34), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ USB_HID_SCLASS_BOOT, // The interface sub-class.
+ USB_HID_PROTOCOL_KEYB, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+static const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
+{
+ //
+ // Interrupt OUT endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(USB_EP_2),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The following is the HID report structure definition that is passed back
+// to the host.
+//
+//*****************************************************************************
+static const uint8_t g_pui8KeybReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_KEYBOARD),
+ Collection(USB_HID_APPLICATION),
+
+ //
+ // Modifier keys.
+ // 8 - 1 bit values indicating the modifier keys (ctrl, shift...)
+ //
+ ReportSize(1),
+ ReportCount(8),
+ UsagePage(USB_HID_USAGE_KEYCODES),
+ UsageMinimum(224),
+ UsageMaximum(231),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),
+
+ //
+ // One byte of rsvd data required by HID spec.
+ //
+ ReportCount(1),
+ ReportSize(8),
+ Input(USB_HID_INPUT_CONSTANT),
+
+ //
+ // Keyboard LEDs.
+ // 5 - 1 bit values.
+ //
+ ReportCount(5),
+ ReportSize(1),
+ UsagePage(USB_HID_USAGE_LEDS),
+ UsageMinimum(1),
+ UsageMaximum(5),
+ Output(USB_HID_OUTPUT_DATA | USB_HID_OUTPUT_VARIABLE |
+ USB_HID_OUTPUT_ABS),
+ //
+ // 1 - 3 bit value to pad out to a full byte.
+ //
+ ReportCount(1),
+ ReportSize(3),
+ Output(USB_HID_OUTPUT_CONSTANT), //LED report padding
+
+ //
+ // The Key buffer.
+ // 6 - 8 bit values to store the current key state.
+ //
+ ReportCount(6),
+ ReportSize(8),
+ LogicalMinimum(0),
+ LogicalMaximum(101),
+ UsagePage(USB_HID_USAGE_KEYCODES),
+ UsageMinimum (0),
+ UsageMaximum (101),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_ARRAY),
+ EndCollection
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the keyboard device.
+//
+//*****************************************************************************
+static const tHIDDescriptor g_sKeybHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8KeybReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four or five sections
+// depending upon the client's configuration choice. These sections are:
+//
+// 1. The 9 byte configuration descriptor (RAM).
+// 2. The interface descriptor (RAM).
+// 3. The HID report and physical descriptors (provided by the client)
+// (FLASH).
+// 4. The mandatory interrupt IN endpoint descriptor (FLASH).
+// 5. The optional interrupt OUT endpoint descriptor (FLASH).
+//
+//*****************************************************************************
+static const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8KeybDescriptor),
+ g_pui8KeybDescriptor
+};
+
+static const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+static const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+static const tConfigSection g_sHIDOutEndpointSection =
+{
+ sizeof(g_pui8HIDOutEndpoint),
+ g_pui8HIDOutEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+static tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sKeybHIDDescriptor),
+ (const uint8_t *)&g_sKeybHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+static const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+ &g_sHIDOutEndpointSection
+};
+
+#define NUM_HID_SECTIONS ((sizeof(g_psHIDSections) / \
+ sizeof(g_psHIDSections[0])) - 1)
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+static tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+static const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the keyboard class, we have only a
+// single report descriptor.
+//
+//*****************************************************************************
+static const uint8_t * const g_pui8KeybClassDescriptors[] =
+{
+ g_pui8KeybReportDescriptor
+};
+
+//*****************************************************************************
+//
+// Forward references for keyboard device callback functions.
+//
+//*****************************************************************************
+static uint32_t HIDKeyboardRxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+static uint32_t HIDKeyboardTxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+
+//*****************************************************************************
+//
+// Main HID device class event handler function.
+//
+// \param pvKeyboardDevice is the event callback pointer provided during
+// USBDHIDInit().This is a pointer to our HID device structure
+// (&g_sHIDKeybDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to operation of the
+// keyboard HID device.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDKeyboardRxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psKeyboardDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psKeyboardDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+ psInst = &psKeyboardDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ui8USBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(psKeyboardDevice->pvCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ui8USBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(psKeyboardDevice->pvCBData,
+ USB_EVENT_DISCONNECTED, 0,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // The host is polling us for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // We only support a single input report so we don't need to check
+ // the ui32MsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(uint8_t **)pvMsgData = psInst->pui8Report;
+ return(KEYB_IN_REPORT_SIZE);
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request. We
+ // must return a pointer to a buffer large enough to receive the
+ // report into.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+ {
+ //
+ // Are we being asked for a report that is shorter than the storage
+ // we have set aside for this? The only output report we define is
+ // 8 bits long so we really expect to see a length of 1 passed.
+ //
+ if((uint32_t)pvMsgData == KEYB_OUT_REPORT_SIZE )
+ {
+ //
+ // Yes - return our pointer.
+ //
+ return((uint32_t)psInst->pui8DataBuffer);
+ }
+ else
+ {
+ //
+ // We are being passed a report that is longer than the
+ // only report we expect so return NULL. This causes the
+ // device class driver to stall the request.
+ //
+ return(0);
+ }
+ }
+
+ //
+ // This event indicates that the host has sent us an Output or
+ // Feature report and that the report is now in the buffer we provided
+ // on the previous USBD_HID_EVENT_GET_REPORT_BUFFER callback.
+ //
+ case USBD_HID_EVENT_SET_REPORT:
+ {
+ //
+ // Inform the application if the keyboard LEDs have changed.
+ //
+ if(psInst->ui8LEDStates != psInst->pui8DataBuffer[0])
+ {
+ //
+ // Note the new LED states.
+ //
+ psInst->ui8LEDStates = psInst->pui8DataBuffer[0];
+
+ //
+ // Pass the information on to the client.
+ //
+ psKeyboardDevice->pfnCallback(
+ psKeyboardDevice->pvCBData,
+ USBD_HID_KEYB_EVENT_SET_LEDS,
+ psInst->pui8DataBuffer[0],
+ (void *)0);
+ }
+ break;
+ }
+
+ //
+ // The host is asking us to set either boot or report protocol (not
+ // that it makes any difference to this particular mouse).
+ //
+ case USBD_HID_EVENT_SET_PROTOCOL:
+ {
+ psInst->ui8Protocol = ui32MsgData;
+ break;
+ }
+
+ //
+ // The host is asking us to tell it which protocol we are currently
+ // using, boot or request.
+ //
+ case USBD_HID_EVENT_GET_PROTOCOL:
+ {
+ return(psInst->ui8Protocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ return(psKeyboardDevice->pfnCallback(
+ psKeyboardDevice->pvCBData,
+ ui32Event, ui32MsgData, pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvKeyboardDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDKeybDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to report
+// transmissions made using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDKeyboardTxHandler(void *pvKeyboardDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+ uint32_t ui32Count;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+ psInst = &psHIDKbDevice->sPrivateData;
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // Do we have any pending changes needing transmitted?
+ //
+ if(psInst->bChangeMade)
+ {
+ //
+ // Yes - go ahead and send another report immediately.
+ //
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report,
+ KEYB_IN_REPORT_SIZE, true);
+
+ //
+ // If we scheduled the report for transmission, clear the
+ // change flag.
+ //
+ if(ui32Count != 0)
+ {
+ psInst->bChangeMade = false;
+ }
+ }
+ else
+ {
+ //
+ // Our last transmission is complete and we have nothing more
+ // to send.
+ //
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_IDLE;
+ }
+
+ //
+ // Pass the event on to the client.
+ //
+ psHIDKbDevice->pfnCallback(psHIDKbDevice->pvCBData,
+ USB_EVENT_TX_COMPLETE, ui32MsgData,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // We ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Add the supplied usage code to the list of keys currently in the pressed
+// state.
+//
+// \param ui8UsageCode is the HID usage code of the newly pressed key.
+//
+// This function adds the supplied usage code to the global list of keys which
+// are currently pressed (assuming it is not already noted as pressed and that
+// there is space in the list to hold the new information). The return code
+// indicates success if the list did not overflow and failure if the list
+// already contains as many pressed keys as can be reported.
+//
+// \return Returns \b true if the usage code was successfully added to the
+// list or \b false if there was insufficient space to hold the new key
+// press (in which case the caller should report a roll over error to the
+// host).
+//
+//*****************************************************************************
+static bool
+AddKeyToPressedList(tHIDKeyboardInstance *psInst, uint8_t ui8UsageCode)
+{
+ uint32_t ui32Loop;
+ bool bRetcode;
+
+ //
+ // Assume all is well until we determine otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Look through the list of existing pressed keys to see if the new one
+ // is already there.
+ //
+ for(ui32Loop = 0; ui32Loop < (uint32_t)psInst->ui8KeyCount; ui32Loop++)
+ {
+ //
+ // Is this key already included in the list of keys in the pressed
+ // state?
+ //
+ if(ui8UsageCode == psInst->pui8KeysPressed[ui32Loop])
+ {
+ //
+ // Yes - drop out.
+ //
+ break;
+ }
+ }
+
+ //
+ // If we exited the loop at the end of the existing key presses, this
+ // key does not exist already so add it if space exists.
+ //
+ if(ui32Loop >= psInst->ui8KeyCount)
+ {
+ if(psInst->ui8KeyCount < KEYB_MAX_CHARS_PER_REPORT)
+ {
+ //
+ // We have room so store the new key press in the list.
+ //
+ psInst->pui8KeysPressed[psInst->ui8KeyCount] = ui8UsageCode;
+ psInst->ui8KeyCount++;
+ bRetcode = true;
+ }
+ else
+ {
+ //
+ // We have no room for the new key - declare a rollover error.
+ //
+ bRetcode = false;
+ }
+ }
+
+ return(bRetcode);
+}
+
+//*****************************************************************************
+//
+// Remove the supplied usage code from the list of keys currently in the
+// pressed state.
+//
+// \param ui8UsageCode is the HID usage code of the newly released key.
+//
+// This function removes the supplied usage code from the global list of keys
+// which are currently pressed. The return code indicates whether the key was
+// found in the list. On exit, the list has been cleaned up to ensure
+// that all key presses are contiguous starting at the first entry.
+//
+// \return Returns \b true if the usage code was found and removed from the
+// list or \b false if the code was not found. The caller need not pass a new
+// report to the host if \b false is returned since the key list has not
+// changed.
+//
+//*****************************************************************************
+static bool
+RemoveKeyFromPressedList(tHIDKeyboardInstance *psInst,
+ uint8_t ui8UsageCode)
+{
+ uint32_t ui32Loop;
+ uint32_t ui32Pos;
+
+ //
+ // Keep the compiler happy by setting ui32Pos to something.
+ //
+ ui32Pos = 0;
+
+ //
+ // Find the usage code in the current list.
+ //
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ if(psInst->pui8KeysPressed[ui32Loop] == ui8UsageCode)
+ {
+ ui32Pos = ui32Loop;
+ break;
+ }
+ }
+
+ //
+ // If we dropped out at the end of the loop, we could not find the code so
+ // just return false.
+ //
+ if(ui32Loop == KEYB_MAX_CHARS_PER_REPORT)
+ {
+ return(false);
+ }
+
+ //
+ // Now shuffle all the values to the right of the usage code we found
+ // down one position to fill the gap left by removing it.
+ //
+ for(ui32Loop = (ui32Pos + 1); ui32Loop < KEYB_MAX_CHARS_PER_REPORT;
+ ui32Loop++)
+ {
+ psInst->pui8KeysPressed[ui32Loop - 1] =
+ psInst->pui8KeysPressed[ui32Loop];
+ }
+
+ //
+ // Clear the last entry in the array and adjust the number of keys in the
+ // array.
+ //
+ psInst->pui8KeysPressed[KEYB_MAX_CHARS_PER_REPORT - 1] =
+ HID_KEYB_USAGE_RESERVED;
+ psInst->ui8KeyCount--;
+
+ //
+ // Tell the caller we were successful.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psHIDKbDevice points to a structure containing parameters
+//! customizing the operation of the HID keyboard device.
+//!
+//! An application wishing to offer a USB HID keyboard interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! keyboard device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function returns the \e psHIDKbDevice
+//! pointer passed to it. This must be passed on all future calls to the HID
+//! keyboard device driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED after which calls can be made to
+//! USBDHIDKeyboardKeyStateChange() to report key presses and releases to the
+//! USB host.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID keyboard device class
+//! API. Doing so causes unpredictable (though almost certainly
+//! unpleasant) behavior.
+//!
+//! \return Returns NULL on failure or the \e psHIDKbDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardInit(uint32_t ui32Index, tUSBDHIDKeyboardDevice *psHIDKbDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psHIDKbDevice);
+ ASSERT(psHIDKbDevice->ppui8StringDescriptors);
+ ASSERT(psHIDKbDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDKeyboardCompositeInit(ui32Index, psHIDKbDevice, 0);
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8KeybDescriptor;
+ pConfigDesc->bmAttributes = psHIDKbDevice->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psHIDKbDevice->ui16MaxPowermA / 2);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // keyboard.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return((void *)psHIDKbDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID keyboard device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID keyboard device operation.
+//! \param psHIDKbDevice points to a structure containing parameters
+//! customizing the operation of the HID keyboard device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDKeyboardInit() except that it is used
+//! for initializing an instance of the HID keyboard device for use in a
+//! composite device. If this HID keyboard is part of a composite device, then
+//! the \e psCompEntry should point to the composite device entry to
+//! initialize. This is part of the array that is passed to the
+//! USBDCompositeInit() function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Keyboard APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardCompositeInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDKeyboardInstance *psInst;
+ uint32_t ui32Loop;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psHIDKbDevice);
+ ASSERT(psHIDKbDevice->ppui8StringDescriptors);
+ ASSERT(psHIDKbDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDKbDevice->sPrivateData;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ui8USBConfigured = 0;
+ psInst->ui8Protocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ui8Duration4mS = 125;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psInst->ui8LEDStates = 0;
+ psInst->ui8KeyCount = 0;
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ psInst->pui8KeysPressed[ui32Loop] = HID_KEYB_USAGE_RESERVED;
+ }
+
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_UNCONFIGURED;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psInst->sHIDDevice;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psHIDKbDevice->ui16PID;
+ psHIDDevice->ui16VID = psHIDKbDevice->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psHIDKbDevice->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psHIDKbDevice->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ui8Protocol = USB_HID_PROTOCOL_KEYB;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = 0;
+ psHIDDevice->pfnRxCallback = HIDKeyboardRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psHIDKbDevice;
+ psHIDDevice->pfnTxCallback = HIDKeyboardTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psHIDKbDevice;
+ psHIDDevice->bUseOutEndpoint = false,
+
+ psHIDDevice->psHIDDescriptor = &g_sKeybHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_pui8KeybClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors =
+ psHIDKbDevice->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psHIDKbDevice->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a keyboard.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID keyboard device.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//!
+//! This function terminates HID keyboard operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvKeyboardDevice instance may not me used in any other call to the HID
+//! keyboard device other than USBDHIDKeyboardInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDKeyboardTerm(void *pvKeyboardDevice)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to the device.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Mark the device as no longer configured.
+ //
+ psHIDKbDevice->sPrivateData.ui8USBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the keyboard callback.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//! \param pvCBData is the pointer that client wishes to be provided on each
+//! event sent to the keyboard callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnCallback function
+//! passed on USBDHIDKeyboardInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the \e pvKeyboardDevice structure passed to
+//! USBDHIDKeyboardInit() resides in RAM. If this structure is in flash,
+//! callback data changes is not possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDKeyboardSetCBData(void *pvKeyboardDevice, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDKeyboardDevice *psKeyboard;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get a pointer to our keyboard device.
+ //
+ psKeyboard = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Save the old callback pointer and replace it with the new value.
+ //
+ pvOldCBData = psKeyboard->pvCBData;
+ psKeyboard->pvCBData = pvCBData;
+
+ //
+ // Pass the old callback pointer back to the caller.
+ //
+ return(pvOldCBData);
+}
+
+//*****************************************************************************
+//
+//! Reports a key state change to the USB host.
+//!
+//! \param pvKeyboardDevice is the pointer to the device instance structure
+//! as returned by USBDHIDKeyboardInit().
+//! \param ui8Modifiers contains the states of each of the keyboard modifiers
+//! (left/right shift, ctrl, alt or GUI keys). Valid values are logical OR
+//! combinations of the labels \b HID_KEYB_LEFT_CTRL, \b HID_KEYB_LEFT_SHIFT,
+//! \b HID_KEYB_LEFT_ALT, \b HID_KEYB_LEFT_GUI, \b HID_KEYB_RIGHT_CTRL, \b
+//! HID_KEYB_RIGHT_SHIFT, \b HID_KEYB_RIGHT_ALT and \b HID_KEYB_RIGHT_GUI.
+//! Presence of one of these bit flags indicates that the relevant modifier
+//! key is pressed and absence indicates that it is released.
+//! \param ui8UsageCode is the usage code of the key whose state has changed.
+//! If only modifier keys have changed, \b HID_KEYB_USAGE_RESERVED should be
+//! passed in this parameter.
+//! \param bPress is \b true if the key has been pressed or \b false if it has
+//! been released. If only modifier keys have changed state, this parameter is
+//! ignored.
+//!
+//! This function adds or removes a key usage code from the list of keys
+//! currently pressed and schedules a report transmission to the host to
+//! inform it of the new keyboard state. If the maximum number of simultaneous
+//! key presses are already recorded, the report to the host contains the
+//! rollover error code, \b HID_KEYB_USAGE_ROLLOVER instead of key usage codes
+//! and the caller receives return code \b KEYB_ERR_TOO_MANY_KEYS.
+//!
+//! \return Returns \b KEYB_SUCCESS if the key usage code was added to or
+//! removed from the current list successfully. \b KEYB_ERR_TOO_MANY_KEYS is
+//! returned if an attempt is made to press a 7th key (the BIOS keyboard
+//! protocol can report no more than 6 simultaneously pressed keys). If called
+//! before the USB host has configured the device, \b KEYB_ERR_NOT_CONFIGURED
+//! is returned and, if an error is reported while attempting to transmit the
+//! report, \b KEYB_ERR_TX_ERROR is returned. If an attempt is made to remove
+//! a key from the pressed list (by setting parameter \e bPressed to \b false)
+//! but the key usage code is not found, \b KEYB_ERR_NOT_FOUND is returned.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDKeyboardKeyStateChange(void *pvKeyboardDevice, uint8_t ui8Modifiers,
+ uint8_t ui8UsageCode, bool bPress)
+{
+ bool bRetcode;
+ uint32_t ui32Loop, ui32Count;
+ tHIDKeyboardInstance *psInst;
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Assume all is well until we determine otherwise.
+ //
+ bRetcode = true;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psHIDKbDevice->sPrivateData;
+
+ //
+ // Update the global keyboard report with the information passed.
+ //
+ psInst->pui8Report[0] = ui8Modifiers;
+ psInst->pui8Report[1] = 0;
+
+ //
+ // Were we passed a usage code for a new key press or release or was
+ // this call just telling us about a modifier change?
+ //
+ if(ui8UsageCode != HID_KEYB_USAGE_RESERVED)
+ {
+ //
+ // Has a key been pressed or released?
+ //
+ if(bPress)
+ {
+ //
+ // A key has been pressed - add it to the list if there is space an
+ // and the key is not already in the list.
+ //
+ bRetcode = AddKeyToPressedList(psInst, ui8UsageCode);
+ }
+ else
+ {
+ //
+ // A key has been released - remove it from the list.
+ //
+ bRetcode = RemoveKeyFromPressedList(psInst, ui8UsageCode);
+
+ //
+ // The return code here indicates whether the key was found. If it
+ // wasn't, the list has not changes so merely exit at this point
+ // without sending anything to the host.
+ //
+ if(!bRetcode)
+ {
+ return(KEYB_ERR_NOT_FOUND);
+ }
+ }
+
+ //
+ // Build the report from the current list of keys. If we added a key
+ // and got a bad return code indicating a roll over error, we need to
+ // send a roll over report
+ //
+ for(ui32Loop = 0; ui32Loop < KEYB_MAX_CHARS_PER_REPORT; ui32Loop++)
+ {
+ psInst->pui8Report[2 + ui32Loop] = (bRetcode ?
+ psInst->pui8KeysPressed[ui32Loop] : HID_KEYB_USAGE_ROLLOVER);
+ }
+ }
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ui8USBConfigured)
+ {
+ return(KEYB_ERR_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->eKeyboardState = HID_KEYBOARD_STATE_SEND;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report, KEYB_IN_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ui32Count)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ return(KEYB_ERR_TX_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // We can't send the report immediately so mark the instance so that
+ // it is sent next time the transmitter is free.
+ //
+ psInst->bChangeMade = true;
+ }
+
+ //
+ // If we get this far, the key information was sent successfully. Are
+ // too many keys currently pressed, though?
+ //
+ return(bRetcode ? KEYB_SUCCESS : KEYB_ERR_TOO_MANY_KEYS);
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus or self powered) to the USB library.
+//!
+//! \param pvKeyboardDevice is the pointer to the keyboard device instance
+//! structure.
+//! \param ui8Power indicates the current power status, either
+//! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus or self powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDKeyboardPowerStatusSet(void *pvKeyboardDevice, uint8_t ui8Power)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvKeyboardDevice is the pointer to the keyboard device instance
+//! structure.
+//!
+//! When the bus is suspended, an application which supports remote wake up
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wake up signaling to the host. If the remote
+//! wake up feature has not been disabled by the host, this causes the bus
+//! to resume operation within 20mS. If the host has disabled remote wake up,
+//! \b false is returned to indicate that the wake up request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wake up is not disabled and the
+//! signaling was started or \b false if remote wake up is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDHIDKeyboardRemoteWakeupRequest(void *pvKeyboardDevice)
+{
+ tUSBDHIDKeyboardDevice *psHIDKbDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvKeyboardDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psHIDKbDevice = (tUSBDHIDKeyboardDevice *)pvKeyboardDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psHIDKbDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDHIDRemoteWakeupRequest((void *)psHIDDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidkeyb.h b/usblib/device/usbdhidkeyb.h
new file mode 100644
index 0000000..c509b9f
--- /dev/null
+++ b/usblib/device/usbdhidkeyb.h
@@ -0,0 +1,365 @@
+//*****************************************************************************
+//
+// usbdhidkeyb.h - Definitions used by HID keyboard class devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDKEYB_H__
+#define __USBDHIDKEYB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_keyboard_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The maximum number of simultaneously-pressed, non-modifier keys that the
+//! HID BIOS keyboard protocol can send at once. Attempts to send more pressed
+//! keys than this results in a rollover error being reported to the host
+//! and KEYB_ERR_TOO_MANY_KEYS being returned from
+//! USBDHIDKeyboardKeyStateChange().
+//
+//*****************************************************************************
+#define KEYB_MAX_CHARS_PER_REPORT \
+ 6
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID keyboard code and are here only to help with the application
+// allocating the correct amount of memory for the USB HID Keyboard device
+// code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the keyboard can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ HID_KEYBOARD_STATE_UNCONFIGURED,
+
+ //
+ // No keys to send and not waiting on data.
+ //
+ HID_KEYBOARD_STATE_IDLE,
+
+ //
+ // Waiting on report data from the host.
+ //
+ HID_KEYBOARD_STATE_WAIT_DATA,
+
+ //
+ // Waiting on data to be sent out.
+ //
+ HID_KEYBOARD_STATE_SEND
+}
+tKeyboardState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The size of the keyboard input and output reports.
+//
+//*****************************************************************************
+#define KEYB_IN_REPORT_SIZE 8
+#define KEYB_OUT_REPORT_SIZE 1
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data structure for the USB HID
+// keyboard device. This structure forms the RAM workspace used by each
+// instance of the keyboard.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The USB configuration number set by the host or 0 of the device is
+ // currently unconfigured.
+ //
+ uint8_t ui8USBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ // The current states that the keyboard LEDs are to be set to.
+ //
+ volatile uint8_t ui8LEDStates;
+
+ //
+ // The total number of keys currently pressed. This indicates the number
+ // of key press entries in the pui8KeysPressed array.
+ //
+ uint8_t ui8KeyCount;
+
+ //
+ // The current state of the keyboard interrupt IN endpoint.
+ //
+ volatile tKeyboardState eKeyboardState;
+
+ //
+ // A flag to indicate that the application pressed or released a key
+ // but that we couldn't send the report immediately.
+ //
+ volatile bool bChangeMade;
+
+ //
+ // A buffer used to receive output reports from the host.
+ //
+ uint8_t pui8DataBuffer[KEYB_OUT_REPORT_SIZE];
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ uint8_t pui8Report[KEYB_IN_REPORT_SIZE];
+
+ //
+ // A buffer containing the usage codes of all non-modifier keys currently
+ // in the pressed state.
+ //
+ uint8_t pui8KeysPressed[KEYB_MAX_CHARS_PER_REPORT];
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDKeyboardInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID keyboard device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //! A pointer to the callback function which is called to notify
+ //! the application of general events and those related to reception of
+ //! Output and Feature reports via the (optional) interrupt OUT endpoint.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the keyboard callback,
+ //! pfnCallback.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the keyboard device is in use and
+ //! must not be modified by any code outside the HID keyboard driver.
+ //
+ tHIDKeyboardInstance sPrivateData;
+}
+tUSBDHIDKeyboardDevice;
+
+//*****************************************************************************
+//
+// Keyboard-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the keyboard LED states are to be set. The
+//! ui32MsgValue parameter contains the requested state for each of the LEDs
+//! defined as a collection of ORed bits where a 1 indicates that the LED is
+//! to be turned on and a 0 indicates that it should be turned off. The
+//! individual LED bits are defined using labels \b HID_KEYB_NUM_LOCK,
+//! \b HID_KEYB_CAPS_LOCK, \b HID_KEYB_SCROLL_LOCK, \b HID_KEYB_COMPOSE and
+//! \b HID_KEYB_KANA.
+//
+//*****************************************************************************
+#define USBD_HID_KEYB_EVENT_SET_LEDS \
+ USBD_HID_KEYB_EVENT_BASE
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates success.
+//
+//*****************************************************************************
+#define KEYB_SUCCESS 0
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates that an
+//! attempt has been made to record more than 6 simultaneously pressed,
+//! non-modifier keys. The USB HID BIOS keyboard protocol allows no more than
+//! 6 pressed keys to be reported at one time. Until at least one key is
+//! released, the device reports a roll over error to the host each time it
+//! is asked for the keyboard input report.
+//
+//*****************************************************************************
+#define KEYB_ERR_TOO_MANY_KEYS 1
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDKeyboardKeyStateChange() indicates that an
+//! error was reported while attempting to send a report to the host. A client
+//! should assume that the host has disconnected if this return code is seen.
+//
+//*****************************************************************************
+#define KEYB_ERR_TX_ERROR 2
+
+//*****************************************************************************
+//
+//! USBDHIDKeyboardKeyStateChange() returns this value if it is called with the
+//! bPress parameter set to false but with a ui8UsageCode parameter which does
+//! does not indicate a key that is currently recorded as being pressed. This
+//! may occur if an attempt was previously made to report more than 6 pressed
+//! keys and the earlier pressed keys are released before the later ones. This
+//! condition is benign and should not be used to indicate a host disconnection
+//! or serious error.
+//
+//*****************************************************************************
+#define KEYB_ERR_NOT_FOUND 3
+
+//*****************************************************************************
+//
+//! USBDHIDKeyboardKeyStateChange() returns this value if it is called before
+//! the USB host has connected and configured the device. Any key usage code
+//! passed is stored and passed to the host once configuration completes.
+//
+//*****************************************************************************
+#define KEYB_ERR_NOT_CONFIGURED 4
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDKeyboardInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice);
+extern void *USBDHIDKeyboardCompositeInit(uint32_t ui32Index,
+ tUSBDHIDKeyboardDevice *psHIDKbDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDKeyboardTerm(void *pvKeyboardInstance);
+extern void *USBDHIDKeyboardSetCBData(void *pvKeyboardInstance,
+ void *pvCBData);
+extern uint32_t USBDHIDKeyboardKeyStateChange(void *pvKeyboardInstance,
+ uint8_t ui8Modifiers,
+ uint8_t ui8UsageCode,
+ bool bPressed);
+extern void USBDHIDKeyboardPowerStatusSet(void *pvKeyboardInstance,
+ uint8_t ui8Power);
+extern bool USBDHIDKeyboardRemoteWakeupRequest(void *pvKeyboardInstance);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHIDKEYB_H__
diff --git a/usblib/device/usbdhidmouse.c b/usblib/device/usbdhidmouse.c
new file mode 100644
index 0000000..8b8a95a
--- /dev/null
+++ b/usblib/device/usbdhidmouse.c
@@ -0,0 +1,1008 @@
+//*****************************************************************************
+//
+// usbdhidmouse.c - USB HID Mouse device class driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/usbhid.h"
+#include "usblib/device/usbdhid.h"
+#include "usblib/device/usbdhidmouse.h"
+
+//*****************************************************************************
+//
+//! \addtogroup hid_mouse_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+uint8_t g_pui8MouseDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(34), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 5, // The string identifier that describes this
+ // configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
+{
+ //
+ // HID Device Class Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this interface.
+ 1, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_HID, // The interface class
+ USB_HID_SCLASS_BOOT, // The interface sub-class.
+ USB_HID_PROTOCOL_MOUSE, // The interface protocol for the sub-class
+ // specified above.
+ 4, // The string index for this interface.
+};
+
+const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
+{
+ //
+ // Interrupt IN endpoint descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
+ USB_EP_ATTR_INT, // Endpoint is an interrupt endpoint.
+ USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
+ // The maximum packet size.
+ 16, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The report descriptor for the mouse class device.
+//
+//*****************************************************************************
+static const uint8_t g_pui8MouseReportDescriptor[] =
+{
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_MOUSE),
+ Collection(USB_HID_APPLICATION),
+ Usage(USB_HID_POINTER),
+ Collection(USB_HID_PHYSICAL),
+
+ //
+ // The buttons.
+ //
+ UsagePage(USB_HID_BUTTONS),
+ UsageMinimum(1),
+ UsageMaximum(3),
+ LogicalMinimum(0),
+ LogicalMaximum(1),
+
+ //
+ // 3 - 1 bit values for the buttons.
+ //
+ ReportSize(1),
+ ReportCount(3),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_ABS),
+
+ //
+ // 1 - 5 bit unused constant value to fill the 8 bits.
+ //
+ ReportSize(5),
+ ReportCount(1),
+ Input(USB_HID_INPUT_CONSTANT | USB_HID_INPUT_ARRAY |
+ USB_HID_INPUT_ABS),
+
+ //
+ // The X and Y axis.
+ //
+ UsagePage(USB_HID_GENERIC_DESKTOP),
+ Usage(USB_HID_X),
+ Usage(USB_HID_Y),
+ LogicalMinimum(-127),
+ LogicalMaximum(127),
+
+ //
+ // 2 - 8 bit Values for x and y.
+ //
+ ReportSize(8),
+ ReportCount(2),
+ Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
+ USB_HID_INPUT_RELATIVE),
+
+ EndCollection,
+ EndCollection,
+};
+
+//*****************************************************************************
+//
+// The HID descriptor for the mouse device.
+//
+//*****************************************************************************
+static const tHIDDescriptor g_sMouseHIDDescriptor =
+{
+ 9, // bLength
+ USB_HID_DTYPE_HID, // bDescriptorType
+ 0x111, // bcdHID (version 1.11 compliant)
+ 0, // bCountryCode (not localized)
+ 1, // bNumDescriptors
+ {
+ {
+ USB_HID_DTYPE_REPORT, // Report descriptor
+ sizeof(g_pui8MouseReportDescriptor)
+ // Size of report descriptor
+ }
+ }
+};
+
+//*****************************************************************************
+//
+// The HID configuration descriptor is defined as four or five sections
+// depending upon the client's configuration choice. These sections are:
+//
+// 1. The 9 byte configuration descriptor (RAM).
+// 2. The interface descriptor (RAM).
+// 3. The HID report and physical descriptors (provided by the client)
+// (FLASH).
+// 4. The mandatory interrupt IN endpoint descriptor (FLASH).
+// 5. The optional interrupt OUT endpoint descriptor (FLASH).
+//
+//*****************************************************************************
+const tConfigSection g_sHIDConfigSection =
+{
+ sizeof(g_pui8MouseDescriptor),
+ g_pui8MouseDescriptor
+};
+
+const tConfigSection g_sHIDInterfaceSection =
+{
+ sizeof(g_pui8HIDInterface),
+ g_pui8HIDInterface
+};
+
+const tConfigSection g_sHIDInEndpointSection =
+{
+ sizeof(g_pui8HIDInEndpoint),
+ g_pui8HIDInEndpoint
+};
+
+//*****************************************************************************
+//
+// Place holder for the user's HID descriptor block.
+//
+//*****************************************************************************
+tConfigSection g_sHIDDescriptorSection =
+{
+ sizeof(g_sMouseHIDDescriptor),
+ (const uint8_t *)&g_sMouseHIDDescriptor
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete HID configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psHIDSections[] =
+{
+ &g_sHIDConfigSection,
+ &g_sHIDInterfaceSection,
+ &g_sHIDDescriptorSection,
+ &g_sHIDInEndpointSection,
+};
+
+#define NUM_HID_SECTIONS (sizeof(g_psHIDSections) / \
+ sizeof(g_psHIDSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor. Note that this must be
+// in RAM since we need to include or exclude the final section based on
+// client supplied initialization parameters.
+//
+//*****************************************************************************
+tConfigHeader g_sHIDConfigHeader =
+{
+ NUM_HID_SECTIONS,
+ g_psHIDSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
+{
+ &g_sHIDConfigHeader
+};
+
+//*****************************************************************************
+//
+// The HID class descriptor table. For the mouse class, we have only a single
+// report descriptor.
+//
+//*****************************************************************************
+static const uint8_t * const g_pui8MouseClassDescriptors[] =
+{
+ g_pui8MouseReportDescriptor
+};
+
+//*****************************************************************************
+//
+// Forward references for mouse device callback functions.
+//
+//*****************************************************************************
+static uint32_t HIDMouseRxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+static uint32_t HIDMouseTxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The HID mouse report offsets for this mouse application.
+//
+//*****************************************************************************
+#define HID_REPORT_BUTTONS 0
+#define HID_REPORT_X 1
+#define HID_REPORT_Y 2
+
+//*****************************************************************************
+//
+// Main HID device class event handler function.
+//
+// \param pvMouseDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDMouseDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to operation of the
+// mouse HID device.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDMouseRxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch(ui32Event)
+ {
+ //
+ // The host has connected to us and configured the device.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ psInst->ui8USBConfigured = true;
+
+ //
+ // Pass the information on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_CONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host has disconnected from us.
+ //
+ case USB_EVENT_DISCONNECTED:
+ {
+ psInst->ui8USBConfigured = false;
+
+ //
+ // Pass the information on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_DISCONNECTED, 0, (void *)0);
+
+ break;
+ }
+
+ //
+ // The host is polling us for a particular report and the HID driver
+ // is asking for the latest version to transmit.
+ //
+ case USBD_HID_EVENT_IDLE_TIMEOUT:
+ case USBD_HID_EVENT_GET_REPORT:
+ {
+ //
+ // We only support a single input report so we don't need to check
+ // the ui32MsgValue parameter in this case. Set the report pointer
+ // in *pvMsgData and return the length of the report in bytes.
+ //
+ *(uint8_t **)pvMsgData = psInst->pui8Report;
+ return(8);
+ }
+
+ //
+ // The device class driver has completed sending a report to the
+ // host in response to a Get_Report request.
+ //
+ case USBD_HID_EVENT_REPORT_SENT:
+ {
+ //
+ // We have nothing to do here.
+ //
+ break;
+ }
+
+ //
+ // This event is sent in response to a host Set_Report request. The
+ // mouse device has no output reports so we return a NULL pointer and
+ // zero length to cause this request to be stalled.
+ //
+ case USBD_HID_EVENT_GET_REPORT_BUFFER:
+ {
+ //
+ // We are being asked for a report that does not exist for
+ // this device. Return 0 to indicate that we are not providing
+ // a buffer.
+ //
+ return(0);
+ }
+
+ //
+ // The host is asking us to set either boot or report protocol (not
+ // that it makes any difference to this particular mouse).
+ //
+ case USBD_HID_EVENT_SET_PROTOCOL:
+ {
+ psInst->ui8Protocol = ui32MsgData;
+ break;
+ }
+
+ //
+ // The host is asking us to tell it which protocol we are currently
+ // using, boot or request.
+ //
+ case USBD_HID_EVENT_GET_PROTOCOL:
+ {
+ return(psInst->ui8Protocol);
+ }
+
+ //
+ // Pass ERROR, SUSPEND and RESUME to the client unchanged.
+ //
+ case USB_EVENT_ERROR:
+ case USB_EVENT_SUSPEND:
+ case USB_EVENT_RESUME:
+ case USB_EVENT_LPM_RESUME:
+ case USB_EVENT_LPM_SLEEP:
+ case USB_EVENT_LPM_ERROR:
+ {
+ return(psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ ui32Event, ui32MsgData,
+ pvMsgData));
+ }
+
+ //
+ // We ignore all other events.
+ //
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// HID device class transmit channel event handler function.
+//
+// \param pvMouseDevice is the event callback pointer provided during
+// USBDHIDInit(). This is a pointer to our HID device structure
+// (&g_sHIDMouseDevice).
+// \param ui32Event identifies the event we are being called back for.
+// \param ui32MsgData is an event-specific value.
+// \param pvMsgData is an event-specific pointer.
+//
+// This function is called by the HID device class driver to inform the
+// application of particular asynchronous events related to report
+// transmissions made using the interrupt IN endpoint.
+//
+// \return Returns a value which is event-specific.
+//
+//*****************************************************************************
+static uint32_t
+HIDMouseTxHandler(void *pvMouseDevice, uint32_t ui32Event,
+ uint32_t ui32MsgData, void *pvMsgData)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+
+ //
+ // Make sure we did not get a NULL pointer.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Which event were we sent?
+ //
+ switch (ui32Event)
+ {
+ //
+ // A report transmitted via the interrupt IN endpoint was acknowledged
+ // by the host.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // Our last transmission is complete.
+ //
+ psInst->iMouseState = eHIDMouseStateIdle;
+
+ //
+ // Pass the event on to the client.
+ //
+ psMouseDevice->pfnCallback(psMouseDevice->pvCBData,
+ USB_EVENT_TX_COMPLETE, ui32MsgData,
+ (void *)0);
+
+ break;
+ }
+
+ //
+ // We ignore all other events related to transmission of reports via
+ // the interrupt IN endpoint.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Initializes HID mouse device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psMouseDevice points to a structure containing parameters
+//! customizing the operation of the HID mouse device.
+//!
+//! An application wishing to offer a USB HID mouse interface to a USB host
+//! must call this function to initialize the USB controller and attach the
+//! mouse device to the USB bus. This function performs all required USB
+//! initialization.
+//!
+//! On successful completion, this function returns the \e psMouseDevice
+//! pointer passed to it. This must be passed on all future calls to the HID
+//! mouse device driver.
+//!
+//! When a host connects and configures the device, the application callback
+//! receives \b USB_EVENT_CONNECTED after which calls can be made to
+//! USBDHIDMouseStateChange() to report pointer movement and button presses
+//! to the host.
+//!
+//! \note The application must not make any calls to the lower level USB device
+//! interfaces if interacting with USB via the USB HID mouse device API.
+//! Doing so causes unpredictable (though almost certainly unpleasant)
+//! behavior.
+//!
+//! \return Returns NULL on failure or the psMouseDevice pointer on success.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseInit(uint32_t ui32Index, tUSBDHIDMouseDevice *psMouseDevice)
+{
+ void *pvRetcode;
+ tUSBDHIDDevice *psHIDDevice;
+ tConfigDescriptor *pConfigDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psMouseDevice);
+ ASSERT(psMouseDevice->ppui8StringDescriptors);
+ ASSERT(psMouseDevice->pfnCallback);
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ pConfigDesc = (tConfigDescriptor *)g_pui8MouseDescriptor;
+ pConfigDesc->bmAttributes = psMouseDevice->ui8PwrAttributes;
+ pConfigDesc->bMaxPower = (uint8_t)(psMouseDevice->ui16MaxPowermA / 2);
+
+ //
+ // Call the common initialization routine.
+ //
+ pvRetcode = USBDHIDMouseCompositeInit(ui32Index, psMouseDevice, 0);
+
+ //
+ // If we initialized the HID layer successfully, pass our device pointer
+ // back as the return code, otherwise return NULL to indicate an error.
+ //
+ if(pvRetcode)
+ {
+ //
+ // Initialize the lower layer HID driver and pass it the various
+ // structures and descriptors necessary to declare that we are a
+ // keyboard.
+ //
+ pvRetcode = USBDHIDInit(ui32Index, psHIDDevice);
+
+ return((void *)psMouseDevice);
+ }
+ else
+ {
+ return((void *)0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes HID mouse device operation for a given USB controller.
+//!
+//! \param ui32Index is the index of the USB controller which is to be
+//! initialized for HID mouse device operation.
+//! \param psMouseDevice points to a structure containing parameters
+//! customizing the operation of the HID mouse device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! This call is very similar to USBDHIDMouseInit() except that it is used for
+//! initializing an instance of the HID mouse device for use in a composite
+//! device. If this HID mouse is part of a composite device, then the
+//! \e psCompEntry should point to the composite device entry to initialize.
+//! This is part of the array that is passed to the USBDCompositeInit()
+//! function.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB HID Mouse APIs.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseCompositeInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tHIDMouseInstance *psInst;
+ tUSBDHIDDevice *psHIDDevice;
+
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psMouseDevice);
+ ASSERT(psMouseDevice->ppui8StringDescriptors);
+ ASSERT(psMouseDevice->pfnCallback);
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Initialize the various fields in our instance structure.
+ //
+ psInst->ui8USBConfigured = 0;
+ psInst->ui8Protocol = USB_HID_PROTOCOL_REPORT;
+ psInst->sReportIdle.ui8Duration4mS = 0;
+ psInst->sReportIdle.ui8ReportID = 0;
+ psInst->sReportIdle.ui32TimeSinceReportmS = 0;
+ psInst->sReportIdle.ui16TimeTillNextmS = 0;
+ psInst->iMouseState = eHIDMouseStateUnconfigured;
+
+ //
+ // Initialize the HID device class instance structure based on input from
+ // the caller.
+ //
+ psHIDDevice->ui16PID = psMouseDevice->ui16PID;
+ psHIDDevice->ui16VID = psMouseDevice->ui16VID;
+ psHIDDevice->ui16MaxPowermA = psMouseDevice->ui16MaxPowermA;
+ psHIDDevice->ui8PwrAttributes = psMouseDevice->ui8PwrAttributes;
+ psHIDDevice->ui8Subclass = USB_HID_SCLASS_BOOT;
+ psHIDDevice->ui8Protocol = USB_HID_PROTOCOL_MOUSE;
+ psHIDDevice->ui8NumInputReports = 1;
+ psHIDDevice->psReportIdle = &psInst->sReportIdle;
+ psHIDDevice->pfnRxCallback = HIDMouseRxHandler;
+ psHIDDevice->pvRxCBData = (void *)psMouseDevice;
+ psHIDDevice->pfnTxCallback = HIDMouseTxHandler;
+ psHIDDevice->pvTxCBData = (void *)psMouseDevice;
+ psHIDDevice->bUseOutEndpoint = false;
+ psHIDDevice->psHIDDescriptor = &g_sMouseHIDDescriptor;
+ psHIDDevice->ppui8ClassDescriptors = g_pui8MouseClassDescriptors;
+ psHIDDevice->ppui8StringDescriptors =
+ psMouseDevice->ppui8StringDescriptors;
+ psHIDDevice->ui32NumStringDescriptors =
+ psMouseDevice->ui32NumStringDescriptors;
+ psHIDDevice->ppsConfigDescriptor = g_ppsHIDConfigDescriptors;
+
+ //
+ // Initialize the lower layer HID driver and pass it the various structures
+ // and descriptors necessary to declare that we are a keyboard.
+ //
+ return(USBDHIDCompositeInit(ui32Index, psHIDDevice, psCompEntry));
+}
+
+//*****************************************************************************
+//
+//! Shuts down the HID mouse device.
+//!
+//! \param pvMouseDevice is the pointer to the device instance structure.
+//!
+//! This function terminates HID mouse operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvMouseDevice instance may not me used in any other call to the HID
+//! mouse device other than USBDHIDMouseInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDMouseTerm(void *pvMouseDevice)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to the device.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Mark our device as no longer configured.
+ //
+ psMouseDevice->sPrivateData.ui8USBConfigured = 0;
+
+ //
+ // Terminate the low level HID driver.
+ //
+ USBDHIDTerm(psHIDDevice);
+}
+
+//*****************************************************************************
+//
+//! Sets the client-specific pointer parameter for the mouse callback.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \param pvCBData is the pointer that client wishes to be provided on
+//! each event sent to the mouse callback function.
+//!
+//! The client uses this function to change the callback pointer passed in
+//! the first parameter on all callbacks to the \e pfnCallback function
+//! passed on USBDHIDMouseInit().
+//!
+//! If a client wants to make runtime changes in the callback pointer, it must
+//! ensure that the pvMouseDevice structure passed to USBDHIDMouseInit()
+//! resides in RAM. If this structure is in flash, callback data changes are
+//! not possible.
+//!
+//! \return Returns the previous callback pointer that was set for this
+//! instance.
+//
+//*****************************************************************************
+void *
+USBDHIDMouseSetCBData(void *pvMouseDevice, void *pvCBData)
+{
+ void *pvOldCBData;
+ tUSBDHIDMouseDevice *psMouse;
+
+ //
+ // Check for a NULL pointer in the device parameter.
+ //
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get a pointer to our mouse device.
+ //
+ psMouse = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Save the old callback pointer and replace it with the new value.
+ //
+ pvOldCBData = psMouse->pvCBData;
+ psMouse->pvCBData = pvCBData;
+
+ //
+ // Pass the old callback pointer back to the caller.
+ //
+ return(pvOldCBData);
+}
+
+//*****************************************************************************
+//
+//! Reports a mouse state change, pointer movement or button press, to the USB
+//! host.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \param i8DeltaX is the relative horizontal pointer movement that the
+//! application wishes to report. Valid values are in the range [-127, 127]
+//! with positive values indicating movement to the right.
+//! \param i8DeltaY is the relative vertical pointer movement that the
+//! application wishes to report. Valid values are in the range [-127, 127]
+//! with positive values indicating downward movement.
+//! \param ui8Buttons is a bit mask indicating which (if any) of the three
+//! mouse buttons is pressed. Valid values are logical OR combinations of
+//! \b MOUSE_REPORT_BUTTON_1, \b MOUSE_REPORT_BUTTON_2 and
+//! \b MOUSE_REPORT_BUTTON_3.
+//!
+//! This function is called to report changes in the mouse state to the USB
+//! host. These changes can be movement of the pointer, reported relative to
+//! its previous position, or changes in the states of up to 3 buttons that
+//! the mouse may support. The return code indicates whether or not the
+//! mouse report could be sent to the host. In cases where a previous
+//! report is still being transmitted, \b MOUSE_ERR_TX_ERROR is returned
+//! and the state change is ignored.
+//!
+//! \return Returns \b MOUSE_SUCCESS on success, \b MOUSE_ERR_TX_ERROR if an
+//! error occurred while attempting to schedule transmission of the mouse
+//! report to the host (typically due to a previous report which has not yet
+//! completed transmission or due to disconnection of the host) or \b
+//! MOUSE_ERR_NOT_CONFIGURED if called before a host has connected to and
+//! configured the device.
+//
+//*****************************************************************************
+uint32_t
+USBDHIDMouseStateChange(void *pvMouseDevice, int8_t i8DeltaX, int8_t i8DeltaY,
+ uint8_t ui8Buttons)
+{
+ uint32_t ui32Retcode, ui32Count;
+ tHIDMouseInstance *psInst;
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ //
+ // Get a pointer to the device.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Get a pointer to our instance data
+ //
+ psInst = &psMouseDevice->sPrivateData;
+
+ //
+ // Update the global mouse report with the information passed.
+ //
+ psInst->pui8Report[HID_REPORT_BUTTONS] = ui8Buttons;
+ psInst->pui8Report[HID_REPORT_X] = (uint8_t)i8DeltaX;
+ psInst->pui8Report[HID_REPORT_Y] = (uint8_t)i8DeltaY;
+
+ //
+ // If we are not configured, return an error here before trying to send
+ // anything.
+ //
+ if(!psInst->ui8USBConfigured)
+ {
+ return(MOUSE_ERR_NOT_CONFIGURED);
+ }
+
+ //
+ // Only send a report if the transmitter is currently free.
+ //
+ if(USBDHIDTxPacketAvailable((void *)psHIDDevice))
+ {
+ //
+ // Send the report to the host.
+ //
+ psInst->iMouseState = eHIDMouseStateSend;
+ ui32Count = USBDHIDReportWrite((void *)psHIDDevice,
+ psInst->pui8Report, MOUSE_REPORT_SIZE,
+ true);
+
+ //
+ // Did we schedule a packet for transmission correctly?
+ //
+ if(!ui32Count)
+ {
+ //
+ // No - report the error to the caller.
+ //
+ ui32Retcode = MOUSE_ERR_TX_ERROR;
+ }
+ else
+ {
+ ui32Retcode = MOUSE_SUCCESS;
+ }
+ }
+ else
+ {
+ ui32Retcode = MOUSE_ERR_TX_ERROR;
+ }
+ //
+ // Return the relevant error code to the caller.
+ //
+ return(ui32Retcode);
+}
+#ifndef DEPRECATED
+
+//*****************************************************************************
+//
+//! Reports the device power status (bus- or self-powered) to the USB library.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//! \param ui8Power indicates the current power status, either \b
+//! USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
+//!
+//! Applications which support switching between bus- or self-powered
+//! operation should call this function whenever the power source changes
+//! to indicate the current power status to the USB library. This information
+//! is required by the USB library to allow correct responses to be provided
+//! when the host requests status from the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDHIDMousePowerStatusSet(void *pvMouseDevice, uint8_t ui8Power)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ USBDHIDPowerStatusSet((void *)psHIDDevice, ui8Power);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Requests a remote wake up to resume communication when in suspended state.
+//!
+//! \param pvMouseDevice is the pointer to the mouse device instance structure.
+//!
+//! When the bus is suspended, an application which supports remote wake up
+//! (advertised to the host via the configuration descriptor) may call this
+//! function to initiate remote wake up signaling to the host. If the remote
+//! wake up feature has not been disabled by the host, this causes the bus
+//! to resume operation within 20mS. If the host has disabled remote wake up,
+//! \b false is returned to indicate that the wake up request was not
+//! successful.
+//!
+//! \return Returns \b true if the remote wake up is not disabled and the
+//! signaling was started or \b false if remote wake up is disabled or if
+//! signaling is currently ongoing following a previous call to this function.
+//
+//*****************************************************************************
+bool
+USBDHIDMouseRemoteWakeupRequest(void *pvMouseDevice)
+{
+ tUSBDHIDMouseDevice *psMouseDevice;
+ tUSBDHIDDevice *psHIDDevice;
+
+ ASSERT(pvMouseDevice);
+
+ //
+ // Get the keyboard device pointer.
+ //
+ psMouseDevice = (tUSBDHIDMouseDevice *)pvMouseDevice;
+
+ //
+ // Get a pointer to the HID device data.
+ //
+ psHIDDevice = &psMouseDevice->sPrivateData.sHIDDevice;
+
+ //
+ // Pass the request through to the lower layer.
+ //
+ return(USBDHIDRemoteWakeupRequest((void *)&psHIDDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdhidmouse.h b/usblib/device/usbdhidmouse.h
new file mode 100644
index 0000000..6978ca7
--- /dev/null
+++ b/usblib/device/usbdhidmouse.h
@@ -0,0 +1,299 @@
+//*****************************************************************************
+//
+// usbdhidmouse.h - Public header file for the USB HID Mouse device class
+// driver
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDHIDMOUSE_H__
+#define __USBDHIDMOUSE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_mouse_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The first few sections of this header are private defines that are used by
+// the USB HID mouse code and are here only to help with the application
+// allocating the correct amount of memory for the HID mouse device code.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// The size of the mouse input report sent to the host.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_SIZE 3
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This enumeration holds the various states that the mouse can be in during
+// normal operation.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // Unconfigured.
+ //
+ eHIDMouseStateUnconfigured,
+
+ //
+ // No keys to send and not waiting on data.
+ //
+ eHIDMouseStateIdle,
+
+ //
+ // Waiting on report data from the host.
+ //
+ eHIDMouseStateWaitData,
+
+ //
+ // Waiting on data to be sent out.
+ //
+ eHIDMouseStateSend
+}
+tMouseState;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure provides the private instance data structure for the USB
+// HID Mouse device. This structure forms the RAM workspace used by each
+// instance of the mouse.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The USB configuration number set by the host or 0 of the device is
+ // currently unconfigured.
+ //
+ uint8_t ui8USBConfigured;
+
+ //
+ // The protocol requested by the host, USB_HID_PROTOCOL_BOOT or
+ // USB_HID_PROTOCOL_REPORT.
+ //
+ uint8_t ui8Protocol;
+
+ //
+ // A buffer used to hold the last input report sent to the host.
+ //
+ uint8_t pui8Report[MOUSE_REPORT_SIZE];
+
+ //
+ // The current state of the mouse interrupt IN endpoint.
+ //
+ volatile tMouseState iMouseState;
+
+ //
+ // The idle timeout control structure for our input report. This is
+ // required by the lower level HID driver.
+ //
+ tHIDReportIdle sReportIdle;
+
+ //
+ // This is needed for the lower level HID driver.
+ //
+ tUSBDHIDDevice sHIDDevice;
+}
+tHIDMouseInstance;
+
+//*****************************************************************************
+//
+//! This structure is used by the application to define operating parameters
+//! for the HID mouse device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self- or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are USB_CONF_ATTR_SELF_PWR or
+ //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the callback function which is called to notify
+ //! the application of events relating to the operation of the mouse.
+ //
+ const tUSBCallback pfnCallback;
+
+ //
+ //! A client-supplied pointer which is sent as the first
+ //! parameter in all calls made to the mouse callback, pfnCallback.
+ //
+ void *pvCBData;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1),HID
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the ppStringDescriptors
+ //! array. This must be (1 + (5 * (num languages))).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! The private instance data for this device. This memory must
+ //! remain accessible for as long as the mouse device is in use and must
+ //! not be modified by any code outside the HID mouse driver.
+ //
+ tHIDMouseInstance sPrivateData;
+}
+tUSBDHIDMouseDevice;
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDMouseStateChange() indicates success.
+//
+//*****************************************************************************
+#define MOUSE_SUCCESS 0
+
+//*****************************************************************************
+//
+//! This return code from USBDHIDMouseStateChange() indicates that an error was
+//! reported while attempting to send a report to the host. A client should
+//! assume that the host has disconnected if this return code is seen.
+//
+//*****************************************************************************
+#define MOUSE_ERR_TX_ERROR 2
+
+//*****************************************************************************
+//
+//! USBDHIDMouseStateChange() returns this value if it is called before the
+//! USB host has connected and configured the device. All mouse state
+//! information passed on the call is been ignored.
+//
+//*****************************************************************************
+#define MOUSE_ERR_NOT_CONFIGURED \
+ 4
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 1 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_1 0x01
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 2 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_2 0x02
+
+//*****************************************************************************
+//
+//! Setting this bit in the ui8Buttons parameter to USBDHIDMouseStateChange()
+//! indicates to the USB host that button 3 on the mouse is pressed.
+//
+//*****************************************************************************
+#define MOUSE_REPORT_BUTTON_3 0x04
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDHIDMouseInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice);
+extern void *USBDHIDMouseCompositeInit(uint32_t ui32Index,
+ tUSBDHIDMouseDevice *psMouseDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDHIDMouseTerm(void *pvMouseDevice);
+extern void *USBDHIDMouseSetCBData(void *pvMouseDevice, void *pvCBData);
+extern uint32_t USBDHIDMouseStateChange(void *pvMouseDevice, int8_t i8DeltaX,
+ int8_t i8DeltaY, uint8_t ui8Buttons);
+extern void USBDHIDMousePowerStatusSet(void *pvMouseDevice,
+ uint8_t ui8Power);
+extern bool USBDHIDMouseRemoteWakeupRequest(void *pvMouseDevice);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBDHIDMOUSE_H__
diff --git a/usblib/device/usbdmsc.c b/usblib/device/usbdmsc.c
new file mode 100644
index 0000000..daea1f0
--- /dev/null
+++ b/usblib/device/usbdmsc.c
@@ -0,0 +1,2441 @@
+//*****************************************************************************
+//
+// usbdmsc.c - USB mass storage device class driver.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbmsc.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/device/usbdmsc.h"
+
+//*****************************************************************************
+//
+//! \addtogroup msc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These are the internal flags used with the ui32Flags member variable.
+//
+//*****************************************************************************
+#define USBD_FLAG_DMA_IN 0x00000001
+#define USBD_FLAG_DMA_OUT 0x00000002
+#define USBD_FLAG_ALLOW_REMOVAL 0x00000004
+
+//*****************************************************************************
+//
+// The subset of endpoint status flags that we consider to be reception
+// errors. These are passed to the client via USB_EVENT_ERROR if seen.
+//
+//*****************************************************************************
+#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \
+ USBERR_DEV_RX_OVERRUN | \
+ USBERR_DEV_RX_FIFO_FULL)
+
+//*****************************************************************************
+//
+// These are fields that are used by the USB descriptors for the Mass Storage
+// Class.
+//
+//*****************************************************************************
+#define USB_MSC_SUBCLASS_SCSI 0x6
+#define USB_MSC_PROTO_BULKONLY 0x50
+
+//*****************************************************************************
+//
+// Endpoints to use for each of the required endpoints in the driver.
+//
+//*****************************************************************************
+#define DATA_IN_ENDPOINT USB_EP_1
+#define DATA_OUT_ENDPOINT USB_EP_1
+
+//*****************************************************************************
+//
+// Maximum packet size for the bulk endpoints is 64 bytes.
+//
+//*****************************************************************************
+#define DATA_IN_EP_MAX_SIZE 64
+#define DATA_OUT_EP_MAX_SIZE 64
+
+//*****************************************************************************
+//
+// These defines control the size of USB transfers for commands.
+//
+//*****************************************************************************
+#define COMMAND_BUFFER_SIZE 64
+
+//*****************************************************************************
+//
+// The block size of a device. It defaults to DEVICE_BLOCK_SIZE
+//
+//*****************************************************************************
+static uint32_t g_pui32BlockSize = DEVICE_BLOCK_SIZE;
+
+//*****************************************************************************
+//
+// The local buffer used to read in commands and process them.
+//
+//*****************************************************************************
+static uint8_t g_pui8Command[COMMAND_BUFFER_SIZE];
+
+//*****************************************************************************
+//
+// The current transfer state is held in these variables.
+//
+//*****************************************************************************
+static tMSCCSW g_sSCSICSW;
+
+//*****************************************************************************
+//
+// The current state for the SCSI commands that are being handled and are
+// stored in the tMSCInstance.ui8SCSIState structure member.
+//
+//*****************************************************************************
+
+//
+// No command in process.
+//
+#define STATE_SCSI_IDLE 0x00
+
+//
+// Sending and reading logical blocks.
+//
+#define STATE_SCSI_SEND_BLOCKS 0x01
+
+//
+// Receiving and writing logical blocks.
+//
+#define STATE_SCSI_RECEIVE_BLOCKS 0x02
+
+//
+// Send the status once the previous transfer is complete.
+//
+#define STATE_SCSI_SEND_STATUS 0x03
+
+//
+// Status was prepared to be sent and now waiting for it to have gone out.
+//
+#define STATE_SCSI_SENT_STATUS 0x04
+
+//*****************************************************************************
+//
+// Device Descriptor. This is stored in RAM to allow several fields to be
+// changed at runtime based on the client's requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8MSCDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts
+ // assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ 0, // USB Device Class (spec 5.1.1)
+ 0, // USB Device Sub-class (spec 5.1.1)
+ 0, // USB Device protocol (spec 5.1.1)
+ 64, // Maximum packet size for default pipe.
+ USBShort(0), // Vendor ID (filled in during
+ // USBDCDCInit).
+ USBShort(0), // Product ID (filled in during
+ // USBDCDCInit).
+ USBShort(0x100), // Device Version BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// Mass storage device configuration descriptor.
+//
+// It is vital that the configuration descriptor bConfigurationValue field
+// (byte 6) is 1 for the first configuration and increments by 1 for each
+// additional configuration defined here. This relationship is assumed in the
+// device stack for simplicity even though the USB 2.0 specification imposes
+// no such restriction on the bConfigurationValue values.
+//
+// Note that this structure is deliberately located in RAM since we need to
+// be able to patch some values in it based on client requirements.
+//
+//*****************************************************************************
+static uint8_t g_pui8MSCDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(32), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes
+ // this configuration.
+ USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake
+ // up.
+ 250, // The maximum power in 2mA increments.
+};
+
+//*****************************************************************************
+//
+// The remainder of the configuration descriptor is stored in flash since we
+// don't need to modify anything in it at runtime.
+//
+//*****************************************************************************
+const uint8_t g_pui8MSCInterface[MSCINTERFACE_SIZE] =
+{
+ //
+ // Vendor-specific Interface Descriptor.
+ //
+ 9, // Size of the interface descriptor.
+ USB_DTYPE_INTERFACE, // Type of this descriptor.
+ 0, // The index for this interface.
+ 0, // The alternate setting for this
+ // interface.
+ 2, // The number of endpoints used by this
+ // interface.
+ USB_CLASS_MASS_STORAGE, // The interface class
+ USB_MSC_SUBCLASS_SCSI, // The interface sub-class.
+ USB_MSC_PROTO_BULKONLY, // The interface protocol for the sub-class
+ // specified above.
+ 0, // The string index for this interface.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+
+ //
+ // Endpoint Descriptor
+ //
+ 7, // The size of the endpoint descriptor.
+ USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint.
+ USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT),
+ USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint.
+ USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size.
+ 0, // The polling interval for this endpoint.
+};
+
+//*****************************************************************************
+//
+// The mass storage configuration descriptor is defined as two sections,
+// one containing just the 9 byte USB configuration descriptor and the other
+// containing everything else that is sent to the host along with it.
+//
+//*****************************************************************************
+const tConfigSection g_sMSCConfigSection =
+{
+ sizeof(g_pui8MSCDescriptor),
+ g_pui8MSCDescriptor
+};
+
+const tConfigSection g_sMSCInterfaceSection =
+{
+ sizeof(g_pui8MSCInterface),
+ g_pui8MSCInterface
+};
+
+//*****************************************************************************
+//
+// This array lists all the sections that must be concatenated to make a
+// single, complete bulk device configuration descriptor.
+//
+//*****************************************************************************
+const tConfigSection *g_psMSCSections[] =
+{
+ &g_sMSCConfigSection,
+ &g_sMSCInterfaceSection
+};
+
+#define NUM_MSC_SECTIONS (sizeof(g_psMSCSections) / \
+ sizeof(g_psMSCSections[0]))
+
+//*****************************************************************************
+//
+// The header for the single configuration we support. This is the root of
+// the data structure that defines all the bits and pieces that are pulled
+// together to generate the configuration descriptor.
+//
+//*****************************************************************************
+const tConfigHeader g_sMSCConfigHeader =
+{
+ NUM_MSC_SECTIONS,
+ g_psMSCSections
+};
+
+//*****************************************************************************
+//
+// Configuration Descriptor.
+//
+//*****************************************************************************
+const tConfigHeader * const g_ppsMSCConfigDescriptors[] =
+{
+ &g_sMSCConfigHeader
+};
+
+//*****************************************************************************
+//
+// Various internal handlers needed by this class.
+//
+//*****************************************************************************
+static void HandleDisconnect(void *pvMSCDevice);
+static void ConfigChangeHandler(void *pvMSCDevice, uint32_t ui32Value);
+static void HandleEndpoints(void *pvMSCDevice, uint32_t ui32Status);
+static void HandleRequests(void *pvMSCDevice, tUSBRequest *psUSBRequest);
+static void USBDSCSISendStatus(tUSBDMSCDevice *psMSCDevice);
+uint32_t USBDSCSICommand(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW);
+static void HandleDevice(void *pvMSCDevice, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+// The device information structure for the USB MSC device.
+//
+//*****************************************************************************
+const tCustomHandlers g_sMSCHandlers =
+{
+ //
+ // GetDescriptor
+ //
+ 0,
+
+ //
+ // RequestHandler
+ //
+ HandleRequests,
+
+ //
+ // InterfaceChange
+ //
+ 0,
+
+ //
+ // ConfigChange
+ //
+ ConfigChangeHandler,
+
+ //
+ // DataReceived
+ //
+ 0,
+
+ //
+ // DataSentCallback
+ //
+ 0,
+
+ //
+ // ResetHandler
+ //
+ 0,
+
+ //
+ // SuspendHandler
+ //
+ 0,
+
+ //
+ // ResumeHandler
+ //
+ 0,
+
+ //
+ // DisconnectHandler
+ //
+ HandleDisconnect,
+
+ //
+ // EndpointHandler
+ //
+ HandleEndpoints,
+
+ //
+ // Device handler
+ //
+ HandleDevice
+};
+
+//*****************************************************************************
+//
+//! This function is used by an application if it can detect insertion or
+//! removal of the media.
+//!
+//! \param pvMSCDevice is the mass storage device instance that had a media
+//! change.
+//! \param iMediaStatus is the updated status for the media.
+//!
+//! This function should be called by an application when it detects a change
+//! in the status of the media in use by the USB mass storage class. The
+//! \e iMediaStatus parameter will indicate the new status of the media and
+//! can also indicate that the application has no knowledge of the media state.
+//!
+//! There are currently the three following values for the \e iMediaStatus
+//! parameter:
+//! - \b eUSBDMSCMediaPresent indicates that the media is present or has been
+//! added.
+//! - \b eUSBDMSCMediaNotPresent indicates that the media is not present or was
+//! removed.
+//! - \b eUSBDMSCMediaUnknown indicates that the application has no knowledge
+//! of the media state and the USB mass storage class.
+//!
+//! It will be left up to the application to call this function whenever it
+//! detects a change or simply call it once with \b eUSBDMSCMediaUnknown and
+//! allow the mass storage class to infer the state from the remaining device
+//! APIs.
+//!
+//! \note It is recommended that the application use this function to inform
+//! the mass storage class of media state changes as it will lead to a more
+//! responsive system.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDMSCMediaChange(void *pvMSCDevice, tUSBDMSCMediaStatus iMediaStatus)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ //
+ // Create a device instance pointer.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // Save the current media status.
+ //
+ psMSCDevice->sPrivateData.iMediaStatus = iMediaStatus;
+}
+
+//*****************************************************************************
+//
+// This function is called to handle the interrupts on the Bulk endpoints for
+// the mass storage class.
+//
+//*****************************************************************************
+static void
+HandleEndpoints(void *pvMSCDevice, uint32_t ui32Status)
+{
+ tUSBDMSCDevice *psMSCDevice;
+ tMSCInstance *psInst;
+ tMSCCBW *psSCSICBW;
+ uint32_t ui32EPStatus, ui32Size;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Determine if the serial device is in single or composite mode because
+ // the meaning of ui32Index is different in both cases.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Get the endpoints status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint);
+
+ //
+ // Handler for the bulk IN data endpoint.
+ //
+ if((ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint))) ||
+ ((psInst->ui32Flags & USBD_FLAG_DMA_IN) &&
+ (USBLibDMAChannelStatus(psInst->psDMAInstance, psInst->ui8INDMA) &
+ USBLIBSTATUS_DMA_COMPLETE)))
+ {
+ switch(psInst->ui8SCSIState)
+ {
+ //
+ // Handle the case where we are sending out data due to a read
+ // command.
+ //
+ case STATE_SCSI_SEND_BLOCKS:
+ {
+ //
+ // Decrement the number of bytes left to send.
+ //
+ psInst->ui32BytesToTransfer -= g_pui32BlockSize;
+
+ //
+ // If we are done then move on to the status phase.
+ //
+ if(psInst->ui32BytesToTransfer == 0)
+ {
+ //
+ // Set the status so that it can be sent when this
+ // response has has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // DMA has completed for the IN endpoint.
+ //
+ psInst->ui32Flags &= ~USBD_FLAG_DMA_IN;
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE,
+ 0, 0);
+ }
+
+ //
+ // Make sure that the transfer has actually finished. If
+ // it has not there will be another interrupt to send
+ // out the status.
+ //
+ if(USBEndpointStatus(USB0_BASE,psInst->ui8INEndpoint) &
+ USB_DEV_TX_TXPKTRDY)
+ {
+ //
+ // Send back the status once this transfer is complete.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+ else
+ {
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+ }
+
+ //
+ // The transfer is complete so don't read anymore data.
+ //
+ break;
+ }
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ui32CurrentLBA++;
+
+ //
+ // Read the new data and send it out.
+ //
+ if(psMSCDevice->sMediaFunctions.pfnBlockRead(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer,
+ psInst->ui32CurrentLBA, 1) == 0)
+ {
+ }
+
+ //
+ // Configure and enable DMA for the IN transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance,
+ psInst->ui8INDMA, psInst->pui32Buffer,
+ g_pui32BlockSize);
+
+ //
+ // Start the DMA transfer.
+ //
+ USBLibDMAChannelEnable(psInst->psDMAInstance,
+ psInst->ui8INDMA);
+
+ break;
+ }
+
+ //
+ // Handle sending status.
+ //
+ case STATE_SCSI_SEND_STATUS:
+ {
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle completing sending status.
+ //
+ case STATE_SCSI_SENT_STATUS:
+ {
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+
+ break;
+ }
+
+ //
+ // These cases should not occur as the being in the IDLE state due
+ // to an IN interrupt is invalid.
+ //
+ case STATE_SCSI_IDLE:
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Handler for the bulk OUT data endpoint.
+ //
+ if((ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint))) ||
+ ((psInst->ui32Flags & USBD_FLAG_DMA_OUT) &&
+ (USBLibDMAChannelStatus(psInst->psDMAInstance, psInst->ui8OUTDMA) &
+ USBLIBSTATUS_DMA_COMPLETE)))
+ {
+ //
+ // Get the endpoint status to see why we were called.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ psInst->ui8OUTEndpoint);
+
+ switch(psInst->ui8SCSIState)
+ {
+ //
+ // Receiving and writing bytes to the storage device.
+ //
+ case STATE_SCSI_RECEIVE_BLOCKS:
+ {
+ //
+ // Update the current status for the buffer.
+ //
+ psInst->ui32BytesToTransfer -= g_pui32BlockSize;
+
+ //
+ // Write the new data.
+ //
+ psMSCDevice->sMediaFunctions.pfnBlockWrite(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer,
+ psInst->ui32CurrentLBA, 1);
+
+ //
+ // Move on to the next Logical Block.
+ //
+ psInst->ui32CurrentLBA++;
+
+ //
+ // Check if all bytes have been received.
+ //
+ if(psInst->ui32BytesToTransfer == 0)
+ {
+ //
+ // Set the status so that it can be sent when this response
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // DMA has completed for the OUT endpoint.
+ //
+ psInst->ui32Flags &= ~USBD_FLAG_DMA_OUT;
+
+ //
+ // Indicate success and no extra data coming.
+ //
+ USBDSCSISendStatus(psMSCDevice);
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE,
+ psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // If there is an event callback then call it to notify
+ // that last operation has completed.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_IDLE,
+ 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance,
+ psInst->ui8OUTDMA, psInst->pui32Buffer,
+ g_pui32BlockSize);
+ }
+
+ break;
+ }
+
+ //
+ // If there is an OUT transfer in idle state then it was a new
+ // command.
+ //
+ case STATE_SCSI_IDLE:
+ {
+ //
+ // Attempt to handle the new command.
+ //
+
+ //
+ // Receive the command.
+ //
+ ui32Size = COMMAND_BUFFER_SIZE;
+ MAP_USBEndpointDataGet(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint,
+ g_pui8Command, &ui32Size);
+ psSCSICBW = (tMSCCBW *)g_pui8Command;
+
+ //
+ // Acknowledge the OUT data packet.
+ //
+ MAP_USBDevEndpointDataAck(psInst->ui32USBBase,
+ psInst->ui8OUTEndpoint, false);
+
+ //
+ // If this is a valid CBW then handle it.
+ //
+ if(psSCSICBW->dCBWSignature == CBW_SIGNATURE)
+ {
+ g_sSCSICSW.dCSWSignature = CSW_SIGNATURE;
+ g_sSCSICSW.dCSWTag = psSCSICBW->dCBWTag;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ g_sSCSICSW.bCSWStatus = 0;
+
+ USBDSCSICommand(psMSCDevice, psSCSICBW);
+ }
+ else
+ {
+ //
+ // Just return to the idle state since we are now out of
+ // sync with the host. This should not happen, but this
+ // should allow the device to synchronize with the host
+ // controller.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // Clear the status bits.
+ //
+ MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint,
+ ui32EPStatus);
+ }
+}
+
+//*****************************************************************************
+//
+// Device instance specific handler.
+//
+//*****************************************************************************
+static void
+HandleDevice(void *pvMSCDevice, uint32_t ui32Request, void *pvRequestData)
+{
+ tMSCInstance *psInst;
+ uint8_t *pui8Data;
+ tUSBDMSCDevice *psMSCDevice;
+
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // Get the instance data pointers.
+ //
+ psInst = &((tUSBDMSCDevice *)pvMSCDevice)->sPrivateData;
+
+ //
+ // Create the 8-bit array used by the events supported by the USB MSC
+ // class.
+ //
+ pui8Data = (uint8_t *)pvRequestData;
+
+ switch(ui32Request)
+ {
+ //
+ // This was an interface change event.
+ //
+ case USB_EVENT_COMP_IFACE_CHANGE:
+ {
+ psInst->ui8Interface = pui8Data[1];
+ break;
+ }
+
+ //
+ // This was an endpoint change event.
+ //
+ case USB_EVENT_COMP_EP_CHANGE:
+ {
+ //
+ // Determine if this is an IN or OUT endpoint that has changed.
+ //
+ if(pui8Data[0] & USB_EP_DESC_IN)
+ {
+ psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f));
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8INDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8INDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8INDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8INEndpoint, 0,
+ USB_DMA_EP_TX |
+ USB_DMA_EP_DEVICE);
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8INDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8INDMA,
+ 16);
+ }
+ else
+ {
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psInst->ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psInst->psDMAInstance,
+ psInst->ui8OUTDMA);
+ }
+
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ psInst->ui8OUTDMA =
+ USBLibDMAChannelAllocate(psInst->psDMAInstance,
+ psInst->ui8OUTEndpoint, 0,
+ USB_DMA_EP_RX |
+ USB_DMA_EP_DEVICE);
+
+ //
+ // Set the DMA individual transfer size.
+ //
+ USBLibDMAUnitSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 32);
+
+ //
+ // Set the DMA arbitration size.
+ //
+ USBLibDMAArbSizeSet(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ 16);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_RESUME:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM resume event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_SLEEP:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM sleep event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ case USB_EVENT_LPM_ERROR:
+ {
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the LPM error event to the client.
+ //
+ psMSCDevice->pfnEventCallback(0, USB_EVENT_LPM_RESUME, 0,
+ (void *)0);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device is
+// disconnected from the host.
+//
+//*****************************************************************************
+static void
+HandleDisconnect(void *pvMSCDevice)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // Close the drive requested.
+ //
+ if(psMSCDevice->sPrivateData.pvMedia != 0)
+ {
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psMSCDevice->pfnEventCallback(pvMSCDevice, USB_EVENT_DISCONNECTED, 0,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever the device
+// configuration changes.
+//
+//*****************************************************************************
+static void
+ConfigChangeHandler(void *pvMSCDevice, uint32_t ui32Value)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Create the instance pointer.
+ //
+ psMSCDevice = (tUSBDMSCDevice *)pvMSCDevice;
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psMSCDevice->sPrivateData.ui8OUTDMA != 0)
+ {
+ USBLibDMAChannelRelease(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA);
+ }
+
+ //
+ // Configure the DMA for the OUT endpoint.
+ //
+ psMSCDevice->sPrivateData.ui8OUTDMA =
+ USBLibDMAChannelAllocate(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTEndpoint, 64,
+ USB_DMA_EP_RX | USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA, 32);
+
+ USBLibDMAArbSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8OUTDMA, 16);
+
+ //
+ // If the DMA channel has already been allocated then clear
+ // that channel and prepare to possibly use a new one.
+ //
+ if(psMSCDevice->sPrivateData.ui8INDMA != 0)
+ {
+ USBLibDMAChannelRelease(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA);
+ }
+
+ //
+ // Configure the DMA for the IN endpoint.
+ //
+ psMSCDevice->sPrivateData.ui8INDMA =
+ USBLibDMAChannelAllocate(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INEndpoint, 64,
+ USB_DMA_EP_TX | USB_DMA_EP_DEVICE);
+
+ USBLibDMAUnitSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA, 32);
+
+ USBLibDMAArbSizeSet(psMSCDevice->sPrivateData.psDMAInstance,
+ psMSCDevice->sPrivateData.ui8INDMA, 16);
+
+ //
+ // If we have a control callback, let the client know we are open for
+ // business.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ //
+ // Pass the connected event to the client.
+ //
+ psMSCDevice->pfnEventCallback(pvMSCDevice, USB_EVENT_CONNECTED, 0, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the mass storage class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psMSCDevice points to a structure containing parameters customizing
+//! the operation of the mass storage device.
+//!
+//! In order for an application to initialize the USB device mass storage
+//! class, it must first call this function with the a valid mass storage
+//! device class structure in the \e psMSCDevice parameter. This allows this
+//! function to initialize the USB controller and device code to be prepared to
+//! enumerate and function as a USB mass storage device.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the mass storage class.
+//!
+//! See the documentation on the tUSBDMSCDevice structure for more information
+//! on how to properly fill the structure members.
+//!
+//! \return Returns 0 on failure or a non-zero void pointer on success.
+//
+//*****************************************************************************
+void *
+USBDMSCInit(uint32_t ui32Index, tUSBDMSCDevice *psMSCDevice)
+{
+ tDeviceDescriptor *psDevDesc;
+ tConfigDescriptor *pConfDesc;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psMSCDevice);
+ ASSERT(psMSCDevice->ppui8StringDescriptors);
+
+ USBDMSCCompositeInit(ui32Index, psMSCDevice, 0);
+
+ //
+ // Fix up the device descriptor with the client-supplied values.
+ //
+ psDevDesc = (tDeviceDescriptor *)g_pui8MSCDeviceDescriptor;
+ psDevDesc->idVendor = psMSCDevice->ui16VID;
+ psDevDesc->idProduct = psMSCDevice->ui16PID;
+
+ //
+ // Fix up the configuration descriptor with client-supplied values.
+ //
+ pConfDesc = (tConfigDescriptor *)g_pui8MSCDescriptor;
+ pConfDesc->bmAttributes = psMSCDevice->ui8PwrAttributes;
+ pConfDesc->bMaxPower = (uint8_t)(psMSCDevice->ui16MaxPowermA / 2);
+
+ //
+ // All is well so now pass the descriptors to the lower layer and put
+ // the bulk device on the bus.
+ //
+ USBDCDInit(ui32Index, &psMSCDevice->sPrivateData.sDevInfo,
+ (void *)psMSCDevice);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called once for the mass storage class device to
+//! initialized basic operation and prepare for enumeration.
+//!
+//! \param ui32Index is the index of the USB controller to initialize for
+//! mass storage class device operation.
+//! \param psMSCDevice points to a structure containing parameters customizing
+//! the operation of the mass storage device.
+//! \param psCompEntry is the composite device entry to initialize when
+//! creating a composite device.
+//!
+//! In order for an application to initialize the USB device mass storage
+//! class, it must first call this function with the a valid mass storage
+//! device class structure in the \e psMSCDevice parameter. This allows this
+//! function to initialize the USB controller and device code to be prepared to
+//! enumerate and function as a USB mass storage device. If this mass storage
+//! device is part of a composite device, then the \e psCompEntry should
+//! point to the composite device entry to initialize. This is part of the
+//! array that is passed to the USBDCompositeInit() function.
+//!
+//! This function returns a void pointer that must be passed in to all other
+//! APIs used by the mass storage class.
+//!
+//! See the documentation on the tUSBDMSCDevice structure for more information
+//! on how to properly fill the structure members.
+//!
+//! \return Returns zero on failure or a non-zero instance value that should be
+//! used with the remaining USB mass storage APIs.
+//
+//*****************************************************************************
+void *
+USBDMSCCompositeInit(uint32_t ui32Index, tUSBDMSCDevice *psMSCDevice,
+ tCompositeEntry *psCompEntry)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(psMSCDevice);
+ ASSERT(psMSCDevice->ppui8StringDescriptors);
+ ASSERT(psCompEntry != 0);
+
+ //
+ // Initialize the workspace in the passed instance structure.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+ psInst->ui32USBBase = USB0_BASE;
+ psInst->bConnected = false;
+ psInst->iMediaStatus = eUSBDMSCMediaUnknown;
+
+ //
+ // Initialize the composite entry that is used by the composite device
+ // class.
+ //
+ if(psCompEntry != 0)
+ {
+ psCompEntry->psDevInfo = &psInst->sDevInfo;
+ psCompEntry->pvInstance = (void *)psMSCDevice;
+ }
+
+ //
+ // Initialize the device information structure.
+ //
+ psInst->sDevInfo.psCallbacks = &g_sMSCHandlers;
+ psInst->sDevInfo.pui8DeviceDescriptor = g_pui8MSCDeviceDescriptor;
+ psInst->sDevInfo.ppsConfigDescriptors = g_ppsMSCConfigDescriptors;
+ psInst->sDevInfo.ppui8StringDescriptors = 0;
+ psInst->sDevInfo.ui32NumStringDescriptors = 0;
+
+ //
+ // Initialize the device info structure for the mass storage device.
+ //
+ USBDCDDeviceInfoInit(0, &psInst->sDevInfo);
+
+ //
+ // Set the initial interface and endpoints.
+ //
+ psInst->ui8Interface = 0;
+ psInst->ui8OUTEndpoint = DATA_OUT_ENDPOINT;
+ psInst->ui8INEndpoint = DATA_IN_ENDPOINT;
+
+ //
+ // Set the initial SCSI state to idle.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+
+ //
+ // Plug in the client's string stable to the device information
+ // structure.
+ //
+ psInst->sDevInfo.ppui8StringDescriptors =
+ psMSCDevice->ppui8StringDescriptors;
+ psInst->sDevInfo.ui32NumStringDescriptors =
+ psMSCDevice->ui32NumStringDescriptors;
+
+ //
+ // Open the drive requested.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ if(psInst->pvMedia == 0)
+ {
+ //
+ // There is no media currently present.
+ //
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+ else
+ {
+ //
+ // Media is now ready for use.
+ //
+ psInst->ui8SenseKey = SCSI_RS_KEY_UNIT_ATTN;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOTRDY2RDY;
+ }
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Get the DMA instance pointer.
+ //
+ psInst->psDMAInstance = USBLibDMAInit(0);
+
+ //
+ // Return the pointer to the instance indicating that everything went well.
+ //
+ return((void *)psMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! Shuts down the mass storage device.
+//!
+//! \param pvMSCDevice is the pointer to the device instance structure as
+//! returned by USBDMSCInit() or USBDMSCCompositeInit().
+//!
+//! This function terminates mass storage operation for the instance supplied
+//! and removes the device from the USB bus. Following this call, the
+//! \e pvMSCDevice instance may not me used in any other call to the mass
+//! storage device other than USBDMSCInit() or USBDMSCCompositeInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDMSCTerm(void *pvMSCDevice)
+{
+ tUSBDMSCDevice *psMSCDevice;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Cleanly exit device mode.
+ //
+ USBDCDTerm(0);
+
+ //
+ // Create a device instance pointer.
+ //
+ psMSCDevice = pvMSCDevice;
+
+ //
+ // If the media was opened the close it out.
+ //
+ if(psMSCDevice->sPrivateData.pvMedia != 0)
+ {
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB device stack whenever a non-standard
+// request is received.
+//
+// \param pvMSCDevice is instance data for this request.
+// \param pUSBRequest points to the request received.
+//
+// This call parses the provided request structure to determine the command.
+// The only mass storage command supported over endpoint 0 is the Get Max LUN
+// command.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HandleRequests(void *pvMSCDevice, tUSBRequest *pUSBRequest)
+{
+ //
+ // This class only support a single LUN.
+ //
+ static const uint8_t ui8MaxLun = 0;
+
+ ASSERT(pvMSCDevice != 0);
+
+ //
+ // Determine the type of request.
+ //
+ switch(pUSBRequest->bRequest)
+ {
+ //
+ // A Set Report request is received from the host when it sends an
+ // Output report via endpoint 0.
+ //
+ case USBREQ_GET_MAX_LUN:
+ {
+ //
+ // Need to ACK the data on end point 0 with last data since there
+ // is no more data expected.
+ //
+ USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Send our response to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8MaxLun, 1);
+
+ break;
+ }
+ case USBREQ_BULK_ONLY_RESET:
+ {
+ //
+ // Need to ACK the data on end point 0 with last data since there
+ // is no more data expected.
+ //
+ USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
+
+ //
+ // Send a null packet to the host.
+ //
+ USBDCDSendDataEP0(0, (uint8_t *)&ui8MaxLun, 0);
+
+ break;
+ }
+
+ //
+ // This request was not recognized so stall.
+ //
+ default:
+ {
+ USBDCDStallEP0(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Inquiry command when it is received
+// from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIInquiry(tUSBDMSCDevice *psMSCDevice)
+{
+ int32_t i32Idx;
+ tMSCInstance *psInst;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)g_pui8Command;
+
+ //
+ // Create the serial instance data.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Direct Access device, Removable storage and SCSI 1 responses.
+ //
+ pui32Data[0] = SCSI_INQ_PDT_SBC | (SCSI_INQ_RMB << 8);
+
+ //
+ // Additional Length is fixed at 31 bytes.
+ //
+ pui32Data[1] = 31;
+
+ //
+ // Copy the Vendor string.
+ //
+ for(i32Idx = 0; i32Idx < 8; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 8] = psMSCDevice->pui8Vendor[i32Idx];
+ }
+
+ //
+ // Copy the Product string.
+ //
+ for(i32Idx = 0; i32Idx < 16; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 16] = psMSCDevice->pui8Product[i32Idx];
+ }
+
+ //
+ // Copy the Version string.
+ //
+ for(i32Idx = 0; i32Idx < 4; i32Idx++)
+ {
+ g_pui8Command[i32Idx + 32] = psMSCDevice->pui8Version[i32Idx];
+ }
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 36);
+
+ //
+ // Send the data to the host.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read Capacities command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIReadCapacities(tUSBDMSCDevice *psMSCDevice)
+{
+ uint32_t ui32Blocks;
+ tMSCInstance *psInst;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)g_pui8Command;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ if(psMSCDevice->sMediaFunctions.pfnBlockSize)
+ {
+ //
+ // Query the block size for the device
+ //
+ g_pui32BlockSize =
+ psMSCDevice->sMediaFunctions.pfnBlockSize(psInst->pvMedia);
+ }
+ ui32Blocks =
+ psMSCDevice->sMediaFunctions.pfnNumBlocks(psInst->pvMedia);
+
+ pui32Data[0] = 0x08000000;
+
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pui8Command[4] = ui32Blocks >> 24;
+ g_pui8Command[5] = 0xff & (ui32Blocks >> 16);
+ g_pui8Command[6] = 0xff & (ui32Blocks >> 8);
+ g_pui8Command[7] = 0xff & (ui32Blocks);
+
+ //
+ // Current media capacity
+ //
+ g_pui8Command[8] = 0x2;
+
+ //
+ // Fill in the block size, which is g_pui32BlockSize.
+ //
+ g_pui8Command[9] = 0xff & (g_pui32BlockSize >> 16);
+ g_pui8Command[10] = 0xff & (g_pui32BlockSize >> 8);
+ g_pui8Command[11] = 0xff & g_pui32BlockSize;
+
+ //
+ // Send out the 12 bytes that are in this response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 12);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read Capacity command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIReadCapacity(tUSBDMSCDevice *psMSCDevice)
+{
+ uint32_t ui32Blocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psMSCDevice->sMediaFunctions.pfnBlockSize)
+ {
+ //
+ // Query the block size for the device
+ //
+ g_pui32BlockSize =
+ psMSCDevice->sMediaFunctions.pfnBlockSize(psInst->pvMedia);
+ }
+
+ ui32Blocks = psMSCDevice->sMediaFunctions.pfnNumBlocks(psInst->pvMedia);
+
+ //
+ // Only decrement if any blocks were found.
+ //
+ if(ui32Blocks != 0)
+ {
+ //
+ // One less than the maximum number is the last addressable
+ // block.
+ //
+ ui32Blocks--;
+ }
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Fill in the number of blocks, the bytes endianness must be changed.
+ //
+ g_pui8Command[0] = 0xff & (ui32Blocks >> 24);
+ g_pui8Command[1] = 0xff & (ui32Blocks >> 16);
+ g_pui8Command[2] = 0xff & (ui32Blocks >> 8);
+ g_pui8Command[3] = 0xff & (ui32Blocks);
+
+ g_pui8Command[4] = 0;
+
+ //
+ // Fill in the block size, which is g_pui32BlockSize.
+ //
+ g_pui8Command[5] = 0xff & (g_pui32BlockSize >> 16);
+ g_pui8Command[6] = 0xff & (g_pui32BlockSize >> 8);
+ g_pui8Command[7] = 0xff & g_pui32BlockSize;
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 8);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Request Sense command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIRequestSense(tUSBDMSCDevice *psMSCDevice)
+{
+ tMSCInstance *psInst;
+ int32_t i32Idx;
+
+ //
+ // Zero out the response data.
+ //
+ for(i32Idx = 0; i32Idx < 18; i32Idx++)
+ {
+ g_pui8Command[i32Idx] = 0;
+ }
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // The request sense response.
+ //
+ g_pui8Command[0] = psInst->ui8ErrorCode;
+ g_pui8Command[2] = psInst->ui8SenseKey;
+
+ //
+ // There are 10 more bytes of data.
+ //
+ g_pui8Command[7] = 10;
+
+ //
+ // Transition from not ready to ready.
+ //
+ g_pui8Command[12] = (uint8_t)psInst->ui16AddSenseCode;
+ g_pui8Command[13] = (uint8_t)(psInst->ui16AddSenseCode >> 8);
+
+ //
+ // Send the SCSI Inquiry Response.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 18);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Reset the valid flag on errors.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_CUR_ERRORS;
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Move on to the status phase.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read 10 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIRead10(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint16_t ui16NumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Default the number of blocks.
+ //
+ ui16NumBlocks = 0;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Get the logical block from the CBW structure. This switching
+ // is required to convert from big to little endian.
+ //
+ psInst->ui32CurrentLBA = (psSCSICBW->CBWCB[2] << 24) |
+ (psSCSICBW->CBWCB[3] << 16) |
+ (psSCSICBW->CBWCB[4] << 8) |
+ (psSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ ui16NumBlocks = (psSCSICBW->CBWCB[7] << 8) | psSCSICBW->CBWCB[8];
+
+ //
+ // Read the next logical block from the storage device.
+ //
+ if(psMSCDevice->sMediaFunctions.pfnBlockRead(psInst->pvMedia,
+ (uint8_t *)psInst->pui32Buffer, psInst->ui32CurrentLBA, 1) == 0)
+ {
+ psInst->pvMedia = 0;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ }
+ }
+
+ //
+ // If there is media present then start transferring the data.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Configure and DMA for the IN transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8INDMA,
+ psInst->pui32Buffer, g_pui32BlockSize);
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ui32Flags |= USBD_FLAG_DMA_IN;
+
+ //
+ // Schedule the remaining bytes to send.
+ //
+ psInst->ui32BytesToTransfer = (g_pui32BlockSize * ui16NumBlocks);
+
+ //
+ // Move on and start sending blocks.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SEND_BLOCKS;
+
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_READING, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Read 10 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIWrite10(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint16_t ui16NumBlocks;
+ tMSCInstance *psInst;
+
+ //
+ // Get instance data pointers.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present then start transferring the data.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Get the logical block from the CBW structure. This switching
+ // is required to convert from big to little endian.
+ //
+ psInst->ui32CurrentLBA = (psSCSICBW->CBWCB[2] << 24) |
+ (psSCSICBW->CBWCB[3] << 16) |
+ (psSCSICBW->CBWCB[4] << 8) |
+ (psSCSICBW->CBWCB[5] << 0);
+
+ //
+ // More bytes to read.
+ //
+ ui16NumBlocks = (psSCSICBW->CBWCB[7] << 8) | psSCSICBW->CBWCB[8];
+
+ psInst->ui32BytesToTransfer = g_pui32BlockSize * ui16NumBlocks;
+
+ //
+ // Start sending logical blocks, these are always multiples of
+ // g_pui32BlockSize bytes.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_RECEIVE_BLOCKS;
+
+ //
+ // Configure and enable DMA for the OUT transfer.
+ //
+ USBLibDMATransfer(psInst->psDMAInstance, psInst->ui8OUTDMA,
+ psInst->pui32Buffer, g_pui32BlockSize);
+
+ //
+ // Remember that a DMA is in progress.
+ //
+ psInst->ui32Flags |= USBD_FLAG_DMA_OUT;
+
+ //
+ // Notify the application of the write event.
+ //
+ if(psMSCDevice->pfnEventCallback)
+ {
+ psMSCDevice->pfnEventCallback(0, USBD_MSC_EVENT_WRITING, 0, 0);
+ }
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Mode Sense 6 command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIModeSense6(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Three extra bytes in this response.
+ //
+ g_pui8Command[0] = 3;
+ g_pui8Command[1] = 0;
+ g_pui8Command[2] = 0;
+ g_pui8Command[3] = 0;
+
+ //
+ // Manually send the response back to the host.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint, g_pui8Command,
+ 4);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint,
+ USB_TRANS_IN);
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = psSCSICBW->dCBWDataTransferLength - 4;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to send out the response data based on the current
+// status of the mass storage class.
+//
+//*****************************************************************************
+static void
+USBDSCSISendStatus(tUSBDMSCDevice *psMSCDevice)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Respond with the requested status.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, psInst->ui8INEndpoint,
+ (uint8_t *)&g_sSCSICSW, 13);
+ MAP_USBEndpointDataSend(USB0_BASE, psInst->ui8INEndpoint, USB_TRANS_IN);
+
+ //
+ // Move the state to status sent so that the next interrupt will move the
+ // statue to idle.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_SENT_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the Prevent/Allow Medium Removal command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIPreventAllowMediumRemoval(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // See if this was an allow or prevent removal request.
+ //
+ if((psSCSICBW->CBWCB[4] & SCSI_PE_MEDRMV_M) == SCSI_PE_MEDRMV_ALLOW)
+ {
+ psInst->ui32Flags |= USBD_FLAG_ALLOW_REMOVAL;
+ }
+ else
+ {
+ psInst->ui32Flags &= ~USBD_FLAG_ALLOW_REMOVAL;
+ }
+
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle the SCSI Start/Stop Unit command when it is
+// received from the host.
+//
+//*****************************************************************************
+static void
+USBDSCSIStartStopUnit(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // If there is media present send the response.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ switch(psSCSICBW->CBWCB[4] & (SCSI_SS_UNIT_START | SCSI_SS_UNIT_LOEJ))
+ {
+ case 0:
+ {
+ //
+ // Media state is now stopped but not ejected.
+ //
+ psInst->iMediaStatus = eUSBDMSCMediaStopped;
+
+ g_sSCSICSW.bCSWStatus = 0;
+
+ break;
+ }
+ case SCSI_SS_UNIT_START:
+ {
+ //
+ // Return to Media present.
+ //
+ psInst->iMediaStatus = eUSBDMSCMediaPresent;
+
+ g_sSCSICSW.bCSWStatus = 0;
+
+ break;
+ }
+ case SCSI_SS_UNIT_LOEJ:
+ {
+ //
+ // Only allow eject if the Prevent/Allow Medium Removal has
+ // been sent and enabled medium removal.
+ //
+ if(psInst->ui32Flags & USBD_FLAG_ALLOW_REMOVAL)
+ {
+ psInst->iMediaStatus = eUSBDMSCMediaNotPresent;
+ psMSCDevice->sMediaFunctions.pfnClose(0);
+ psMSCDevice->sPrivateData.pvMedia = 0;
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+
+ break;
+ }
+ case SCSI_SS_UNIT_START | SCSI_SS_UNIT_LOEJ:
+ {
+ //
+ // Since there was no media, check for media here.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ //
+ // If it is still not present then fail this command.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // There is no further data to send.
+ //
+ g_sSCSICSW.dCSWDataResidue = 0;
+ }
+ else
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+
+ //
+ // Mark the sense code as valid and indicate that these is no media
+ // present.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+
+ psInst->ui8SCSIState = STATE_SCSI_SEND_STATUS;
+}
+
+//*****************************************************************************
+//
+// This function is used to handle all SCSI commands.
+//
+//*****************************************************************************
+uint32_t
+USBDSCSICommand(tUSBDMSCDevice *psMSCDevice, tMSCCBW *psSCSICBW)
+{
+ uint32_t ui32RetCode, ui32TransferLength;
+ tMSCInstance *psInst;
+
+ //
+ // Get our instance data pointer.
+ //
+ psInst = &psMSCDevice->sPrivateData;
+
+ //
+ // Initialize the return code.
+ //
+ ui32RetCode = 1;
+
+ //
+ // Save the transfer length because it may be overwritten by some calls.
+ //
+ ui32TransferLength = psSCSICBW->dCBWDataTransferLength;
+
+ switch(psSCSICBW->CBWCB[0])
+ {
+ //
+ // Respond to the SCSI Inquiry command.
+ //
+ case SCSI_INQUIRY_CMD:
+ {
+ USBDSCSIInquiry(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Respond to the test unit ready command.
+ //
+ case SCSI_TEST_UNIT_READY:
+ {
+ g_sSCSICSW.dCSWDataResidue = 0;
+
+ if(psInst->pvMedia != 0)
+ {
+ //
+ // Set the status to success for now, this could be different
+ // if there is no media present.
+ //
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else if(psInst->iMediaStatus == eUSBDMSCMediaNotPresent)
+ {
+ //
+ // Set the status to success for now, this could be different
+ // if there is no media present.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_NOT_READY;
+ psInst->ui16AddSenseCode = SCSI_RS_MED_NOT_PRSNT;
+ }
+ else
+ {
+ //
+ // Since there was no media, check for media here.
+ //
+ psInst->pvMedia = psMSCDevice->sMediaFunctions.pfnOpen(0);
+
+ //
+ // If it is still not present then fail this command.
+ //
+ if(psInst->pvMedia != 0)
+ {
+ g_sSCSICSW.bCSWStatus = 0;
+ }
+ else
+ {
+ g_sSCSICSW.bCSWStatus = 1;
+ }
+ }
+ break;
+ }
+
+ //
+ // Handle the Read Capacities command.
+ //
+ case SCSI_READ_CAPACITIES:
+ {
+ USBDSCSIReadCapacities(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read Capacity command.
+ //
+ case SCSI_READ_CAPACITY:
+ {
+ USBDSCSIReadCapacity(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Request Sense command.
+ //
+ case SCSI_REQUEST_SENSE:
+ {
+ USBDSCSIRequestSense(psMSCDevice);
+
+ break;
+ }
+
+ //
+ // Handle the Read 10 command.
+ //
+ case SCSI_READ_10:
+ {
+ USBDSCSIRead10(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Write 10 command.
+ //
+ case SCSI_WRITE_10:
+ {
+ USBDSCSIWrite10(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Mode Sense 6 command.
+ //
+ case SCSI_MODE_SENSE_6:
+ {
+ USBDSCSIModeSense6(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Prevent/Allow Medium Removal command.
+ //
+ case SCSI_MEDIUM_REMOVAL:
+ {
+ USBDSCSIPreventAllowMediumRemoval(psMSCDevice, psSCSICBW);
+
+ break;
+ }
+
+ //
+ // Handle the Prevent/Allow Medium Removal command.
+ //
+ case SCSI_START_STOP_UNIT:
+ {
+ USBDSCSIStartStopUnit(psMSCDevice, psSCSICBW);
+ break;
+ }
+
+ default:
+ {
+ //
+ // Set the status so that it can be sent when this response has
+ // has be successfully sent.
+ //
+ g_sSCSICSW.bCSWStatus = 1;
+ g_sSCSICSW.dCSWDataResidue = psSCSICBW->dCBWDataTransferLength;
+
+ //
+ // If there is data then there is more work to do.
+ //
+ if(psSCSICBW->dCBWDataTransferLength != 0)
+ {
+ if(psSCSICBW->bmCBWFlags & CBWFLAGS_DIR_IN)
+ {
+ //
+ // Stall the IN endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8INEndpoint,
+ USB_EP_DEV_IN);
+ }
+ else
+ {
+ //
+ // Stall the OUT endpoint
+ //
+ MAP_USBDevEndpointStall(USB0_BASE, psInst->ui8OUTEndpoint,
+ USB_EP_DEV_OUT);
+
+ }
+
+ //
+ // Go back to the idle state and wait for the host to clear
+ // the stall later.
+ //
+ psInst->ui8SCSIState = STATE_SCSI_IDLE;
+ }
+
+ //
+ // Set the sense codes.
+ //
+ psInst->ui8ErrorCode = SCSI_RS_VALID | SCSI_RS_CUR_ERRORS;
+ psInst->ui8SenseKey = SCSI_RS_KEY_ILGL_RQST;
+ psInst->ui16AddSenseCode = SCSI_RS_PV_INVALID;
+
+ break;
+ }
+ }
+
+ //
+ // If there is no data then send out the current status.
+ //
+ if(ui32TransferLength == 0)
+ {
+ USBDSCSISendStatus(psMSCDevice);
+ }
+ return(ui32RetCode);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/device/usbdmsc.h b/usblib/device/usbdmsc.h
new file mode 100644
index 0000000..9f33e4c
--- /dev/null
+++ b/usblib/device/usbdmsc.h
@@ -0,0 +1,420 @@
+//*****************************************************************************
+//
+// usbdmsc.h - USB mass storage device class driver.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDMSC_H__
+#define __USBDMSC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup msc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Media Access functions.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This function is used to initialize and open the physical drive number
+ //! associated with the parameter \e ui32Drive. The function returns
+ //! zero if the drive could not be opened for some reason. In the case of
+ //! removable device like an SD card this function must return zero if
+ //! the SD card is not present.
+ //! The function returns a pointer to data that should be passed to other
+ //! APIs or returns 0 if no drive was found.
+ //
+ void *(*pfnOpen)(uint32_t ui32Drive);
+
+ //*************************************************************************
+ //
+ //! This function closes the drive number in use by the mass storage class
+ //! device. The \e pvDrive is the pointer that was returned from a call to
+ //! \e pfnOpen. This function is used to close the physical drive
+ //! number associated with the parameter \e pvDrive. This function
+ //! returns 0 if the drive was closed successfully and any other value
+ //! indicates a failure.
+ //
+ //*************************************************************************
+ void (*pfnClose)(void *pvDrive);
+
+ //*************************************************************************
+ //
+ //! This function reads a block of data from a device opened by the
+ //! \e pfnOpen call. The \e pvDrive parameter is the pointer that was
+ //! returned from the original call to \e pfnOpen. The \e pui8Data
+ //! parameter is the buffer that data will be written into. The data area
+ //! pointed to by \e pui8Data must be at least \e ui32NumBlocks * Block
+ //! Size bytes to prevent overwriting data. The \e ui32Sector is the block
+ //! address to read and \e ui32NumBlocks is the number of blocks to read.
+ //! This function returns the number of bytes that were read from the
+ //! and placed into the \e pui8Data buffer..
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockRead)(void *pvDrive, uint8_t *pui8Data,
+ uint32_t ui32Sector, uint32_t ui32NumBlocks);
+
+ //*************************************************************************
+ //
+ //! This function is use to write blocks to a physical device from the
+ //! buffer pointed to by the \e pui8Data buffer. The \e pvDrive parameter
+ //! is the pointer that was returned from the original call to \e pfnOpen.
+ //! The \e pui8Data is the pointer to the data to write to the storage
+ //! device and \e ui32NumBlocks is the number of blocks to write. The
+ //! \e ui32Sector parameter is the sector number used to write the block.
+ //! If the number of blocks is greater than one then the block address
+ //! increments and writes to the next block until
+ //! \e ui32NumBlocks * Block Size bytes are written. This function returns
+ //! the number of bytes that were written to the device.
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockWrite)(void *pvDrive, uint8_t *pui8Data,
+ uint32_t ui32Sector, uint32_t ui32NumBlocks);
+
+ //*************************************************************************
+ //
+ //! This function returns the total number of blocks on a physical device
+ //! based on the \e pvDrive parameter. The \e pvDrive parameter
+ //! is the pointer that was returned from the original call to \e pfnOpen.
+ //
+ //*************************************************************************
+ uint32_t (*pfnNumBlocks)(void *pvDrive);
+
+ //*************************************************************************
+ //
+ //! This function returns the block size for a physical device based on the
+ //! \e pvDrive parameter. The \e pvDrive parameter is the pointer
+ //! that was returned from the original call to \e pfnOpen.
+ //
+ //*************************************************************************
+ uint32_t (*pfnBlockSize)(void *pvDrive);
+
+}
+tMSCDMedia;
+
+//*****************************************************************************
+//
+// These defines control the default sizes of USB transfers for data and
+// commands.
+//
+//*****************************************************************************
+#define DEVICE_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// USBDMSCMediaChange() tUSBDMSCMediaStatus values.
+//
+//*****************************************************************************
+typedef enum
+{
+ eUSBDMSCMediaPresent,
+ eUSBDMSCMediaNotPresent,
+ eUSBDMSCMediaStopped,
+ eUSBDMSCMediaUnknown
+}
+tUSBDMSCMediaStatus;
+
+//*****************************************************************************
+//
+// PRIVATE
+//
+// This structure defines the private instance data and state variables for the
+// mass storage class. The memory for this structure is in the the
+// sPrivateData field in the tUSBDMSCDevice structure passed on
+// USBDMSCInit() and should not be modified by any code outside of the mass
+// storage device code.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Base address for the USB controller.
+ //
+ uint32_t ui32USBBase;
+
+ //
+ // The device info to interact with the lower level DCD code.
+ //
+ tDeviceInfo sDevInfo;
+
+ //
+ // These three values are used to return the current sense data for an
+ // instance of the mass storage class.
+ //
+ uint8_t ui8ErrorCode;
+ uint8_t ui8SenseKey;
+ uint16_t ui16AddSenseCode;
+
+ //
+ // The pointer to the instance returned from the Open call to the media.
+ //
+ void *pvMedia;
+
+ //
+ // The connection status of the device.
+ //
+ volatile bool bConnected;
+
+ //
+ // Holds the flag settings for this instance.
+ //
+ uint32_t ui32Flags;
+
+ //
+ // Holds the current media status.
+ //
+ tUSBDMSCMediaStatus iMediaStatus;
+
+ //
+ // MSC block buffer.
+ //
+ uint32_t pui32Buffer[0x1000>>2];
+
+ //
+ // Current number of bytes to transfer.
+ //
+ uint32_t ui32BytesToTransfer;
+
+ //
+ // The LBA for the current transfer.
+ //
+ uint32_t ui32CurrentLBA;
+
+ //
+ // The IN endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8INEndpoint;
+
+ //
+ // The IN DMA channel.
+ //
+ uint8_t ui8INDMA;
+
+ //
+ // The OUT endpoint number, this is modified in composite devices.
+ //
+ uint8_t ui8OUTEndpoint;
+
+ //
+ // The OUT DMA channel.
+ //
+ uint8_t ui8OUTDMA;
+
+ //
+ // The bulk class interface number, this is modified in composite devices.
+ //
+ uint8_t ui8Interface;
+
+ //
+ // Active SCSI state.
+ //
+ uint8_t ui8SCSIState;
+
+ //
+ // A copy of the DMA instance data used with calls to USBLibDMA functions.
+ //
+ tUSBDMAInstance *psDMAInstance;
+}
+tMSCInstance;
+
+//*****************************************************************************
+//
+// This is the size of the g_pui8MSCInterface array in bytes.
+//
+//*****************************************************************************
+#define MSCINTERFACE_SIZE (23)
+
+//*****************************************************************************
+//
+//! The size of the memory that should be allocated to create a configuration
+//! descriptor for a single instance of the USB Audio Device.
+//! This does not include the configuration descriptor which is automatically
+//! ignored by the composite device class.
+//
+//
+//*****************************************************************************
+#define COMPOSITE_DMSC_SIZE (MSCINTERFACE_SIZE)
+
+//*****************************************************************************
+//
+//! The structure used by the application to define operating parameters for
+//! the mass storage device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The vendor ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16VID;
+
+ //
+ //! The product ID that this device is to present in the device descriptor.
+ //
+ const uint16_t ui16PID;
+
+ //
+ //! 8 byte vendor string.
+ //
+ const uint8_t pui8Vendor[8];
+
+ //
+ //! 16 byte vendor string.
+ //
+ const uint8_t pui8Product[16];
+
+ //
+ //! 4 byte vendor string.
+ //
+ const uint8_t pui8Version[4];
+
+ //
+ //! The maximum power consumption of the device, expressed in milliamps.
+ //
+ const uint16_t ui16MaxPowermA;
+
+ //
+ //! Indicates whether the device is self or bus-powered and whether or not
+ //! it supports remote wakeup. Valid values are \b USB_CONF_ATTR_SELF_PWR
+ //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
+ //! \b USB_CONF_ATTR_RWAKE.
+ //
+ const uint8_t ui8PwrAttributes;
+
+ //
+ //! A pointer to the string descriptor array for this device. This array
+ //! must contain the following string descriptor pointers in this order.
+ //! Language descriptor, Manufacturer name string (language 1), Product
+ //! name string (language 1), Serial number string (language 1), MSC
+ //! Interface description string (language 1), Configuration description
+ //! string (language 1).
+ //!
+ //! If supporting more than 1 language, the descriptor block (except for
+ //! string descriptor 0) must be repeated for each language defined in the
+ //! language descriptor.
+ //!
+ //
+ const uint8_t * const *ppui8StringDescriptors;
+
+ //
+ //! The number of descriptors provided in the \e ppStringDescriptors
+ //! array. This must be 1 + ((5 + (num HID strings)) * (num languages)).
+ //
+ const uint32_t ui32NumStringDescriptors;
+
+ //
+ //! This structure holds the access functions for the media used by this
+ //! instance of the mass storage class device. All of the functions in
+ //! this structure are required to be filled out with valid functions.
+ //
+ const tMSCDMedia sMediaFunctions;
+
+ //
+ //! This is the callback function for various events that occur during
+ //! mass storage class operation.
+ //
+ const tUSBCallback pfnEventCallback;
+
+ //
+ //! The private instance data for this device. This memory
+ //! must remain accessible for as long as the MSC device is in use and
+ //! must not be modified by any code outside the MSC class driver.
+ //
+ tMSCInstance sPrivateData;
+}
+tUSBDMSCDevice;
+
+//*****************************************************************************
+//
+// MSC-specific device class driver events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This event indicates that the host has completed other operations and is
+//! no longer accessing the device.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_IDLE (USBD_MSC_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This event indicates that the host is reading the storage media.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_READING (USBD_MSC_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+//! This event indicates that the host is writing to the storage media.
+//
+//*****************************************************************************
+#define USBD_MSC_EVENT_WRITING (USBD_MSC_EVENT_BASE + 2)
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern void *USBDMSCInit(uint32_t ui32Index,
+ tUSBDMSCDevice *psMSCDevice);
+extern void *USBDMSCCompositeInit(uint32_t ui32Index,
+ tUSBDMSCDevice *psMSCDevice,
+ tCompositeEntry *psCompEntry);
+extern void USBDMSCTerm(void *pvInstance);
+extern void USBDMSCMediaChange(void *pvInstance,
+ tUSBDMSCMediaStatus eMediaStatus);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/ewarm/Exe/usblib.a b/usblib/ewarm/Exe/usblib.a
new file mode 100644
index 0000000..ac41998
--- /dev/null
+++ b/usblib/ewarm/Exe/usblib.a
Binary files differ
diff --git a/usblib/gcc/libusb.a b/usblib/gcc/libusb.a
new file mode 100644
index 0000000..8b25639
--- /dev/null
+++ b/usblib/gcc/libusb.a
Binary files differ
diff --git a/usblib/host/usbhaudio.c b/usblib/host/usbhaudio.c
new file mode 100644
index 0000000..129130c
--- /dev/null
+++ b/usblib/host/usbhaudio.c
@@ -0,0 +1,1557 @@
+//*****************************************************************************
+//
+// usbhaudio.c - USB host audio driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbaudio.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhaudio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These defines are used with the USBHostAudioFormatSet()
+// USBHostAudioFormatGet() to parse out interface number and alternate
+// setting number for an interface.
+//
+//*****************************************************************************
+#define INTERFACE_NUM_M 0x000000FF
+#define INTERFACE_ALTSETTING_M 0x0000FF00
+#define INTERFACE_ALTSETTING_S 8
+
+//*****************************************************************************
+//
+// Used to indicate an invalid interface descriptor number.
+//
+//*****************************************************************************
+#define INVALID_INTERFACE 0xffffffff
+
+//*****************************************************************************
+//
+// Forward declarations for the driver open and close calls.
+//
+//*****************************************************************************
+static void *USBAudioOpen(tUSBHostDevice *psDevice);
+static void USBAudioClose(void *pvInstance);
+
+//*****************************************************************************
+//
+// This is the structure for an instance of a USB host audio driver.
+//
+//*****************************************************************************
+struct tUSBHostAudioInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the call back.
+ //
+ tUSBHostAudioCallback pfnCallback;
+
+ //
+ // This is the control interface.
+ //
+ uint8_t ui8IControl;
+
+ //
+ // This is the output streaming interface.
+ //
+ uint8_t ui8OutInterface;
+
+ //
+ // This is the currently selected active output interface used with
+ // ui8OutInterface interface.
+ //
+ uint8_t ui8OutAltSetting;
+
+ //
+ // This is the streaming interface.
+ //
+ uint8_t ui8InInterface;
+
+ //
+ // This is the currently selected active input interface used with
+ // ui8InInterface interface.
+ //
+ uint8_t ui8InAltSetting;
+
+ //
+ // The Isochronous endpoint addresses.
+ //
+ uint8_t ui8IsochInAddress;
+ uint8_t ui8IsochOutAddress;
+
+ tACInputTerminal *psInTerminal;
+ tACOutputTerminal *psOutTerminal;
+
+ //
+ // Holds the identifier for the Feature Unit for controlling volume.
+ //
+ uint8_t ui8VolumeID;
+
+ tACFeatureUnit *psFeatureUnit;
+
+ //
+ // Holds what types of controls are enabled on the device.
+ //
+ uint16_t pui16Controls[3];
+
+ //
+ // Isochronous IN pipe.
+ //
+ uint32_t ui32IsochInPipe;
+ uint16_t ui16PipeSizeIn;
+ tUSBHostAudioCallback pfnInCallback;
+ void *pvInBuffer;
+
+ //
+ // Isochronous OUT pipe.
+ //
+ uint32_t ui32IsochOutPipe;
+ uint16_t ui16PipeSizeOut;
+ tUSBHostAudioCallback pfnOutCallback;
+ void *pvOutBuffer;
+
+ //
+ // State flags for this audio instance.
+ //
+ uint32_t ui32Flags;
+};
+
+//*****************************************************************************
+//
+// The internal flags for an audio interface.
+//
+//*****************************************************************************
+#define AUDIO_FLAG_OUT_ACTIVE 1 // Audio output is active.
+#define AUDIO_FLAG_IN_ACTIVE 2 // Audio input is active.
+
+//*****************************************************************************
+//
+// The USB Host audio instance.
+//
+//*****************************************************************************
+static tUSBHostAudioInstance g_sAudioDevice =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Audio Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHostAudioClassDriver =
+{
+ USB_CLASS_AUDIO,
+ USBAudioOpen,
+ USBAudioClose,
+ 0
+};
+
+//*****************************************************************************
+//
+// This is the internal function that handles callbacks from the USB IN pipe.
+//
+//*****************************************************************************
+static void
+PipeCallbackIN(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ //
+ // Only handle the data available callback and pass it on to the
+ // application.
+ //
+ if(ui32Event == USB_EVENT_RX_AVAILABLE)
+ {
+ if(g_sAudioDevice.pfnInCallback)
+ {
+ g_sAudioDevice.pfnInCallback(&g_sAudioDevice,
+ USB_EVENT_RX_AVAILABLE,
+ USBHCDPipeTransferSizeGet(ui32Pipe),
+ g_sAudioDevice.pvInBuffer);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This is the internal function that handles callbacks from the USB OUT pipe.
+//
+//*****************************************************************************
+static void
+PipeCallbackOUT(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ //
+ // Only handle the transmit complete callback and pass it on to the
+ // application.
+ //
+ if(ui32Event == USB_EVENT_TX_COMPLETE)
+ {
+ if(g_sAudioDevice.pfnOutCallback)
+ {
+ g_sAudioDevice.pfnOutCallback(&g_sAudioDevice,
+ USB_EVENT_TX_COMPLETE, 0,
+ g_sAudioDevice.pvOutBuffer);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Finds a given terminal and type in an audio configuration descriptor.
+//
+//*****************************************************************************
+static tDescriptorHeader *
+AudioTerminalGet(tConfigDescriptor *psConfigDesc, uint32_t ui32Terminal,
+ uint32_t ui32TerminalType)
+{
+ tACOutputTerminal *psOutput;
+ tDescriptorHeader *psHeader;
+ int32_t i32BytesRemaining;
+
+ psHeader = (tDescriptorHeader *)psConfigDesc;
+ i32BytesRemaining = psConfigDesc->wTotalLength;
+
+ while(i32BytesRemaining > 0)
+ {
+ //
+ // Output and input terminals are the same past the bDescriptorSubtype
+ // and wTerminalType that are being searched for.
+ //
+ psOutput = (tACOutputTerminal *)psHeader;
+
+ //
+ // Only CS_INTERFACE descriptors can be a terminal.
+ //
+ if((psHeader->bDescriptorType == USB_DTYPE_CS_INTERFACE) &&
+ (ui32Terminal == psOutput->bDescriptorSubtype))
+ {
+ if((psOutput->bDescriptorSubtype == USB_AI_OUTPUT_TERMINAL) ||
+ (psOutput->bDescriptorSubtype == USB_AI_INPUT_TERMINAL))
+
+ {
+ //
+ // If this was the terminal type that was requested, the
+ // return it.
+ //
+ if(psOutput->wTerminalType == ui32TerminalType)
+ {
+ return(psHeader);
+ }
+ }
+ else if(psOutput->bDescriptorSubtype == USB_AI_FEATURE_UNIT)
+ {
+ return(psHeader);
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32BytesRemaining -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader *)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+ return((tDescriptorHeader *)0);
+}
+
+//*****************************************************************************
+//
+// This function returns the interface number for the control interface
+// in the structure passed in the psConfigDesc.
+//
+// \param psConfigDescriptor is a pointer to the memory containing a valid
+// configuration descriptor for a device.
+//
+// This function searches a configuration descriptor for a control interface
+// descriptor. The function only search for the first descriptor and then
+// returns when it finds one.
+//
+// \return The first control interface descriptor number for an audio device
+// or INVALID_INTERFACE if no control interface descriptor was found.
+//
+//*****************************************************************************
+static uint32_t
+AudioControlGet(tConfigDescriptor *psConfigDesc)
+{
+ tDescriptorHeader *psHeader;
+ tInterfaceDescriptor *psInterface;
+ uint32_t ui32Interface;
+ int32_t i32Bytes;
+
+ psHeader = (tDescriptorHeader *)psConfigDesc;
+ i32Bytes = psConfigDesc->wTotalLength;
+
+ //
+ // Initialize the interface number to an invalid value.
+ //
+ ui32Interface = INVALID_INTERFACE;
+
+ //
+ // Search the whole configuration descriptor.
+ //
+ while(i32Bytes > 0)
+ {
+ //
+ // Find an interface descriptor and see if it is a control interface.
+ //
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // If this is the control interface then return the value to the
+ // caller.
+ //
+ if(psInterface->bInterfaceSubClass == USB_ASC_AUDIO_CONTROL)
+ {
+ ui32Interface = psInterface->bInterfaceNumber;
+
+ break;
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32Bytes -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader*)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+ return(ui32Interface);
+}
+
+//*****************************************************************************
+//
+// If it exists, finds the correct audio interface for a given audio format.
+//
+//*****************************************************************************
+static uint32_t
+AudioGetInterface(tUSBHostAudioInstance *psAudioDevice, uint16_t ui16Format,
+ uint32_t ui32SampleRate, uint32_t ui32Bytes,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ tDescriptorHeader *psHeader;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *pINEndpoint, *pOUTEndpoint;
+ tACHeader *pACHeader;
+ tACGeneral *pGeneral;
+ tASFormat *pFormat;
+ tEndpointDescriptor *pEndpoint;
+ uint8_t *pui8Value;
+ uint32_t ui32Value;
+ int32_t i32Bytes, i32Idx;
+
+ //
+ // Initialize the Interface pointer to null.
+ //
+ psInterface = 0;
+ pINEndpoint = 0;
+ pOUTEndpoint = 0;
+
+ //
+ // Start at the top of the configuration descriptor.
+ //
+ psHeader = (tDescriptorHeader *)psAudioDevice->psDevice->psConfigDescriptor;
+
+ i32Bytes = psAudioDevice->psDevice->psConfigDescriptor->wTotalLength;
+
+ while(i32Bytes > 0)
+ {
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ //
+ // If a new interface was found and the last one satisfied all
+ // requirements then a valid interface was found so break out.
+ //
+ if(psInterface)
+ {
+ break;
+ }
+
+ //
+ // Get the new interface pointer.
+ //
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // Reset the endpoints on finding a new interface descriptor.
+ //
+ pINEndpoint = 0;
+ pOUTEndpoint = 0;
+
+ //
+ // If this is not a valid audio streaming interface then reset
+ // the interface pointer to null.
+ //
+ if((psInterface->bNumEndpoints == 0) ||
+ (psInterface->bInterfaceClass != USB_CLASS_AUDIO) ||
+ (psInterface->bInterfaceSubClass != USB_ASC_AUDIO_STREAMING))
+ {
+ psInterface = 0;
+ }
+ }
+ if((psInterface) &&
+ (psHeader->bDescriptorType == USB_DTYPE_CS_INTERFACE))
+ {
+ pACHeader = (tACHeader *)psHeader;
+
+ //
+ // If this is a General descriptor the check if the format matches.
+ //
+ if(pACHeader->bDescriptorSubtype == USB_AS_GENERAL)
+ {
+ //
+ // Just save the pointer to the format descriptor.
+ //
+ pGeneral = (tACGeneral *)psHeader;
+
+ //
+ // If this interface has the wrong format then set it to null
+ // so that the rest of this interface is ignored.
+ //
+ if(pGeneral->wFormatTag != ui16Format)
+ {
+ psInterface = 0;
+ }
+ }
+ else if(pACHeader->bDescriptorSubtype == USB_AS_FORMAT_TYPE)
+ {
+ pFormat = (tASFormat *)psHeader;
+
+ //
+ // If the number of bytes per sample and number of channels do
+ // not match then reset the interface pointer so that the rest
+ // of this interface is ignored.
+ //
+ if((pFormat->bNrChannels != ui32Channels) ||
+ (pFormat->bSubFrameSize != ui32Bytes))
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ pui8Value = &pFormat->tSamFreq;
+
+ //
+ // Attempt to find the sample rate in the sample rate
+ // table for this interface.
+ //
+ for(i32Idx = 0; i32Idx < pFormat->bSamFreqType; i32Idx++)
+ {
+ ui32Value = (*((uint32_t *)&pui8Value[i32Idx * 3]) &
+ 0xffffff);
+
+ if(ui32Value == ui32SampleRate)
+ {
+ break;
+ }
+ }
+
+ //
+ // If the sample rate was not found then set the interface
+ // pointer to null so that the rest of this interface is
+ // ignored.
+ //
+ if(i32Idx == pFormat->bSamFreqType)
+ {
+ psInterface = 0;
+ }
+ }
+ }
+ }
+ else if((psInterface) &&
+ (psHeader->bDescriptorType == USB_DTYPE_ENDPOINT))
+ {
+ pEndpoint = (tEndpointDescriptor *)psHeader;
+
+ //
+ // See what direction is being requested.
+ //
+ if(ui32Flags & USBH_AUDIO_FORMAT_IN)
+ {
+ //
+ // If this is an input endpoint and is just a feed back input
+ // then ignore it.
+ //
+ if(pEndpoint->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ if((pEndpoint->bmAttributes & USB_EP_ATTR_USAGE_M)
+ == USB_EP_ATTR_USAGE_FEEDBACK)
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ //
+ // Save this endpoint as a possible valid endpoint
+ //
+ pINEndpoint = pEndpoint;
+ }
+ }
+ }
+ else
+ {
+ //
+ // If this is an output endpoint and is just a feed back input
+ // then ignore it.
+ //
+ if((pEndpoint->bEndpointAddress & USB_EP_DESC_IN) == 0)
+ {
+ if((pEndpoint->bmAttributes & USB_EP_ATTR_USAGE_M)
+ == USB_EP_ATTR_USAGE_FEEDBACK)
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ //
+ // Save this endpoint as a possible valid endpoint;
+ //
+ pOUTEndpoint = pEndpoint;
+ }
+ }
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32Bytes -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader*)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+
+ //
+ // If there is still a valid interface then return the values.
+ //
+ if(psInterface)
+ {
+ //
+ // Check a valid IN endpoint descriptor.
+ //
+ if(pINEndpoint)
+ {
+ //
+ // Save the endpoint address.
+ //
+ g_sAudioDevice.ui8IsochInAddress = pINEndpoint->bEndpointAddress &
+ USB_EP_DESC_NUM_M;
+
+ //
+ // If there is no current pipe then just allocate a new one with
+ // the settings for this interface.
+ //
+ if(g_sAudioDevice.ui32IsochInPipe == 0)
+ {
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice,
+ pINEndpoint->wMaxPacketSize,
+ PipeCallbackIN);
+ }
+ else if(g_sAudioDevice.ui16PipeSizeIn < pINEndpoint->wMaxPacketSize)
+ {
+ //
+ // Free the old endpoint and allocate a new one.
+ //
+ USBHCDPipeFree(g_sAudioDevice.ui32IsochInPipe);
+
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice,
+ pINEndpoint->wMaxPacketSize,
+ PipeCallbackIN);
+
+ //
+ // Save the new size of the maximum packet size for this
+ // USB pipe.
+ //
+ g_sAudioDevice.ui16PipeSizeIn = pINEndpoint->wMaxPacketSize;
+ }
+
+ //
+ // Configure the USB pipe as a Isochronous IN end point.
+ //
+ USBHCDPipeConfig(g_sAudioDevice.ui32IsochInPipe,
+ pINEndpoint->wMaxPacketSize,
+ 0,
+ g_sAudioDevice.ui8IsochInAddress);
+ }
+
+ //
+ // Check a valid OUT endpoint descriptor.
+ //
+ if(pOUTEndpoint)
+ {
+ //
+ // Save the endpoint address.
+ //
+ g_sAudioDevice.ui8IsochOutAddress =
+ pOUTEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+
+ //
+ // If there is no current pipe then just allocate a new one with
+ // the settings for this interface.
+ //
+ if(g_sAudioDevice.ui32IsochOutPipe == 0)
+ {
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice,
+ pOUTEndpoint->wMaxPacketSize,
+ PipeCallbackOUT);
+ }
+ else if(g_sAudioDevice.ui16PipeSizeOut <
+ pOUTEndpoint->wMaxPacketSize)
+ {
+ //
+ // Free the old endpoint and allocate a new one.
+ //
+ USBHCDPipeFree(g_sAudioDevice.ui32IsochOutPipe);
+
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice,
+ pOUTEndpoint->wMaxPacketSize,
+ PipeCallbackOUT);
+
+ //
+ // Save the new size of the maximum packet size for this
+ // USB pipe.
+ //
+ g_sAudioDevice.ui16PipeSizeOut = pOUTEndpoint->wMaxPacketSize;
+ }
+
+ //
+ // Configure the USB pipe as a Isochronous OUT end point.
+ //
+ USBHCDPipeConfig(g_sAudioDevice.ui32IsochOutPipe,
+ pOUTEndpoint->wMaxPacketSize, 0,
+ g_sAudioDevice.ui8IsochOutAddress);
+ }
+
+ return(psInterface->bInterfaceNumber |
+ (psInterface->bAlternateSetting << INTERFACE_ALTSETTING_S));
+ }
+ return(INVALID_INTERFACE);
+}
+
+//*****************************************************************************
+//
+// This function is used to open an instance of the USB host audio driver.
+//
+// \param psDevice is a pointer to the device information structure.
+//
+// This function attempts to open an instance of the USB host audio driver
+// based on the information contained in the psDevice structure. This call
+// fails if there are not sufficient resources to open the device. The
+// function returns a value that should be passed back into USBHostAudioClose()
+// when the driver is no longer needed.
+//
+// \return The function returns a pointer to a USB host audio driver
+// instance.
+//
+//*****************************************************************************
+static void *
+USBAudioOpen(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Temp;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Don't allow the device to be opened without closing first.
+ //
+ if(g_sAudioDevice.psDevice)
+ {
+ return(0);
+ }
+
+ //
+ // Save the Host device pointer.
+ //
+ g_sAudioDevice.psDevice = psDevice;
+
+ //
+ // Save a shorter name for the configuration descriptor.
+ //
+ psConfigDesc = psDevice->psConfigDescriptor;
+
+ //
+ // Find the input terminal.
+ //
+ g_sAudioDevice.psInTerminal =
+ (tACInputTerminal *)AudioTerminalGet(psConfigDesc,
+ USB_AI_INPUT_TERMINAL,
+ USB_TTYPE_STREAMING);
+
+ //
+ // Find the output terminal.
+ //
+ g_sAudioDevice.psOutTerminal =
+ (tACOutputTerminal *)AudioTerminalGet(psConfigDesc,
+ USB_AI_OUTPUT_TERMINAL,
+ USB_TTYPE_STREAMING);
+
+ //
+ // Find the feature unit.
+ g_sAudioDevice.psFeatureUnit =
+ (tACFeatureUnit *)AudioTerminalGet(psConfigDesc,
+ USB_AI_FEATURE_UNIT, 0);
+
+ //
+ // Need some kind of terminal to send or receive audio from.
+ //
+ if((g_sAudioDevice.psOutTerminal == 0) &&
+ (g_sAudioDevice.psInTerminal == 0))
+ {
+ return(0);
+ }
+
+ //
+ // Find the Audio control interface.
+ //
+ ui32Temp = AudioControlGet(psConfigDesc);
+
+ if(ui32Temp == INVALID_INTERFACE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the control interface index and increment the number
+ // of interfaces that have been found.
+ //
+ g_sAudioDevice.ui8IControl = (uint8_t)ui32Temp;
+
+ //
+ // If the call back exists, call it with an Open event.
+ //
+ if(g_sAudioDevice.pfnCallback != 0)
+ {
+ g_sAudioDevice.pfnCallback(&g_sAudioDevice,
+ USBH_AUDIO_EVENT_OPEN, 0, 0);
+ }
+
+ //
+ // If a feature unit was found, save the ID
+ //
+ if(g_sAudioDevice.psFeatureUnit != 0)
+ {
+ g_sAudioDevice.ui8VolumeID = g_sAudioDevice.psFeatureUnit->bUnitID;
+ }
+
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice, 256, PipeCallbackIN);
+ g_sAudioDevice.ui16PipeSizeIn = 256;
+
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice, 256, PipeCallbackOUT);
+ g_sAudioDevice.ui16PipeSizeOut = 256;
+
+ //
+ // Clear the flags.
+ //
+ g_sAudioDevice.ui32Flags = 0;
+
+ //
+ // Return the only instance of this device.
+ //
+ return(&g_sAudioDevice);
+}
+
+//*****************************************************************************
+//
+// This function is used to release an instance of the USB host audio driver.
+//
+// \param pvAudioDevice is an instance pointer that needs to be released.
+//
+// This function frees up any resources in use by the USB host audio
+// driver instance that is passed in. The \e pvAudioDevice pointer should be a
+// valid value that was returned from a call to USBHostAudioOpen().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBAudioClose(void *pvAudioDevice)
+{
+ tUSBHostAudioInstance *psAudioDevice;
+
+ psAudioDevice = (tUSBHostAudioInstance *)pvAudioDevice;
+
+ //
+ // Do nothing if there is not a driver open.
+ //
+ if(psAudioDevice->psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ psAudioDevice->psDevice = 0;
+
+ //
+ // Free the Isochronous IN pipe.
+ //
+ if(psAudioDevice->ui32IsochInPipe != 0)
+ {
+ USBHCDPipeFree(psAudioDevice->ui32IsochInPipe);
+ }
+
+ //
+ // Free the Isochronous OUT pipe.
+ //
+ if(psAudioDevice->ui32IsochOutPipe != 0)
+ {
+ USBHCDPipeFree(psAudioDevice->ui32IsochOutPipe);
+ }
+
+ //
+ // If the call back exists then call it.
+ //
+ if(psAudioDevice->pfnCallback != 0)
+ {
+ psAudioDevice->pfnCallback(psAudioDevice, USBH_AUDIO_EVENT_CLOSE, 0,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called before any devices are present to enable
+//! the host audio class driver.
+//!
+//! \param ui32Index is the audio device to open (currently only 0 is
+//! supported).
+//! \param pfnCallback is the driver call back for host audio events.
+//!
+//! This function is called to open an instance of a host audio device and
+//! should provide a valid callback function for host audio events in the
+//! \e pfnCallback parameter. This function must be called before the USB
+//! host code can successfully enumerate an audio device.
+//!
+//! \return This function returns the driver instance to use for the other
+//! host audio functions. If there is no instance available at the time of
+//! this call, this function returns zero.
+//
+//*****************************************************************************
+tUSBHostAudioInstance *
+USBHostAudioOpen(uint32_t ui32Index, tUSBHostAudioCallback pfnCallback)
+{
+ //
+ // Only one audio device is supported at this time and on one instance
+ // is supported so if there is already a call back then fail.
+ //
+ if((ui32Index != 0) || (g_sAudioDevice.pfnCallback))
+ {
+ return(0);
+ }
+
+ //
+ // Save the call back.
+ //
+ g_sAudioDevice.pfnCallback = pfnCallback;
+
+ //
+ // Return the requested device instance.
+ //
+ return(&g_sAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called to release an audio device instance.
+//!
+//! \param psAudioInstance is the device instance that is to be released.
+//!
+//! This function is called when a host audio device needs to be released.
+//! This could be in preparation for shutdown or a switch to USB device mode,
+//! for example. Following this call, the audio device is available and can
+//! be opened again using a call to USBHostAudioOpen(). After calling this
+//! function, the host audio driver will no longer provide any callbacks or
+//! accept calls to other audio driver APIs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHostAudioClose(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Close the audio device.
+ //
+ USBAudioClose(psAudioInstance);
+
+ //
+ // Clear the call back indicating that the device is now closed.
+ //
+ psAudioInstance->pfnCallback = 0;
+}
+
+//*****************************************************************************
+//
+// This function is used to request settings from a given audio interface.
+//
+// \param psAudioDevice is the audio device instance to access.
+// \param ui32Interface is the interface to access.
+// \param ui32Channel is the channel number to access.
+// \param ui32Request is the audio device request.
+//
+// This function is used to get volume control parameters from a given
+// interface and on a given channel. The \e ui32Interface is the interface to
+// make the request specified by \e ui32Channel and \e ui32Request. The
+// \e ui32Request parameter must be one of the USB_AC_GET_* values.
+//
+// \return This function returns the requested value.
+//
+//*****************************************************************************
+static uint32_t
+VolumeSettingGet(tUSBHostAudioInstance *psAudioDevice, uint32_t ui32Interface,
+ uint32_t ui32Channel, uint32_t ui32Request)
+{
+ uint32_t ui32Value;
+ tUSBRequest sSetupPacket;
+
+ ui32Value = 0;
+
+ //
+ // This is a Class specific Interface IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = (ui32Request & 0xff);
+
+ //
+ // Request for a string descriptor.
+ //
+ sSetupPacket.wValue = VOLUME_CONTROL | (ui32Channel & 0xff);
+
+ //
+ // Set the language ID.
+ //
+ sSetupPacket.wIndex = (psAudioDevice->ui8VolumeID << 8) |
+ (ui32Interface & 0xff);
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 2;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psAudioDevice->psDevice,
+ (uint8_t *)&ui32Value, 4,
+ psAudioDevice->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Value);
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the current volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the current
+//! volume setting.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the current volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. The \e ui32Channel value starts with 0 which is the master
+//! audio volume control interface. The remaining \e ui32Channel values
+//! provide access to various other audio channels, with 1 and 2 being left and
+//! right audio channels.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the current volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_CUR));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the maximum volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the maximum
+//! volume control value.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the maximum volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. The \e ui32Channel value starts with 0 which is the master
+//! audio volume control interface. The remaining \e ui32Channel values
+//! provide access to various other audio channels, with 1 and 2 being left and
+//! right audio channels.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the maximum volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeMaxGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_MAX));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the minimum volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the minimum
+//! volume control value.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the minimum volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. The \e ui32Channel value starts with 0 which is the master
+//! audio volume control interface. The remaining \e ui32Channel values
+//! provide access to various other audio channels, with 1 and 2 being left and
+//! right audio channels.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the minimum volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeMinGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_MIN));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the volume control resolution for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the resolution
+//! for the volume control.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the volume control resolution for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. The \e ui32Channel value starts with 0 which is the master
+//! audio volume control interface. The remaining \e ui32Channel values
+//! provide access to various other audio channels, with 1 and 2 being left and
+//! right audio channels.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the volume control resolution for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeResGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_RES));
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to set the current
+//! volume setting.
+//! \param ui32Channel is the 0 based channel number to query.
+//! \param ui32Value is the value to write to the USB audio device.
+//!
+//! The function is used to set the current volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. The \e ui32Channel value starts with 0 which is the master
+//! audio volume control interface. The remaining \e ui32Channel values
+//! provide access to various other audio channels, with 1 and 2 being left and
+//! right audio channels.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHostAudioVolumeSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel,
+ uint32_t ui32Value)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific Interface OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request is to set the current value.
+ //
+ sSetupPacket.bRequest = USB_AC_SET_CUR;
+
+ //
+ // Request the volume control.
+ //
+ sSetupPacket.wValue = VOLUME_CONTROL | (ui32Channel & 0xff);
+
+ //
+ // Set Volume control ID and interface to 0.
+ //
+ sSetupPacket.wIndex = psAudioInstance->ui8VolumeID << 8;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 2;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psAudioInstance->psDevice,
+ (uint8_t *)&ui32Value, 2,
+ psAudioInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+//! This function is called to determine if an audio format is supported by the
+//! connected USB Audio device.
+//!
+//! \param psAudioInstance is the device instance for this call.
+//! \param ui32SampleRate is the sample rate of the audio stream.
+//! \param ui32Bits is the number of bits per sample in the audio stream.
+//! \param ui32Channels is the number of channels in the audio stream.
+//! \param ui32Flags is a set of flags to determine what type of interface to
+//! retrieve.
+//!
+//! This function is called when an application needs to determine which audio
+//! formats are supported by a USB audio device that has been connected. The
+//! \e psAudioInstance value that is used with this call is the value that was
+//! returned from the USBHostAudioOpen() function. This call checks the
+//! USB audio device to determine if it can support the values provided in the
+//! \e ui32SampleRate, \e ui32Bits, and \e ui32Channels values. The
+//! \e ui32Flags currently only supports either the \b USBH_AUDIO_FORMAT_IN or
+//! \b USBH_AUDIO_FORMAT_OUT values that indicates if a request is for an
+//! audio input and an audio output. If the format is supported this
+//! function returns zero, and this function returns a non-zero value if the
+//! format is not supported. This function does not set the current output or
+//! input format.
+//!
+//! \return A value of zero indicates the supplied format is supported and
+//! a non-zero value indicates that the format is not supported.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioFormatGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate, uint32_t ui32Bits,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ //
+ // Look for the requested format.
+ //
+ if(AudioGetInterface(psAudioInstance, USB_ADF_PCM, ui32SampleRate,
+ ui32Bits >> 3, ui32Channels, ui32Flags) !=
+ INVALID_INTERFACE)
+ {
+ return(0);
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! This function is called to set the current sample rate on an audio
+//! interface.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param ui32SampleRate is the sample rate in Hz.
+//! \param ui32Bits is the number of bits per sample.
+//! \param ui32Channels is then number of audio channels.
+//! \param ui32Flags is a set of flags that determine the access type.
+//!
+//! This function is called when to set the current audio output or input
+//! format for a USB audio device. The \e psAudioInstance value that is used
+//! with this call is the value that was returned from the USBHostAudioOpen()
+//! function. The application can use this call to insure that the audio
+//! format is supported and set the format at the same time. If the
+//! application is just checking for supported rates, then it should call the
+//! USBHostAudioFormatGet().
+//!
+//! \note This function must be called before attempting to send or receive
+//! audio with the USBHostAudioPlay() or USBHostAudioRecord() functions.
+//!
+//! \return A non-zero value indicates the supplied format is not supported and
+//! a zero value indicates that the format was supported and has been
+//! configured.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioFormatSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate, uint32_t ui32Bits,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ uint32_t ui32Interface;
+
+ //
+ // Look for the requested format.
+ //
+ ui32Interface = AudioGetInterface(psAudioInstance, USB_ADF_PCM,
+ ui32SampleRate, ui32Bits >> 3,
+ ui32Channels, ui32Flags);
+
+ if(ui32Interface == INVALID_INTERFACE)
+ {
+ return(1);
+ }
+
+ //
+ // Determine if this is an input or output request.
+ //
+ if(ui32Flags & USBH_AUDIO_FORMAT_IN)
+ {
+ //
+ // Get the active interface number and alternate setting for this
+ // format.
+ //
+ psAudioInstance->ui8InInterface =
+ (uint8_t)(ui32Interface & INTERFACE_NUM_M);
+ psAudioInstance->ui8InAltSetting =
+ (uint8_t)((ui32Interface & INTERFACE_ALTSETTING_M) >>
+ INTERFACE_ALTSETTING_S);
+ }
+ else
+ {
+ //
+ // Get the active interface number and alternate setting for this
+ // format.
+ //
+ psAudioInstance->ui8OutInterface =
+ (uint8_t)(ui32Interface & INTERFACE_NUM_M);
+ psAudioInstance->ui8OutAltSetting =
+ (uint8_t)((ui32Interface & INTERFACE_ALTSETTING_M) >>
+ INTERFACE_ALTSETTING_S);
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is called to send an audio buffer to the USB audio device.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param pvBuffer is the audio buffer to send.
+//! \param ui32Size is the size of the buffer in bytes.
+//! \param pfnCallback is a pointer to a callback function that is called
+//! when the buffer can be used again.
+//!
+//! This function is called when an application needs to schedule a new buffer
+//! for output to the USB audio device. Since this call schedules the transfer
+//! and returns immediately, the application should provide a \e pfnCallback
+//! function to be notified when the buffer can be used again by the
+//! application. The \e pfnCallback function provided is called with the
+//! \e pvBuffer parameter set to the \e pvBuffer provided by this call, the
+//! \e ui32Param can be ignored and the \e ui32Event parameter is
+//! \b USB_EVENT_TX_COMPLETE.
+//!
+//! \return This function returns the number of bytes that were scheduled
+//! to be sent. If this function returns zero then there was no USB audio
+//! device present or the request could not be satisfied at this time.
+//
+//*****************************************************************************
+int32_t
+USBHostAudioPlay(tUSBHostAudioInstance *psAudioInstance, void *pvBuffer,
+ uint32_t ui32Size, tUSBHostAudioCallback pfnCallback)
+{
+ uint32_t ui32Bytes;
+
+ //
+ // Make sure that there is a device present.
+ //
+ if(psAudioInstance->psDevice == 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the audio output interface is not active then select the current
+ // active audio interface.
+ //
+ if(HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_OUT_ACTIVE) == 0)
+ {
+ //
+ // Indicate the active audio interface has been selected.
+ //
+ HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_OUT_ACTIVE) = 1;
+
+ //
+ // Configure the USB audio device to use the selected audio interface.
+ //
+ USBHCDSetInterface(0, (uint32_t)psAudioInstance->psDevice,
+ psAudioInstance->ui8OutInterface,
+ psAudioInstance->ui8OutAltSetting);
+ }
+
+ //
+ // Save the callback function and the buffer pointer.
+ //
+ psAudioInstance->pfnOutCallback = pfnCallback;
+ psAudioInstance->pvOutBuffer = (void *)pvBuffer;
+
+ //
+ // Schedule the data to be written out to the FIFO.
+ //
+ ui32Bytes = USBHCDPipeSchedule(psAudioInstance->ui32IsochOutPipe, pvBuffer,
+ ui32Size);
+
+ //
+ // Return the number of bytes scheduled to be sent.
+ //
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function is called to provide an audio buffer to the USB audio device
+//! for audio input.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param pvBuffer is the audio buffer to send.
+//! \param ui32Size is the size of the buffer in bytes.
+//! \param pfnCallback is a pointer to a callback function that is called
+//! when the buffer has been filled.
+//!
+//! This function is called when an application needs to schedule a new buffer
+//! for input from the USB audio device. Since this call schedules the
+//! transfer and returns immediately, the application should provide a
+//! \e pfnCallback function to be notified when the buffer has been filled with
+//! audio data. When the \e pfnCallback function is called, the \e pvBuffer
+//! parameter is set to \e pvBuffer provided in this call, the \e ui32Param is
+//! the number of valid bytes in the pvBuffer and the \e ui32Event is set to
+//! \b USB_EVENT_RX_AVAILABLE.
+//!
+//! \return This function returns the number of bytes that were scheduled
+//! to be sent. If this function returns zero then there was no USB audio
+//! device present or the device does not support audio input.
+//
+//*****************************************************************************
+int32_t
+USBHostAudioRecord(tUSBHostAudioInstance *psAudioInstance, void *pvBuffer,
+ uint32_t ui32Size, tUSBHostAudioCallback pfnCallback)
+{
+ uint32_t ui32Bytes;
+
+ //
+ // Make sure that there is a device present.
+ //
+ if(psAudioInstance->psDevice == 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the audio input interface is not active then select the current
+ // active audio interface.
+ //
+ if(HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_IN_ACTIVE) == 0)
+ {
+ //
+ // Indicate the active audio interface has been selected.
+ //
+ HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_IN_ACTIVE) = 1;
+
+ //
+ // Configure the USB audio device to use the selected audio interface.
+ //
+ USBHCDSetInterface(0, (uint32_t)psAudioInstance->psDevice,
+ psAudioInstance->ui8InInterface,
+ psAudioInstance->ui8InAltSetting);
+ }
+
+ //
+ // Save the callback function and the buffer pointer.
+ //
+ psAudioInstance->pfnInCallback = pfnCallback;
+ psAudioInstance->pvInBuffer = (void *)pvBuffer;
+
+ //
+ // Schedule the data to be read from the FIFO.
+ //
+ ui32Bytes = USBHCDPipeSchedule(psAudioInstance->ui32IsochInPipe, pvBuffer,
+ ui32Size);
+
+ //
+ // Return the number of bytes scheduled to be sent.
+ //
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psAudioInstance is the audio device instance that was returned
+//! from the call to USBHostAudioOpen().
+//!
+//! This function forwards a request from an application to the audio device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioLPMSleep(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psAudioInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psAudioInstance is the audio device instance that was returned
+//! from the call to USBHostAudioOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioLPMStatus(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psAudioInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/usblib/host/usbhaudio.h b/usblib/host/usbhaudio.h
new file mode 100644
index 0000000..fc768ee
--- /dev/null
+++ b/usblib/host/usbhaudio.h
@@ -0,0 +1,163 @@
+//*****************************************************************************
+//
+// usbhaudio.h - USB host audio class driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHAUDIO_H__
+#define __USBHAUDIO_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// USB host audio specific events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This USB host audio event indicates that the device is connected and
+//! ready to send or receive buffers. The \e pvBuffer and \e ui32Param
+//! values are not used in this event.
+//
+//*****************************************************************************
+#define USBH_AUDIO_EVENT_OPEN (USBH_AUDIO_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This USB host audio event indicates that the previously connected device
+//! has been disconnected. The \e pvBuffer and \e ui32Param values are not used
+//! in this event.
+//
+//*****************************************************************************
+#define USBH_AUDIO_EVENT_CLOSE (USBH_AUDIO_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+// This definition is used with the USBHostAudioFormatGet() and
+// USBHostAudioFormatSet() API's to determine if the audio input is being
+// accesses(USBH_AUDIO_FORMAT_IN set) or audio output(USBH_AUDIO_FORMAT clear).
+//
+//*****************************************************************************
+#define USBH_AUDIO_FORMAT_IN 0x00000001
+#define USBH_AUDIO_FORMAT_OUT 0x00000000
+
+typedef struct
+{
+ uint8_t ui8Channels;
+ uint8_t ui8Bits;
+ uint32_t ui32SampleRate;
+}
+tUSBAudioFormat;
+
+typedef struct tUSBHostAudioInstance tUSBHostAudioInstance;
+
+//*****************************************************************************
+//
+// The prototype for the host USB Audio driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHostAudioCallback)(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern tUSBHostAudioInstance * USBHostAudioOpen(uint32_t ui32Index,
+ tUSBHostAudioCallback pfnCallback);
+extern void USBHostAudioClose(tUSBHostAudioInstance *psAudioInstance);
+extern int32_t USBHostAudioPlay(tUSBHostAudioInstance *psAudioInstance,
+ void *pvBuffer, uint32_t ui32Size,
+ tUSBHostAudioCallback pfnCallback);
+
+extern uint32_t USBHostAudioFormatGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate,
+ uint32_t ui32Bits, uint32_t ui32Channels,
+ uint32_t ui32Flags);
+extern uint32_t USBHostAudioFormatSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate,
+ uint32_t ui32Bits, uint32_t ui32Channels,
+ uint32_t ui32Flags);
+
+extern int32_t USBHostAudioRecord(tUSBHostAudioInstance *psAudioInstance,
+ void *pvBuffer, uint32_t ui32Size,
+ tUSBHostAudioCallback pfnAudioCallback);
+
+extern uint32_t USBHostAudioVolumeGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern void USBHostAudioVolumeSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel,
+ uint32_t ui32Value);
+
+extern uint32_t USBHostAudioVolumeMaxGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern uint32_t USBHostAudioVolumeMinGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern uint32_t USBHostAudioVolumeResGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+extern uint32_t USBHostAudioLPMSleep(tUSBHostAudioInstance *psAudioInstance);
+extern uint32_t USBHostAudioLPMStatus(tUSBHostAudioInstance *psAudioInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/host/usbhhid.c b/usblib/host/usbhhid.c
new file mode 100644
index 0000000..bfbea85
--- /dev/null
+++ b/usblib/host/usbhhid.c
@@ -0,0 +1,746 @@
+//*****************************************************************************
+//
+// usbhhid.c - This file contains the host HID driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhid.h"
+
+static void * HIDDriverOpen(tUSBHostDevice *psDevice);
+static void HIDDriverClose(void *pvInstance);
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If the user has not explicitly stated the maximum number of HID devices to
+// support, we assume that we need to support up to the maximum number of USB
+// devices that the build is configured for.
+//
+//*****************************************************************************
+#ifndef MAX_HID_DEVICES
+#define MAX_HID_DEVICES MAX_USB_DEVICES
+#endif
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the data for a given instance of
+// a HID device.
+//
+//*****************************************************************************
+struct tHIDInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ // Callback data provided by caller.
+ //
+ void *pvCBData;
+
+ //
+ // Used to remember what type of device was registered.
+ //
+ tHIDSubClassProtocol iDeviceType;
+
+ //
+ // Interrupt IN pipe.
+ //
+ uint32_t ui32IntInPipe;
+};
+
+//*****************************************************************************
+//
+// The instance data storage for attached hid devices.
+//
+//*****************************************************************************
+static tHIDInstance g_psHIDDevice[MAX_HID_DEVICES];
+
+//*****************************************************************************
+//
+//! This constant global structure defines the HID Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHIDClassDriver =
+{
+ USB_CLASS_HID,
+ HIDDriverOpen,
+ HIDDriverClose,
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of a HID device.
+//!
+//! \param iDeviceType is the type of device that should be loaded for this
+//! instance of the HID device.
+//! \param pfnCallback is the function that will be called whenever changes
+//! are detected for this device.
+//! \param pvCBData is the data that will be returned in when the
+//! \e pfnCallback function is called.
+//!
+//! This function creates an instance of an specific type of HID device. The
+//! \e iDeviceType parameter is one subclass/protocol values of the types
+//! specified in enumerated types tHIDSubClassProtocol. Only devices that
+//! enumerate with this type will be called back via the \e pfnCallback
+//! function. The \e pfnCallback parameter is the callback function for any
+//! events that occur for this device type. The \e pfnCallback function must
+//! point to a valid function of type \e tUSBCallback for this call to complete
+//! successfully. To release this device instance the caller of USBHHIDOpen()
+//! should call USBHHIDClose() and pass in the value returned from the
+//! USBHHIDOpen() call.
+//!
+//! \return This function returns and instance value that should be used with
+//! any other APIs that require an instance value. If a value of 0 is returned
+//! then the device instance could not be created.
+//
+//*****************************************************************************
+tHIDInstance *
+USBHHIDOpen(tHIDSubClassProtocol iDeviceType, tUSBCallback pfnCallback,
+ void *pvCBData)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Find a free device instance structure.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_HID_DEVICES; ui32Loop++)
+ {
+ if(g_psHIDDevice[ui32Loop].iDeviceType == eUSBHHIDClassNone)
+ {
+ //
+ // Save the instance data for this device.
+ //
+ g_psHIDDevice[ui32Loop].pfnCallback = pfnCallback;
+ g_psHIDDevice[ui32Loop].iDeviceType = iDeviceType;
+ g_psHIDDevice[ui32Loop].pvCBData = pvCBData;
+
+ //
+ // Return the device instance pointer.
+ //
+ return(&g_psHIDDevice[ui32Loop]);
+ }
+ }
+
+ //
+ // If we get here, there are no space device slots so return NULL to
+ // indicate a problem.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of a HID device.
+//!
+//! \param psHIDInstance is the instance value for a HID device to release.
+//!
+//! This function releases an instance of a HID device that was created by a
+//! call to USBHHIDOpen(). This call is required to allow other HID devices
+//! to be enumerated after another HID device has been disconnected. The
+//! \e psHIDInstance parameter should hold the value that was returned from
+//! the previous call to USBHHIDOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHIDClose(tHIDInstance *psHIDInstance)
+{
+ //
+ // Disable any more notifications from the HID layer.
+ //
+ psHIDInstance->pfnCallback = 0;
+
+ //
+ // Mark this device slot as free.
+ //
+ psHIDInstance->iDeviceType = eUSBHHIDClassNone;
+}
+
+//*****************************************************************************
+//
+// This function handles callbacks for the interrupt IN endpoint.
+//
+//*****************************************************************************
+static void
+HIDIntINCallback(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ int32_t i32Dev;
+
+ switch (ui32Event)
+ {
+ //
+ // Handles a request to schedule a new request on the interrupt IN
+ // pipe.
+ //
+ case USB_EVENT_SCHEDULER:
+ {
+ USBHCDPipeSchedule(ui32Pipe, 0, 1);
+ break;
+ }
+ //
+ // Called when new data is available on the interrupt IN pipe.
+ //
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // Determine which device this notification is intended for.
+ //
+ for(i32Dev = 0; i32Dev < MAX_HID_DEVICES; i32Dev++)
+ {
+ //
+ // Does this device own the pipe we have been passed?
+ //
+ if(g_psHIDDevice[i32Dev].ui32IntInPipe == ui32Pipe)
+ {
+ //
+ // Yes - send the report data to the USB host HID device
+ // class driver.
+ //
+ g_psHIDDevice[i32Dev].pfnCallback(
+ g_psHIDDevice[i32Dev].pvCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Pipe, 0);
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of the HID driver.
+//!
+//! \param psDevice is a pointer to the device information structure.
+//!
+//! This function will attempt to open an instance of the HID driver based on
+//! the information contained in the psDevice structure. This call can fail if
+//! there are not sufficient resources to open the device. The function will
+//! return a value that should be passed back into USBHIDClose() when the
+//! driver is no longer needed.
+//!
+//! \return The function will return a pointer to a HID driver instance.
+//
+//*****************************************************************************
+static void *
+HIDDriverOpen(tUSBHostDevice *psDevice)
+{
+ int32_t i32Idx, i32Dev;
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+
+ //
+ // Search the currently open instances for one that supports the protocol
+ // of this device.
+ //
+ for(i32Dev = 0; i32Dev < MAX_HID_DEVICES; i32Dev++)
+ {
+ if(g_psHIDDevice[i32Dev].iDeviceType ==
+ psInterface->bInterfaceProtocol)
+ {
+ //
+ // Save the device pointer.
+ //
+ g_psHIDDevice[i32Dev].psDevice = psDevice;
+
+ for(i32Idx = 0; i32Idx < 3; i32Idx++)
+ {
+ //
+ // Get the first endpoint descriptor.
+ //
+ psEndpointDescriptor = USBDescGetInterfaceEndpoint(psInterface,
+ i32Idx,
+ 256);
+
+ //
+ // If no more endpoints then break out.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ break;
+ }
+
+ //
+ // Interrupt
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT)
+ {
+ //
+ // Interrupt IN.
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ g_psHIDDevice[i32Dev].ui32IntInPipe =
+ USBHCDPipeAlloc(0, USBHCD_PIPE_INTR_IN,
+ psDevice, HIDIntINCallback);
+ USBHCDPipeConfig(g_psHIDDevice[i32Dev].ui32IntInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ psEndpointDescriptor->bInterval,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ }
+ }
+
+ //
+ // If there is a callback function call it to inform the application that
+ // the device has been enumerated.
+ //
+ if(g_psHIDDevice[i32Dev].pfnCallback != 0)
+ {
+ g_psHIDDevice[i32Dev].pfnCallback(
+ g_psHIDDevice[i32Dev].pvCBData,
+ USB_EVENT_CONNECTED,
+ (uint32_t)&g_psHIDDevice[i32Dev], 0);
+ }
+
+ //
+ // Save the device pointer.
+ //
+ g_psHIDDevice[i32Dev].psDevice = psDevice;
+
+ return (&g_psHIDDevice[i32Dev]);
+ }
+ }
+
+ //
+ // If we get here, no user has registered an interest in this particular
+ // HID device so we return an error.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of the HID driver.
+//!
+//! \param pvInstance is an instance pointer that needs to be released.
+//!
+//! This function will free up any resources in use by the HID driver instance
+//! that is passed in. The \e pvInstance pointer should be a valid value that
+//! was returned from a call to USBHIDOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+HIDDriverClose(void *pvInstance)
+{
+ tHIDInstance *psInst;
+
+ //
+ // Get our instance pointer.
+ //
+ psInst = (tHIDInstance *)pvInstance;
+
+ //
+ // Reset the device pointer.
+ //
+ psInst->psDevice = 0;
+
+ //
+ // Free the Interrupt IN pipe.
+ //
+ if(psInst->ui32IntInPipe != 0)
+ {
+ USBHCDPipeFree(psInst->ui32IntInPipe);
+ }
+
+ //
+ // If the callback exists, call it with a DISCONNECTED event.
+ //
+ if(psInst->pfnCallback != 0)
+ {
+ psInst->pfnCallback(psInst->pvCBData, USB_EVENT_DISCONNECTED,
+ (uint32_t)pvInstance, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the idle timeout for a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui8Duration is the duration of the timeout in milliseconds.
+//! \param ui8ReportID is the report identifier to set the timeout on.
+//!
+//! This function will send the Set Idle command to a HID device to set the
+//! idle timeout for a given report. The length of the timeout is specified
+//! by the \e ui8Duration parameter and the report the timeout for is in the
+//! \e ui8ReportID value.
+//!
+//! \return Always returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetIdle(tHIDInstance *psHIDInstance, uint8_t ui8Duration,
+ uint8_t ui8ReportID)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific interface OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_IDLE;
+ sSetupPacket.wValue = (ui8Duration << 8) | ui8ReportID;
+
+ //
+ // Set this on interface 1.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // This is always 0 for this request.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ return(USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice,
+ 0, 0, MAX_PACKET_SIZE_EP0));
+}
+
+//*****************************************************************************
+//
+//! This function can be used to retrieve the report descriptor for a given
+//! device instance.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param pui8Buffer is the memory buffer to use to store the report
+//! descriptor.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to return a report descriptor from a HID device
+//! instance so that it can determine how to interpret reports that are
+//! returned from the device indicated by the \e psHIDInstance parameter.
+//! This call is blocking and will return the number of bytes read into the
+//! \e pui8Buffer.
+//!
+//! \return Returns the number of bytes read into the \e pui8Buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDGetReportDescriptor(tHIDInstance *psHIDInstance, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_HID_DTYPE_REPORT << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // All devices must have at least an 8 byte max packet size so just ask
+ // for 8 bytes to start with.
+ //
+ sSetupPacket.wLength = ui32Size;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ ui32Bytes = USBHCDControlTransfer(0, &sSetupPacket,
+ psHIDInstance->psDevice, pui8Buffer, ui32Size,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set or clear the boot protocol state of a device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32BootProtocol is either zero or non-zero to indicate which
+//! protocol to use for the device.
+//!
+//! A USB host device can use this function to set the protocol for a connected
+//! HID device. This is commonly used to set keyboards and mice into their
+//! simplified boot protocol modes to fix the report structure to a know
+//! state.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetProtocol(tHIDInstance *psHIDInstance, uint32_t ui32BootProtocol)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_PROTOCOL;
+
+ if(ui32BootProtocol)
+ {
+ //
+ // Boot Protocol.
+ //
+ sSetupPacket.wValue = 0;
+ }
+ else
+ {
+ //
+ // Report Protocol.
+ //
+ sSetupPacket.wValue = 1;
+ }
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Always 0.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice, 0, 0,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to retrieve a report from a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32Interface is the interface to retrieve the report from.
+//! \param pui8Data is the memory buffer to use to store the report.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to retrieve a report from a USB pipe. It is usually
+//! called when the USB HID layer has detected a new data available in a USB
+//! pipe. The USB HID host device code will receive a
+//! \b USB_EVENT_RX_AVAILABLE event when data is available, allowing the
+//! callback function to retrieve the data.
+//!
+//! \return Returns the number of bytes read from report.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDGetReport(tHIDInstance *psHIDInstance, uint32_t ui32Interface,
+ uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Read the Data out.
+ //
+ ui32Size = USBHCDPipeReadNonBlocking(psHIDInstance->ui32IntInPipe,
+ pui8Data, ui32Size);
+
+ //
+ // Return the number of bytes read from the interrupt in pipe.
+ //
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send a report to a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32Interface is the interface to send the report to.
+//! \param pui8Data is the memory buffer to use to store the report.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to send a report to a USB HID device. It can be
+//! only be called from outside the callback context as this function will not
+//! return from the call until the data has been sent successfully.
+//!
+//! \return Returns the number of bytes sent to the device.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetReport(tHIDInstance *psHIDInstance, uint32_t ui32Interface,
+ uint8_t *pui8Data, uint32_t ui32Size)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a class specific OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_REPORT;
+ sSetupPacket.wValue = USB_HID_REPORT_OUTPUT << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = (uint16_t)ui32Interface;
+
+ //
+ // Always 0.
+ //
+ sSetupPacket.wLength = ui32Size;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice,
+ pui8Data, ui32Size,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psHIDInstance is the HID instance that was returned from the call
+//! to USBHHIDOpen().
+//!
+//! This function forwards a request from a HID device class to the host
+//! controller to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDLPMSleep(tHIDInstance *psHIDInstance)
+{
+ //
+ // Forward the request to the control endpoint of the device.
+ //
+ return(USBHCDLPMSleep(psHIDInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psHIDInstance is the HID instance that was returned from the call
+//! to USBHHIDOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDLPMStatus(tHIDInstance *psHIDInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psHIDInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhid.h b/usblib/host/usbhhid.h
new file mode 100644
index 0000000..f2df536
--- /dev/null
+++ b/usblib/host/usbhhid.h
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// usbhhid.h - This hold the host driver for hid class.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHID_H__
+#define __USBHHID_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tHIDInstance tHIDInstance;
+
+//*****************************************************************************
+//
+// These defines are the the events that will be passed in the ui32Event
+// parameter of the callback from the driver.
+//
+//*****************************************************************************
+#define USBH_EVENT_HID_SETRPT USBH_HID_EVENT_BASE + 0
+#define USBH_EVENT_HID_REPORT USBH_HID_EVENT_BASE + 1
+
+//
+//! The HID keyboard detected a key being pressed.
+//
+#define USBH_EVENT_HID_KB_PRESS USBH_HID_EVENT_BASE + 16
+
+//
+//! The HID keyboard detected a key being released.
+//
+#define USBH_EVENT_HID_KB_REL USBH_HID_EVENT_BASE + 17
+
+//
+//! The HID keyboard detected one of the keyboard modifiers being pressed.
+//
+#define USBH_EVENT_HID_KB_MOD USBH_HID_EVENT_BASE + 18
+
+//
+//! A button was pressed on a HID mouse.
+//
+#define USBH_EVENT_HID_MS_PRESS USBH_HID_EVENT_BASE + 32
+
+//
+//! A button was released on a HID mouse.
+//
+#define USBH_EVENT_HID_MS_REL USBH_HID_EVENT_BASE + 33
+
+//
+//! The HID mouse detected movement in the X direction.
+//
+#define USBH_EVENT_HID_MS_X USBH_HID_EVENT_BASE + 34
+
+//
+//! The HID mouse detected movement in the Y direction.
+//
+#define USBH_EVENT_HID_MS_Y USBH_HID_EVENT_BASE + 35
+
+//*****************************************************************************
+//
+//! The following values are used to register callbacks to the USB HOST HID
+//! device class layer.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! No device should be used. This value should not be used by
+ //! applications.
+ //
+ eUSBHHIDClassNone = 0,
+
+ //
+ //! This is a keyboard device.
+ //
+ eUSBHHIDClassKeyboard,
+
+ //
+ //! This is a mouse device.
+ //
+ eUSBHHIDClassMouse,
+
+ //
+ //! This is a vendor specific device.
+ //
+ eUSBHHIDClassVendor
+}
+tHIDSubClassProtocol;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern tHIDInstance * USBHHIDOpen(tHIDSubClassProtocol iDeviceType,
+ tUSBCallback pfnCallback,
+ void *pvCBData);
+extern void USBHHIDClose(tHIDInstance *psHIDInstance);
+extern uint32_t USBHHIDGetReportDescriptor(tHIDInstance *psHIDInstance,
+ uint8_t *pui8Buffer,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDSetIdle(tHIDInstance *psHIDInstance, uint8_t ui8Duration,
+ uint8_t ui8ReportID);
+extern uint32_t USBHHIDSetProtocol(tHIDInstance *psHIDInstance,
+ uint32_t ui32BootProtocol);
+extern uint32_t USBHHIDSetReport(tHIDInstance *psHIDInstance,
+ uint32_t ui32Interface, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDGetReport(tHIDInstance *psHIDInstance,
+ uint32_t ui32Interface, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDLPMSleep(tHIDInstance *psHIDInstance);
+extern uint32_t USBHHIDLPMStatus(tHIDInstance *psHIDInstance);
+
+extern const tUSBHostClassDriver g_sUSBHIDClassDriver;
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHHID_H__
diff --git a/usblib/host/usbhhidkeyboard.c b/usblib/host/usbhhidkeyboard.c
new file mode 100644
index 0000000..08f2b6a
--- /dev/null
+++ b/usblib/host/usbhhidkeyboard.c
@@ -0,0 +1,752 @@
+//*****************************************************************************
+//
+// usbhhidkeyboard.c - This file holds the application interfaces for USB
+// keyboard devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhhid.h"
+#include "usblib/host/usbhhidkeyboard.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for local functions.
+//
+//*****************************************************************************
+static uint32_t USBHKeyboardCallback(void *pvKeyboard, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The size of a USB keyboard report.
+//
+//*****************************************************************************
+#define USBHKEYB_REPORT_SIZE 8
+
+//*****************************************************************************
+//
+// These are the flags for the tUSBHKeyboard.ui32HIDFlags member variable.
+//
+//*****************************************************************************
+#define USBHKEYB_DEVICE_PRESENT 0x00000001
+
+//*****************************************************************************
+//
+// This is the structure definition for a keyboard device instance.
+//
+//*****************************************************************************
+struct tUSBHKeyboard
+{
+ //
+ // Global flags for an instance of a keyboard.
+ //
+ uint32_t ui32HIDFlags;
+
+ //
+ // The applications registered callback.
+ //
+ tUSBHIDKeyboardCallback pfnCallback;
+
+ //
+ // The HID instance pointer for this keyboard instance.
+ //
+ tHIDInstance *psHIDInstance;
+
+ //
+ // NUM_LOCK, CAPS_LOCK, SCROLL_LOCK, COMPOSE or KANA keys.
+ //
+ uint8_t ui8KeyModSticky;
+
+ //
+ // This is the current state of the keyboard modifier keys.
+ //
+ uint8_t ui8KeyModState;
+
+ //
+ // This holds the keyboard usage codes for keys that are being held down.
+ //
+ uint8_t pui8KeyState[6];
+
+ //
+ // This is a local buffer to hold the current HID report that comes up
+ // from the HID driver layer.
+ //
+ uint8_t pui8Buffer[USBHKEYB_REPORT_SIZE];
+};
+
+//*****************************************************************************
+//
+// This is the per instance information for a keyboard device.
+//
+//*****************************************************************************
+static tUSBHKeyboard g_sUSBHKeyboard =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used open an instance of a keyboard.
+//!
+//! \param pfnCallback is the callback function to call when new events occur
+//! with the keyboard returned.
+//! \param pui8Buffer is the memory used by the keyboard to interact with the
+//! USB keyboard.
+//! \param ui32Size is the size of the buffer provided by \e pui8Buffer.
+//!
+//! This function is used to open an instance of the keyboard. The value
+//! returned from this function should be used as the instance identifier for
+//! all other USBHKeyboard calls. The \e pui8Buffer memory buffer is used to
+//! access the keyboard. The buffer size required is at least enough to hold
+//! a normal report descriptor for the device. If there is not enough space
+//! only a partial report descriptor will be read out.
+//!
+//! \return Returns the instance identifier for the keyboard that is attached.
+//! If there is no keyboard present this will return 0.
+//
+//*****************************************************************************
+tUSBHKeyboard *
+USBHKeyboardOpen(tUSBHIDKeyboardCallback pfnCallback, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ //
+ // Save the callback and data pointers.
+ //
+ g_sUSBHKeyboard.pfnCallback = pfnCallback;
+
+ //
+ // Save the instance pointer for the HID device that was opened.
+ //
+ g_sUSBHKeyboard.psHIDInstance =
+ USBHHIDOpen(eUSBHHIDClassKeyboard, USBHKeyboardCallback,
+ (void *)&g_sUSBHKeyboard);
+
+ return(&g_sUSBHKeyboard);
+}
+
+//*****************************************************************************
+//
+//! This function is used close an instance of a keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//!
+//! This function is used to close an instance of the keyboard that was opened
+//! with a call to USBHKeyboardOpen(). The \e psKbInstance value is the
+//! value that was returned when the application called USBHKeyboardOpen().
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardClose(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Reset the callback to null.
+ //
+ psKbInstance->pfnCallback = 0;
+
+ //
+ // Call the HID driver layer to close out this instance.
+ //
+ USBHHIDClose(psKbInstance->psHIDInstance);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to map a USB usage ID to a printable character.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param psTable is the table to use to map the usage ID to characters.
+//! \param ui8UsageID is the USB usage ID to map to a character.
+//!
+//! This function is used to map a USB usage ID to a character. The provided
+//! \e psTable is used to perform the mapping and is described by the
+//! tHIDKeyboardUsageTable type defined structure. See the documentation on
+//! the tHIDKeyboardUsageTable structure for more details on the internals of
+//! this structure. This function uses the current state of the shift keys
+//! and the Caps Lock key to modify the data returned by this function. The
+//! psTable structure has values indicating which keys are modified by Caps
+//! and alternate values for shifted cases. The number of bytes returned from
+//! Lock this function depends on the \e psTable structure passed in as it
+//! holds the number of bytes per character in the table.
+//!
+//! \return Returns the character value for the given usage id.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardUsageToChar(tUSBHKeyboard *psKbInstance,
+ const tHIDKeyboardUsageTable *psTable,
+ uint8_t ui8UsageID)
+{
+ uint32_t ui32Value, ui32Offset, ui32Shift;
+ const uint8_t *pui8KeyBoardMap;
+ const uint16_t *pui16KeyBoardMap;
+
+ //
+ // The added offset for the shifted character value.
+ //
+ ui32Shift = 0;
+
+ //
+ // Offset in the table for the character.
+ //
+ ui32Offset = (ui8UsageID * psTable->ui8BytesPerChar * 2);
+
+ //
+ // Handle the case where CAPS lock has been set.
+ //
+ if(psKbInstance->ui8KeyModSticky &= HID_KEYB_CAPS_LOCK)
+ {
+ //
+ // See if this usage ID is modified by Caps Lock by checking the packed
+ // bit array in the pui32ShiftState member of the psTable array.
+ //
+ if((psTable->pui32CapsLock[ui8UsageID >> 5]) >>
+ (ui8UsageID & 0x1f) & 1)
+ {
+ ui32Shift = psTable->ui8BytesPerChar;
+ }
+ }
+
+ //
+ // Now handle if a shift key is being held.
+ //
+ if((psKbInstance->ui8KeyModState & 0x22) != 0)
+ {
+ //
+ // Not shifted yet so we need to shift.
+ //
+ if(ui32Shift == 0)
+ {
+ ui32Shift = psTable->ui8BytesPerChar;
+ }
+ else
+ {
+ //
+ // Unshift because CAPS LOCK and shift were pressed.
+ //
+ ui32Shift = 0;
+ }
+ }
+
+ //
+ // One byte per character.
+ //
+ if(psTable->ui8BytesPerChar == 1)
+ {
+ //
+ // Get the base address of the table.
+ //
+ pui8KeyBoardMap = psTable->pvCharMapping;
+
+ ui32Value = pui8KeyBoardMap[ui32Offset + ui32Shift];
+ }
+ //
+ // Two bytes per character.
+ //
+ else if(psTable->ui8BytesPerChar == 2)
+ {
+ //
+ // Get the base address of the table.
+ //
+ pui16KeyBoardMap = (uint16_t *)psTable->pvCharMapping;
+
+ ui32Value = pui16KeyBoardMap[ui32Offset + ui32Shift];
+ }
+ //
+ // All other sizes are unsupported for now.
+ //
+ else
+ {
+ ui32Value = 0;
+ }
+
+ return(ui32Value);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set one of the fixed modifier keys on a keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param ui32Modifiers is a bit mask of the modifiers to set on the keyboard.
+//!
+//! This function is used to set the modifier key states on a keyboard. The
+//! \e ui32Modifiers value is a bitmask of the following set of values:
+//! - \b HID_KEYB_NUM_LOCK
+//! - \b HID_KEYB_CAPS_LOCK
+//! - \b HID_KEYB_SCROLL_LOCK
+//! - \b HID_KEYB_COMPOSE
+//! - \b HID_KEYB_KANA
+//!
+//! Not all of these will be supported on all keyboards however setting values
+//! on a keyboard that does not have them should have no effect. The
+//! \e psKbInstance value is the value that was returned when the application
+//! called USBHKeyboardOpen(). If the value \b HID_KEYB_CAPS_LOCK is used it
+//! will modify the values returned from the USBHKeyboardUsageToChar()
+//! function.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardModifierSet(tUSBHKeyboard *psKbInstance, uint32_t ui32Modifiers)
+{
+ //
+ // Remember the fact that this is set.
+ //
+ psKbInstance->ui8KeyModSticky = (uint8_t)ui32Modifiers;
+
+ //
+ // Set the LEDs on the keyboard.
+ //
+ USBHHIDSetReport(psKbInstance->psHIDInstance, 0,
+ (uint8_t *)&ui32Modifiers, 1);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize a keyboard interface after a keyboard
+//! has been detected.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//!
+//! This function should be called after receiving a \b USB_EVENT_CONNECTED
+//! event in the callback function provided by USBHKeyboardOpen(), however this
+//! function should only be called outside the callback function. This will
+//! initialize the keyboard interface and determine the keyboard's
+//! layout and how it reports keys to the USB host controller. The
+//! \e psKbInstance value is the value that was returned when the application
+//! called USBHKeyboardOpen(). This function only needs to be called once
+//! per connection event but it should be called every time a
+//! \b USB_EVENT_CONNECTED event occurs.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardInit(tUSBHKeyboard *psKbInstance)
+{
+ uint8_t ui8ModData;
+ int32_t i32Idx;
+
+ //
+ // Set the initial rate to only update on keyboard state changes.
+ //
+ USBHHIDSetIdle(psKbInstance->psHIDInstance, 0, 0);
+
+ //
+ // Read out the Report Descriptor from the keyboard and parse it for
+ // the format of the reports coming back from the keyboard.
+ //
+ USBHHIDGetReportDescriptor(psKbInstance->psHIDInstance,
+ psKbInstance->pui8Buffer,
+ USBHKEYB_REPORT_SIZE);
+
+ //
+ // Set the keyboard to boot protocol.
+ //
+ USBHHIDSetProtocol(psKbInstance->psHIDInstance, 1);
+
+ //
+ // Used to clear the initial state of all on keyboard modifiers.
+ //
+ ui8ModData = 0;
+
+ //
+ // Update the keyboard LED state.
+ //
+ USBHHIDSetReport(psKbInstance->psHIDInstance, 0, &ui8ModData, 1);
+
+ //
+ // Reset the key state.
+ //
+ for(i32Idx = 0;
+ i32Idx < sizeof(psKbInstance->pui8KeyState) / sizeof(uint8_t);
+ i32Idx++)
+ {
+ psKbInstance->pui8KeyState[i32Idx] =0;
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the automatic poll rate of the keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param ui32PollRate is the rate in ms to cause the keyboard to update the
+//! host regardless of no change in key state.
+//!
+//! This function will allow an application to tell the keyboard how often it
+//! should send updates to the USB host controller regardless of any changes
+//! in keyboard state. The \e psKbInstance value is the value that was
+//! returned when the application called USBHKeyboardOpen(). The
+//! \e ui32PollRate is the new value in ms for the update rate on the keyboard.
+//! This value is initially set to 0 which indicates that the keyboard should
+//! only to update when the keyboard state changes. Any value other than 0 can
+//! be used to force the keyboard to generate auto-repeat sequences for the
+//! application.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardPollRateSet(tUSBHKeyboard *psKbInstance, uint32_t ui32PollRate)
+{
+ //
+ // Send the Set Idle command to the USB keyboard.
+ //
+ USBHHIDSetIdle(psKbInstance->psHIDInstance, ui32PollRate, 0);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// This is an internal function used to modify the current keyboard state.
+//
+// This function checks for changes in the keyboard state due to a new report
+// being received from the device. It first checks if this is a "roll-over"
+// case by seeing if 0x01 is in the first position of the new keyboard report.
+// This indicates that too many keys were pressed to handle and to ignore this
+// report. Next the keyboard modifier state is stored and if any changes are
+// detected a \b USBH_EVENT_HID_KB_MOD event is sent back to the application.
+// Then this function will check for any keys that have been released and send
+// a \b USBH_EVENT_HID_KB_REL even for each of these keys. The last check is
+// for any new keys that are pressed and a \b USBH_EVENT_HID_KB_PRESS event
+// will be sent for each new key pressed.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateKeyboardState(tUSBHKeyboard *psKbInstance)
+{
+ int32_t i32NewKey, i32OldKey;
+
+ //
+ // rollover code so ignore this buffer.
+ //
+ if(psKbInstance->pui8Buffer[2] == 0x01)
+ {
+ return;
+ }
+
+ //
+ // Handle the keyboard modifier states.
+ //
+ if(psKbInstance->ui8KeyModState != psKbInstance->pui8Buffer[0])
+ {
+ //
+ // Notify the application of the event.
+ //
+ psKbInstance->pfnCallback(0, USBH_EVENT_HID_KB_MOD,
+ psKbInstance->pui8Buffer[0], 0);
+
+ //
+ // Save the new state of the modifier keys.
+ //
+ psKbInstance->ui8KeyModState = psKbInstance->pui8Buffer[0];
+ }
+
+ //
+ // This loop checks for keys that have been released to make room for new
+ // ones that may have been pressed.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If there is no old key pressed in this entry go to the next one.
+ //
+ if(psKbInstance->pui8KeyState[i32OldKey] == 0)
+ {
+ continue;
+ }
+
+ //
+ // Check if this old key is still in the list of currently pressed
+ // keys.
+ //
+ for(i32NewKey = 2; i32NewKey < 8; i32NewKey++)
+ {
+ //
+ // Break out if the key is still present.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] ==
+ psKbInstance->pui8KeyState[i32OldKey])
+ {
+ break;
+ }
+ }
+ //
+ // If the old key was no longer in the list of pressed keys then
+ // notify the application of the key release.
+ //
+ if(i32NewKey == 8)
+ {
+ //
+ // Send the key release notification to the application.
+ //
+ psKbInstance->pfnCallback(0, USBH_EVENT_HID_KB_REL,
+ psKbInstance->pui8KeyState[i32OldKey],
+ 0);
+ //
+ // Remove the old key from the currently held key list.
+ //
+ psKbInstance->pui8KeyState[i32OldKey] = 0;
+
+ }
+ }
+
+ //
+ // This loop checks for new keys that have been pressed.
+ //
+ for(i32NewKey = 2; i32NewKey < 8; i32NewKey++)
+ {
+ //
+ // The new list is empty so no new keys are pressed.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] == 0)
+ {
+ break;
+ }
+
+ //
+ // This loop checks if the current key was already pressed.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If it is in both lists then it was already pressed so ignore it.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] ==
+ psKbInstance->pui8KeyState[i32OldKey])
+ {
+ break;
+ }
+ }
+ //
+ // The key in the new list was not found so it is new.
+ //
+ if(i32OldKey == 6)
+ {
+ //
+ // Look for a free location to store this key usage code.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If an empty location is found, store it and notify the
+ // application.
+ //
+ if(psKbInstance->pui8KeyState[i32OldKey] == 0)
+ {
+ //
+ // Save the newly pressed key.
+ //
+ psKbInstance->pui8KeyState[i32OldKey] =
+ psKbInstance->pui8Buffer[i32NewKey];
+
+ //
+ // Notify the application of the new key that has been
+ // pressed.
+ //
+ psKbInstance->pfnCallback( 0, USBH_EVENT_HID_KB_PRESS,
+ psKbInstance->pui8Buffer[i32NewKey],
+ 0);
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function handles event callbacks from the USB HID driver layer.
+//!
+//! \param pvKeyboard is the pointer that was passed in to the USBHHIDOpen()
+//! call.
+//! \param ui32Event is the event that has been passed up from the HID driver.
+//! \param ui32MsgParam has meaning related to the \e ui32Event that occurred.
+//! \param pvMsgData has meaning related to the \e ui32Event that occurred.
+//!
+//! This function will receive all event updates from the HID driver layer.
+//! The keyboard driver itself will mostly be concerned with report callbacks
+//! from the HID driver layer and parsing them into keystrokes for the
+//! application that has registered for callbacks with the USBHKeyboardOpen()
+//! call.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+static uint32_t
+USBHKeyboardCallback(void *pvKeyboard, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData)
+{
+ tUSBHKeyboard *psKbInstance;
+
+ //
+ // Recover the pointer to the instance data.
+ //
+ psKbInstance = (tUSBHKeyboard *)pvKeyboard;
+
+ switch (ui32Event)
+ {
+ //
+ // New keyboard has been connected so notify the application.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Remember that a keyboard is present.
+ //
+ psKbInstance->ui32HIDFlags |= USBHKEYB_DEVICE_PRESENT;
+
+ //
+ // Notify the application that a new keyboard was connected.
+ //
+ psKbInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ //
+ // No keyboard is present.
+ //
+ psKbInstance->ui32HIDFlags &= ~USBHKEYB_DEVICE_PRESENT;
+
+ //
+ // Notify the application that the keyboard was disconnected.
+ //
+ psKbInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // New keyboard report structure was received.
+ //
+ USBHHIDGetReport(psKbInstance->psHIDInstance, 0,
+ psKbInstance->pui8Buffer,
+ USBHKEYB_REPORT_SIZE);
+
+ //
+ // Update the application on the changes in the keyboard state.
+ //
+ UpdateKeyboardState(psKbInstance);
+
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psKbInstance is the HID keyboard instance that was
+//! returned from the call to USBHKeyboardOpen().
+//!
+//! This function forwards a request from an application to the HID device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardLPMSleep(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Call the HID function to send the sleep command.
+ //
+ return(USBHHIDLPMSleep(psKbInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psKbInstance is the HID keyboard instance that was
+//! returned from the call to USBHKeyboardOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardLPMStatus(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Call the HID function to get the current LPM status.
+ //
+ return(USBHHIDLPMStatus(psKbInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhidkeyboard.h b/usblib/host/usbhhidkeyboard.h
new file mode 100644
index 0000000..09852f1
--- /dev/null
+++ b/usblib/host/usbhhidkeyboard.h
@@ -0,0 +1,89 @@
+//*****************************************************************************
+//
+// usbhhidkeyboard.h - This file holds the application interfaces for USB
+// keyboard devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHIDKEYBOARD_H__
+#define __USBHHIDKEYBOARD_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHKeyboard tUSBHKeyboard;
+
+//*****************************************************************************
+//
+// The prototype for the host USB Keyboard driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHIDKeyboardCallback)(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+extern tUSBHKeyboard * USBHKeyboardOpen(tUSBHIDKeyboardCallback pfnCallback,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferSize);
+extern uint32_t USBHKeyboardClose(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardInit(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardModifierSet(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32Modifiers);
+extern uint32_t USBHKeyboardPollRateSet(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32PollRate);
+extern uint32_t USBHKeyboardLPMSleep(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardLPMStatus(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardUsageToChar(tUSBHKeyboard *psKbInstance,
+ const tHIDKeyboardUsageTable *psTable,
+ uint8_t ui8UsageID);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/host/usbhhidmouse.c b/usblib/host/usbhhidmouse.c
new file mode 100644
index 0000000..f1eb8d5
--- /dev/null
+++ b/usblib/host/usbhhidmouse.c
@@ -0,0 +1,452 @@
+//*****************************************************************************
+//
+// usbhhidmouse.c - This file holds the application interfaces for USB
+// mouse devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhhid.h"
+#include "usblib/host/usbhhidmouse.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for local functions.
+//
+//*****************************************************************************
+static uint32_t USBHMouseCallback(void *pvMouse, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The size of a USB mouse report.
+//
+//*****************************************************************************
+#define USBHMS_REPORT_SIZE 4
+
+//*****************************************************************************
+//
+// These are the flags for the tUSBHMouse.ui32HIDFlags member variable.
+//
+//*****************************************************************************
+#define USBHMS_DEVICE_PRESENT 0x00000001
+
+//*****************************************************************************
+//
+// This is the structure definition for a mouse device instance.
+//
+//*****************************************************************************
+struct tUSBHMouse
+{
+ //
+ // Global flags for an instance of a mouse.
+ //
+ uint32_t ui32HIDFlags;
+
+ //
+ // The applications registered callback.
+ //
+ tUSBHIDMouseCallback pfnCallback;
+
+ //
+ // The current state of the buttons.
+ //
+ uint8_t ui8Buttons;
+
+ //
+ // This is a local buffer to hold the current HID report that comes up
+ // from the HID driver layer.
+ //
+ uint8_t pui8Buffer[USBHMS_REPORT_SIZE];
+
+ //
+ // Heap data for the mouse currently used to read the HID Report
+ // Descriptor.
+ //
+ uint8_t *pui8Heap;
+
+ //
+ // Size of the heap in bytes.
+ //
+ uint32_t ui32HeapSize;
+
+ //
+ // This is the instance value for the HID device that will be used for the
+ // mouse.
+ //
+ tHIDInstance *psHIDInstance;
+};
+
+//*****************************************************************************
+//
+// This is the per instance information for a mouse device.
+//
+//*****************************************************************************
+static tUSBHMouse g_sUSBHMouse =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used open an instance of a mouse.
+//!
+//! \param pfnCallback is the callback function to call when new events occur
+//! with the mouse returned.
+//! \param pui8Buffer is the memory used by the driver to interact with the
+//! USB mouse.
+//! \param ui32Size is the size of the buffer provided by \e pui8Buffer.
+//!
+//! This function is used to open an instance of the mouse. The value
+//! returned from this function should be used as the instance identifier for
+//! all other USBHMouse calls. The \e pui8Buffer memory buffer is used to
+//! access the mouse. The buffer size required is at least enough to hold
+//! a normal report descriptor for the device.
+//!
+//! \return Returns the instance identifier for the mouse that is attached.
+//! If there is no mouse present this will return 0.
+//
+//*****************************************************************************
+tUSBHMouse *
+USBHMouseOpen(tUSBHIDMouseCallback pfnCallback, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ //
+ // Save the callback and data pointers.
+ //
+ g_sUSBHMouse.pfnCallback = pfnCallback;
+
+ //
+ // Save the instance pointer for the HID device that was opened.
+ //
+ g_sUSBHMouse.psHIDInstance = USBHHIDOpen(eUSBHHIDClassMouse,
+ USBHMouseCallback,
+ (void *)&g_sUSBHMouse);
+
+ //
+ // Save the heap buffer and size.
+ //
+ g_sUSBHMouse.pui8Heap = pui8Buffer;
+ g_sUSBHMouse.ui32HeapSize = ui32Size;
+
+ return(&g_sUSBHMouse);
+}
+
+//*****************************************************************************
+//
+//! This function is used close an instance of a mouse.
+//!
+//! \param psMsInstance is the instance value for this mouse.
+//!
+//! This function is used to close an instance of the mouse that was opened
+//! with a call to USBHMouseOpen(). The \e psMsInstance value is the value
+//! that was returned when the application called USBHMouseOpen().
+//!
+//! \return Returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseClose(tUSBHMouse *psMsInstance)
+{
+ //
+ // Reset the callback to null.
+ //
+ psMsInstance->pfnCallback = 0;
+
+ //
+ // Call the HID driver layer to close out this instance.
+ //
+ USBHHIDClose(psMsInstance->psHIDInstance);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize a mouse interface after a mouse has
+//! been detected.
+//!
+//! \param psMsInstance is the instance value for this mouse.
+//!
+//! This function should be called after receiving a \b USB_EVENT_CONNECTED
+//! event in the callback function provided by USBHMouseOpen(), however it
+//! should only be called outside of the callback function. This will
+//! initialize the mouse interface and determine how it reports events to the
+//! USB host controller. The \e psMsInstance value is the value that was
+//! returned when the application called USBHMouseOpen(). This function only
+//! needs to be called once per connection event but it should be called every
+//! time a \b USB_EVENT_CONNECTED event occurs.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseInit(tUSBHMouse *psMsInstance)
+{
+ //
+ // Set the initial rate to only update on mouse state changes.
+ //
+ USBHHIDSetIdle(psMsInstance->psHIDInstance, 0, 0);
+
+ //
+ // Read out the Report Descriptor from the mouse and parse it for
+ // the format of the reports coming back from the mouse.
+ //
+ USBHHIDGetReportDescriptor(psMsInstance->psHIDInstance,
+ psMsInstance->pui8Heap,
+ psMsInstance->ui32HeapSize);
+
+ //
+ // Set the mouse to boot protocol.
+ //
+ USBHHIDSetProtocol(psMsInstance->psHIDInstance, 1);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// This function handles updating the state of the mouse buttons and axis.
+//
+// \param psMsInstance is the pointer to an instance of the mouse data.
+//
+// This function will check for updates to buttons or X/Y movements and send
+// callbacks to the mouse callback function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateMouseState(tUSBHMouse *psMsInstance)
+{
+ uint32_t ui32Button;
+
+ if(psMsInstance->pui8Buffer[0] != psMsInstance->ui8Buttons)
+ {
+ for(ui32Button = 1; ui32Button <= 0x4; ui32Button <<= 1)
+ {
+ if(((psMsInstance->pui8Buffer[0] & ui32Button) != 0) &&
+ ((psMsInstance->ui8Buttons & ui32Button) == 0))
+ {
+ //
+ // Send the mouse button press notification to the application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_PRESS,
+ ui32Button, 0);
+ }
+ if(((psMsInstance->pui8Buffer[0] & ui32Button) == 0) &&
+ ((psMsInstance->ui8Buttons & ui32Button) != 0))
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_REL,
+ ui32Button, 0);
+ }
+ }
+
+ //
+ // Save the new state.
+ //
+ psMsInstance->ui8Buttons = psMsInstance->pui8Buffer[0];
+ }
+
+ if(psMsInstance->pui8Buffer[1] != 0)
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_X,
+ (uint32_t)psMsInstance->pui8Buffer[1], 0);
+ }
+
+ if(psMsInstance->pui8Buffer[2] != 0)
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_Y,
+ (uint32_t)psMsInstance->pui8Buffer[2], 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function handles event callbacks from the USB HID driver layer.
+//!
+//! \param pvMouse is the pointer that was passed in to the USBHHIDOpen()
+//! call.
+//! \param ui32Event is the event that has been passed up from the HID driver.
+//! \param ui32MsgParam has meaning related to the \e ui32Event that occurred.
+//! \param pvMsgData has meaning related to the \e ui32Event that occurred.
+//!
+//! This function will receive all event updates from the HID driver layer.
+//! The mouse driver itself will mostly be concerned with report callbacks
+//! from the HID driver layer and parsing them into keystrokes for the
+//! application that has registered for callbacks with the USBHMouseOpen()
+//! call.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseCallback(void *pvMouse, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData)
+{
+ tUSBHMouse *psMsInstance;
+
+ //
+ // Recover the pointer to the instance data.
+ //
+ psMsInstance = (tUSBHMouse *)pvMouse;
+
+ switch(ui32Event)
+ {
+ //
+ // New mouse has been connected so notify the application.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Remember that a mouse is present.
+ //
+ psMsInstance->ui32HIDFlags |= USBHMS_DEVICE_PRESENT;
+
+ //
+ // Notify the application that a new mouse was connected.
+ //
+ psMsInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ //
+ // No mouse is present.
+ //
+ psMsInstance->ui32HIDFlags &= ~USBHMS_DEVICE_PRESENT;
+
+ //
+ // Notify the application that the mouse was disconnected.
+ //
+ psMsInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // New mouse report structure was received.
+ //
+ USBHHIDGetReport(psMsInstance->psHIDInstance, 0,
+ psMsInstance->pui8Buffer, USBHMS_REPORT_SIZE);
+
+ //
+ // Update the current state of the mouse and notify the application
+ // of any changes.
+ //
+ UpdateMouseState(psMsInstance);
+
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psMsInstance is the HID keyboard instance that was returned
+//! from the call to USBHMouseOpen().
+//!
+//! This function forwards a request from an application to the HID device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseLPMSleep(tUSBHMouse *psMsInstance)
+{
+ //
+ // Call the HID function to send the sleep command.
+ //
+ return(USBHHIDLPMSleep(psMsInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psMsInstance is the HID keyboard instance that was returned
+//! from the call to USBHMouseOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseLPMStatus(tUSBHMouse *psMsInstance)
+{
+ //
+ // Call the HID function to get the current LPM status.
+ //
+ return(USBHHIDLPMStatus(psMsInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhidmouse.h b/usblib/host/usbhhidmouse.h
new file mode 100644
index 0000000..295f6c1
--- /dev/null
+++ b/usblib/host/usbhhidmouse.h
@@ -0,0 +1,81 @@
+//*****************************************************************************
+//
+// usbhhidmouse.h - This file holds the application interfaces for USB
+// mouse devices.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHIDMOUSE_H__
+#define __USBHHIDMOUSE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHMouse tUSBHMouse;
+
+//*****************************************************************************
+//
+// The prototype for the host USB mouse driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHIDMouseCallback)(tUSBHMouse *psMsInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+extern tUSBHMouse * USBHMouseOpen(tUSBHIDMouseCallback pfnCallback,
+ uint8_t *pui8Buffer, uint32_t ui32Size);
+extern uint32_t USBHMouseClose(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseInit(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseLPMSleep(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseLPMStatus(tUSBHMouse *psMsInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/host/usbhhub.c b/usblib/host/usbhhub.c
new file mode 100644
index 0000000..8042dfc
--- /dev/null
+++ b/usblib/host/usbhhub.c
@@ -0,0 +1,1522 @@
+//*****************************************************************************
+//
+// usbhhub.c - This file contains the host HID driver.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhub.h"
+#ifdef INCLUDE_DEBUG_OUTPUT
+#include "utils/uartstdio.h"
+#define DEBUG_OUTPUT UARTprintf
+#else
+#define DEBUG_OUTPUT while(0)((int (*)(char *, ...))0)
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+//! The USB standard hub descriptor structure. Full documentation for the
+//! contents of this structure can be found in chapter 11.23.2.1 of the USB
+//! 2.0 specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The total number of bytes in the descriptor (including this field).
+ //
+ uint8_t bLength;
+
+ //
+ //! The descriptor type. For a hub descriptor, this will be USB_DTYPE_HUB
+ //! (0x29 or 41 decimal).
+ //
+ uint8_t bDescType;
+
+ //
+ //! The number of downstream-facing ports that the hub supports.
+ //
+ uint8_t bNbrPorts;
+
+ //
+ //! Characteristics of the hub device including its power switching
+ //! capabilities and over-current protection mode.
+ //
+ uint16_t wHubCharacteristics;
+
+ //
+ //! The time between the start of the power-on sequence for a port and
+ //! the power to the port becoming stable. This is expressed in 2mS units.
+ //
+ uint8_t bPwrOn2PwrGood;
+
+ //
+ //! The maximum current requirement for the hub circuitry in mA.
+ //
+ uint8_t bHubContrCurrent;
+
+ //
+ //! The last two fields in the structure are bit masks indicating which
+ //! downstream ports support removable devices and, following this, another
+ //! obsolete field from USB1.0 related to port power control. Each field
+ //! is byte aligned and contains a bit for each hub port. This structure
+ //! definition is set up with enough storage to handle ROOT_HUB_MAX_PORTS
+ //! ports but beware that the actual size of each field is dependent upon
+ //! the bNbrPorts field above.
+ //
+ uint8_t PortInfo[((ROOT_HUB_MAX_PORTS + 7) / 8) * 2];
+}
+PACKED tUsbHubDescriptor;
+
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// This structure holds all data specific to a single hub port.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The handle used by the HCD layer to identify this device.
+ //
+ uint32_t ui32DevHandle;
+
+ //
+ // The current state of the port.
+ //
+ volatile tHubPortState iState;
+
+ //
+ // General counter used in various states.
+ //
+ volatile uint32_t ui32Count;
+
+ //
+ // A flag used to indicate that the downstream device is a low speed
+ // device.
+ //
+ bool bLowSpeed;
+
+ //
+ // The speed of the device on this port.
+ //
+ uint32_t ui32Speed;
+
+ //
+ // This flag is set if the hub reports that a change is pending on this
+ // port.
+ //
+ volatile bool bChanged;
+}
+tHubPort;
+
+//*****************************************************************************
+//
+// USB hub flags values for tHubInstance.ui32Flags.
+//
+//*****************************************************************************
+#define USBLIB_HUB_ACTIVE 0x00000001
+#define USBLIB_HUB_HS 0x00000002
+#define USBLIB_HUB_MULTI_TT 0x00000004
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the data for a given instance of
+// a Hub device.
+//
+//*****************************************************************************
+struct tHubInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback function pointer.
+ //
+ tUSBHHubCallback pfnCallback;
+
+ //
+ // Callback data provided by caller.
+ //
+ uint32_t ui32CBData;
+
+ //
+ // Interrupt IN pipe.
+ //
+ uint32_t ui32IntInPipe;
+
+ //
+ // Hub characteristics as reported in the class-specific hub descriptor.
+ //
+ uint16_t ui16HubCharacteristics;
+
+ //
+ // The number of downstream-facing ports the hub supports.
+ //
+ uint8_t ui8NumPorts;
+
+ //
+ // The number of ports on the hub that we can actually talk to. This will
+ // be the smaller of the number of ports on the hub and MAX_USB_DEVICES.
+ //
+ uint8_t ui8NumPortsInUse;
+
+ //
+ // The size of a status change packet sent by the hub. This is determined
+ // from the number of ports supported by the hub.
+ //
+ uint8_t ui8ReportSize;
+
+ //
+ // Flags indicating whether the hub is connected.
+ //
+ uint32_t ui32Flags;
+
+ //
+ // Flag indicating that a device is currently in process of being
+ // enumerated.
+ //
+ volatile bool bEnumerationBusy;
+
+ //
+ // This is valid if bEnumerationBusy is set and indicates the port
+ // that is in the process of enumeration.
+ //
+ uint8_t ui8EnumIdx;
+
+ //
+ // The state of each of the ports we support on the hub.
+ //
+ tHubPort psPorts[MAX_USB_DEVICES];
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+};
+
+//*****************************************************************************
+//
+//! Forward references to the hub class driver functions.
+//
+//*****************************************************************************
+static void *HubDriverOpen(tUSBHostDevice *psDevice);
+static void HubDriverClose(void *pvHubDevice);
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Hub Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHubClassDriver =
+{
+ USB_CLASS_HUB,
+ HubDriverOpen,
+ HubDriverClose,
+ 0
+};
+
+//*****************************************************************************
+//
+// The instance data storage for attached hub.
+//
+//*****************************************************************************
+static tHubInstance g_sRootHub;
+
+//*****************************************************************************
+//
+// Hub and port state change flags as reported via the hub's IN endpoint.
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32ChangeFlags;
+
+//
+// Note: The following assumes ROOT_HUB_MAX_PORTS is less than 32!
+//
+static uint32_t g_ui32HubChanges;
+
+//*****************************************************************************
+//
+// This function is called to set the operating speed of a given port.
+//
+// \param ui8Port is the port number for this request.
+// \param ui32Speed is one of the HUB_FEATURE_PORT_* values.
+//
+// This function sets the operating speed of the hub port specified in the
+// \e ui8Port parameter. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui32Speed value is one of the
+// \b USB_EP_SPEED_ values.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHubPortSpeedSet(uint8_t ui8Port, uint32_t ui32Speed)
+{
+ g_sRootHub.psPorts[ui8Port].ui32Speed = ui32Speed;
+}
+
+//*****************************************************************************
+//
+// This function is called to send a request to the hub to set a feature on
+// a given port.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param ui16Feature is one of the HUB_FEATURE_PORT_* values.
+//
+// This function will send the set feature request to the hub indicated by the
+// \e psHubInstance parameter. The \e ui8Port value indicates which port
+// number to send this request to and can range from 0 to the number of valid
+// ports on the given hub. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui16Feature is the feature
+// request toset on the given port. For example, a \e ui16Feature value of
+// \e HUB_FEATURE_PORT_RESET and \e ui8Port value of 1 will cause reset
+// signaling to hub port 1.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HubSetPortFeature(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t ui16Feature)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the hub instance and device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the field to clear the requested port feature.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_FEATURE;
+ sSetupPacket.wValue = ui16Feature;
+ sSetupPacket.wIndex = ui8Port;
+ sSetupPacket.wLength = 0;
+
+ //
+ // Send the request.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+// This function is called to send a request to the hub to clear a feature on
+// a given port.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param ui16Feature is one of the HUB_FEATURE_PORT_* values.
+//
+// This function will send the clear feature request to the hub indicated by
+// the \e psHubInstance parameter. The \e ui8Port value indicates which port
+// number to send this request to and can range from 0 to the number of valid
+// ports on the given hub. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui16Feature is the feature
+// request to clear on the given port. For example, a \e ui16Feature value of
+// \e HUB_FEATURE_C_PORT_RESET and \e ui8Port value of 1 will clear the reset
+// complete signaling on hub port 1. Values like the reset feature will
+// remain set until actively cleared by this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HubClearPortFeature(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t ui16Feature)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the hub instance and device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the field to clear the requested port feature.
+ //
+ sSetupPacket.bRequest = USBREQ_CLEAR_FEATURE;
+ sSetupPacket.wValue = ui16Feature;
+ sSetupPacket.wIndex = ui8Port;
+ sSetupPacket.wLength = 0;
+
+ //
+ // Send the request.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+// This function is used to retrieve the current status of a port on the
+// hub.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param pui16PortStatus is a pointer to the memory to store the current
+// status of the port.
+// \param pui16PortChange is a pointer to the memory to store the current
+// change status of the ports.
+//
+// This function is used to retrieve the current overall status and change
+// status for the port given in the \e ui8Port parameter. The \e ui8Port value
+// indicates which port number to send this request to and can range from 0 to
+// the number of valid ports on the given hub. A \e ui8Port value of 0 is an
+// access to the hub itself and not one of the hub ports.
+//
+// \return None.
+//
+//*****************************************************************************
+static bool
+HubGetPortStatus(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t *pui16PortStatus, uint16_t *pui16PortChange)
+{
+ uint32_t ui32Data, ui32Read;
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the fields to get the hub status.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_STATUS;
+ sSetupPacket.wValue = 0;
+ sSetupPacket.wIndex = (uint16_t)ui8Port;
+ sSetupPacket.wLength = 4;
+
+ //
+ // Send the request.
+ //
+ ui32Read = USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)&ui32Data, 4,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Check that we received the correct number of bytes.
+ //
+ if(ui32Read != 4)
+ {
+ return(false);
+ }
+ else
+ {
+ //
+ // We got 4 bytes from the device. Now translate these into the 2
+ // 16-bit values we pass back to the caller.
+ //
+ *pui16PortStatus = (uint16_t)(ui32Data & 0xFFFF);
+ *pui16PortChange = (uint16_t)(ui32Data >> 16);
+
+ DEBUG_OUTPUT("Port %d, status 0x%04x, change 0x%04x\n", ui8Port,
+ *pui16PortStatus, *pui16PortChange);
+ }
+
+ //
+ // All is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+// This function handles callbacks for the interrupt IN endpoint for the hub
+// device.
+//
+//*****************************************************************************
+static void
+HubIntINCallback(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ switch (ui32Event)
+ {
+ //
+ // Handles a request to schedule a new request on the interrupt IN
+ // pipe.
+ //
+ case USB_EVENT_SCHEDULER:
+ {
+ //
+ // Set things up to read the next change indication from the hub.
+ //
+ USBHCDPipeSchedule(ui32Pipe, (uint8_t *)&g_ui32HubChanges,
+ (uint32_t)g_sRootHub.ui8ReportSize);
+ break;
+ }
+
+ //
+ // Called when new data is available on the interrupt IN pipe.
+ //
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // For data transfers on INT IN endpoints, we need to acknowledge
+ // the data from this callback.
+ //
+ USBHCDPipeDataAck(ui32Pipe);
+
+ //
+ // Update our global "ports needing service" flags with the latest
+ // information we have just received.
+ //
+ g_ui32ChangeFlags |= g_ui32HubChanges;
+
+ //
+ // Send the report data to the USB host hub device class driver if
+ // we have been given a callback function.
+ //
+ if(g_sRootHub.pfnCallback)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_RX_AVAILABLE,
+ ui32Pipe, &g_ui32HubChanges);
+ }
+
+ break;
+ }
+ case USB_EVENT_ERROR:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Query the class-specific hub descriptor.
+//
+//*****************************************************************************
+static bool
+GetHubDescriptor(tUsbHubDescriptor *psDesc)
+{
+ uint32_t ui32Read;
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the device pointer.
+ //
+ psDevice = g_sRootHub.psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_DEVICE;
+
+ //
+ // Set the fields to get the hub descriptor. Initially, we request only
+ // the first 4 bytes of the descriptor. This will give us the size which
+ // we use to determine how many bytes to read to get the full descriptor.
+ // This is necessary since we don't know how many ports the hub can support
+ // and we only support up to MAX_USB_DEVICES.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = (USB_DTYPE_HUB << 8);
+ sSetupPacket.wIndex = 0;
+ sSetupPacket.wLength = sizeof(tUsbHubDescriptor);
+
+ //
+ // Send the request.
+ //
+ ui32Read = USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (void *)psDesc, sizeof(tUsbHubDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Make sure we got at least some data.
+ //
+ if(ui32Read == 0)
+ {
+ return(false);
+ }
+
+ //
+ // All is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Open an instance of the hub driver. This is called when the USB host
+// has enumerated a new hub device.
+//
+//*****************************************************************************
+static void *
+HubDriverOpen(tUSBHostDevice *psDevice)
+{
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+ tUsbHubDescriptor sHubDesc;
+ bool bRetcode;
+ uint32_t ui32Loop;
+
+ //
+ // If we are already talking to a hub, fail the call. We only support
+ // a single hub.
+ //
+ if(g_sRootHub.ui32Flags & USBLIB_HUB_ACTIVE)
+ {
+ return(0);
+ }
+
+ //
+ // Get pointers to the device descriptors we need to look at.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+ psEndpointDescriptor = USBDescGetInterfaceEndpoint(psInterface, 0,
+ psDevice->ui32ConfigDescriptorSize);
+
+ //
+ // If there are no endpoints, something is wrong since a hub must have
+ // a single INT endpoint for signaling.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ return 0;
+ }
+
+ //
+ // Make sure we really are talking to a hub.
+ //
+ if((psInterface->bInterfaceClass != USB_CLASS_HUB) ||
+ (psInterface->bInterfaceSubClass != 0))
+ {
+ //
+ // Something is wrong - this isn't a hub or, if it is, we don't
+ // understand the protocol it is using.
+ //
+ return(0);
+ }
+
+ //
+ // Remember that this is a high speed hub with either single or multiple
+ // transaction translators.
+ //
+ if(psInterface->bInterfaceProtocol == USB_HUB_PROTOCOL_SINGLE)
+ {
+ g_sRootHub.ui32Flags |= USBLIB_HUB_HS;
+ }
+ else if(psInterface->bInterfaceProtocol == USB_HUB_PROTOCOL_MULTI)
+ {
+ g_sRootHub.ui32Flags |= USBLIB_HUB_HS | USBLIB_HUB_MULTI_TT;
+ }
+
+ //
+ // Remember the device information for later.
+ //
+ g_sRootHub.psDevice = psDevice;
+
+ //
+ // A hub must support an interrupt endpoint so check this.
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT)
+ {
+ //
+ // The endpoint is the correct type. Is it an IN endpoint?
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ //
+ // Yes - all is well with the hub endpoint so allocate a pipe to
+ // handle traffic from the hub.
+ //
+ g_sRootHub.ui32IntInPipe = USBHCDPipeAlloc(0, USBHCD_PIPE_INTR_IN,
+ psDevice,
+ HubIntINCallback);
+ USBHCDPipeConfig(g_sRootHub.ui32IntInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ psEndpointDescriptor->bInterval,
+ psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M);
+ }
+ }
+
+ //
+ // Did we allocate the endpoint successfully?
+ //
+ if(!g_sRootHub.ui32IntInPipe)
+ {
+ //
+ // No - return an error.
+ //
+ return 0;
+ }
+
+ //
+ // Assuming we have a callback, call it to tell the owner that a hub is
+ // now connected.
+ //
+ if(g_sRootHub.pfnCallback != 0)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_CONNECTED, (uint32_t)&g_sRootHub, 0);
+ }
+
+ //
+ // Get the hub descriptor and store information we'll need for later.
+ //
+ bRetcode = GetHubDescriptor(&sHubDesc);
+ if(bRetcode)
+ {
+
+ //
+ // We read the descriptor successfully so extract the parts we need.
+ //
+ g_sRootHub.ui8NumPorts = sHubDesc.bNbrPorts;
+ g_sRootHub.ui16HubCharacteristics = sHubDesc.wHubCharacteristics;
+ g_sRootHub.ui8NumPortsInUse =
+ (sHubDesc.bNbrPorts > MAX_USB_DEVICES) ? MAX_USB_DEVICES :
+ sHubDesc.bNbrPorts;
+
+ //
+ // The size of the status change report that the hub sends is dependent
+ // upon the number of ports that the hub supports. Calculate this by
+ // adding 1 to the number of ports (bit 0 of the report is the hub
+ // status, higher bits are one per port) then dividing by 8 (bits per
+ // byte) and rounding up.
+ //
+ g_sRootHub.ui8ReportSize = ((sHubDesc.bNbrPorts + 1) + 7) / 8;
+
+ //
+ // Enable power to all ports on the hub.
+ //
+ for(ui32Loop = 1; ui32Loop <= sHubDesc.bNbrPorts; ui32Loop++)
+ {
+ //
+ // Turn on power to this port.
+ //
+ HubSetPortFeature(&g_sRootHub, ui32Loop,
+ HUB_FEATURE_PORT_POWER);
+ }
+
+ //
+ // Clear out our port state structures.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_USB_DEVICES; ui32Loop++)
+ {
+ g_sRootHub.psPorts[ui32Loop].bChanged = false;
+ g_sRootHub.psPorts[ui32Loop].iState = ePortIdle;
+ }
+ }
+ else
+ {
+ //
+ // Oops - we can't read the hub descriptor! Tidy up and return
+ // an error.
+ //
+ USBHCDPipeFree(g_sRootHub.ui32IntInPipe);
+ g_sRootHub.pfnCallback = 0;
+ g_sRootHub.ui32Flags &= ~USBLIB_HUB_ACTIVE;
+ return(0);
+ }
+
+ //
+ // If we get here, all is well so remember that the hub is connected and
+ // active.
+ //
+ g_sRootHub.ui32Flags |= USBLIB_HUB_ACTIVE;
+
+ //
+ // Return our instance data pointer to the caller to use as a handle.
+ //
+ return((void *)&g_sRootHub);
+}
+
+//*****************************************************************************
+//
+// Close an instance of the hub driver.
+//
+//*****************************************************************************
+static void
+HubDriverClose(void *pvHubDevice)
+{
+ uint32_t ui32Loop;
+
+ //
+ // No device so just exit.
+ //
+ if(g_sRootHub.psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Disconnect any devices that are currently connected to the hub.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_USB_DEVICES; ui32Loop++)
+ {
+ //
+ // Does this port have a device connected to it that we have previously
+ // reported to the host control layer?h
+ //
+ if((g_sRootHub.psPorts[ui32Loop].iState == ePortActive) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortEnumerated) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortError))
+ {
+ //
+ // Yes - tell the host controller to disconnect the device.
+ //
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui32Loop].ui32DevHandle);
+
+ }
+
+ //
+ // Make sure that the state returns to idle.
+ //
+ g_sRootHub.psPorts[ui32Loop].iState = ePortIdle;
+
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ g_sRootHub.psDevice = 0;
+
+ //
+ // Mark the hub as absent.
+ //
+ g_sRootHub.ui32Flags &= ~USBLIB_HUB_ACTIVE;
+
+ //
+ // Note that we are not in the middle of enumerating anything.
+ //
+ g_sRootHub.bEnumerationBusy = false;
+
+ //
+ // Free the Interrupt IN pipe.
+ //
+ if(g_sRootHub.ui32IntInPipe != 0)
+ {
+ USBHCDPipeFree(g_sRootHub.ui32IntInPipe);
+ }
+
+ //
+ // If the callback exists, call it with a DISCONNECTED event.
+ //
+ if(g_sRootHub.pfnCallback != 0)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_DISCONNECTED, (uint32_t)&g_sRootHub,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+// Perform any processing required as a result of a change in the reset
+// signaling for a given port.
+//
+//*****************************************************************************
+static void
+HubDriverReset(uint8_t ui8Port, bool bResetActive)
+{
+ //
+ // Did the reset sequence end or begin?
+ //
+ if(!bResetActive)
+ {
+ //
+ // The reset ended. Now wait for at least 10ms before signaling
+ // USB enumeration code that a new device is waiting to be enumerated.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetWait;
+
+ //
+ // Set the wait to 10ms (10 frames) from now.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32Count = 10;
+ }
+ else
+ {
+ //
+ // Was this device previously active?
+ //
+ if(g_sRootHub.psPorts[ui8Port].iState == ePortActive)
+ {
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle);
+ }
+
+ //
+ // The reset is active so mark our port as in reset.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetActive;
+ }
+}
+
+//*****************************************************************************
+//
+// Start the process of enumerating a new device by issuing a reset to the
+// appropriate downstream port.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceReset(uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Starting enumeration for port %d\n", ui8Port);
+
+ //
+ // Record the fact that we are in the process of enumerating a device.
+ //
+ g_sRootHub.bEnumerationBusy = true;
+
+ //
+ // Save the port that is being enumerated.
+ //
+ g_sRootHub.ui8EnumIdx = ui8Port;
+
+ //
+ // Mark the port as being reset.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetActive;
+
+ //
+ // Initiate a reset on the relevant port to start the enumeration process.
+ //
+ HubSetPortFeature(&g_sRootHub, ui8Port, HUB_FEATURE_PORT_RESET);
+}
+
+//*****************************************************************************
+//
+// A new device has been connected to the hub. Allocate resources to manage
+// it and pass details back to the main USB host enumeration code to have the
+// device enumerated.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceConnect(uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("HubDriverDeviceConnect\n");
+
+ //
+ // We've allocated a port table entry so fill it in then initiate a reset
+ // on the device.
+ //
+ g_sRootHub.psPorts[ui8Port].bChanged = false;
+
+ //
+ // Mark the port as having a device present but not enumerated.
+ //
+ DEBUG_OUTPUT("Deferring enumeration for port %d\n", ui8Port);
+ g_sRootHub.psPorts[ui8Port].iState = ePortConnected;
+
+ //
+ // Wait 100ms to reset the device.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32Count = 100;
+}
+
+//*****************************************************************************
+//
+// An existing device has been removed from the hub. Tidy up and let the main
+// USB host code know so that it can free device resources.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceDisconnect(uint8_t ui8Port)
+{
+ //
+ // This is a device we are currently managing. Have we already informed
+ // the host controller that it is present?
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortActive) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortEnumerated) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortError))
+ {
+ //
+ // Yes - tell the host controller that the device is not longer
+ // connected.
+ //
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle);
+ }
+
+ //
+ // If the device was being enumerated, make sure we clear the flag
+ // indicating that an enumeration is still ongoing.
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortResetActive) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortActive))
+ {
+ g_sRootHub.bEnumerationBusy = false;
+ }
+
+ //
+ // Free up the port state structure.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortIdle;
+}
+
+//*****************************************************************************
+//
+// This function is called periodically by USBHCDMain(). We use it to handle
+// the hub port state machine.
+//
+//*****************************************************************************
+void
+USBHHubMain(void)
+{
+ uint16_t ui16Status, ui16Changed;
+ uint_fast8_t ui8Port;
+ bool bRetcode;
+
+ //
+ // If the hub is not present, just return.
+ //
+ if((g_sRootHub.ui32Flags & USBLIB_HUB_ACTIVE) == 0)
+ {
+ return;
+ }
+
+ //
+ // Initialize the status variables.
+ //
+ ui16Status = 0;
+ ui16Changed = 0;
+
+ //
+ // The hub is active and something changed. Check to see which port changed
+ // state and handle as necessary.
+ //
+ for(ui8Port = 0; ui8Port <= g_sRootHub.ui8NumPortsInUse; ui8Port++)
+ {
+ //
+ // Decrement any wait counter if there is one present.
+ //
+ if(g_sRootHub.psPorts[ui8Port].ui32Count != 0)
+ {
+ g_sRootHub.psPorts[ui8Port].ui32Count--;
+ }
+
+ //
+ // Is this port waiting to be enumerated and is the last device
+ // enumeration finished?
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortConnected) &&
+ (!g_sRootHub.bEnumerationBusy) &&
+ (g_sRootHub.psPorts[ui8Port].ui32Count == 0))
+ {
+ //
+ // Yes - start the enumeration processing for this device.
+ //
+ HubDriverDeviceReset(ui8Port);
+ }
+
+ //
+ // If the state is ePortResetWait then the hub is waiting before
+ // accessing device as the USB 2.0 specification requires.
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) &&
+ (g_sRootHub.psPorts[ui8Port].ui32Count == 0))
+ {
+ //
+ // Start the enumeration process if the timeout has passed and
+ // the hub is waiting to start enumerating the device.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortActive;
+
+ //
+ // Call the main host controller layer to have it enumerate the
+ // newly connected device.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle =
+ USBHCDHubDeviceConnected(0, 1, ui8Port,
+ g_sRootHub.psPorts[ui8Port].ui32Speed);
+ }
+
+ //
+ // If an enumeration is in progress and the loop is not on the port
+ // being enumerated then skip the port.
+ //
+ if(g_sRootHub.bEnumerationBusy &&
+ (g_sRootHub.ui8EnumIdx != ui8Port))
+ {
+ continue;
+ }
+
+ //
+ // Did something change for this particular port?
+ //
+ if(g_ui32ChangeFlags & (1 << ui8Port))
+ {
+ //
+ // Yes - query the port status.
+ //
+ bRetcode = HubGetPortStatus(&g_sRootHub, ui8Port, &ui16Status,
+ &ui16Changed);
+
+ //
+ // Clear this change with the USB interrupt temporarily disabled to
+ // ensure that we do not clear a flag that the interrupt routine
+ // has just set.
+ //
+ OS_INT_DISABLE(g_sRootHub.ui32IntNum);
+ g_ui32ChangeFlags &= ~(1 << ui8Port);
+ OS_INT_ENABLE(g_sRootHub.ui32IntNum);
+
+ //
+ // If there was an error, go on and look at the next bit.
+ //
+ if(!bRetcode)
+ {
+ continue;
+ }
+
+ //
+ // Now consider what changed and handle it as necessary.
+ //
+
+ //
+ // Was a device connected to or disconnected from the port?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_DEVICE_PRESENT)
+ {
+ DEBUG_OUTPUT("Connection change on port %d\n", ui8Port);
+
+ //
+ // Clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_CONNECTION);
+
+ //
+ // Was a device connected or disconnected?
+ //
+ if(ui16Status & HUB_PORT_STATUS_DEVICE_PRESENT)
+ {
+ DEBUG_OUTPUT("Connected\n");
+
+ //
+ // A device was connected.
+ //
+ HubDriverDeviceConnect(ui8Port);
+ }
+ else
+ {
+ DEBUG_OUTPUT("Disconnected\n");
+
+ //
+ // A device was disconnected.
+ //
+ HubDriverDeviceDisconnect(ui8Port);
+ }
+ }
+
+ //
+ // Did a reset on the port complete?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_RESET)
+ {
+ //
+ // Clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_RESET);
+
+ //
+ // Yes - query the port status.
+ //
+ bRetcode = HubGetPortStatus(&g_sRootHub, ui8Port,
+ &ui16Status, &ui16Changed);
+
+ DEBUG_OUTPUT("Reset %s for port %d\n",
+ ((ui16Status & HUB_PORT_STATUS_RESET) ? "asserted" :
+ "deasserted"), ui8Port);
+
+ //
+ // Handle the reset case.
+ //
+ HubDriverReset(ui8Port, (ui16Status & HUB_PORT_STATUS_RESET) ?
+ true : false);
+
+ //
+ // A device was connected.
+ //
+ if(ui16Status & HUB_PORT_STATUS_LOW_SPEED)
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_LOW);
+ }
+ else if(ui16Status & HUB_PORT_STATUS_HIGH_SPEED)
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_HIGH);
+ }
+ else
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_FULL);
+ }
+ }
+
+ //
+ // Did an over-current reset on the port complete?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_OVER_CURRENT)
+ {
+ DEBUG_OUTPUT("Port %d over current.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_OVER_CURRENT);
+ }
+
+ //
+ // Has the port been enabled or disabled?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_ENABLED)
+ {
+ DEBUG_OUTPUT("Enable change for port %d.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_ENABLE);
+ }
+
+ //
+ // Has the port been suspended or resumed?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_SUSPENDED)
+ {
+ DEBUG_OUTPUT("Suspend change for port %d.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_SUSPEND);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Informs the hub class driver that a downstream device has been enumerated.
+//!
+//! \param ui8Hub is the address of the hub to which the downstream device
+//! is attached.
+//! \param ui8Port is the port on the hub to which the downstream device is
+//! attached.
+//!
+//! This function is called by the host controller driver to inform the hub
+//! class driver that a downstream device has been enumerated successfully.
+//! The hub driver then moves on and continues enumeration of any other newly
+//! connected devices.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubEnumerationComplete(uint8_t ui8Hub, uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Enumeration complete for hub %d, port %d\n", ui8Hub, ui8Port);
+
+ //
+ // Record the fact that the device is up and running.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortEnumerated;
+
+ //
+ // Clear the flag we use to defer further enumerations. This will cause
+ // the next connected device (if any) to start enumeration on the next
+ // call to USBHHubMain().
+ //
+ g_sRootHub.bEnumerationBusy = false;
+}
+
+//*****************************************************************************
+//
+//! Informs the hub class driver that a downstream device failed to enumerate.
+//!
+//! \param ui8Hub is the address of the hub to which the downstream device
+//! is attached.
+//! \param ui8Port is the port on the hub to which the downstream device is
+//! attached.
+//!
+//! This function is called by the host controller driver to inform the hub
+//! class driver that an attempt to enumerate a downstream device has failed.
+//! The hub driver then cleans up and continues enumeration of any other newly
+//! connected devices.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubEnumerationError(uint8_t ui8Hub, uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Enumeration error for hub %d, port %d\n", ui8Hub, ui8Port);
+
+ //
+ // Record the fact that the device is not working correctly.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortError;
+
+ //
+ // Clear the flag we use to defer further enumerations. This will cause
+ // the next connected device (if any) to start enumeration on the next
+ // call to USBHHubMain().
+ //
+ g_sRootHub.bEnumerationBusy = false;
+}
+
+//*****************************************************************************
+//
+//! This function is used to enable the host hub class driver before any
+//! devices are present.
+//!
+//! \param pfnCallback is the driver call back for host hub events.
+//!
+//! This function is called to open an instance of a host hub device and
+//! provides a valid callback function for host hub events in the
+//! \e pfnCallback parameter. This function must be called before the USB
+//! host code can successfully enumerate a hub device or any devices attached
+//! to the hub. The \e pui8HubPool is memory provided to the hub class to
+//! manage the devices that are connected to the hub. The \e ui32PoolSize is
+//! the number of bytes and should be at least 32 bytes per device including
+//! the hub device itself. A simple formula for providing memory to the hub
+//! class is \b MAX_USB_DEVICES * 32 bytes of data to allow for proper
+//! enumeration of connected devices. The value for \b MAX_USB_DEVICES is
+//! defined in the usblib.h file and controls the number of devices
+//! supported by the USB library. The \e ui32NumHubs parameter
+//! defaults to one and only one buffer of size tHubInstance is required to
+//! be passed in the \e psHubInstance parameter.
+//!
+//! \note Changing the value of \b MAX_USB_DEVICES requires a rebuild of the
+//! USB library to have an effect on the library.
+//!
+//! \return This function returns the driver instance to use for the other
+//! host hub functions. If there is no instance available at the time of
+//! this call, this function returns zero.
+//
+//*****************************************************************************
+tHubInstance *
+USBHHubOpen(tUSBHHubCallback pfnCallback)
+{
+ //
+ // Only one hub is supported.
+ //
+ if(g_sRootHub.pfnCallback)
+ {
+ DEBUG_OUTPUT("USBHHubOpen failed - already connected.\n");
+ return(0);
+ }
+
+ //
+ // Save the instance data for this device.
+ //
+ g_sRootHub.pfnCallback = pfnCallback;
+
+ DEBUG_OUTPUT("USBHHubOpen completed.\n");
+
+ //
+ // Return the device instance pointer.
+ //
+ return(&g_sRootHub);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release a hub device instance.
+//!
+//! \param psHubInstance is the hub device instance that is to be released.
+//!
+//! This function is called when an instance of the hub device must be
+//! released. This function is typically made in preparation for shutdown or a
+//! switch to function as a USB device when in OTG mode. Following this call,
+//! the hub device is no longer available, but it can be opened again using a
+//! call to USBHHubOpen(). After calling USBHHubClose(), the host hub driver
+//! no longer provides any callbacks or accepts calls to other hub driver APIs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubClose(tHubInstance *psHubInstance)
+{
+ //
+ // Forget the instance pointer and callback.
+ //
+ psHubInstance->psDevice = 0;
+ psHubInstance->pfnCallback = 0;
+
+ DEBUG_OUTPUT("USBHHubClose completed.\n");
+}
+
+//*****************************************************************************
+//
+// This function is used to initialize the Hub driver. This is an internal
+// function that should not be called by the application.
+//
+//*****************************************************************************
+void
+USBHHubInit(void)
+{
+ //
+ // Initialize Hub state.
+ //
+ g_ui32ChangeFlags = 0;
+ g_ui32HubChanges = 0;
+
+ if(g_sRootHub.psDevice != 0)
+ {
+ //
+ // Save the USB interrupt number.
+ //
+ g_sRootHub.ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_sRootHub.ui32IntNum = INT_USB0_TM4C129;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psHubInstance is the hub device instance that was returned
+//! from the call to USBHHubOpen().
+//!
+//! This function forwards a request from an application to the hub device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHHubLPMSleep(tHubInstance *psHubInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psHubInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psHubInstance is the hub device instance that was returned
+//! from the call to USBHHubOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHHubLPMStatus(tHubInstance *psHubInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psHubInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhub.h b/usblib/host/usbhhub.h
new file mode 100644
index 0000000..17a3c08
--- /dev/null
+++ b/usblib/host/usbhhub.h
@@ -0,0 +1,174 @@
+//*****************************************************************************
+//
+// usbhhub.h - This hold the host driver for hid class.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHUB_H__
+#define __USBHHUB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct tHubInstance tHubInstance;
+
+extern const tUSBHostClassDriver g_sUSBHubClassDriver;
+
+//*****************************************************************************
+//
+// The USB standard allows for up to 127 downstream ports on a single hub.
+// This would require rather more memory than we would like to set aside so the
+// default configuration of the hub driver supports hubs with up to 7
+// downstream-facing ports. In practice, this should be more than enough
+// since this covers the vast majority of consumer hubs. Note that, by
+// default, we will only support 4 devices so you can't fully populate a 7 port
+// hub and have everything work.
+//
+// Feel free to change this but bad things will happen if you increase it above
+// 31 since we assume the reports will always fit inside a 4 byte buffer.
+//
+//*****************************************************************************
+#define ROOT_HUB_MAX_PORTS 7
+
+//*****************************************************************************
+//
+// Values used as the ui16Feature parameter to USBHHubClearHubFeature().
+//
+//*****************************************************************************
+#define HUB_FEATURE_C_HUB_LOCAL_POWER \
+ 0
+#define HUB_FEATURE_C_HUB_OVER_CURRENT \
+ 1
+
+//*****************************************************************************
+//
+// Values used as the ui16Feature parameter to USBHHubSetPortFeature() and
+// USBHHubClearPortFeature().
+//
+//*****************************************************************************
+#define HUB_FEATURE_PORT_CONNECTION \
+ 0
+#define HUB_FEATURE_PORT_ENABLE 1
+#define HUB_FEATURE_PORT_SUSPEND \
+ 2
+#define HUB_FEATURE_PORT_OVER_CURRENT \
+ 3
+#define HUB_FEATURE_PORT_RESET 4
+#define HUB_FEATURE_PORT_POWER 8
+#define HUB_FEATURE_PORT_LOW_SPEED \
+ 9
+#define HUB_FEATURE_C_PORT_CONNECTION \
+ 16
+#define HUB_FEATURE_C_PORT_ENABLE \
+ 17
+#define HUB_FEATURE_C_PORT_SUSPEND \
+ 18
+#define HUB_FEATURE_C_PORT_OVER_CURRENT \
+ 19
+#define HUB_FEATURE_C_PORT_RESET \
+ 20
+#define HUB_FEATURE_PORT_TEST 21
+#define HUB_FEATURE_PORT_INDICATOR \
+ 22
+
+//*****************************************************************************
+//
+// Values returned via the *pui16HubStatus and *pui16HubChange parameters
+// passed to USBHHubGetHubStatus(). These may be ORed together into the
+// returned status value.
+//
+//*****************************************************************************
+#define HUB_STATUS_PWR_LOST 1
+#define HUB_STATUS_OVER_CURRENT 2
+
+//*****************************************************************************
+//
+// Values returned via the *pui16PortStatus parameter passed to
+// USBHHubGetPortStatus(). These may be ORed together into the returned status
+// value.
+//
+//*****************************************************************************
+#define HUB_PORT_STATUS_DEVICE_PRESENT \
+ 0x0001
+#define HUB_PORT_STATUS_ENABLED 0x0002
+#define HUB_PORT_STATUS_SUSPENDED \
+ 0x0004
+#define HUB_PORT_STATUS_OVER_CURRENT \
+ 0x0008
+#define HUB_PORT_STATUS_RESET 0x0010
+#define HUB_PORT_STATUS_POWERED 0x0100
+#define HUB_PORT_STATUS_LOW_SPEED \
+ 0x0200
+#define HUB_PORT_STATUS_HIGH_SPEED \
+ 0x0400
+#define HUB_PORT_STATUS_TEST_MODE \
+ 0x0800
+#define HUB_PORT_STATUS_INDICATOR_CONTROL \
+ 0x1000
+
+//*****************************************************************************
+//
+// Values returned via the *pui16PortChange parameter passed to
+// USBHHubGetPortStatus(). These may be ORed together into the returned status
+// value.
+//
+//*****************************************************************************
+#define HUB_PORT_CHANGE_DEVICE_PRESENT \
+ 0x0001
+#define HUB_PORT_CHANGE_ENABLED 0x0002
+#define HUB_PORT_CHANGE_SUSPENDED \
+ 0x0004
+#define HUB_PORT_CHANGE_OVER_CURRENT \
+ 0x0008
+#define HUB_PORT_CHANGE_RESET 0x0010
+
+//*****************************************************************************
+//
+// The prototype for the USB Hub host driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHHubCallback)(tHubInstance *psHubInstance,
+ uint32_t ui32Event, uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+//*****************************************************************************
+//
+// Public function prototypes for the HUB class driver.
+//
+//*****************************************************************************
+extern tHubInstance * USBHHubOpen(tUSBHHubCallback pfnCallback);
+extern void USBHHubClose(tHubInstance *psHubInstance);
+extern uint32_t USBHHubLPMSleep(tHubInstance *psHubInstance);
+extern uint32_t USBHHubLPMStatus(tHubInstance *psHubInstance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHHUB_H__
diff --git a/usblib/host/usbhmsc.c b/usblib/host/usbhmsc.c
new file mode 100644
index 0000000..9ef72fa
--- /dev/null
+++ b/usblib/host/usbhmsc.c
@@ -0,0 +1,756 @@
+//*****************************************************************************
+//
+// usbhmsc.c - USB MSC host driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbmsc.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhmsc.h"
+#include "usblib/host/usbhscsi.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Forward declarations for the driver open and close calls.
+//
+//*****************************************************************************
+static void *USBHMSCOpen(tUSBHostDevice *psDevice);
+static void USBHMSCClose(void *pvInstance);
+
+//*****************************************************************************
+//
+// This is the structure for an instance of a USB MSC host driver.
+//
+//*****************************************************************************
+struct tUSBHMSCInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback.
+ //
+ tUSBHMSCCallback pfnCallback;
+
+ //
+ // The Maximum LUNs
+ //
+ uint32_t ui32MaxLUN;
+
+ //
+ // The total number of blocks associated with this device.
+ //
+ uint32_t ui32NumBlocks;
+
+ //
+ // The size of the blocks associated with this device.
+ //
+ uint32_t ui32BlockSize;
+
+ //
+ // Bulk IN pipe.
+ //
+ uint32_t ui32BulkInPipe;
+
+ //
+ // Bulk OUT pipe.
+ //
+ uint32_t ui32BulkOutPipe;
+};
+
+//*****************************************************************************
+//
+// The array of USB MSC host drivers.
+//
+//*****************************************************************************
+static tUSBHMSCInstance g_sUSBHMSCDevice =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Mass Storage Class Driver that
+//! is provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHostMSCClassDriver =
+{
+ USB_CLASS_MASS_STORAGE,
+ USBHMSCOpen,
+ USBHMSCClose,
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of the MSC driver.
+//!
+//! \param psDevice is a pointer to the device information structure.
+//!
+//! This function will attempt to open an instance of the MSC driver based on
+//! the information contained in the \e psDevice structure. This call can fail
+//! if there are not sufficient resources to open the device. The function
+//! returns a value that should be passed back into USBMSCClose() when the
+//! driver is no longer needed.
+//!
+//! \return The function will return a pointer to a MSC driver instance.
+//
+//*****************************************************************************
+static void *
+USBHMSCOpen(tUSBHostDevice *psDevice)
+{
+ int32_t i32Idx;
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+
+ //
+ // Don't allow the device to be opened without closing first.
+ //
+ if(g_sUSBHMSCDevice.psDevice)
+ {
+ return(0);
+ }
+
+ //
+ // Save the device pointer.
+ //
+ g_sUSBHMSCDevice.psDevice = psDevice;
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+
+ //
+ // Loop through the endpoints of the device.
+ //
+ for(i32Idx = 0; i32Idx < 3; i32Idx++)
+ {
+ //
+ // Get the first endpoint descriptor.
+ //
+ psEndpointDescriptor =
+ USBDescGetInterfaceEndpoint(psInterface, i32Idx,
+ psDevice->ui32ConfigDescriptorSize);
+
+ //
+ // If no more endpoints then break out.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ break;
+ }
+
+ //
+ // See if this is a bulk endpoint.
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_BULK)
+ {
+ //
+ // See if this is bulk IN or bulk OUT.
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ //
+ // Allocate the USB Pipe for this Bulk IN endpoint.
+ //
+ g_sUSBHMSCDevice.ui32BulkInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN_DMA,
+ psDevice,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0);
+ //
+ // Configure the USB pipe as a Bulk IN endpoint.
+ //
+ USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ else
+ {
+ //
+ // Allocate the USB Pipe for this Bulk OUT endpoint.
+ //
+ g_sUSBHMSCDevice.ui32BulkOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT_DMA,
+ psDevice,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0);
+ //
+ // Configure the USB pipe as a Bulk OUT endpoint.
+ //
+ USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkOutPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ }
+ }
+
+ //
+ // If the callback exists, call it with an Open event.
+ //
+ if(g_sUSBHMSCDevice.pfnCallback != 0)
+ {
+ g_sUSBHMSCDevice.pfnCallback(&g_sUSBHMSCDevice, MSC_EVENT_OPEN, 0);
+ }
+
+
+ g_sUSBHMSCDevice.ui32MaxLUN = 0xffffffff;
+
+ //
+ // Return the only instance of this device.
+ //
+ return(&g_sUSBHMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of the MSC driver.
+//!
+//! \param pvInstance is an instance pointer that needs to be released.
+//!
+//! This function will free up any resources in use by the MSC driver instance
+//! that is passed in. The \e pvInstance pointer should be a valid value that
+//! was returned from a call to USBMSCOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+USBHMSCClose(void *pvInstance)
+{
+ //
+ // Do nothing if there is not a driver open.
+ //
+ if(g_sUSBHMSCDevice.psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ g_sUSBHMSCDevice.psDevice = 0;
+
+ //
+ // Free the Bulk IN pipe.
+ //
+ if(g_sUSBHMSCDevice.ui32BulkInPipe != 0)
+ {
+ USBHCDPipeFree(g_sUSBHMSCDevice.ui32BulkInPipe);
+ }
+
+ //
+ // Free the Bulk OUT pipe.
+ //
+ if(g_sUSBHMSCDevice.ui32BulkOutPipe != 0)
+ {
+ USBHCDPipeFree(g_sUSBHMSCDevice.ui32BulkOutPipe);
+ }
+
+ //
+ // If the callback exists then call it.
+ //
+ if(g_sUSBHMSCDevice.pfnCallback != 0)
+ {
+ g_sUSBHMSCDevice.pfnCallback(&g_sUSBHMSCDevice, MSC_EVENT_CLOSE, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function retrieves the maximum number of the logical units on a
+//! mass storage device.
+//!
+//! \param psDevice is the device instance pointer for this request.
+//! \param ui32Interface is the interface number on the device specified by the
+//! \e ui32Address parameter.
+//! \param pui8MaxLUN is the byte value returned from the device for the
+//! device's maximum logical unit.
+//!
+//! The device will return one byte of data that contains the maximum LUN
+//! supported by the device. For example, if the device supports four LUNs
+//! then the LUNs would be numbered from 0 to 3 and the return value would be
+//! 3. If no LUN is associated with the device, the value returned shall be 0.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+USBHMSCGetMaxLUN(tUSBHostDevice *psDevice, uint32_t ui32Interface,
+ uint8_t *pui8MaxLUN)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific interface IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE;
+
+ //
+ // Request a the Max LUN for this interface.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_MAX_LUN;
+ sSetupPacket.wValue = 0;
+
+ //
+ // Indicate the interface to use.
+ //
+ sSetupPacket.wIndex = (uint16_t)ui32Interface;
+
+ //
+ // Only request a single byte of data.
+ //
+ sSetupPacket.wLength = 1;
+
+ //
+ // Put the setup packet in the buffer and send the command.
+ //
+ if(USBHCDControlTransfer(0, &sSetupPacket, psDevice, pui8MaxLUN, 1,
+ MAX_PACKET_SIZE_EP0) != 1)
+ {
+ *pui8MaxLUN = 0;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function checks if a drive is ready to be accessed.
+//!
+//! \param psMSCInstance is the device instance to use for this read.
+//!
+//! This function checks if the current device is ready to be accessed.
+//! It uses the \e psMSCInstance parameter to determine which device to check
+//! and returns zero when the device is ready. Any non-zero return code
+//! indicates that the device was not ready.
+//!
+//! \return This function returns zero if the device is ready and it
+//! returns a other value if the device is not ready or if an error occurred.
+//
+//*****************************************************************************
+int32_t
+USBHMSCDriveReady(tUSBHMSCInstance *psMSCInstance)
+{
+ uint8_t ui8MaxLUN, pui8Buffer[SCSI_INQUIRY_DATA_SZ];
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Only request the maximum number of LUNs once.
+ //
+ if(g_sUSBHMSCDevice.ui32MaxLUN == 0xffffffff)
+ {
+ //
+ // Get the Maximum LUNs on this device.
+ //
+ USBHMSCGetMaxLUN(g_sUSBHMSCDevice.psDevice,
+ g_sUSBHMSCDevice.psDevice->ui32Interface, &ui8MaxLUN);
+
+ //
+ // Save the Maximum number of LUNs on this device.
+ //
+ g_sUSBHMSCDevice.ui32MaxLUN = ui8MaxLUN;
+ }
+
+ //
+ // Just return if the device is returning not present.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ if(USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ if((pui8Buffer[SCSI_RS_SKEY] == SCSI_RS_KEY_UNIT_ATTN) &&
+ (pui8Buffer[SCSI_RS_SKEY_AD_SKEY] == SCSI_RS_KEY_NOTPRSNT))
+ {
+ return(-1);
+ }
+
+ //
+ // Issue a SCSI Inquiry to get basic information on the device
+ //
+ ui32Size = SCSI_INQUIRY_DATA_SZ;
+ if((USBHSCSIInquiry(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS))
+ {
+ return(-1);
+ }
+
+ //
+ // Get the size of the drive.
+ //
+ ui32Size = SCSI_INQUIRY_DATA_SZ;
+ if(USBHSCSIReadCapacity(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Read Capacity command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+
+ //
+ // If the read capacity failed then check if the drive is ready.
+ //
+ if(USBHSCSITestUnitReady(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe) !=
+ SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Test Unit Ready command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+ }
+
+ return(-1);
+ }
+ else
+ {
+ //
+ // Read the block size out, value is stored big endian.
+ //
+ psMSCInstance->ui32BlockSize =
+ (pui8Buffer[7] | (pui8Buffer[6] << 8) | pui8Buffer[5] << 16 |
+ (pui8Buffer[4] << 24));
+
+ //
+ // Read the block size out.
+ //
+ psMSCInstance->ui32NumBlocks =
+ (pui8Buffer[3] | (pui8Buffer[2] << 8) | pui8Buffer[1] << 16 |
+ (pui8Buffer[0] << 24));
+ }
+
+ //
+ // See if the drive is ready to use.
+ //
+ if(USBHSCSITestUnitReady(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe) !=
+ SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Test Unit Ready command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function should be called before any devices are present to enable
+//! the mass storage device class driver.
+//!
+//! \param ui32Drive is the drive number to open.
+//! \param pfnCallback is the driver callback for any mass storage events.
+//!
+//! This function is called to open an instance of a mass storage device. It
+//! should be called before any devices are connected to allow for proper
+//! notification of drive connection and disconnection. The \e ui32Drive
+//! parameter is a zero based index of the drives present in the system.
+//! There are a constant number of drives, and this number should only
+//! be greater than 0 if there is a USB hub present in the system. The
+//! application should also provide the \e pfnCallback to be notified of mass
+//! storage related events like device enumeration and device removal.
+//!
+//! \return This function will return the driver instance to use for the other
+//! mass storage functions. If there is no driver available at the time of
+//! this call, this function will return zero.
+//
+//*****************************************************************************
+tUSBHMSCInstance *
+USBHMSCDriveOpen(uint32_t ui32Drive, tUSBHMSCCallback pfnCallback)
+{
+ //
+ // Only the first drive is supported and only one callback is supported.
+ //
+ if((ui32Drive != 0) || (g_sUSBHMSCDevice.pfnCallback))
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback.
+ //
+ g_sUSBHMSCDevice.pfnCallback = pfnCallback;
+
+ //
+ // Return the requested device instance.
+ //
+ return(&g_sUSBHMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called to release a drive instance.
+//!
+//! \param psMSCInstance is the device instance that is to be released.
+//!
+//! This function is called when an MSC drive is to be released in preparation
+//! for shutdown or a switch to USB device mode, for example. Following this
+//! call, the drive is available for other clients who may open it again using
+//! a call to USBHMSCDriveOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHMSCDriveClose(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Close the drive (if it is already open)
+ //
+ USBHMSCClose((void *)psMSCInstance);
+
+ //
+ // Clear the callback indicating that the device is now closed.
+ //
+ psMSCInstance->pfnCallback = 0;
+}
+
+//*****************************************************************************
+//
+//! This function performs a block read to an MSC device.
+//!
+//! \param psMSCInstance is the device instance to use for this read.
+//! \param ui32LBA is the logical block address to read on the device.
+//! \param pui8Data is a pointer to the returned data buffer.
+//! \param ui32NumBlocks is the number of blocks to read from the device.
+//!
+//! This function will perform a block sized read from the device associated
+//! with the \e psMSCInstance parameter. The \e ui32LBA parameter specifies
+//! the logical block address to read on the device. This function will only
+//! perform \e ui32NumBlocks block sized reads. In most cases this is a read
+//! of 512 bytes of data. The \e *pui8Data buffer should be at least
+//! \e ui32NumBlocks * 512 bytes in size.
+//!
+//! \return The function returns zero for success and any negative value
+//! indicates a failure.
+//
+//*****************************************************************************
+int32_t
+USBHMSCBlockRead(tUSBHMSCInstance *psMSCInstance, uint32_t ui32LBA,
+ uint8_t *pui8Data, uint32_t ui32NumBlocks)
+{
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Calculate the actual byte size of the read.
+ //
+ ui32Size = psMSCInstance->ui32BlockSize * ui32NumBlocks;
+
+ //
+ // Perform the SCSI read command.
+ //
+ if(USBHSCSIRead10(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, ui32LBA, pui8Data,
+ &ui32Size, ui32NumBlocks) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function performs a block write to an MSC device.
+//!
+//! \param psMSCInstance is the device instance to use for this write.
+//! \param ui32LBA is the logical block address to write on the device.
+//! \param pui8Data is a pointer to the data to write out.
+//! \param ui32NumBlocks is the number of blocks to write to the device.
+//!
+//! This function will perform a block sized write to the device associated
+//! with the \e psMSCInstance parameter. The \e ui32LBA parameter specifies
+//! the logical block address to write on the device. This function will only
+//! perform \e ui32NumBlocks block sized writes. In most cases this is a write
+//! of 512 bytes of data. The \e *pui8Data buffer should contain at least
+//! \e ui32NumBlocks * 512 bytes in size to prevent unwanted data being written
+//! to the device.
+//!
+//! \return The function returns zero for success and any negative value
+//! indicates a failure.
+//
+//*****************************************************************************
+int32_t
+USBHMSCBlockWrite(tUSBHMSCInstance *psMSCInstance, uint32_t ui32LBA,
+ uint8_t *pui8Data, uint32_t ui32NumBlocks)
+{
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Calculate the actual byte size of the write.
+ //
+ ui32Size = psMSCInstance->ui32BlockSize * ui32NumBlocks;
+
+ //
+ // Perform the SCSI write command.
+ //
+ if(USBHSCSIWrite10(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, ui32LBA, pui8Data,
+ &ui32Size, ui32NumBlocks) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psMSCInstance is the host mass storage class instance that was
+//! returned from the call to USBHMSCDriveOpen().
+//!
+//! This function forwards a request from an application to the mass storage
+//! device class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHMSCLPMSleep(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psMSCInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psMSCInstance is the host mass storage class instance that was
+//! returned from the call to USBHMSCDriveOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHMSCLPMStatus(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psMSCInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhmsc.h b/usblib/host/usbhmsc.h
new file mode 100644
index 0000000..f163b71
--- /dev/null
+++ b/usblib/host/usbhmsc.h
@@ -0,0 +1,99 @@
+//*****************************************************************************
+//
+// usbhmsc.h - Definitions for the USB MSC host driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHMSC_H__
+#define __USBHMSC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHMSCInstance tUSBHMSCInstance;
+
+//*****************************************************************************
+//
+// These defines are the the events that will be passed in the \e ui32Event
+// parameter of the callback from the driver.
+//
+//*****************************************************************************
+#define MSC_EVENT_OPEN 1
+#define MSC_EVENT_CLOSE 2
+
+//*****************************************************************************
+//
+// The prototype for the USB MSC host driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHMSCCallback)(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32Event,
+ void *pvEventData);
+
+//*****************************************************************************
+//
+// Prototypes for the USB MSC host driver APIs.
+//
+//*****************************************************************************
+extern tUSBHMSCInstance * USBHMSCDriveOpen(uint32_t ui32Drive,
+ tUSBHMSCCallback pfnCallback);
+extern void USBHMSCDriveClose(tUSBHMSCInstance *psMSCInstance);
+extern int32_t USBHMSCDriveReady(tUSBHMSCInstance *psMSCInstance);
+extern int32_t USBHMSCBlockRead(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t ui32NumBlocks);
+extern int32_t USBHMSCBlockWrite(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t ui32NumBlocks);
+extern uint32_t USBHMSCLPMSleep(tUSBHMSCInstance *psMSCInstance);
+extern uint32_t USBHMSCLPMStatus(tUSBHMSCInstance *psMSCInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHMSC_H__
diff --git a/usblib/host/usbhost.h b/usblib/host/usbhost.h
new file mode 100644
index 0000000..1d4c455
--- /dev/null
+++ b/usblib/host/usbhost.h
@@ -0,0 +1,295 @@
+//*****************************************************************************
+//
+// usbhost.h - Host specific definitions for the USB host library.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHOST_H__
+#define __USBHOST_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_hcd
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the type used to identify what the pipe is currently in use for.
+//
+//*****************************************************************************
+#define USBHCD_PIPE_UNUSED 0x00100000
+#define USBHCD_PIPE_CONTROL 0x00130000
+#define USBHCD_PIPE_BULK_OUT 0x00210000
+#define USBHCD_PIPE_BULK_IN 0x00220000
+#define USBHCD_PIPE_INTR_OUT 0x00410000
+#define USBHCD_PIPE_INTR_IN 0x00420000
+#define USBHCD_PIPE_ISOC_OUT 0x00810000
+#define USBHCD_PIPE_ISOC_IN 0x00820000
+#define USBHCD_PIPE_ISOC_OUT_DMA 0x01810000
+#define USBHCD_PIPE_ISOC_IN_DMA 0x01820000
+#define USBHCD_PIPE_BULK_OUT_DMA 0x01210000
+#define USBHCD_PIPE_BULK_IN_DMA 0x01220000
+
+//*****************************************************************************
+//
+// These are the defines that are used with USBHCDPowerConfigInit().
+//
+//*****************************************************************************
+#define USBHCD_FAULT_LOW 0x00000010
+#define USBHCD_FAULT_HIGH 0x00000030
+#define USBHCD_FAULT_VBUS_NONE 0x00000000
+#define USBHCD_FAULT_VBUS_TRI 0x00000140
+#define USBHCD_FAULT_VBUS_DIS 0x00000400
+#define USBHCD_VBUS_MANUAL 0x00000004
+#define USBHCD_VBUS_AUTO_LOW 0x00000002
+#define USBHCD_VBUS_AUTO_HIGH 0x00000003
+#define USBHCD_VBUS_FILTER 0x00010000
+
+//*****************************************************************************
+//
+// These are the defines that are used with USBHCDLPMStatus().
+//
+//*****************************************************************************
+#define USBHCD_LPM_AVAIL 0x00000000
+#define USBHCD_LPM_ERROR 0x00000001
+#define USBHCD_LPM_PENDING 0x00000002
+
+//*****************************************************************************
+//
+//! This macro is used to declare an instance of an Event driver for the USB
+//! library.
+//!
+//! \param VarName is the name of the variable.
+//! \param pfnOpen is the callback for the Open call to this driver. This
+//! value is currently reserved and should be set to 0.
+//! \param pfnClose is the callback for the Close call to this driver. This
+//! value is currently reserved and should be set to 0.
+//! \param pfnEvent is the callback that will be called for various USB events.
+//!
+//! The first parameter is the actual name of the variable that will
+//! be declared by this macro. The second and third parameter are reserved
+//! for future functionality and are unused and should be set to zero. The
+//! last parameter is the actual callback function and is specified as
+//! a function pointer of the type:
+//!
+//! \verbatim
+//! void (*pfnEvent)(void *pvData);
+//! \endverbatim
+//!
+//! When the \e pfnEvent function is called the void pointer that is passed in
+//! as a parameter should be cast to a pointer to a structure of type
+//! tEventInfo. This will contain the event that caused the pfnEvent function
+//! to be called.
+//
+//*****************************************************************************
+#define DECLARE_EVENT_DRIVER(VarName, pfnOpen, pfnClose, pfnEvent) \
+void IntFn(void *pvData); \
+const tUSBHostClassDriver VarName = \
+{ \
+ USB_CLASS_EVENTS, \
+ 0, \
+ 0, \
+ pfnEvent \
+}
+
+//*****************************************************************************
+//
+// This is the type definition a callback for events on USB Pipes allocated
+// by USBHCDPipeAlloc().
+//
+// \param ui32Pipe is well the pipe
+// \param ui32Event is well the event
+//
+// This prototype is used by any Pipe callbacks that are used in the host
+// class drivers. These functions typically handle data events like
+// USB_EVENT_RX_AVAILABLE or USB_EVENT_TX_COMPLETE but can be sent other events
+// depending on the USB host class in use. See the documentation for the
+// individual classes for the valid events for that class.
+//
+// \return None.
+//
+//*****************************************************************************
+typedef void (* tHCDPipeCallback)(uint32_t ui32Pipe, uint32_t ui32Event);
+
+//*****************************************************************************
+//
+// Predeclare the private tUSBHostDevice structure.
+//
+//*****************************************************************************
+typedef struct tUSBHostDevice tUSBHostDevice;
+
+//*****************************************************************************
+//
+//! This structure defines a USB host class driver interface, it is parsed to
+//! find a USB class driver once a USB device is enumerated.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The interface class that this device class driver supports.
+ //
+ uint32_t ui32InterfaceClass;
+
+ //
+ //! The function is called when this class of device has been detected.
+ //
+ void *(*pfnOpen)(tUSBHostDevice *psDevice);
+
+ //
+ //! The function is called when the device, originally opened with a call
+ //! to the pfnOpen function, is disconnected.
+ //
+ void (*pfnClose)(void *pvInstance);
+
+ //
+ //! This is the optional interrupt handler that will be called when an
+ //! endpoint associated with this device instance generates an interrupt.
+ //
+ void (*pfnIntHandler)(void *pvInstance);
+}
+tUSBHostClassDriver;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If the g_USBEventDriver is included in the host controller driver list then
+// this function must be provided by the application.
+//
+//*****************************************************************************
+extern void USBHCDEvents(void *pvData);
+
+//*****************************************************************************
+//
+// Prototypes for the USB Host controller APIs.
+//
+//*****************************************************************************
+extern void USBHCDMain(void);
+extern int32_t USBHCDEventEnable(uint32_t ui32Index, void *pvEventDriver,
+ uint32_t ui32Event);
+extern int32_t USBHCDEventDisable(uint32_t ui32Index, void *pvEventDriver,
+ uint32_t ui32Event);
+extern void USBHCDInit(uint32_t ui32Index, void *pvData,
+ uint32_t ui32Size);
+extern void USBHCDPowerConfigInit(uint32_t ui32Index,
+ uint32_t ui32Flags);
+extern uint32_t USBHCDPowerConfigGet(uint32_t ui32Index);
+extern uint32_t USBHCDPowerConfigSet(uint32_t ui32Index,
+ uint32_t ui32Config);
+extern uint32_t USBHCDPowerAutomatic(uint32_t ui32Index);
+extern void USBHCDRegisterDrivers(uint32_t ui32Index,
+ const tUSBHostClassDriver * const *ppsHClassDrvrs,
+ uint32_t ui32NumDrivers);
+extern void USBHCDTerm(uint32_t ui32Index);
+extern void USBHCDSetConfig(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Configuration);
+extern void USBHCDSetInterface(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Interface,
+ uint32_t ui32AltSetting);
+extern void USBHCDSuspend(uint32_t ui32Index);
+extern void USBHCDResume(uint32_t ui32Index);
+extern void USBHCDReset(uint32_t ui32Index);
+extern void USBHCDPipeFree(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeAlloc(uint32_t ui32Index,
+ uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice,
+ tHCDPipeCallback pfnCallback);
+extern uint32_t USBHCDPipeAllocSize(uint32_t ui32Index,
+ uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice,
+ uint32_t ui32FIFOSize,
+ tHCDPipeCallback pfnCallback);
+extern uint32_t USBHCDPipeConfig(uint32_t ui32Pipe, uint32_t ui32MaxPayload,
+ uint32_t ui32Interval,
+ uint32_t ui32TargetEndpoint);
+extern uint32_t USBHCDPipeStatus(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeWrite(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeRead(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeSchedule(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeTransferSizeGet(uint32_t ui32Pipe);
+extern void USBHCDPipeDataAck(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeReadNonBlocking(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDStringDescriptorGet(tUSBHostDevice *psDevice,
+ uint8_t *pui8Buffer,
+ uint32_t ui32Size,
+ uint32_t ui32LangID,
+ uint32_t ui32StringIndex);
+extern uint32_t USBHCDControlTransfer(uint32_t ui32Index,
+ tUSBRequest *psSetupPacket,
+ tUSBHostDevice *psDevice,
+ uint8_t *pui8Data, uint32_t ui32Size,
+ uint32_t ui32MaxPacketSize);
+extern void USB0HostIntHandler(void);
+
+extern uint8_t USBHCDDevHubPort(uint32_t ui32Instance);
+extern uint8_t USBHCDDevAddress(uint32_t ui32Instance);
+extern uint8_t USBHCDDevClass(uint32_t ui32Instance, uint32_t ui32Interface);
+extern uint8_t USBHCDDevSubClass(uint32_t ui32Instance,
+ uint32_t ui32Interface);
+extern uint8_t USBHCDDevProtocol(uint32_t ui32Instance,
+ uint32_t ui32Interface);
+extern bool USBHCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature);
+extern uint32_t USBHCDLPMSleep(tUSBHostDevice *psDevice);
+extern void USBHCDLPMResume(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// The host class drivers supported by the USB library.
+//
+//*****************************************************************************
+extern const tUSBHostClassDriver g_sUSBHostMSCClassDriver;
+extern const tUSBHostClassDriver g_sUSBHIDClassDriver;
+extern const tUSBHostClassDriver g_sUSBHostAudioClassDriver;
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHOST_H__
diff --git a/usblib/host/usbhostenum.c b/usblib/host/usbhostenum.c
new file mode 100644
index 0000000..69b8c39
--- /dev/null
+++ b/usblib/host/usbhostenum.c
@@ -0,0 +1,6284 @@
+//*****************************************************************************
+//
+// usbhostenum.c - Device enumeration code for the USB host library.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbulpi.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhub.h"
+
+#ifdef INCLUDE_DEBUG_OUTPUT
+#include "utils/uartstdio.h"
+#define DEBUG_OUTPUT UARTprintf
+#else
+#define DEBUG_OUTPUT while(0)((int32_t (*)(char *, ...))0)
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_hcd
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// External prototypes.
+//
+//*****************************************************************************
+extern tUSBMode g_iUSBMode;
+
+extern void OTGDeviceDisconnect(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// Internal function prototypes.
+//
+//*****************************************************************************
+static void USBHCDEP0StateTx(void);
+static void USBHCDEnumHandler(void);
+static void USBHCDClearFeature(uint32_t ui32DevAddress, uint32_t ui32Endpoint,
+ uint32_t ui32Feature);
+
+//*****************************************************************************
+//
+// Automatic power enable.
+//
+//*****************************************************************************
+#define USB_HOST_PWREN_AUTO 0x00000002
+
+//*****************************************************************************
+//
+// Flags used to signal between the interrupt handler and USBHCDMain().
+//
+//*****************************************************************************
+#define INT_EVENT_VBUS_ERR 0x01
+#define INT_EVENT_CONNECT 0x02
+#define INT_EVENT_DISCONNECT 0x04
+#define INT_EVENT_POWER_FAULT 0x08
+#define INT_EVENT_SOF 0x10
+#define INT_EVENT_ENUM 0x20
+#define INT_EVENT_LPM_PEND 0x40
+#define INT_EVENT_LPM 0x80
+
+//*****************************************************************************
+//
+// Flags used with the tUSBHostDevice.ui32Flags structure member.
+//
+//*****************************************************************************
+#define USBHDEV_FLAG_NOTIFYINT 0x00000001
+#define USBHDEV_FLAG_LPMPEND 0x00000002
+#define USBHDEV_FLAG_LPMERROR 0x00000004
+#define USBHDEV_FLAG_ALLOCATED 0x80000000
+
+//*****************************************************************************
+//
+// This holds the current power configuration that is used when USBHCDInit()
+// is called.
+//
+//*****************************************************************************
+static uint32_t g_ui32PowerConfig = USBHCD_VBUS_AUTO_HIGH;
+
+//*****************************************************************************
+//
+// The states for endpoint 0 during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint 0.
+ //
+ eEP0StateIdle,
+
+ //
+ // Setup packet is expecting data IN.
+ //
+ eEP0StateSetupIN,
+
+ //
+ // Setup packet is sending data OUT.
+ //
+ eEP0StateSetupOUT,
+
+ //
+ // The USB device is receiving data from the device due to an SETUP IN
+ // request.
+ //
+ eEP0StateRx,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ eEP0StateStatus,
+
+ //
+ // This state is for when a response only has a status phase and no
+ // data phase.
+ //
+ eEP0StateStatusIN,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ eEP0StateStall,
+
+ //
+ // An error has occurred on endpoint 0.
+ //
+ eEP0StateError
+}
+tEP0State;
+
+//*****************************************************************************
+//
+// This structure holds the full state for the device enumeration.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint 0.
+ //
+ uint8_t *pui8Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_DeviceState.pEP0Data data buffer.
+ //
+ volatile uint32_t ui32BytesRemaining;
+
+ //
+ // The amount of data being sent/received due to a request.
+ //
+ uint32_t ui32DataSize;
+
+ //
+ // This is the current device address in use by endpoint 0.
+ //
+ uint32_t ui32DevAddress;
+
+ //
+ // The maximum packet size for the device responding to the setup packet.
+ //
+ uint32_t ui32MaxPacketSize;
+
+ //
+ // The host controller's state.
+ //
+ tEP0State iState;
+}
+tHostState;
+
+//*****************************************************************************
+//
+// This variable holds the current state of endpoint 0.
+//
+//*****************************************************************************
+static volatile tHostState g_sUSBHEP0State =
+{
+ 0, // pui8Data
+ 0, // ui32BytesRemaining
+ 0, // ui32DataSize
+ 0, // ui32DevAddress
+ 0, // ui32MaxPacketSize
+ eEP0StateIdle // iState
+};
+
+//*****************************************************************************
+//
+// The global delay time for use by SysCtlDelay() function. This is
+// initialized to an appropriate value for a 50MHz clock. The correct value
+// will be set in USBHCDInit().
+//
+//*****************************************************************************
+static uint32_t g_ui32Tickms = 0;
+static volatile uint32_t g_ui32CurrentTick = 0;
+
+//*****************************************************************************
+//
+// This is 480000000/60000000 or a PLL Divide of 8.
+//
+//*****************************************************************************
+static uint32_t g_ui32PLLDiv = 8;
+
+//*****************************************************************************
+//
+// Holds the ULPI configuration.
+//
+//*****************************************************************************
+static uint32_t g_ui32ULPISupport;
+
+//*****************************************************************************
+//
+// The current active drivers.
+//
+//*****************************************************************************
+static int32_t g_pi32USBHActiveDriver[MAX_USB_DEVICES + 1];
+static void *g_ppvDriverInstance[MAX_USB_DEVICES + 1];
+
+//*****************************************************************************
+//
+// This is the structure used to hold the information for a given USB pipe
+// that is attached to a device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The current address for this pipe.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // The current address for this pipe.
+ //
+ uint8_t ui8EPNumber;
+
+ //
+ // The DMA channel assigned to this endpoint.
+ //
+ uint8_t ui8DMAChannel;
+
+ //
+ // The current type for this pipe.
+ //
+ uint32_t ui32Type;
+
+ //
+ // The millisecond interval for this pipe.
+ //
+ uint32_t ui32Interval;
+
+ //
+ // The next tick value to trigger and event on this pipe.
+ //
+ uint32_t ui32NextEventTick;
+
+ //
+ // The current call back for this pipe.
+ //
+ tHCDPipeCallback pfnCallback;
+
+ //
+ // The pointer to which IN data must be copied.
+ //
+ uint8_t *pui8ReadPtr;
+
+ //
+ // The size of the buffer pointed to by pui8ReadPtr.
+ //
+ uint32_t ui32ReadSize;
+
+ //
+ // The number of bytes read, which can be less than ui32ReadSize.
+ //
+ uint32_t ui32DataRead;
+
+ //
+ // The state of a given USB pipe.
+ //
+ volatile enum
+ {
+ ePipeReading,
+ ePipeReadDMA,
+ ePipeReadDMAWait,
+ ePipeReadSingle,
+ ePipeDataReady,
+ ePipeDataSent,
+ ePipeWriting,
+ ePipeWriteDMA,
+ ePipeWriteDMASend,
+ ePipeWriteDMAWait,
+ ePipeWriteSingle,
+ ePipeStalled,
+ ePipeError,
+ ePipeIdle,
+ ePipeDisabled
+ }
+ iState;
+
+ //
+ // The actual FIFO offset allocated to this endpoint.
+ //
+ uint16_t ui16FIFOAddr;
+
+ //
+ // The size of the FIFO entry based on the size parameter. These are
+ // equivalent to the USB_FIFO_SZ_* values in usb.h.
+ //
+ uint8_t ui8FIFOSize;
+
+ //
+ // The bit offset in the allocation structure.
+ //
+ uint8_t ui8FIFOBitOffset;
+}
+tUSBHCDPipe;
+
+//*****************************************************************************
+//
+// The internal state of the device.
+//
+//*****************************************************************************
+typedef enum
+{
+ eHCDDevDisconnected,
+ eHCDDevConnected,
+ eHCDDevConnectedHub,
+ eHCDDevRequest,
+ eHCDDevReset,
+ eHCDDevAddressed,
+ eHCDDevConfigured,
+ eHCDDevGetStrings,
+ eHCDDevError,
+ eHCDVBUSError,
+ eHCDPowerFault,
+ eHCDIdle
+}
+tUSBHDeviceState;
+
+static void ProcessUSBDeviceStateMachine(tUSBHDeviceState iOldState,
+ uint32_t ui32DevIndex);
+
+//*****************************************************************************
+//
+// This is a fixed number as it relates to the maximum number of USB pipes
+// available on any USB controller. The actual number on a given device may
+// be less than this number.
+//
+//*****************************************************************************
+#define MAX_NUM_PIPES 15
+
+//*****************************************************************************
+//
+// This is a fixed number as it relates to the number of USB pipes available
+// in the USB controller.
+//
+//*****************************************************************************
+#define MAX_NUM_DMA_CHANNELS 6
+
+//*****************************************************************************
+//
+// Marker for an unused DMA channel slot.
+//
+//*****************************************************************************
+#define USBHCD_DMA_UNUSED 0xff
+
+//*****************************************************************************
+//
+// These definitions are used to manipulate the values returned as allocated
+// USB pipes.
+//
+//*****************************************************************************
+#define EP_PIPE_TYPE_LOW_SPEED 0x02000000
+#define EP_PIPE_USE_UDMA 0x01000000
+#define EP_PIPE_TYPE_ISOC 0x00800000
+#define EP_PIPE_TYPE_INTR 0x00400000
+#define EP_PIPE_TYPE_BULK 0x00200000
+#define EP_PIPE_TYPE_CONTROL 0x00100000
+#define EP_PIPE_TYPE_IN 0x00020000
+#define EP_PIPE_TYPE_OUT 0x00010000
+#define EP_PIPE_IDX_M 0x0000ffff
+
+//*****************************************************************************
+//
+// This creates a USB pipe handle from an index.
+//
+//*****************************************************************************
+#define OUT_PIPE_HANDLE(ui32Idx) \
+ (g_sUSBHCD.psUSBOUTPipes[ui32Idx].ui32Type | \
+ ui32Idx)
+#define IN_PIPE_HANDLE(ui32Idx) (g_sUSBHCD.psUSBINPipes[ui32Idx].ui32Type | \
+ ui32Idx)
+
+//*****************************************************************************
+//
+// Converts from an endpoint specifier to the offset of the endpoint's
+// control/status registers.
+//
+//*****************************************************************************
+#define EP_OFFSET(Endpoint) (Endpoint - 0x10)
+
+//*****************************************************************************
+//
+// This structure holds the state information for a given host controller.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint32_t ui32USBBase;
+
+ tUSBHCDPipe sUSBControlPipe;
+ tUSBHCDPipe psUSBOUTPipes[MAX_NUM_PIPES];
+ tUSBHCDPipe psUSBINPipes[MAX_NUM_PIPES];
+
+ //
+ // Each devices state. We support a total of (MAX_USB_DEVICES + 1) devices
+ // to allow for the use if MAX_USB_DEVICES through a single hub (which is
+ // itself a device).
+ //
+ tUSBHostDevice psUSBDevice[MAX_USB_DEVICES + 1];
+
+ //
+ // Holds the current state of the device.
+ //
+ volatile tUSBHDeviceState piDeviceState[MAX_USB_DEVICES + 1];
+
+ //
+ // Pointer to the memory pool for this controller.
+ //
+ void *pvPool;
+
+ //
+ // The pool size for this controller.
+ //
+ uint32_t ui32PoolSize;
+
+ //
+ // The number of endpoint pairs supported by the controller.
+ //
+ uint32_t ui32NumEndpoints;
+
+ //
+ // The class drivers for this controller.
+ //
+ const tUSBHostClassDriver * const *ppsClassDrivers;
+
+ //
+ // The number of class drivers.
+ //
+ uint32_t ui32NumClassDrivers;
+
+ //
+ // This is the index in the driver list of the event driver.
+ //
+ int32_t i32EventDriver;
+
+ //
+ // These are the generic event information used by the event driver.
+ //
+ uint32_t ui32EventEnables;
+
+ uint32_t ui32Class;
+
+ //
+ // The DMA instance information for this class.
+ //
+ tUSBDMAInstance *psDMAInstance;
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+
+ //
+ // The pending interrupt events that are processed in USBHCDMain().
+ //
+ uint32_t ui32IntEvents;
+
+ //
+ // Features.
+ //
+ uint32_t ui32Features;
+
+ //
+ // The host initiated resume duration in us.
+ //
+ uint32_t ui32LPMHIRD;
+}
+tUSBHCD;
+
+//*****************************************************************************
+//
+// The global to hold all of the state information for a given host controller.
+//
+//*****************************************************************************
+static tUSBHCD g_sUSBHCD;
+
+//*****************************************************************************
+//
+// Allocates the memory needed to support configuration descriptors for
+// devices.
+//
+//*****************************************************************************
+uint32_t
+ConfigDescAlloc(tUSBHostDevice *psDevice, uint32_t ui32Size)
+{
+ uint32_t ui32Idx, ui32BlockSize, ui32PoolSize;
+ uint8_t *pui8Pool;
+
+ if(g_sUSBHCD.psUSBDevice[0].psConfigDescriptor == 0)
+ {
+ //
+ // 32 bit align the allocation.
+ //
+ ui32Size = (ui32Size + 3) & ~3;
+
+ if(g_sUSBHCD.ui32PoolSize < ui32Size)
+ {
+ return(0);
+ }
+
+ //
+ // Allocate the root connection to the device.
+ //
+ g_sUSBHCD.psUSBDevice[0].psConfigDescriptor = g_sUSBHCD.pvPool;
+ g_sUSBHCD.psUSBDevice[0].ui32ConfigDescriptorSize = ui32Size;
+
+ //
+ // Allocate the hub memory pools (these can end up null).
+ //
+ pui8Pool = (uint8_t *)g_sUSBHCD.pvPool + ui32Size;
+ ui32PoolSize = g_sUSBHCD.ui32PoolSize - ui32Size;
+
+ //
+ // Divide the pool up into blocks, one for each supported port. We make
+ // sure that each block is a multiple of 4 bytes.
+ //
+ ui32BlockSize = (ui32PoolSize / MAX_USB_DEVICES) & ~3;
+ for(ui32Idx = 1; ui32Idx < MAX_USB_DEVICES; ui32Idx++)
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].psConfigDescriptor =
+ (tConfigDescriptor *)(pui8Pool +
+ (ui32Idx * ui32BlockSize));
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32ConfigDescriptorSize =
+ ui32BlockSize;
+ }
+ }
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+// Frees the memory needed to support configuration descriptors for
+// devices.
+//
+//*****************************************************************************
+void
+ConfigDescFree(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Idx;
+
+ //
+ // If this is the root device then deallocate.
+ //
+ if(&g_sUSBHCD.psUSBDevice[0] == psDevice)
+ {
+ for(ui32Idx = 0; ui32Idx < MAX_USB_DEVICES; ui32Idx++)
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &=
+ ~USBHDEV_FLAG_ALLOCATED;
+ g_sUSBHCD.psUSBDevice[ui32Idx].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32ConfigDescriptorSize = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Return the device index from a ui32Instance value passed from an external
+// source.
+//
+//*****************************************************************************
+static uint8_t
+HCDInstanceToDevIndex(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ //
+ // Get the device instance from the instance value.
+ //
+ ui32DevIndex = (ui32Instance & 0xff);
+
+ //
+ // If the above math went negative or is too large just return 0xff.
+ //
+ if(ui32DevIndex > MAX_USB_DEVICES)
+ {
+ ui32DevIndex = 0xff;
+ }
+
+ return(ui32DevIndex);
+}
+
+//=============================================================================
+//
+// This is the internal function that will map an event to a valid event flag.
+//
+// \param ui32Event specifies which event flag to retrieve.
+//
+// \return The event flag or 0 if there is no support event flag for the
+// event specified by the \e ui32Event parameter.
+//
+//=============================================================================
+static uint32_t
+GetEventFlag(uint32_t ui32Event)
+{
+ uint32_t ui32EventFlag;
+
+ ui32EventFlag = 0;
+
+ //
+ // Search for a valid event flag for the requested event.
+ //
+ switch(ui32Event)
+ {
+ case USB_EVENT_SOF:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_SOF;
+ break;
+ }
+ case USB_EVENT_CONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_CONNECT;
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_DISCNCT;
+ break;
+ }
+ case USB_EVENT_UNKNOWN_CONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_UNKCNCT;
+ break;
+ }
+ case USB_EVENT_POWER_FAULT:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWRFAULT;
+ break;
+ }
+ case USB_EVENT_POWER_DISABLE:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWRDIS;
+ break;
+ }
+ case USB_EVENT_POWER_ENABLE:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWREN;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return(ui32EventFlag);
+}
+
+//=============================================================================
+//
+//! This function is called to enable a specific USB HCD event notification.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvEventDriver is the event driver structure that was passed into
+//! the USBHCDRegisterDrivers() function as part of the array of
+//! tUSBHostClassDriver structures.
+//! \param ui32Event is the event to enable.
+//!
+//! This function is called to enable event callbacks for a specific USB HCD
+//! event. The requested event is passed in the \e ui32Event parameter. Not
+//! all events can be enables so the function will return zero if the event
+//! provided cannot be enabled. The \e pvEventDriver is a pointer to the
+//! event driver structure that the caller passed into the
+//! USBHCDRegisterDrivers() function. This structure is typically declared
+//! with the DECLARE_EVENT_DRIVER() macro and included as part of the array
+//! of pointers to tUSBHostClassDriver structures that is passed to the
+//! USBHCDRegisterDrivers() function.
+//!
+//! \return This function returns a non-zero number if the event was
+//! successfully enabled and returns zero if the event cannot be enabled.
+//
+//=============================================================================
+int32_t
+USBHCDEventEnable(uint32_t ui32Index, void *pvEventDriver, uint32_t ui32Event)
+{
+ int32_t i32Ret;
+ uint32_t ui32EventFlag;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Default the return to fail the call unless a valid event is found.
+ //
+ i32Ret = 0;
+
+ //
+ // Get the event flag for this event.
+ //
+ ui32EventFlag = GetEventFlag(ui32Event);
+
+ //
+ // Check if there was an event flag for the corresponding event.
+ //
+ if(ui32EventFlag)
+ {
+ //
+ // Set the enable for this event.
+ //
+ g_sUSBHCD.ui32EventEnables |= ui32EventFlag;
+
+ //
+ // Indicate that the event was valid and is now enabled.
+ //
+ i32Ret = 1;
+ }
+
+ return(i32Ret);
+}
+
+//=============================================================================
+//
+//! This function is called to disable a specific USB HCD event notification.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvEventDriver is the event driver structure that was passed into
+//! the USBHCDRegisterDrivers() function as part of the array of
+//! tUSBHostClassDriver structures.
+//! \param ui32Event is the event to disable.
+//!
+//! This function is called to disable event callbacks for a specific USB HCD
+//! event. The requested event is passed in the \e ui32Event parameter. Not
+//! all events can be enables so the function will return zero if the event
+//! provided cannot be enabled. The \e pvEventDriver is a pointer to the
+//! event driver structure that the caller passed into the
+//! USBHCDRegisterDrivers() function. This structure is typically declared
+//! with the DECLARE_EVENT_DRIVER() macro and included as part of the array
+//! of pointers to tUSBHostClassDriver structures that is passed to the
+//! USBHCDRegisterDrivers() function.
+//!
+//! \return This function returns a non-zero number if the event was
+//! successfully disabled and returns zero if the event cannot be disabled.
+//
+//=============================================================================
+int32_t
+USBHCDEventDisable(uint32_t ui32Index, void *pvEventDriver, uint32_t ui32Event)
+{
+ int32_t i32Ret;
+ uint32_t ui32EventFlag;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Default the return to fail the call unless a valid event is found.
+ //
+ i32Ret = 0;
+
+ //
+ // Get the event flag for this event.
+ //
+ ui32EventFlag = GetEventFlag(ui32Event);
+
+ //
+ // Check if there was an event flag for the corresponding event.
+ //
+ if(ui32EventFlag)
+ {
+ //
+ // Clear the enable for this event.
+ //
+ g_sUSBHCD.ui32EventEnables &= ~ui32EventFlag;
+
+ //
+ // Indicate that the event was valid and is now disabled.
+ //
+ i32Ret = 1;
+ }
+
+ return(i32Ret);
+}
+
+//*****************************************************************************
+//
+// If there is an event driver this function will send out a generic connection
+// event USB_EVENT_UNKNOWN_CONNECTED indicating that an unknown connection
+// event has occurred.
+//
+//*****************************************************************************
+static void
+SendUnknownConnect(uint32_t ui32Index, uint32_t ui32Class)
+{
+ tEventInfo sEvent;
+
+ //
+ // If there is an event driver registered and it has a event handler and
+ // the USBHCD_EVFLAG_UNKCNCT is enabled then call the function.
+ //
+ sEvent.ui32Event = USB_EVENT_UNKNOWN_CONNECTED;
+ sEvent.ui32Instance = ui32Class;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_UNKCNCT);
+}
+
+//*****************************************************************************
+//
+// Internal memory allocation space is two 32-bit values where each
+// bit represents a 64 byte block in the FIFO. This requires 64 bits for
+// the 4096 bytes of FIFO available.
+//
+//*****************************************************************************
+static uint32_t g_pui32Alloc[2];
+
+//*****************************************************************************
+//
+// This function handles freeing FIFO memory that has been allocated using the
+// FIFOAlloc() function.
+//
+//*****************************************************************************
+static void
+FIFOFree(tUSBHCDPipe *psUSBPipe)
+{
+ uint32_t ui32Mask;
+
+ //
+ // Calculate the mask value to use to clear off the allocated blocks used
+ // by the USB pipe specified by psUSBPipe.
+ //
+ ui32Mask = (1 << (psUSBPipe->ui8FIFOSize - 2)) - 1;
+ ui32Mask = ui32Mask << psUSBPipe->ui8FIFOBitOffset;
+
+ //
+ // Determine which 32 bit word to access based on the size.
+ //
+ if(psUSBPipe->ui8FIFOSize > USB_FIFO_SZ_64)
+ {
+ //
+ // If the FIFO size is greater than 64 then use the upper 32 bits.
+ //
+ g_pui32Alloc[1] &= ~ui32Mask;
+ }
+ else
+ {
+ //
+ // If the FIFO size is less than or equal to 64 then use the lower
+ // 32 bits.
+ //
+ g_pui32Alloc[0] &= ~ui32Mask;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to allocate FIFO memory to a given USB pipe.
+//
+// \param psUSBPipe is the USB pipe that needs FIFO memory allocated.
+// \param ui32Size is the minimum size in bytes of the FIFO to allocate.
+//
+// This function will allocate \e ui32Size bytes to the USB pipe in the
+// \e psUSBPipe parameter. The function will fill the psUSBPipe structure
+// members ui8FIFOSize and ui8FIFOAddr with values that can be used with the
+// USBFIFOConfigSet() API. This allocation uses a first fit algorithm.
+//
+// \return This function returns the size of the block allocated.
+//
+//*****************************************************************************
+static uint32_t
+FIFOAlloc(tUSBHCDPipe *psUSBPipe, uint32_t ui32Size)
+{
+ uint32_t ui32Blocks, ui32Start, ui32BlockSize, ui32Temp, ui32Index;
+ uint16_t ui16FIFOAddr;
+
+ //
+ // Save which 32 bit value to access, the upper is for blocks greater
+ // than 64 and the lower is for block 64 or less.
+ //
+ if(ui32Size > 64)
+ {
+ ui32Index = 1;
+ }
+ else
+ {
+ ui32Index = 0;
+ }
+
+ //
+ // Initial FIFO address is 0.
+ //
+ ui16FIFOAddr = 0;
+
+ //
+ // Initialize the bit pattern and bit location.
+ //
+ ui32Blocks = 1;
+ ui32Start = 0;
+
+ //
+ // The initial block size is always the minimum size of 64 bytes.
+ //
+ ui32BlockSize = 64;
+
+ //
+ // The initial size and offset are 64 and 0.
+ //
+ psUSBPipe->ui8FIFOBitOffset = 0;
+ psUSBPipe->ui8FIFOSize = 3;
+
+ //
+ // Scan through 32 bits looking for a memory block large enough to fill
+ // the request.
+ //
+ while(ui16FIFOAddr <= 32)
+ {
+ //
+ // If the pattern is zero then it is a possible match.
+ //
+ if((g_pui32Alloc[ui32Index] & ui32Blocks) == 0)
+ {
+ //
+ // If the size is large enough then save it and break out of the
+ // loop.
+ //
+ if(ui32BlockSize >= ui32Size)
+ {
+ //
+ // Mark the memory as allocated.
+ //
+ g_pui32Alloc[ui32Index] |= ui32Blocks;
+
+ break;
+ }
+
+ //
+ // Increment the size of the FIFO block.
+ //
+ psUSBPipe->ui8FIFOSize++;
+
+ //
+ // Add in a new bit to the size of the allocation.
+ //
+ ui32Blocks = ui32Blocks | (ui32Blocks << 1) ;
+
+ //
+ // Double the current size.
+ //
+ ui32BlockSize <<= 1;
+
+ }
+ else
+ {
+ //
+ // Need to start over looking because the last allocation match
+ // failed, so reset the bit offset to the current location and the
+ // size to 64 bytes.
+ //
+ psUSBPipe->ui8FIFOBitOffset = ui16FIFOAddr;
+ psUSBPipe->ui8FIFOSize = 3;
+
+ //
+ // Reset the block size to the minimum (64 bytes).
+ //
+ ui32BlockSize = 64;
+
+ //
+ // Store the current starting bit location and set the block mask
+ // to this value.
+ //
+ ui32Start = 1 << ui16FIFOAddr;
+ ui32Blocks = ui32Start;
+ }
+
+ //
+ // Increase the address of the FIFO offset.
+ //
+ ui16FIFOAddr++;
+ }
+
+ //
+ // If there was no block large enough then fail this call.
+ //
+ if(ui16FIFOAddr > 32)
+ {
+ ui32BlockSize = 0;
+ psUSBPipe->ui16FIFOAddr = 0;
+ psUSBPipe->ui8FIFOBitOffset = 0;
+ psUSBPipe->ui8FIFOSize = 0;
+ }
+ else
+ {
+ //
+ // Calculate the offset in the FIFO.
+ //
+ ui32Temp = psUSBPipe->ui8FIFOBitOffset * 64;
+
+ //
+ // Sizes greater than 64 are allocated in the second half of the FIFO
+ // memory space.
+ //
+ if(ui32Size > 64)
+ {
+ ui32Temp += 2048;
+ }
+
+ //
+ // Convert this to the value that can be set in the USB controller.
+ //
+ psUSBPipe->ui16FIFOAddr = (uint16_t)ui32Temp;
+ }
+ return(ui32BlockSize);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current byte count of a USB HCD pipe.
+//!
+//! \param ui32Pipe is the allocated endpoint to modify.
+//!
+//! This call returns the current or last byte count for a transfer using the
+//! pipe specified by the \e ui32Pipe parameter. This is typically used to
+//! determine the actual byte count received when a \b USB_EVENT_RX_AVAILABLE
+//! occurs.
+//!
+//! \return If the call was successful, this function returns the number of
+//! bytes transfered by the USB pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeTransferSizeGet(uint32_t ui32Pipe)
+{
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ return(g_sUSBHCD.psUSBINPipes[ui32Index].ui32DataRead);
+}
+
+//*****************************************************************************
+//
+//! This function is used to allocate a USB HCD pipe.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32EndpointType is the type of endpoint that this pipe will be
+//! communicating with.
+//! \param psDevice is the device instance associated with this endpoint.
+//! \param ui32Size is the size of the FIFO in bytes.
+//! \param pfnCallback is the function that will be called when events occur on
+//! this USB Pipe.
+//!
+//! Since there are a limited number of USB HCD pipes that can be used in the
+//! host controller, this function is used to temporarily or permanently
+//! acquire one of the endpoints. Unlike the USBHCDPipeAlloc() function this
+//! function allows the caller to specify the size of the FIFO allocated to
+//! this endpoint in the \e ui32Size parameter. This function also provides a
+//! method to register a callback for status changes on this endpoint. If no
+//! callbacks are desired then the \e pfnCallback function should be set to 0.
+//! The callback should be used when using the USBHCDPipeSchedule() function
+//! so that the caller is notified when the action is complete.
+//!
+//! \return This function returns a value indicating which pipe was reserved.
+//! If the value is 0 then there were no pipes currently available. This value
+//! should be passed to any USBHCDPipe APIs to indicate which pipe is being
+//! accessed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeAllocSize(uint32_t ui32Index, uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice, uint32_t ui32Size,
+ tHCDPipeCallback pfnCallback)
+{
+ int32_t i32Idx;
+
+ uint32_t ui32HubAddr;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Find a USB pipe that is free.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ //
+ // Handle OUT Pipes.
+ //
+ if(ui32EndpointType & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // A zero address indicates free.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice == 0)
+ {
+ //
+ // Set up uDMA for the pipe.
+ //
+ if(ui32EndpointType & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel =
+ USBLibDMAChannelAllocate(g_sUSBHCD.psDMAInstance,
+ IndexToUSBEP(i32Idx + 1),
+ ui32Size,
+ USB_DMA_EP_TX |
+ USB_DMA_EP_HOST);
+
+ //
+ // If no DMA channel was available then just disable DMA
+ // on this pipe.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel == 0)
+ {
+ ui32EndpointType &= ~EP_PIPE_USE_UDMA;
+ }
+ }
+
+ //
+ // Save the endpoint type and device address and callback
+ // function.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = ui32EndpointType;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice = psDevice;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].pfnCallback = pfnCallback;
+
+ //
+ // Clear out any pending status on this endpoint in case it
+ // was in use before a allowing a new device class to use it.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ USB_HOST_OUT_STATUS);
+
+ //
+ // Make sure to reset the data toggle.
+ //
+ USBEndpointDataToggleClear(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ USB_EP_HOST_OUT);
+
+ //
+ // Initialize the endpoint as idle.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].iState = ePipeIdle;
+
+ //
+ // Allocate space in the FIFO for this endpoint.
+ //
+ if(FIFOAlloc(&g_sUSBHCD.psUSBOUTPipes[i32Idx], ui32Size) != 0)
+ {
+ //
+ // Configure the FIFO.
+ //
+ MAP_USBFIFOConfigSet(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui16FIFOAddr,
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8FIFOSize,
+ USB_EP_HOST_OUT);
+ }
+
+ //
+ // Set the function address for this endpoint.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ psDevice->ui32Address, USB_EP_HOST_OUT);
+
+ //
+ // Set the hub and port address for the endpoint.
+ //
+ ui32HubAddr = psDevice->ui8Hub | (psDevice->ui8HubPort << 8);
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ ui32HubAddr, (USB_EP_HOST_OUT |
+ psDevice->ui32Speed));
+ break;
+ }
+ }
+ //
+ // Handle IN Pipes.
+ //
+ else if(ui32EndpointType & EP_PIPE_TYPE_IN)
+ {
+ //
+ // A zero address indicates free.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].psDevice == 0)
+ {
+ //
+ // Set up uDMA for the pipe.
+ //
+ if(ui32EndpointType & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel =
+ USBLibDMAChannelAllocate(g_sUSBHCD.psDMAInstance,
+ IndexToUSBEP(i32Idx + 1),
+ ui32Size,
+ USB_DMA_EP_RX |
+ USB_DMA_EP_HOST);
+
+ //
+ // If no DMA channel was available then just disable DMA
+ // on this pipe.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel == 0)
+ {
+ ui32EndpointType &= ~EP_PIPE_USE_UDMA;
+ }
+ }
+
+ //
+ // Save the endpoint type and device address and callback
+ // function.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = ui32EndpointType;
+ g_sUSBHCD.psUSBINPipes[i32Idx].psDevice = psDevice;
+ g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback = pfnCallback;
+
+ //
+ // Clear out any pending status on this endpoint in case it
+ // was in use before a allowing a new device class to use it.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ USB_HOST_IN_STATUS);
+
+ //
+ // Make sure to reset the data toggle.
+ //
+ USBEndpointDataToggleClear(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ USB_EP_HOST_IN);
+
+ //
+ // Allocate space in the FIFO for this endpoint.
+ //
+ if(FIFOAlloc(&g_sUSBHCD.psUSBINPipes[i32Idx], ui32Size) != 0)
+ {
+ //
+ // Configure the FIFO.
+ //
+ MAP_USBFIFOConfigSet(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui16FIFOAddr,
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8FIFOSize,
+ USB_EP_HOST_IN);
+ }
+
+ //
+ // Set the function address for this endpoint.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ psDevice->ui32Address, USB_EP_HOST_IN);
+
+ //
+ // Set the hub and port address for the endpoint.
+ //
+ ui32HubAddr = psDevice->ui8Hub | (psDevice->ui8HubPort << 8);
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ ui32HubAddr, (USB_EP_HOST_IN |
+ psDevice->ui32Speed));
+
+ //
+ // Reset the state of the pipe to idle.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].iState = ePipeIdle;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Did not find a free pipe.
+ //
+ if(i32Idx == MAX_NUM_PIPES)
+ {
+ return(0);
+ }
+
+ //
+ // Return the pipe index and type that was allocated.
+ //
+ return(ui32EndpointType | i32Idx);
+}
+
+//*****************************************************************************
+//
+//! This function is used to allocate a USB HCD pipe.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32EndpointType is the type of endpoint that this pipe will be
+//! communicating with.
+//! \param psDevice is the device instance associated with this endpoint.
+//! \param pfnCallback is the function that will be called when events occur on
+//! this USB Pipe.
+//!
+//! Since there are a limited number of USB HCD pipes that can be used in the
+//! host controller, this function is used to temporarily or permanently
+//! acquire one of the endpoints. It also provides a method to register a
+//! callback for status changes on this endpoint. If no callbacks are desired
+//! then the \e pfnCallback function should be set to 0. The callback should
+//! be used when using the USBHCDPipeSchedule() function so that the caller is
+//! notified when the action is complete.
+//!
+//! \return This function returns a value indicating which pipe was reserved.
+//! If the value is 0 then there were no pipes currently available. This value
+//! should be passed to any USBHCDPipe APIs to indicate which pipe is being
+//! accessed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeAlloc(uint32_t ui32Index, uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice, tHCDPipeCallback pfnCallback)
+{
+ //
+ // The old API allocated only 64 bytes to each endpoint.
+ //
+ return(USBHCDPipeAllocSize(ui32Index, ui32EndpointType, psDevice, 64,
+ pfnCallback));
+}
+
+//*****************************************************************************
+//
+//! This function is used to configure a USB HCD pipe.
+//!
+//! This should be called after allocating a USB pipe with a call to
+//! USBHCDPipeAlloc(). It is used to set the configuration associated with an
+//! endpoint like the max payload and target endpoint. The \e ui32MaxPayload
+//! parameter is typically read directly from the devices endpoint descriptor
+//! and is expressed in bytes.
+//!
+//! Setting the \e ui32Interval parameter depends on the type of endpoint being
+//! configured. For endpoints that do not need to use the \e ui32Interval
+//! parameter \e ui32Interval should be set to 0. For Bulk \e ui32Interval is
+//! a value from 2-16 and will set the NAK timeout value as
+//! 2^(\e ui32Interval-1) frames. For interrupt endpoints \e ui32Interval is a
+//! value from 1-255 and is the count in frames between polling the endpoint.
+//! For isochronous endpoints \e ui32Interval ranges from 1-16 and is the
+//! polling interval in frames represented as 2^(\e ui32Interval-1) frames.
+//!
+//! \param ui32Pipe is the allocated endpoint to modify.
+//! \param ui32MaxPayload is maximum data that can be handled per transaction.
+//! \param ui32Interval is the polling interval for data transfers expressed in
+//! frames.
+//! \param ui32TargetEndpoint is the target endpoint on the device to
+//! communicate with.
+//!
+//! \return If the call was successful, this function returns zero any other
+//! value indicates an error.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeConfig(uint32_t ui32Pipe, uint32_t ui32MaxPayload,
+ uint32_t ui32Interval, uint32_t ui32TargetEndpoint)
+{
+ uint32_t ui32Flags;
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ //
+ // Set the direction.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Set the mode for this endpoint.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type & EP_PIPE_TYPE_BULK)
+ {
+ ui32Flags = USB_EP_MODE_BULK;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type &
+ EP_PIPE_TYPE_INTR)
+ {
+ ui32Flags = USB_EP_MODE_INT;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type &
+ EP_PIPE_TYPE_ISOC)
+ {
+ ui32Flags = USB_EP_MODE_ISOC;
+ }
+ else
+ {
+ ui32Flags = USB_EP_MODE_CTRL;
+ }
+
+ ui32Flags |= USB_EP_HOST_OUT;
+
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8EPNumber =
+ (uint8_t)ui32TargetEndpoint;
+
+ //
+ // Save the interval and the next tick to trigger a scheduler event.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Interval = ui32Interval;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32NextEventTick =
+ ui32Interval + g_ui32CurrentTick;
+
+ //
+ // Set the device speed.
+ //
+ ui32Flags |= (g_sUSBHCD.psUSBOUTPipes[ui32Index].psDevice->ui32Speed);
+
+ //
+ // Set up the appropriate flags if uDMA is used.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ ui32Flags |= USB_EP_DMA_MODE_0 | USB_EP_AUTO_SET;
+ }
+ }
+ else
+ {
+ //
+ // Set the mode for this endpoint.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_BULK)
+ {
+ ui32Flags = USB_EP_MODE_BULK;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_INTR)
+ {
+ ui32Flags = USB_EP_MODE_INT;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_ISOC)
+ {
+ ui32Flags = USB_EP_MODE_ISOC;
+ }
+ else
+ {
+ ui32Flags = USB_EP_MODE_CTRL;
+ }
+ ui32Flags |= USB_EP_HOST_IN;
+
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8EPNumber =
+ (uint8_t)ui32TargetEndpoint;
+
+ //
+ // Save the interval and the next tick to trigger a scheduler event.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32Interval = ui32Interval;
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32NextEventTick =
+ ui32Interval + g_ui32CurrentTick;
+
+ //
+ // Set the device speed.
+ //
+ ui32Flags |= g_sUSBHCD.psUSBINPipes[ui32Index].psDevice->ui32Speed;
+ //
+ // Set up the appropriate flags if uDMA is used.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ ui32Flags |= USB_EP_DMA_MODE_1 | USB_EP_AUTO_CLEAR |
+ USB_EP_AUTO_REQUEST;
+ }
+ }
+
+
+ //
+ // Configure the endpoint according to the flags determined above.
+ //
+ USBHostEndpointConfig(USB0_BASE,
+ IndexToUSBEP((ui32Pipe & EP_PIPE_IDX_M) + 1),
+ ui32MaxPayload, ui32Interval, ui32TargetEndpoint,
+ ui32Flags);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to return the current status of a USB HCD pipe.
+//!
+//! This function will return the current status for a given USB pipe. If
+//! there is no status to report this call will simply return
+//! \b USBHCD_PIPE_NO_CHANGE.
+//!
+//! \param ui32Pipe is the USB pipe for this status request.
+//!
+//! \return This function returns the current status for the given endpoint.
+//! This will be one of the \b USBHCD_PIPE_* values.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeStatus(uint32_t ui32Pipe)
+{
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to write data to a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to put data into.
+//! \param pui8Data is a pointer to the data to send.
+//! \param ui32Size is the amount of data to send.
+//!
+//! This function will block until it has sent as much data as was
+//! requested using the USB pipe's FIFO. The caller should have registered a
+//! callback with the USBHCDPipeAlloc() call in order to be informed when the
+//! data has been transmitted. The value returned by this function can be less
+//! than the \e ui32Size requested if the USB pipe has less space available
+//! than this request is making.
+//!
+//! \return This function returns the number of bytes that were scheduled to
+//! be sent on the given USB pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeWrite(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32RemainingBytes, ui32ByteToSend, ui32PipeIdx;
+ bool bUseDMA;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Set the total number of bytes to send out.
+ //
+ ui32RemainingBytes = ui32Size;
+
+ //
+ // Default to using DMA.
+ //
+ bUseDMA = false;
+
+ //
+ // Initialize the bytes to send to all of the remaining bytes.
+ //
+ ui32ByteToSend = ui32RemainingBytes;
+
+ //
+ // Send all of the requested data.
+ //
+ while(ui32RemainingBytes != 0)
+ {
+ //
+ // If uDMA is not enabled for this pipe, or if the uDMA workaround
+ // is applied, then don't use uDMA for this transfer.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // Start the DMA transfer.
+ //
+ if(USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32RemainingBytes) != 0)
+ {
+ if(ui32RemainingBytes < 64)
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMASend;
+ }
+ else if((ui32RemainingBytes % 64) == 0)
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMA;
+ }
+ else
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMASend;
+ }
+
+ bUseDMA = true;
+ }
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ if(bUseDMA == false)
+ {
+ //
+ // Only send 64 bytes at a time if not using DMA.
+ //
+ if(ui32ByteToSend > 64)
+ {
+ ui32ByteToSend = 64;
+ }
+ else
+ {
+ //
+ // Send the requested number of bytes.
+ //
+ ui32ByteToSend = ui32RemainingBytes;
+ }
+
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeWriting;
+
+ //
+ // Disable uDMA on the USB endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint,
+ USB_EP_HOST_OUT);
+
+ //
+ // Put the data in the buffer.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, ui32Endpoint, pui8Data,
+ ui32ByteToSend);
+
+ //
+ // Schedule the data to be sent.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, ui32Endpoint, USB_TRANS_OUT);
+ }
+
+ //
+ // Wait for a status change.
+ //
+ while(1)
+ {
+ //
+ // If an error event occurs then exit out of the loop.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_DISCONNECT |
+ INT_EVENT_VBUS_ERR |
+ INT_EVENT_POWER_FAULT))
+ {
+ //
+ // Set the pipe state to error.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeError;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ //
+ // If the data was successfully sent then decrement the count and
+ // continue.
+ //
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
+ ePipeDataSent)
+ {
+ //
+ // Decrement the remaining data and advance the pointer.
+ //
+ ui32RemainingBytes -= ui32ByteToSend;
+ pui8Data += ui32ByteToSend;
+
+ //
+ // If there are less than 64 bytes to send then this is the
+ // last of the data to go out.
+ //
+ if(ui32RemainingBytes < 64)
+ {
+ ui32ByteToSend = ui32RemainingBytes;
+ }
+ break;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
+ ePipeStalled)
+ {
+ //
+ // Zero out the size so that the caller knows that no data was
+ // written.
+ //
+ ui32Size = 0;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ //
+ // If DMA is being used, then disable the channel.
+ //
+ if(bUseDMA == true)
+ {
+ //
+ // Disable the DMA channel.
+ //
+ USBLibDMAChannelDisable(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel);
+ }
+
+ //
+ // This is the actual endpoint number.
+ //
+ USBHCDClearFeature(
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].psDevice->ui32Address,
+ ui32Pipe, USB_FEATURE_EP_HALT);
+
+ //
+ // If there was a stall, then no more data is coming so break
+ // out.
+ //
+ break;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState == ePipeError)
+ {
+ //
+ // An error occurred so stop this transaction and set the
+ // number of bytes to zero.
+ //
+ ui32Size = 0;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to schedule and IN transaction on a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will not block depending on the type of pipe passed in will
+//! schedule either a send of data to the device or a read of data from the
+//! device. In either case the amount of data will be limited to what will
+//! fit in the FIFO for a given endpoint.
+//!
+//! \return This function returns the number of bytes that were sent in the
+//! case of a transfer of data or it will return 0 for a request on a USB IN
+//! pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeSchedule(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32PipeIdx;
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Check if uDMA is enabled on this pipe.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeWriteDMASend;
+
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size);
+ }
+ else
+ {
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeWriting;
+
+ //
+ // Put the data in the buffer.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, ui32Endpoint, pui8Data,
+ ui32Size);
+
+ //
+ // Schedule the data to be sent.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, ui32Endpoint, USB_TRANS_OUT);
+ }
+ }
+ else
+ {
+ //
+ // If uDMA is not enabled for this pipe, or if the uDMA workaround
+ // is applied, then do not use uDMA for this transfer.
+ //
+ if((ui32Pipe & EP_PIPE_USE_UDMA) == 0)
+ {
+ //
+ // Start a read request.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeReading;
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint, USB_EP_HOST_IN);
+ }
+ //
+ // Otherwise, uDMA should be used for this transfer, so set up
+ // the uDMA channel in advance of triggering the IN request.
+ //
+ else
+ {
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeReadDMA;
+
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size);
+ }
+
+ //
+ // Remember details of the buffer into which the data will be read.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].pui8ReadPtr = pui8Data;
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui32ReadSize = ui32Size;
+
+ //
+ // Trigger a request for data from the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, ui32Endpoint);
+
+ //
+ // No data was put into or read from the buffer.
+ //
+ ui32Size = 0;
+ }
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to read data from a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will not block and will only read as much data as requested
+//! or as much data is currently available from the USB pipe. The caller
+//! should have registered a callback with the USBHCDPipeAlloc() call in order
+//! to be informed when the data has been received. The value returned by this
+//! function can be less than the \e ui32Size requested if the USB pipe has
+//! less data available than was requested.
+//!
+//! \return This function returns the number of bytes that were returned in the
+//! \e pui8Data buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeReadNonBlocking(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Read the data out of the USB endpoint interface.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, ui32Endpoint, pui8Data, &ui32Size);
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function acknowledges data received via an interrupt IN pipe.
+//!
+//! \param ui32Pipe is the USB INT pipe whose last packet is to be
+//! acknowledged.
+//!
+//! This function is used to acknowledge reception of data on an interrupt IN
+//! pipe. A transfer on an interrupt IN endpoint is scheduled via a call to
+//! USBHCDPipeSchedule() and the application is notified when data is received
+//! using a \b USB_EVENT_RX_AVAILABLE event. In the handler for this event,
+//! the application must call USBHCDPipeDataAck() to have the USB controller
+//! ACK the data from the device and complete the transaction.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPipeDataAck(uint32_t ui32Pipe)
+{
+ uint32_t ui32Endpoint;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState = ePipeIdle;
+}
+
+//*****************************************************************************
+//
+//! This function is used to read data from a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will block and will only return when it has read as much data
+//! as requested from the USB pipe. The caller must register a callback with
+//! the USBHCDPipeAlloc() call in order to be informed when the data has been
+//! received. If the caller provides a non-zero pointer in the \e pui8Data
+//! parameter then the data is copied into the buffer before the callback
+//! occurs. If the caller provides a zero in \e pui8Data parameter
+//! then the caller is responsible for reading the data out of the FIFO when
+//! the \b USB_EVENT_RX_AVAILABLE callback event occurs. The value returned
+//! by this function can be less than the \e ui32Size requested if the USB pipe
+//! has less data available than was requested.
+//!
+//! \return This function returns the number of bytes that were returned in the
+//! \e pui8Data buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeRead(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32RemainingBytes, ui32BytesRead, ui32PipeIdx;
+ bool bUseDMA;
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Initialized the number of bytes read.
+ //
+ ui32BytesRead = 0;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP(ui32PipeIdx + 1);
+
+ //
+ // Set the remaining bytes to received.
+ //
+ ui32RemainingBytes = ui32Size;
+
+ //
+ // Default to using DMA.
+ //
+ bUseDMA = true;
+
+ //
+ // Continue until all data requested has been received.
+ //
+ while(ui32RemainingBytes != 0)
+ {
+ //
+ // Start a read request.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeReading;
+
+ //
+ // Try the DMA transfer should be used for this transfer, so set up
+ // the uDMA channel in advance of triggering the IN request.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if(USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size) != 0)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeReadDMA;
+
+ ui32BytesRead = ui32Size;
+ }
+ else
+ {
+ bUseDMA = false;
+ }
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ //
+ // If unable to use DMA then get ready to transfer without DMA.
+ //
+ if(bUseDMA == false)
+ {
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint, USB_EP_HOST_IN);
+
+ //
+ // Set up for the next transaction.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].pui8ReadPtr = pui8Data;
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui32ReadSize =
+ (ui32RemainingBytes < 64) ? ui32RemainingBytes : 64;
+ }
+
+ //
+ // Trigger a request for data from the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, ui32Endpoint);
+
+ //
+ // Wait for a status change.
+ //
+ while(1)
+ {
+ //
+ // Check if the device stalled the request.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeStalled)
+ {
+ //
+ // Zero out the size so that the caller knows that no data was
+ // read.
+ //
+ ui32Size = 0;
+
+ //
+ // There are also no remaining bytes to read.
+ //
+ ui32RemainingBytes = 0;
+
+ //
+ // If DMA is being used, then disable the channel.
+ //
+ if(bUseDMA == true)
+ {
+ USBLibDMAChannelDisable(
+ g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel);
+ }
+
+ //
+ // This is the actual endpoint number.
+ //
+ USBHCDClearFeature(
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].psDevice->ui32Address,
+ ui32Pipe, USB_FEATURE_EP_HALT);
+
+ //
+ // If there was a stall, then no more data is coming so break
+ // out.
+ //
+ break;
+ }
+
+ //
+ // If any error event occurs then exit out of the loop.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_DISCONNECT |
+ INT_EVENT_VBUS_ERR |
+ INT_EVENT_POWER_FAULT))
+ {
+ //
+ // Set the pipe state to error.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeError;
+ break;
+ }
+
+ //
+ // If data is ready then return it.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeDataReady)
+ {
+ //
+ // If not using DMA then read the data from the USB. Otherwise
+ // the data will already be in the buffer.
+ //
+ if(bUseDMA == false)
+ {
+ //
+ // Compute bytes to transfer and set up transfer
+ //
+ ui32BytesRead =
+ ui32RemainingBytes > 64 ? 64 : ui32RemainingBytes;
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+ }
+
+ //
+ // Subtract the number of bytes read from the bytes remaining.
+ //
+ ui32RemainingBytes -= ui32BytesRead;
+
+ //
+ // If there were less than 64 bytes read, then this was a short
+ // packet and no more data will be returned.
+ //
+ if(ui32BytesRead < 64)
+ {
+ //
+ // Subtract off the bytes that were not received and exit
+ // the loop.
+ //
+ ui32Size = ui32Size - ui32RemainingBytes;
+ break;
+ }
+ else
+ {
+ //
+ // Move the buffer ahead to receive more data into the
+ // buffer.
+ //
+ pui8Data += 64;
+ }
+ break;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeError)
+ {
+ //
+ // An error occurred so stop this transaction and set the
+ // number of bytes to zero.
+ //
+ ui32Size = 0;
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ else if((g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState ==
+ ePipeReadDMAWait) &&
+ (USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel) &
+ USBLIBSTATUS_DMA_COMPLETE))
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release a USB pipe.
+//!
+//! \param ui32Pipe is the allocated USB pipe to release.
+//!
+//! This function is used to release a USB pipe that was allocated by a call to
+//! USBHCDPipeAlloc() for use by some other device endpoint in the system.
+//! Freeing an unallocated or invalid pipe will not generate an error and will
+//! instead simply return.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPipeFree(uint32_t ui32Pipe)
+{
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Clear the address and type for this endpoint to free it up.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].psDevice = 0;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type = 0;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].pfnCallback = 0;
+
+ //
+ // Check if this pipe has allocated a DMA channel.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel !=
+ USBHCD_DMA_UNUSED)
+ {
+ //
+ // Release the DMA channel associated with this endpoint.
+ //
+ USBLibDMAChannelRelease(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel);
+
+ //
+ // Clear out the current channel in use by this pipe.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel =
+ USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Free up the FIFO memory used by this endpoint.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8FIFOSize)
+ {
+ FIFOFree(&g_sUSBHCD.psUSBOUTPipes[ui32Index]);
+ }
+
+ //
+ // Set the function address for this endpoint back to zero.
+ //
+ USBHostAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, USB_EP_HOST_OUT);
+
+ //
+ // Set the hub and port address for the endpoint back to zero and the
+ // speed back to LOW.
+ //
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, (USB_EP_HOST_OUT | USB_EP_SPEED_LOW));
+ }
+ else if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ //
+ // Clear the address and type for this endpoint to free it up.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].psDevice = 0;
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type = 0;
+ g_sUSBHCD.psUSBINPipes[ui32Index].pfnCallback = 0;
+
+ //
+ // Check if this pipe has allocated a DMA channel.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel !=
+ USBHCD_DMA_UNUSED)
+ {
+ //
+ // Release the DMA channel associated with this endpoint.
+ //
+ USBLibDMAChannelRelease(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel);
+
+ //
+ // Clear out the current channel in use by this pipe.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel =
+ USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Free up the FIFO memory used by this endpoint.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Pipe & EP_PIPE_IDX_M].ui8FIFOSize)
+ {
+ FIFOFree(&g_sUSBHCD.psUSBINPipes[ui32Pipe & EP_PIPE_IDX_M]);
+ }
+
+ //
+ // Set the function address for this endpoint back to zero.
+ //
+ USBHostAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, USB_EP_HOST_IN);
+
+ //
+ // Set the hub and port address for the endpoint back to zero and the
+ // speed back to LOW.
+ //
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, (USB_EP_HOST_IN | USB_EP_SPEED_LOW));
+
+ //
+ // Clear any pending IN transactions.
+ //
+ USBHostRequestINClear(USB0_BASE, IndexToUSBEP(ui32Index + 1));
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function initializes the HCD code.
+//
+// \param ui32Index specifies which USB controller to use.
+// \param pvPool is a pointer to the data to use as a memory pool for this
+// controller.
+// \param ui32PoolSize is the size in bytes of the buffer passed in as pvPool.
+//
+// This function will perform all the necessary operations to allow the USB
+// host controller to begin enumeration and communication with a device. This
+// function should typically be called once at the start of an application
+// before any other calls are made to the host controller.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDInitInternal(uint32_t ui32Index, void *pvPool, uint32_t ui32PoolSize)
+{
+ int32_t i32Idx;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Get the number of endpoints supported by this device.
+ //
+ g_sUSBHCD.ui32NumEndpoints = USBNumEndpointsGet(USB0_BASE);
+
+ //
+ // The first 64 Bytes are allocated to endpoint 0.
+ //
+ g_pui32Alloc[0] = 1;
+ g_pui32Alloc[1] = 0;
+
+ //
+ // Save the base address for this controller.
+ //
+ g_sUSBHCD.ui32USBBase = USB0_BASE;
+
+ //
+ // Save the USB interrupt number.
+ //
+ g_sUSBHCD.ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_sUSBHCD.ui32IntNum = INT_USB0_TM4C129;
+ }
+
+ //
+ // All Pipes are unused at start.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].psDevice = 0;
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel = USBHCD_DMA_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice = 0;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel = USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Make sure that the hub driver is initialized since it is called even
+ // if it is not present in the system.
+ //
+ USBHHubInit();
+
+ //
+ // Initialize the DMA interface.
+ //
+ g_sUSBHCD.psDMAInstance = USBLibDMAInit(g_sUSBHCD.ui32USBBase);
+
+ //
+ // Initialized the device structures.
+ //
+ for(i32Idx = 0; i32Idx <= MAX_USB_DEVICES; i32Idx++)
+ {
+ //
+ // Clear the configuration descriptor and state.
+ //
+ g_sUSBHCD.piDeviceState[i32Idx] = eHCDIdle;
+ g_sUSBHCD.psUSBDevice[i32Idx].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[i32Idx].bConfigRead = false;
+
+ //
+ // Initialize the device descriptor.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].sDeviceDescriptor.bLength = 0;
+ g_sUSBHCD.psUSBDevice[i32Idx].sDeviceDescriptor.bMaxPacketSize0 = 0;
+
+ //
+ // Initialize the device address.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Address = 0;
+
+ //
+ // Set the current interface to 0.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Interface = 0;
+
+ //
+ // Clear the active driver for the device.
+ //
+ g_pi32USBHActiveDriver[i32Idx] = -1;
+
+ //
+ // Initialize the device flags.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Flags = 0;
+ }
+
+ //
+ // Allocate the memory needed for reading descriptors.
+ //
+ g_sUSBHCD.pvPool = pvPool;
+ g_sUSBHCD.ui32PoolSize = ui32PoolSize;
+
+ //
+ // Initialize the device class.
+ //
+ g_sUSBHCD.ui32Class = USB_CLASS_EVENTS;
+
+ //
+ // Default enable connect, disconnect, unknown device and power fault
+ // event notifications.
+ //
+ g_sUSBHCD.ui32EventEnables = USBHCD_EVFLAG_CONNECT |
+ USBHCD_EVFLAG_UNKCNCT |
+ USBHCD_EVFLAG_DISCNCT |
+ USBHCD_EVFLAG_PWRFAULT |
+ USBHCD_EVFLAG_PWREN |
+ USBHCD_EVFLAG_PWRDIS;
+
+ //
+ // Initialize the USB tick module.
+ //
+ InternalUSBTickInit();
+
+ //
+ // Only do hardware update if the stack is in Host mode, do not touch the
+ // hardware for OTG mode operation.
+ //
+ if((g_iUSBMode == eUSBModeHost) || (g_iUSBMode == eUSBModeForceHost))
+ {
+ //
+ // Configure the End point 0.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | USB_EP_SPEED_FULL |
+ USB_EP_HOST_OUT));
+
+ //
+ // Enable USB Interrupts.
+ //
+ MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
+ USB_INTCTRL_DISCONNECT |
+ USB_INTCTRL_SOF |
+ USB_INTCTRL_SESSION |
+ USB_INTCTRL_BABBLE |
+ USB_INTCTRL_CONNECT |
+ USB_INTCTRL_RESUME |
+ USB_INTCTRL_SUSPEND |
+ USB_INTCTRL_VBUS_ERR |
+ USB_INTCTRL_POWER_FAULT);
+
+ MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // There is no automatic power in pure host mode.
+ //
+ USBHCDPowerConfigSet(ui32Index, (g_ui32PowerConfig &
+ ~USB_HOST_PWREN_AUTO));
+
+ //
+ // Force the power on as well as this point.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+
+ //
+ // This is required to get into host mode on some parts.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+ }
+
+ //
+ // Configure LPM if it is enabled.
+ //
+ if(g_sUSBHCD.ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ if(g_sUSBHCD.ui32Features & USBLIB_FEATURE_LPM_RMT_WAKE)
+ {
+ USBHostLPMConfig(USB0_BASE, g_sUSBHCD.ui32LPMHIRD,
+ USB_DEV_LPM_LS_L1 | USB_DEV_LPM_LS_RMTWAKE);
+ }
+ else
+ {
+ USBHostLPMConfig(USB0_BASE, g_sUSBHCD.ui32LPMHIRD,
+ USB_DEV_LPM_LS_L1);
+ }
+
+ //
+ // Enable USB interrupts for LPM mode, these enables have no effect on
+ // devices that do not support LPM.
+ //
+ USBLPMIntEnable(USB0_BASE, USB_INTLPM_ERROR | USB_INTLPM_RESUME |
+ USB_INTLPM_INCOMPLETE | USB_INTLPM_ACK |
+ USB_INTLPM_NYET | USB_INTLPM_STALL);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32PwrConfig is the power configuration to use for the application.
+//!
+//! This function must be called before HCDInit() is called so that the power
+//! pin configuration can be set before power is enabled. The \e ui32PwrConfig
+//! flags specify the power fault level sensitivity, the power fault action,
+//! and the power enable pin level and source.
+//!
+//! One of the following can be selected as the power fault level sensitivity:
+//!
+//! - \b USBHCD_FAULT_LOW - An external power fault is indicated by the pin
+//! being driven low.
+//! - \b USBHCD_FAULT_HIGH - An external power fault is indicated by the pin
+//! being driven high.
+//!
+//! One of the following can be selected as the power fault action:
+//!
+//! - \b USBHCD_FAULT_VBUS_NONE - No automatic action when power fault
+//! detected.
+//! - \b USBHCD_FAULT_VBUS_TRI - Automatically Tri-state the USBnEPEN pin on a
+//! power fault.
+//! - \b USBHCD_FAULT_VBUS_DIS - Automatically drive the USBnEPEN pin to it's
+//! inactive state on a power fault.
+//!
+//! One of the following can be selected as the power enable level and source:
+//!
+//! - \b USBHCD_VBUS_MANUAL - Power control is completely managed by the
+//! application, the USB library will provide a
+//! power callback to request power state changes.
+//! - \b USBHCD_VBUS_AUTO_LOW - USBEPEN is driven low by the USB controller
+//! automatically if USBOTGSessionRequest() has
+//! enabled a session.
+//! - \b USBHCD_VBUS_AUTO_HIGH - USBEPEN is driven high by the USB controller
+//! automatically if USBOTGSessionRequest() has
+//! enabled a session.
+//!
+//! If \b USBHCD_VBUS_MANUAL is used then the application must provide an
+//! event driver to receive the \b USB_EVENT_POWER_ENABLE and
+//! \b USB_EVENT_POWER_DISABLE events and enable and disable power to VBUS when
+//! requested by the USB library. The application should respond to a power
+//! control callback by enabling or disabling VBUS as soon as possible and
+//! before returning from the callback function.
+//!
+//! \note The following values should no longer be used with the USB
+//! library: \b USB_HOST_PWRFLT_LOW, \b USB_HOST_PWRFLT_HIGH,
+//! \b USB_HOST_PWRFLT_EP_NONE, \b USB_HOST_PWRFLT_EP_TRI,
+//! \b USB_HOST_PWRFLT_EP_LOW, \b USB_HOST_PWRFLT_EP_HIGH,
+//! \b USB_HOST_PWREN_LOW, \b USB_HOST_PWREN_HIGH, \b USB_HOST_PWREN_VBLOW, and
+//! \b USB_HOST_PWREN_VBHIGH.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPowerConfigInit(uint32_t ui32Index, uint32_t ui32PwrConfig)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the value as it will be used later.
+ //
+ g_ui32PowerConfig = ui32PwrConfig;
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function will return the current power control pin configuration as
+//! set by the USBHCDPowerConfigInit() function or the defaults if not yet set.
+//! See the USBHCDPowerConfigInit() documentation for the meaning of the bits
+//! that are returned by this function.
+//!
+//! \return The configuration of the power control pins.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerConfigGet(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the value as it will be used later.
+ //
+ return(g_ui32PowerConfig);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Config specifies which USB power configuration to use.
+//!
+//! This function will set the current power control pin configuration as
+//! set by the USBHCDPowerConfigInit() function or the defaults if not yet set.
+//! See the USBHCDPowerConfigInit() documentation for the meaning of the bits
+//! that are set by this function.
+//!
+//! \return Returns zero to indicate the power setting is now active.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerConfigSet(uint32_t ui32Index, uint32_t ui32Config)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Remember the current setting.
+ //
+ g_ui32PowerConfig = ui32Config;
+
+ //
+ // Clear out the two flag bits.
+ //
+ ui32Config = g_ui32PowerConfig & ~(USBHCD_VBUS_MANUAL |
+ USBHCD_FAULT_VBUS_DIS);
+
+ //
+ // If there is an automatic disable power action specified then set the
+ // polarity of the signal to match EPEN.
+ //
+ if(g_ui32PowerConfig & USBHCD_FAULT_VBUS_DIS)
+ {
+ //
+ // Insure that the assumption below is true.
+ //
+ ASSERT((USBHCD_VBUS_AUTO_HIGH & 1) == 1);
+ ASSERT((USBHCD_VBUS_AUTO_LOW & 1) == 0);
+
+ //
+ // This is taking advantage of the difference between
+ // USBHCD_VBUS_AUTO_LOW and USBHCD_VBUS_AUTO_HIGH being that bit
+ // one is set when EPEN is active high.
+ //
+ if(g_ui32PowerConfig & 1)
+ {
+ g_ui32PowerConfig |= USB_HOST_PWRFLT_EP_LOW;
+ ui32Config |= USB_HOST_PWRFLT_EP_LOW;
+ }
+ else
+ {
+ g_ui32PowerConfig |= USB_HOST_PWRFLT_EP_HIGH;
+ ui32Config |= USB_HOST_PWRFLT_EP_HIGH;
+ }
+ }
+
+ //
+ // Initialize the power configuration.
+ //
+ MAP_USBHostPwrConfig(USB0_BASE, ui32Config);
+
+ //
+ // If not in manual mode then just turn on power.
+ //
+ if((g_ui32PowerConfig & USBHCD_VBUS_MANUAL) == 0)
+ {
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+ }
+
+ //
+ // Return success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns if the current power settings will automatically
+//! handle enabling and disabling VBUS power.
+//!
+//! \param ui32Index specifies which USB controller to query.
+//!
+//! This function returns if the current power control pin configuration will
+//! automatically apply power or whether it will be left to the application
+//! to turn on power when it is notified.
+//!
+//! \return A non-zero value indicates that power is automatically applied and
+//! a value of zero indicates that the application must manually apply power.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerAutomatic(uint32_t ui32Index)
+{
+ //
+ // Check if the controller is automatically applying power or not.
+ //
+ if(g_ui32PowerConfig & USBHCD_VBUS_MANUAL)
+ {
+ return(0);
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize the HCD code.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvPool is a pointer to the data to use as a memory pool for this
+//! controller.
+//! \param ui32PoolSize is the size in bytes of the buffer passed in as
+//! \e pvPool.
+//!
+//! This function will perform all the necessary operations to allow the USB
+//! host controller to begin enumeration and communication with devices. This
+//! function should typically be called once at the start of an application
+//! once all of the device and class drivers are ready for normal operation.
+//! This call will start up the USB host controller and any connected device
+//! will immediately start the enumeration sequence.
+//!
+//! The USBStackModeSet() function can be called with eUSBModeHost in order to
+//! cause the USB library to force the USB operating mode to a host controller.
+//! This allows the application to used the USBVBUS and USBID pins as GPIOs on
+//! devices that support forcing OTG to operate as a host only controller. By
+//! default the USB library will assume that the USBVBUS and USBID pins are
+//! configured as USB pins and not GPIOs.
+//!
+//! The memory pool passed to this function must be at least as large as a
+//! typical configuration descriptor for devices that are to be supported.
+//! This value is application-dependent however it should never be less than 32
+//! bytes and, in most cases, should be at least 64 bytes. If there is not
+//! sufficient memory to load a configuration descriptor from a device, the
+//! device will not be recognized by the USB library's host controller driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDInit(uint32_t ui32Index, void *pvPool, uint32_t ui32PoolSize)
+{
+ int32_t i32Driver;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Make sure there is at least enough to read the configuration descriptor.
+ //
+ ASSERT(ui32PoolSize >= sizeof(tConfigDescriptor));
+
+ //
+ // Should not call this if the stack is in device mode.
+ //
+ ASSERT(g_iUSBMode != eUSBModeDevice);
+ ASSERT(g_iUSBMode != eUSBModeForceDevice);
+
+ //
+ // If the mode was not set then default to eUSBModeHost.
+ //
+ if(g_iUSBMode == eUSBModeNone)
+ {
+ g_iUSBMode = eUSBModeHost;
+ }
+
+ //
+ // Reset the USB controller.
+ //
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Set the PLL to USB clock divider.
+ //
+ if(g_ui32PLLDiv == 0)
+ {
+ USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_EXTERNAL);
+ }
+ else
+ {
+ USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_INTERNAL);
+ }
+
+ //
+ // Configure ULPI support.
+ //
+ if(g_ui32ULPISupport != USBLIB_FEATURE_ULPI_NONE)
+ {
+ USBULPIEnable(USB0_BASE);
+
+ if(g_ui32ULPISupport & USBLIB_FEATURE_ULPI_HS)
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_HS);
+ }
+ else
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_FS);
+ }
+ }
+ else
+ {
+ USBULPIDisable(USB0_BASE);
+ }
+
+ //
+ // If the application not requesting OTG mode then set the mode to forced
+ // host mode. If the mode is actually eUSBModeHost, this will be switched
+ // off when ID pin detection is complete and the ID is no longer in use.
+ //
+ if(g_iUSBMode != eUSBModeOTG)
+ {
+ //
+ // Force Host mode on devices that support force host mode.
+ //
+ MAP_USBHostMode(USB0_BASE);
+ }
+
+ //
+ // Call our internal function to perform the initialization.
+ //
+ USBHCDInitInternal(ui32Index, pvPool, ui32PoolSize);
+
+ //
+ // No event driver is present by default.
+ //
+ g_sUSBHCD.i32EventDriver = -1;
+
+ //
+ // Search through the Host Class driver list for the devices class.
+ //
+ for(i32Driver = 0; i32Driver < g_sUSBHCD.ui32NumClassDrivers; i32Driver++)
+ {
+ if(g_sUSBHCD.ppsClassDrivers[i32Driver]->ui32InterfaceClass ==
+ USB_CLASS_EVENTS)
+ {
+ //
+ // Event driver was found so remember it.
+ //
+ g_sUSBHCD.i32EventDriver = i32Driver;
+ }
+ }
+
+ //
+ // Get the number of ticks per millisecond, this is only used by blocking
+ // delays using the SysCtlDelay() function.
+ //
+ if(g_ui32Tickms == 0)
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ g_ui32Tickms = 120000000 / 3000;
+ }
+ else
+ {
+ g_ui32Tickms = 80000000 / 3000;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize the HCD class driver list.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ppsHClassDrvs is an array of host class drivers that are
+//! supported on this controller.
+//! \param ui32NumDrivers is the number of entries in the \e pHostClassDrivers
+//! array.
+//!
+//! This function will set the host classes supported by the host controller
+//! specified by the \e ui32Index parameter. This function should be called
+//! before enabling the host controller driver with the USBHCDInit() function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDRegisterDrivers(uint32_t ui32Index,
+ const tUSBHostClassDriver * const *ppsHClassDrvs,
+ uint32_t ui32NumDrivers)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the class drivers.
+ //
+ g_sUSBHCD.ppsClassDrivers = ppsHClassDrvs;
+
+ //
+ // Save the number of class drivers.
+ //
+ g_sUSBHCD.ui32NumClassDrivers = ui32NumDrivers;
+}
+
+//*****************************************************************************
+//
+//! This function is used to terminate the HCD code.
+//!
+//! \param ui32Index specifies which USB controller to release.
+//!
+//! This function will clean up the USB host controller and disable it in
+//! preparation for shutdown or a switch to USB device mode. Once this call is
+//! made, \e USBHCDInit() may be called to reinitialize the controller and
+//! prepare for host mode operation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDTerm(uint32_t ui32Index)
+{
+ int32_t i32Idx;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // End the session.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+
+ //
+ // Remove power from the USB bus.
+ //
+ MAP_USBHostPwrDisable(USB0_BASE);
+
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Set the host controller state back to it's initial values.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ }
+
+ //
+ // Free the memory used by the configuration descriptor.
+ //
+ ConfigDescFree(&g_sUSBHCD.psUSBDevice[0]);
+
+ g_sUSBHCD.piDeviceState[0] = eHCDIdle;
+ g_sUSBHCD.psUSBDevice[0].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[0].bConfigRead = false;
+ g_sUSBHCD.psUSBDevice[0].sDeviceDescriptor.bLength = 0;
+ g_sUSBHCD.psUSBDevice[0].sDeviceDescriptor.bMaxPacketSize0 = 0;
+ g_sUSBHCD.psUSBDevice[0].ui32Address = 0;
+ g_sUSBHCD.psUSBDevice[0].ui32Interface = 0;
+ g_sUSBHCD.pvPool = 0;
+ g_sUSBHCD.ui32PoolSize = 0;
+}
+
+//*****************************************************************************
+//
+//! This function generates reset signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function handles sending out reset signaling on the USB bus. After
+//! returning from this function, any attached device on the USB bus should
+//! have returned to it's reset state.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDReset(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the reset signaling.
+ //
+ MAP_USBHostReset(USB0_BASE, 1);
+
+ //
+ // Wait 20ms
+ //
+ OS_DELAY(g_ui32Tickms * 20);
+
+ //
+ // End reset signaling on the bus.
+ //
+ MAP_USBHostReset(USB0_BASE, 0);
+
+ //
+ // Need to wait at least 10ms to let the device recover from
+ // the reset. This is the delay specified in the USB 2.0 spec.
+ // We will hold the reset for 20ms.
+ //
+ OS_DELAY(g_ui32Tickms * 20);
+}
+
+//*****************************************************************************
+//
+//! This function will generate suspend signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function is used to generate suspend signaling on the USB bus. In
+//! order to leave the suspended state, the application should call
+//! USBHCDResume().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSuspend(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the suspend signaling.
+ //
+ MAP_USBHostSuspend(USB0_BASE);
+}
+
+//*****************************************************************************
+//
+//! This function will generate resume signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function is used to generate resume signaling on the USB bus in order
+//! to cause USB devices to leave their suspended state. This call should
+//! not be made unless a preceding call to USBHCDSuspend() has been made.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDResume(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the resume signaling.
+ //
+ MAP_USBHostResume(USB0_BASE, 1);
+
+ //
+ // Wait 100ms
+ //
+ OS_DELAY(g_ui32Tickms * 100);
+
+ //
+ // End reset signaling on the bus.
+ //
+ MAP_USBHostResume(USB0_BASE, 0);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for the current configuration descriptor
+//! from a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param psDevice is a pointer to the device structure that holds the buffer
+//! to store the configuration descriptor.
+//!
+//! This function will request the configuration descriptor from the device.
+//! The \e psDevice->ConfigDescriptor member variable is used to hold the data
+//! for this request. This buffer will be allocated from the pool provided by
+//! the HCDInit() function. \e psDevice->sDeviceDescriptor.bMaxPacketSize0
+//! should be valid prior to this call in order to correctly receive the
+//! configuration descriptor. If this variable is not valid then this call
+//! will not return accurate data.
+//!
+//! \return The number of bytes returned due to the request. This value can be
+//! zero if the device did not respond.
+//
+//*****************************************************************************
+static uint32_t
+USBHCDGetConfigDescriptor(uint32_t ui32Index, tUSBHostDevice *psDevice)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+ tConfigDescriptor sConfigDescriptor;
+
+ ASSERT(ui32Index == 0);
+
+ ui32Bytes = 0;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_DTYPE_CONFIGURATION << 8;
+
+ //
+ // Index is always 0 for device configurations requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only ask for the configuration header first to see how big the
+ // whole thing is.
+ //
+ if(!psDevice->bConfigRead)
+ {
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = sizeof(tConfigDescriptor);
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)&sConfigDescriptor,
+ sizeof(tConfigDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+ }
+
+ //
+ // If the Configuration header was successfully returned then get the
+ // full configuration descriptor.
+ //
+ if(ui32Bytes == sizeof(tConfigDescriptor))
+ {
+ //
+ // Save the total size and request the full configuration descriptor.
+ //
+ sSetupPacket.wLength = sConfigDescriptor.wTotalLength;
+
+ //
+ // Not enough space to hold this configuration descriptor.
+ //
+ if(ConfigDescAlloc(psDevice, sConfigDescriptor.wTotalLength) == 0)
+ {
+ return(0);
+ }
+
+ //
+ // Don't allow the buffer to be larger than was allocated.
+ //
+ if(sSetupPacket.wLength > psDevice->ui32ConfigDescriptorSize)
+ {
+ return(0);
+ }
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)psDevice->psConfigDescriptor,
+ sSetupPacket.wLength,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // If we read the descriptor, remember the fact.
+ //
+ if(ui32Bytes)
+ {
+ psDevice->bConfigRead = true;
+ }
+ }
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for a device descriptor from a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param psDevice is a pointer to the device structure that holds the buffer
+//! to store the device descriptor into.
+//!
+//! This function will request the device descriptor from the device. The
+//! \e psDevice->sDeviceDescriptor descriptor is used to hold the data for this
+//! request. \e psDevice->sDeviceDescriptor.bMaxPacketSize0 should be
+//! initialized to zero or to the valid maximum packet size if it is known. If
+//! this variable is not set to zero, then this call will determine the maximum
+//! packet size for endpoint 0 and save it in the structure member
+//! bMaxPacketSize0.
+//!
+//! \return The number of bytes returned due to the request. This value can be
+//! zero if the device did not respond.
+//
+//*****************************************************************************
+static uint32_t
+USBHCDGetDeviceDescriptor(uint32_t ui32Index, tUSBHostDevice *psDevice)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_DTYPE_DEVICE << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // All devices must have at least an 8 byte max packet size so just ask
+ // for 8 bytes to start with.
+ //
+ sSetupPacket.wLength = sizeof(tDeviceDescriptor);
+
+ ui32Bytes = 0;
+
+ //
+ // Discover the max packet size for endpoint 0.
+ //
+ if(psDevice->sDeviceDescriptor.bMaxPacketSize0 == 0)
+ {
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(ui32Index, &sSetupPacket, psDevice,
+ (uint8_t *)&(psDevice->sDeviceDescriptor),
+ sizeof(tDeviceDescriptor), 8);
+ }
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ if(ui32Bytes < sizeof(tDeviceDescriptor))
+ {
+ sSetupPacket.wLength = (uint16_t)sizeof(tDeviceDescriptor);
+
+ ui32Bytes =
+ USBHCDControlTransfer(ui32Index, &sSetupPacket, psDevice,
+ (uint8_t *)&(psDevice->sDeviceDescriptor),
+ sizeof(tDeviceDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+ }
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for a string descriptor from a device.
+//!
+//! \param psDevice is the device for this request.
+//! \param pui8Buffer is the pointer to the buffer to store the requested
+//! string descriptor.
+//! \param ui32Size is the size of the buffer passed in the buffer that will
+//! be used for this request.
+//! \param ui32LangID is the ID of the language for the requested string.
+//! \param ui32StringIndex is the index for the request.
+//!
+//! This function will request a string descriptor from the device of the type
+//! specified in the \e ui32DescriptorType parameter. The \e pui8Descriptor
+//! pointer is the location where the request results will be stored. The
+//! \e ui32Size should be passed in to indicate the size of the
+//! \e pui8Descriptor buffer. The \e ui32DevAddress parameter is used to
+//! specify the device address to communicate with on the USB bus. This value
+//! should be specified as 0 for any non-configured device on the USB bus and
+//! be changed to the address set by a call to USBHCDSetAddress().
+//!
+//! \return The number of bytes returned in the \e pui8Buffer due to the
+//! request. This value can be zero if the device did not respond.
+//
+//*****************************************************************************
+uint32_t
+USBHCDStringDescriptorGet(tUSBHostDevice *psDevice, uint8_t *pui8Buffer,
+ uint32_t ui32Size, uint32_t ui32LangID,
+ uint32_t ui32StringIndex)
+{
+ uint32_t ui32BytesReturned;
+ tUSBRequest sSetupPacket;
+
+ //
+ // Default the number of bytes to zero.
+ //
+ ui32BytesReturned = 0;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+
+ //
+ // Request for a string descriptor.
+ //
+ sSetupPacket.wValue = (USB_DTYPE_STRING << 8) |
+ (uint16_t)ui32StringIndex;
+
+ //
+ // Set the language ID.
+ //
+ sSetupPacket.wIndex = ui32LangID;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = (uint16_t)ui32Size;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32BytesReturned =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, pui8Buffer, ui32Size,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Return the number of bytes in the string.
+ //
+ return(ui32BytesReturned);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send the set address command to a device.
+//!
+//! \param ui32DevIndex is the index of the device whose address is to be
+//! set. This value must be 0 to indicate that the device is connected
+//! directly to the host controller. Higher values indicate devices connected
+//! via a hub.
+//! \param ui32DevAddress is the new device address to use for a device.
+//!
+//! The USBHCDSetAddress() function is used to set the USB device address, once
+//! a device has been discovered on the bus. This call is typically issued
+//! following a USB reset triggered by a call the USBHCDReset(). The
+//! address passed into this function via the \e ui32DevAddress parameter is
+//! used for all further communications with the device after this function
+//! returns.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetAddress(uint32_t ui32DevIndex, uint32_t ui32DevAddress)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_ADDRESS;
+ sSetupPacket.wValue = ui32DevAddress;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex], 0,
+ 0, MAX_PACKET_SIZE_EP0);
+
+ //
+ // Must delay 2ms after setting the address.
+ //
+ OS_DELAY(g_ui32Tickms * 2);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send a Clear Feature request to a device.
+//!
+//! \param ui32DevAddress is the USB bus address of the device that will
+//! receive this request.
+//! \param ui32Pipe is the pipe that will be used to send the request.
+//! \param ui32Feature is one of the USB_FEATURE_* definitions.
+//!
+//! This function will issue a Clear Feature request to the device indicated
+//! by the \e ui32DevAddress parameter. The \e ui32Pipe parameter is the USB
+//! pipe that should be used to send this request. The \e ui32Feature
+//! parameter should be one of the following values:
+//!
+//! * \b USB_FEATURE_EP_HALT is used to end a HALT condition on a devices
+//! endpoint.
+//! * \b USB_FEATURE_REMOTE_WAKE is used to disable a device's remote wake
+//! feature.
+//! * \b USB_FEATURE_TEST_MODE is used take the USB device out of test mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDClearFeature(uint32_t ui32DevAddress, uint32_t ui32Pipe,
+ uint32_t ui32Feature)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_ENDPOINT;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_CLEAR_FEATURE;
+ sSetupPacket.wValue = ui32Feature;
+
+ //
+ // Set the endpoint to access.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ sSetupPacket.wIndex = g_sUSBHCD.psUSBINPipes[ui32Index].ui8EPNumber |
+ 0x80;
+ }
+ else
+ {
+ sSetupPacket.wIndex = g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8EPNumber;
+ }
+
+ //
+ // This is always 0.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket,
+ &g_sUSBHCD.psUSBDevice[ui32DevAddress - 1], 0, 0,
+ MAX_PACKET_SIZE_EP0);
+
+ //
+ // Set the endpoint to access.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ MAP_USBEndpointDataToggleClear(USB0_BASE,
+ IndexToUSBEP(ui32Index + 1),
+ USB_EP_HOST_IN);
+ }
+ else
+ {
+ MAP_USBEndpointDataToggleClear(USB0_BASE,
+ IndexToUSBEP(ui32Index + 1),
+ USB_EP_HOST_OUT);
+ }
+
+ //
+ // Must delay 2ms after clearing the feature.
+ //
+ OS_DELAY(g_ui32Tickms * 2);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current configuration for a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Device is the USB device for this function.
+//! \param ui32Configuration is one of the devices valid configurations.
+//!
+//! This function is used to set the current device configuration for a USB
+//! device. The \e ui32Configuration value must be one of the configuration
+//! indexes that was returned in the configuration descriptor from the device,
+//! or a value of 0. If 0 is passed in, the device will return to it's
+//! addressed state and no longer be in a configured state. If the value is
+//! non-zero then the device will change to the requested configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetConfig(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Configuration)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ ASSERT(ui32Index == 0);
+
+ psDevice = (tUSBHostDevice *)ui32Device;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_CONFIG;
+ sSetupPacket.wValue = ui32Configuration;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ MAX_PACKET_SIZE_EP0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current interface and alternate setting
+//! for an interface on a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Device is the USB device for this function.
+//! \param ui32Interface is one of the valid interface numbers for a device.
+//! \param ui32AltSetting is one of the valid alternate interfaces for the
+//! \e ui32Interface number.
+//!
+//! This function is used to change the alternate setting for one of the valid
+//! interfaces on a USB device. The \e ui32Device specifies the device
+//! instance that was returned when the device was connected. This call will
+//! set the USB device's interface based on the \e ui32Interface and
+//! \e ui32AltSetting.
+//!
+//! \b Example: Set the USB device interface 2 to alternate setting 1.
+//!
+//! \verbatim
+//! USBHCDSetInterface(0, ui32Device, 2, 1);
+//! \endverbatim
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetInterface(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Interface, uint32_t ui32AltSetting)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ ASSERT(ui32Index == 0);
+
+ psDevice = (tUSBHostDevice *)ui32Device;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_INTERFACE;
+
+ //
+ // Index is the interface to access.
+ //
+ sSetupPacket.wIndex = ui32Interface;
+
+ //
+ // wValue is the alternate setting.
+ //
+ sSetupPacket.wValue = ui32AltSetting;
+
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ MAX_PACKET_SIZE_EP0);
+}
+
+//*****************************************************************************
+//
+// The internal function to see if a new schedule event should occur.
+//
+// This function is called by the main interrupt handler due to start of frame
+// interrupts to determine if a new scheduler event should be sent to the USB
+// pipe.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBHostCheckPipes(void)
+{
+ int32_t i32Idx;
+
+ g_ui32CurrentTick++;
+
+ for(i32Idx = 0; i32Idx < g_sUSBHCD.ui32NumEndpoints; i32Idx++)
+ {
+ //
+ // Skip unused pipes.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type == USBHCD_PIPE_UNUSED)
+ {
+ continue;
+ }
+
+ //
+ // If the tick has expired and it has an interval then update it.
+ //
+ if((g_sUSBHCD.psUSBINPipes[i32Idx].ui32Interval != 0) &&
+ (g_sUSBHCD.psUSBINPipes[i32Idx].ui32NextEventTick ==
+ g_ui32CurrentTick))
+ {
+ //
+ // Schedule the next event.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32NextEventTick +=
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Interval;
+
+ //
+ // If the pipe is IDLE and there is a callback, let the higher
+ // level drivers know that a new transfer can be scheduled.
+ //
+ if((g_sUSBHCD.psUSBINPipes[i32Idx].iState == ePipeIdle) &&
+ (g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback))
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback(
+ IN_PIPE_HANDLE(i32Idx),
+ USB_EVENT_SCHEDULER);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// The internal USB host mode interrupt handler.
+//
+// \param ui32Index is the USB controller associated with this interrupt.
+// \param ui32Status is the current interrupt status as read via a call to
+// \e USBIntStatusControl().
+//
+// This the main USB interrupt handler called when operating in host mode.
+// This handler will branch the interrupt off to the appropriate handlers
+// depending on the current status of the USB controller.
+//
+// The two-tiered structure for the interrupt handler ensures that it is
+// possible to use the same handler code in both host and OTG modes and
+// means that device code can be excluded from applications that only require
+// support for USB host mode operation.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBHostIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32DMAIntStatus, ui32Idx, ui32DevIndex;
+ static uint32_t ui32SOFDivide = 0;
+ int32_t i32ClassDrvr;
+
+ //
+ // By default, assume we are dealing with the device directly connected
+ // to the host controller and that we need to notify its class driver of
+ // this interrupt.
+ //
+ g_sUSBHCD.psUSBDevice[0].ui32Flags |= USBHDEV_FLAG_NOTIFYINT;
+
+ if(ui32Status & USB_INTCTRL_SOF)
+ {
+ //
+ // Indicate that a start of frame has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_SOF;
+ }
+
+ //
+ // A power fault has occurred so notify the application.
+ //
+ if(ui32Status & USB_INTCTRL_POWER_FAULT)
+ {
+ //
+ // Indicate that a power fault has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_POWER_FAULT;
+
+ //
+ // Turn off power to the bus.
+ //
+ MAP_USBHostPwrDisable(USB0_BASE);
+
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ return;
+ }
+
+ //
+ // In the event of a USB VBUS error, end the session and remove power to
+ // the device.
+ //
+ if(ui32Status & USB_INTCTRL_VBUS_ERR)
+ {
+ //
+ // Set the VBUS error event. We deliberately clear all other events
+ // since this one means anything else that is outstanding is
+ // irrelevant.
+ //
+ g_sUSBHCD.ui32IntEvents = INT_EVENT_VBUS_ERR;
+ return;
+ }
+
+ //
+ // Received a reset from the host.
+ //
+ if(ui32Status & USB_INTCTRL_BABBLE)
+ {
+ }
+
+ //
+ // Suspend was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_SUSPEND)
+ {
+ }
+
+ //
+ // Start the session.
+ //
+ if(ui32Status & USB_INTCTRL_SESSION)
+ {
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+
+ USBOTGSessionRequest(USB0_BASE, true);
+ }
+
+ //
+ // Resume was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_RESUME)
+ {
+ }
+
+ //
+ // Device connected so tell the main routine to issue a reset.
+ //
+ if(ui32Status & USB_INTCTRL_CONNECT)
+ {
+ //
+ // Set the connect flag and clear disconnect if it happens to be set.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_CONNECT;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_DISCONNECT;
+
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+ }
+
+ //
+ // Handle the ID detection so that the ID pin can be used as a
+ // GPIO in eUSBModeHost.
+ //
+ if(ui32Status & USB_INTCTRL_MODE_DETECT)
+ {
+ //
+ // If in eUSBModeHost mode then switch back to OTG detection
+ // so that VBUS can be monitored but free up the ID pin.
+ //
+ if(g_iUSBMode == eUSBModeHost)
+ {
+ USBOTGMode(USB0_BASE);
+ }
+ }
+
+ //
+ // Device was unplugged.
+ //
+ if(ui32Status & USB_INTCTRL_DISCONNECT)
+ {
+ //
+ // Set the disconnect flag and clear connect if it happens to be set.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_DISCONNECT;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_CONNECT;
+ }
+
+ //
+ // Start of Frame was received.
+ //
+ if(ui32Status & USB_INTCTRL_SOF)
+ {
+ //
+ // Increment the global Start of Frame counter.
+ //
+ g_ui32USBSOFCount++;
+
+ //
+ // Increment our SOF divider.
+ //
+ ui32SOFDivide++;
+
+ //
+ // Have we counted enough SOFs to allow us to call the tick function?
+ //
+ if(ui32SOFDivide == USB_SOF_TICK_DIVIDE)
+ {
+ //
+ // Yes - reset the divider and call the SOF tick handler.
+ //
+ ui32SOFDivide = 0;
+ InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
+ }
+ }
+
+ //
+ // Handle the LPM interrupt
+ //
+ ui32Status = USBLPMIntStatus(USB0_BASE);
+
+ if(ui32Status)
+ {
+ //
+ // Set the LPM interrupt event and clear the pending event.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_LPM;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_LPM_PEND;
+
+ //
+ // Anything other than and acknowledge means that the transfer
+ // was not complete for some reason.
+ //
+ for(ui32Idx = 0; ui32Idx < (MAX_USB_DEVICES + 1); ui32Idx++)
+ {
+ if((ui32Status != USB_INTLPM_ACK) &&
+ (g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &
+ USBHDEV_FLAG_LPMPEND))
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags |=
+ USBHDEV_FLAG_LPMERROR;
+ }
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &= ~USBHDEV_FLAG_LPMPEND;
+ }
+ }
+
+ //
+ // Check to see if any DMA transfers are pending
+ //
+ ui32DMAIntStatus = USBLibDMAIntStatus(g_sUSBHCD.psDMAInstance);
+
+ if(ui32DMAIntStatus)
+ {
+ //
+ // Handle any DMA interrupt processing.
+ //
+ USBLibDMAIntHandler(g_sUSBHCD.psDMAInstance, ui32DMAIntStatus);
+
+ for(ui32Idx = 0; ui32Idx < MAX_NUM_PIPES; ui32Idx++)
+ {
+ if((g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMAWait) ||
+ (g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMA))
+ {
+ //
+ // If the DMA channel transfer is complete, send an ack.
+ //
+ if(USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel) ==
+ USBLIBSTATUS_DMA_COMPLETE)
+ {
+ //
+ // Acknowledge the IN request.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // If using uDMA then the endpoint status interrupt will
+ // not occur. So process the data ready event here.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeDataReady;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx), USB_EVENT_RX_AVAILABLE);
+ }
+
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriteDMASend)
+ {
+ //
+ // If the uDMA channel transfer is complete, then tell
+ // the USB controller to go ahead and send the data
+ //
+ if(USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].ui8DMAChannel) &
+ USBLIBSTATUS_DMA_COMPLETE)
+ {
+ MAP_USBEndpointDataSend(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_TRANS_OUT);
+
+ //
+ // Now waiting on the final endpoint interrupt.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState =
+ ePipeWriteDMAWait;
+ }
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState == ePipeWriteDMA)
+ {
+ //
+ // Data was transmitted successfully.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeDataSent;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_TX_COMPLETE);
+ }
+ }
+ }
+ }
+
+ //
+ // Get the current endpoint interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Handle end point 0 interrupts.
+ //
+ if(ui32Status & USB_INTEP_0)
+ {
+ //
+ // Indicate that a start of frame has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_ENUM;
+ }
+
+ for(ui32Idx = 0; ui32Idx < MAX_NUM_PIPES; ui32Idx++)
+ {
+ //
+ // Check the next pipe, the first time through this will clear out
+ // any interrupts dealing with endpoint zero since it was handled
+ // above.
+ //
+ ui32Status >>= 1;
+
+ //
+ // Break out if there are no more pending interrupts.
+ //
+ if(ui32Status == 0)
+ {
+ break;
+ }
+
+ //
+ // Check the status of the receive(IN) pipes.
+ //
+ if(ui32Status & 0x10000)
+ {
+ //
+ // Clear the status flag for the IN Pipe.
+ //
+ ui32Status &= ~0x10000;
+
+ //
+ // Read the status of the endpoint connected to this pipe.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Check if the device stalled the request.
+ //
+ if(ui32EPStatus & USB_HOST_IN_STALL)
+ {
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_IN_STALL);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeStalled;
+
+ //
+ // Notify the pipe that it was stalled.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_STALL);
+ }
+ }
+ else if(ui32EPStatus & USB_HOST_IN_ERROR)
+ {
+ //
+ // We can no longer communicate with this device for some
+ // reason. It may have been disconnected from a hub, for
+ // example. Merely clear the status and continue.
+ //
+ USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_IN_ERROR);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeError;
+
+ //
+ // Notify the pipe that it was stalled.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_ERROR);
+ }
+ }
+ //
+ // Handle the case where the pipe is reading a single packet.
+ //
+ else if(g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMA)
+ {
+ void *pvAddr;
+
+ //
+ // Enable the DMA channel and wait for it to complete.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeReadDMAWait;
+
+ pvAddr = USBLibDMAAddrGet(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel);
+
+ //
+ // Save the amount of data available.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ USBEndpointDataAvail(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Only request what is available.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead <=
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize)
+ {
+ //
+ // Reset the transfer size.
+ //
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel,
+ pvAddr,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead);
+ }
+ else
+ {
+ //
+ // The transfer size did not change, this leaves some
+ // data in the FIFO.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize;
+ }
+
+ USBLibDMAChannelEnable(
+ g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel);
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReading)
+ {
+ //
+ // Data is available.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeDataReady;
+
+ //
+ // Read the data out of the USB endpoint interface into the
+ // buffer provided by the caller to USBHCDPipeRead() or
+ // USBHCDPipeSchedule() if a buffer was provided already.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pui8ReadPtr)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize;
+
+ USBEndpointDataGet(USB0_BASE, IndexToUSBEP(ui32Idx + 1),
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pui8ReadPtr,
+ &g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead);
+ }
+
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_RX_AVAILABLE);
+ }
+
+ }
+
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+
+ //
+ // Check the status of the transmit(OUT) pipes.
+ //
+ if(ui32Status & 1)
+ {
+ //
+ // Read the status of the endpoint connected to this pipe.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Check if the device stalled the request.
+ //
+ if(ui32EPStatus & USB_HOST_OUT_STALL)
+ {
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_OUT_STALL);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeStalled;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that it was stalled.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_STALL);
+ }
+ }
+ else if(ui32EPStatus & USB_HOST_OUT_ERROR)
+ {
+ //
+ // Clear the error condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_OUT_ERROR);
+
+ //
+ // Save the Pipes error state.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeError;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that had an error.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_ERROR);
+ }
+ }
+ else if((g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriting) ||
+ (g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriteDMAWait))
+ {
+ //
+ // Data was transmitted successfully.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeDataSent;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_TX_COMPLETE);
+ }
+ }
+
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ ui32EPStatus & USB_HOST_OUT_STATUS);
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].psDevice)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+ }
+ }
+
+ //
+ // Send back notifications to any class driver whose endpoint required
+ // service during the handler.
+ //
+ for(ui32DevIndex = 0; ui32DevIndex <= MAX_USB_DEVICES; ui32DevIndex++)
+ {
+ //
+ // Which class driver does this device use?
+ //
+ i32ClassDrvr = g_pi32USBHActiveDriver[ui32DevIndex];
+
+ //
+ // If a class driver is in use, and one of its endpoints was serviced
+ // and the class driver has an interrupt callback...
+ //
+ if((i32ClassDrvr >= 0) &&
+ (g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags &
+ USBHDEV_FLAG_NOTIFYINT) &&
+ (g_sUSBHCD.ppsClassDrivers[i32ClassDrvr]->pfnIntHandler))
+ {
+ //
+ // ...call the class driver's interrupt notification callback.
+ //
+ g_sUSBHCD.ppsClassDrivers[i32ClassDrvr]->pfnIntHandler(
+ g_ppvDriverInstance[ui32DevIndex]);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! The USB host mode interrupt handler for controller index 0.
+//!
+//! This the main USB interrupt handler entry point. This handler will branch
+//! the interrupt off to the appropriate handlers depending on the current
+//! status of the USB controller. This function must be placed in the
+//! interrupt table in order for the USB Library host stack to function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0HostIntHandler(void)
+{
+ uint32_t ui32Status;
+
+ //
+ // Get the control interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusControl(USB0_BASE);
+
+ //
+ // Call the internal handler to process the interrupts.
+ //
+ USBHostIntHandlerInternal(0, ui32Status);
+}
+
+//*****************************************************************************
+//
+//! This function opens the class driver.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32DeviceNum is the device number for the driver to load.
+//!
+//! This function opens the driver needed based on the class value found in
+//! the device's interface descriptor.
+//!
+//! \return This function returns -1 if no driver is found, or it returns the
+//! index of the driver found in the list of host class drivers.
+//
+//*****************************************************************************
+static int32_t
+USBHCDOpenDriver(uint32_t ui32Index, uint32_t ui32DeviceNum)
+{
+ int32_t i32Driver;
+ uint32_t ui32Class;
+ tInterfaceDescriptor *psInterface;
+ tEventInfo sEvent;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DeviceNum].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DeviceNum].ui32Interface,
+ USB_DESC_ANY);
+
+ //
+ // Read the interface class.
+ //
+ ui32Class = psInterface->bInterfaceClass;
+
+ //
+ // Search through the Host Class driver list for the devices class.
+ //
+ for(i32Driver = 0; i32Driver < g_sUSBHCD.ui32NumClassDrivers; i32Driver++)
+ {
+ //
+ // If a driver was found call the open for this driver and save which
+ // driver is in use.
+ //
+ if(g_sUSBHCD.ppsClassDrivers[i32Driver]->ui32InterfaceClass ==
+ ui32Class)
+ {
+ //
+ // Call the open function for the class driver.
+ //
+ g_ppvDriverInstance[ui32DeviceNum] =
+ g_sUSBHCD.ppsClassDrivers[i32Driver]->pfnOpen(
+ &g_sUSBHCD.psUSBDevice[ui32DeviceNum]);
+
+ //
+ // If the driver was successfully loaded then break out of the
+ // loop.
+ //
+ if(g_ppvDriverInstance[ui32DeviceNum] != 0)
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // If no drivers were found then return -1 to indicate an invalid
+ // driver instance.
+ //
+ if(i32Driver == g_sUSBHCD.ui32NumClassDrivers)
+ {
+ //
+ // Send an unknown connection event.
+ //
+ SendUnknownConnect(ui32Index, (ui32Index << 16) | ui32DeviceNum);
+
+ //
+ // Indicate that no driver was found.
+ //
+ i32Driver = -1;
+ }
+ else
+ {
+ //
+ // If the connect event is enabled then send the event.
+ //
+ sEvent.ui32Event = USB_EVENT_CONNECTED;
+ sEvent.ui32Instance = (ui32Index << 16) | ui32DeviceNum;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_CONNECT);
+ }
+
+ return(i32Driver);
+}
+
+//*****************************************************************************
+//
+// This function will send an event to a registered event driver.
+//
+// \param ui32Index specifies which USB controller to use.
+// \param psEvent is a pointer to the event structure to send.
+//
+// This function is only used internally to the USB library and will check
+// if an event driver is registered and send on the event.
+//
+// Note: This function should not be called outside of the USB library.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+InternalUSBHCDSendEvent(uint32_t ui32Index, tEventInfo *psEvent,
+ uint32_t ui32EvFlag)
+{
+ //
+ // Make sure that an event driver has been registered.
+ //
+ if((g_sUSBHCD.i32EventDriver != -1) &&
+ (g_sUSBHCD.ppsClassDrivers[g_sUSBHCD.i32EventDriver]->pfnIntHandler) &&
+ (g_sUSBHCD.ui32EventEnables & ui32EvFlag))
+ {
+ g_sUSBHCD.ppsClassDrivers[g_sUSBHCD.i32EventDriver]->pfnIntHandler(
+ psEvent);
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the necessary clean up for device disconnect.
+//
+// \param ui32Index is the device number for the device that was disconnected.
+//
+// This function handles all of the necessary clean up after a device
+// disconnect has been detected by the stack. This includes calling back the
+// appropriate driver if necessary.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDDeviceDisconnected(uint32_t ui32Index, uint32_t ui32DevIndex)
+{
+ tEventInfo sEvent;
+
+ ASSERT(ui32Index == 0);
+ ASSERT(ui32DevIndex <= MAX_USB_DEVICES);
+
+ //
+ // If there is an event driver with a valid event handler and the
+ // USBHCD_EVFLAG_DISCNCT is enabled, then call the registered event
+ // handler.
+ //
+ sEvent.ui32Event = USB_EVENT_DISCONNECTED;
+ sEvent.ui32Instance = (ui32Index << 16) | ui32DevIndex;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_DISCNCT);
+
+ //
+ // Reset the class.
+ //
+ g_sUSBHCD.ui32Class = USB_CLASS_EVENTS;
+
+ //
+ // Free the memory used by the configuration descriptor.
+ //
+ ConfigDescFree(&g_sUSBHCD.psUSBDevice[ui32DevIndex]);
+
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags = 0;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].bConfigRead = false;
+
+ //
+ // Reset the max packet size so that this will be re-read from new devices.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bMaxPacketSize0 = 0;
+
+ //
+ // No longer have a device descriptor.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength = 0;
+
+ //
+ // No longer addressed.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address = 0;
+
+ //
+ // If this was an active driver then close it out.
+ //
+ if(g_pi32USBHActiveDriver[ui32DevIndex] >= 0)
+ {
+ //
+ // Call the driver Close entry point.
+ //
+ g_sUSBHCD.ppsClassDrivers[g_pi32USBHActiveDriver[ui32DevIndex]]->
+ pfnClose(g_ppvDriverInstance[ui32DevIndex]);
+
+ //
+ // No active driver now present.
+ //
+ g_pi32USBHActiveDriver[ui32DevIndex] = -1;
+ g_ppvDriverInstance[ui32DevIndex] = 0;
+ }
+
+ //
+ // This call is necessary for OTG controllers to know that the host
+ // stack has completed handling the disconnect of the device before
+ // removing power and returning to a state that can allow OTG
+ // negotiations once again.
+ // We only do this if the disconnected device
+ // was attached directly to us (device index 0).
+ //
+ if((ui32DevIndex == 0) && (g_iUSBMode == eUSBModeOTG))
+ {
+ OTGDeviceDisconnect(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is the main routine for the Host Controller Driver.
+//!
+//! This function is the main routine for the host controller driver, and must
+//! be called periodically by the main application outside of a callback
+//! context. This allows for a simple cooperative system to access the the
+//! host controller driver interface without the need for an RTOS. All time
+//! critical operations are handled in interrupt context but all blocking
+//! operations are run from the this function to allow them to block and wait
+//! for completion without holding off other interrupts.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDMain(void)
+{
+ tUSBHDeviceState iOldState;
+ int32_t i32Dev;
+ tEventInfo sEvent;
+
+ //
+ // Save the old state to detect changes properly.
+ //
+ iOldState = g_sUSBHCD.piDeviceState[0];
+
+ //
+ // Fix up the state if any important interrupt events occurred.
+ //
+ if(g_sUSBHCD.ui32IntEvents)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_POWER_FAULT)
+ {
+ //
+ // A power fault has occurred so notify the application if there
+ // is an event handler and the event has been enabled.
+ //
+ sEvent.ui32Event = USB_EVENT_POWER_FAULT;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWRFAULT);
+
+ g_sUSBHCD.piDeviceState[0] = eHCDPowerFault;
+ }
+ else if(g_sUSBHCD.ui32IntEvents & INT_EVENT_VBUS_ERR)
+ {
+ //
+ // A VBUS error has occurred. This event trumps connect and
+ // disconnect since it will cause a controller reset.
+ //
+ g_sUSBHCD.piDeviceState[0] = eHCDVBUSError;
+ }
+ else
+ {
+ //
+ // Has a device connected?
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_CONNECT)
+ {
+ g_sUSBHCD.piDeviceState[0] = eHCDDevReset;
+ g_sUSBHCD.psUSBDevice[0].ui8Hub = 0;
+ g_sUSBHCD.psUSBDevice[0].ui8HubPort = 0;
+ }
+ else
+ {
+ //
+ // Has a device disconnected?
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_DISCONNECT)
+ {
+ g_sUSBHCD.piDeviceState[0] = eHCDDevDisconnected;
+ }
+ }
+
+ //
+ // Handle the start of frame event
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_SOF)
+ {
+ //
+ // If the connect event is enabled then send the event.
+ //
+ sEvent.ui32Event = USB_EVENT_SOF;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_SOF);
+
+ USBHostCheckPipes();
+
+ //
+ // Call the hub driver to have it perform any necessary
+ // processing to handle downstream devices.
+ //
+ USBHHubMain();
+ }
+
+ //
+ // Handle LPM interrupt events.
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM)
+ {
+ //
+ // There should be a pending LPM request.
+ //
+ ASSERT((g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM_PEND) != 0);
+
+ for(i32Dev = 0; i32Dev < MAX_USB_DEVICES + 1; i32Dev++)
+ {
+ //
+ // Find the device with the pending LPM request.
+ //
+ if(g_sUSBHCD.psUSBDevice[i32Dev].ui32Flags &
+ USBHDEV_FLAG_LPMPEND)
+ {
+ //
+ // Clear the pending event at the device level, this
+ // leaves the error set if it was already set.
+ //
+ g_sUSBHCD.psUSBDevice[i32Dev].ui32Flags &=
+ ~USBHDEV_FLAG_LPMPEND;
+
+ //
+ // Clear the pending request and event at the host
+ // controller level.
+ //
+ g_sUSBHCD.ui32IntEvents &= ~(INT_EVENT_LPM_PEND |
+ INT_EVENT_LPM);
+ }
+ }
+ }
+ }
+
+ //
+ // Clear the flags.
+ //
+ g_sUSBHCD.ui32IntEvents = 0;
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ //
+ // Process the state machine for each connected device. Yes, the exit
+ // condition for this loop is correct since we support (MAX_USB_DEVICES+1)
+ // devices (the hub counts as one).
+ //
+ for(i32Dev = 0; i32Dev <= MAX_USB_DEVICES; i32Dev++)
+ {
+ //
+ // If this is not the first device (i.e. the one directly connected to
+ // the host controller) then set the old state to the current state
+ // since we won't have mucked with it in any of the previous code.
+ //
+ if(i32Dev != 0)
+ {
+ iOldState = g_sUSBHCD.piDeviceState[i32Dev];
+ }
+
+ //
+ // Process the state machine for this device.
+ //
+ ProcessUSBDeviceStateMachine(iOldState, i32Dev);
+ }
+}
+
+static void
+ProcessUSBDeviceStateMachine(tUSBHDeviceState iOldState,
+ uint32_t ui32DevIndex)
+{
+ switch(g_sUSBHCD.piDeviceState[ui32DevIndex])
+ {
+ //
+ // There was a power fault condition so shut down and wait for the
+ // application to re-initialized the system.
+ //
+ case eHCDPowerFault:
+ {
+ break;
+ }
+
+ //
+ // There was a VBUS error so handle it.
+ //
+ case eHCDVBUSError:
+ {
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // If there was a device in any state of connection then indicate
+ // that it has been disconnected.
+ //
+ if((iOldState != eHCDIdle) && (iOldState != eHCDPowerFault))
+ {
+ //
+ // Handle device disconnect.
+ //
+ USBHCDDeviceDisconnected(0, ui32DevIndex);
+ }
+
+ //
+ // Reset the controller.
+ //
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+
+ //
+ // Wait for 100ms before trying to re-power the device.
+ //
+ OS_DELAY(g_ui32Tickms * 100);
+
+ //
+ // Re-initialize the HCD.
+ //
+ USBHCDInitInternal(0, g_sUSBHCD.pvPool, g_sUSBHCD.ui32PoolSize);
+
+ break;
+ }
+ //
+ // Trigger a reset to the connected device.
+ //
+ case eHCDDevReset:
+ {
+ if(!ui32DevIndex)
+ {
+ //
+ // Trigger a Reset. This is only ever done for devices
+ // attached directly to the controller.
+ //
+ DEBUG_OUTPUT("USB reset.\n");
+ USBHCDReset(0);
+ }
+
+ //
+ // The state moves to connected but not configured.
+ //
+ g_sUSBHCD.piDeviceState[0] = eHCDDevConnected;
+
+ //
+ // Remember that we don't have a valid configuration descriptor
+ // yet.
+ //
+ g_sUSBHCD.psUSBDevice[0].bConfigRead = false;
+
+ break;
+ }
+ //
+ // Device connection has been established now start enumerating
+ // the device.
+ //
+ case eHCDDevConnected:
+ case eHCDDevConnectedHub:
+ {
+ //
+ // First check if we have read the device descriptor at all
+ // before proceeding.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength ==
+ 0)
+ {
+ //
+ // Initialize a request for the device descriptor.
+ //
+ DEBUG_OUTPUT("Connection %d - getting device descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Hub enumeration has already set the speed so do not
+ // override the setting here.
+ //
+ if(g_sUSBHCD.piDeviceState[ui32DevIndex] == eHCDDevConnected)
+ {
+ //
+ // Remember the speed of this device to ensure endpoints
+ // are properly configured.
+ //
+ switch(USBHostSpeedGet(USB0_BASE))
+ {
+ case USB_HIGH_SPEED:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_HIGH;
+ break;
+ }
+ case USB_FULL_SPEED:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_FULL;
+ break;
+ }
+ default:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_LOW;
+ break;
+ }
+ }
+ }
+
+ if(USBHCDGetDeviceDescriptor(0,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex]) == 0)
+ {
+ //
+ // If the device descriptor cannot be read then the device
+ // will be treated as unknown.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevError;
+
+ DEBUG_OUTPUT("Connection %d - failed to get descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Send an unknown connection event to let the application
+ // know that there is a device connected but return no
+ // zero for the instance.
+ //
+ SendUnknownConnect(0, 0);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that we experienced an error enumerating the
+ // device.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationError(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ }
+ //
+ // If we have the device descriptor then move on to setting
+ // the address of the device.
+ //
+ else if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address == 0)
+ {
+ DEBUG_OUTPUT("Connection %d - setting address %d\n",
+ ui32DevIndex, ui32DevIndex + 1);
+
+ //
+ // Send the set address command.
+ //
+ USBHCDSetAddress(ui32DevIndex, (ui32DevIndex + 1));
+
+ //
+ // Save the address.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address =
+ (ui32DevIndex + 1);
+
+ //
+ // Move on to the addressed state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevAddressed;
+ }
+ break;
+ }
+ case eHCDDevAddressed:
+ {
+ //
+ // First check if we have read the configuration descriptor.
+ //
+ if(!g_sUSBHCD.psUSBDevice[ui32DevIndex].bConfigRead)
+ {
+ DEBUG_OUTPUT("Connection %d - getting config descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Initialize a request for the configuration descriptor.
+ //
+ if(USBHCDGetConfigDescriptor(0,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex]) == 0)
+ {
+ //
+ // If the device descriptor cannot be read then the device
+ // will be treated as unknown.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevError;
+
+ DEBUG_OUTPUT("Connection %d - failed to get descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Send an unknown connection event to let the application
+ // know that there is a device connected but return no
+ // zero for the instance.
+ //
+ SendUnknownConnect(0, 0);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that we experienced an error enumerating the
+ // device.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationError(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ }
+ //
+ // Now have addressed and received the device configuration,
+ // so get ready to set the device configuration.
+ //
+ else
+ {
+ DEBUG_OUTPUT("Connection %d - setting configuration.\n",
+ ui32DevIndex);
+
+ //
+ // Use the first configuration to set the device
+ // configuration.
+ //
+ USBHCDSetConfig(0,
+ (uint32_t)&g_sUSBHCD.psUSBDevice[ui32DevIndex], 1);
+
+ //
+ // Move on to the configured state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConfigured;
+
+ //
+ // Open the driver for the device.
+ //
+ g_pi32USBHActiveDriver[ui32DevIndex] = USBHCDOpenDriver(0,
+ ui32DevIndex);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that enumeration is complete.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationComplete(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ break;
+ }
+ //
+ // The device was making a request and is now complete.
+ //
+ case eHCDDevRequest:
+ {
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConnected;
+ break;
+ }
+ //
+ // The strings are currently not accessed.
+ //
+ case eHCDDevGetStrings:
+ {
+ break;
+ }
+ //
+ // Basically Idle at this point.
+ //
+ case eHCDDevDisconnected:
+ {
+ DEBUG_OUTPUT("Connection %d - disconnected.\n",
+ ui32DevIndex);
+
+ //
+ // Handle device disconnect.
+ //
+ USBHCDDeviceDisconnected(0, ui32DevIndex);
+
+ //
+ // Return to the Idle state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDIdle;
+ break;
+ }
+
+ //
+ // Connection and enumeration is complete so allow this function
+ // to exit.
+ //
+ case eHCDDevConfigured:
+ {
+ break;
+ }
+
+ //
+ // Poorly behaving device are in limbo in this state until removed.
+ //
+ case eHCDDevError:
+ {
+ DEBUG_OUTPUT("Connection %d - Error!\n", ui32DevIndex);
+
+ //
+ // If this device is connected directly to us, tidy up and ignore
+ // it until it is removed. If the device is connected to a hub,
+ // we just leave it in the error state until it is removed.
+ //
+ if(ui32DevIndex == 0)
+ {
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_DISCONNECT;
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDIdle;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function completes a control transaction to a device.
+//!
+//! \param ui32Index is the controller index to use for this transfer.
+//! \param psSetupPacket is the setup request to be sent.
+//! \param psDevice is the device instance pointer for this request.
+//! \param pui8Data is the data to send for OUT requests or the receive buffer
+//! for IN requests.
+//! \param ui32Size is the size of the buffer in \e pui8Data.
+//! \param ui32MaxPacketSize is the maximum packet size for the device for this
+//! request.
+//!
+//! This function handles the state changes necessary to send a control
+//! transaction to a device. This function should not be called from within
+//! an interrupt callback as it is a blocking function.
+//!
+//! \return The number of bytes of data that were sent or received as a result
+//! of this request.
+//
+//*****************************************************************************
+uint32_t
+USBHCDControlTransfer(uint32_t ui32Index, tUSBRequest *psSetupPacket,
+ tUSBHostDevice *psDevice, uint8_t *pui8Data,
+ uint32_t ui32Size, uint32_t ui32MaxPacketSize)
+{
+ uint32_t ui32Remaining;
+ uint32_t ui32DataSize;
+
+ //
+ // Debug sanity check.
+ //
+ ASSERT(g_sUSBHEP0State.iState == eEP0StateIdle);
+ ASSERT(ui32Index == 0);
+
+ //
+ // Initialize the state of the data for this request.
+ //
+ g_sUSBHEP0State.pui8Data = pui8Data;
+ g_sUSBHEP0State.ui32BytesRemaining = ui32Size;
+ g_sUSBHEP0State.ui32DataSize = ui32Size;
+
+ //
+ // Set the maximum packet size.
+ //
+ g_sUSBHEP0State.ui32MaxPacketSize = ui32MaxPacketSize;
+
+ //
+ // Save the current address.
+ //
+ g_sUSBHEP0State.ui32DevAddress = psDevice->ui32Address;
+
+ //
+ // Set the address the host will used to communicate with the device.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, USB_EP_0, g_sUSBHEP0State.ui32DevAddress,
+ USB_EP_HOST_OUT);
+
+ //
+ // Make sure that endpoint 0 has the proper speed setting.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | psDevice->ui32Speed |
+ USB_EP_HOST_OUT));
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (uint8_t *)psSetupPacket,
+ sizeof(tUSBRequest));
+
+ //
+ // If this is an IN request, change to that state.
+ //
+ if(psSetupPacket->bmRequestType & USB_RTYPE_DIR_IN)
+ {
+ g_sUSBHEP0State.iState = eEP0StateSetupIN;
+ }
+ else
+ {
+ //
+ // If there is no data then this is not an OUT request.
+ //
+ if(ui32Size != 0)
+ {
+ //
+ // Since there is data, this is an OUT request.
+ //
+ g_sUSBHEP0State.iState = eEP0StateSetupOUT;
+ }
+ else
+ {
+ //
+ // Otherwise this request has no data and just a status phase.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatusIN;
+ }
+ }
+
+ //
+ // Make sure we are talking to the correct device.
+ //
+ if(psDevice->ui8Hub == 0)
+ {
+ USBHostHubAddrSet(USB0_BASE, USB_EP_0, 0,
+ USB_EP_HOST_OUT | psDevice->ui32Speed);
+ }
+ else
+ {
+ USBHostHubAddrSet(USB0_BASE, USB_EP_0,
+ (psDevice->ui8Hub | (psDevice->ui8HubPort << 8)),
+ USB_EP_HOST_OUT | psDevice->ui32Speed);
+ }
+
+ //
+ // Send the Setup packet.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_SETUP);
+
+ //
+ // Block until endpoint 0 returns to the IDLE state.
+ //
+ while(g_sUSBHEP0State.iState != eEP0StateIdle)
+ {
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if((g_sUSBHCD.ui32IntEvents & (INT_EVENT_ENUM | INT_EVENT_SOF)) ==
+ (INT_EVENT_ENUM | INT_EVENT_SOF))
+ {
+ g_sUSBHCD.ui32IntEvents &= ~(INT_EVENT_ENUM | INT_EVENT_SOF);
+
+ USBHCDEnumHandler();
+ }
+
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ if(g_sUSBHEP0State.iState == eEP0StateError)
+ {
+ return(0xffffffff);
+ }
+
+ //
+ // If we aborted the transfer due to an error, tell the caller
+ // that no bytes were transferred.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_VBUS_ERR |
+ INT_EVENT_DISCONNECT))
+ {
+ return(0xffffffff);
+ }
+ }
+
+ //
+ // Calculate and return the number of bytes that were sent or received.
+ // The extra copy into local variables is required to prevent some
+ // compilers from warning about undefined order of volatile access.
+ //
+ ui32DataSize = g_sUSBHEP0State.ui32DataSize;
+ ui32Remaining = g_sUSBHEP0State.ui32BytesRemaining;
+
+ return(ui32DataSize - ui32Remaining);
+}
+
+//*****************************************************************************
+//
+// Starts enumerating a new device connected via the hub.
+//
+// \param ui32Index is the index of the USB controller to use.
+// \param ui32Hub is the hub address from which the connection is being made.
+// \param ui32Port is the hub port number that the new device is connected to.
+// \param pui8ConfigPool is memory to be used to store the device's
+// configuration descriptor.
+// \param ui32ConfigSize is the number of bytes available in the buffer pointed
+// to by pui8ConfigPool.
+//
+// This function is called by the hub class driver after it has detected a new
+// device connection and reset the device.
+//
+// \return Returns the index of the device allocated or 0 if no resources are
+// available. Device index 0 is the hub itself.
+//
+//*****************************************************************************
+uint32_t
+USBHCDHubDeviceConnected(uint32_t ui32Index, uint8_t ui8Hub,
+ uint8_t ui8Port, uint32_t ui32Speed)
+{
+ uint32_t ui32DevIndex;
+
+ //
+ // Debug sanity checks.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(ui8Port);
+
+ DEBUG_OUTPUT("Connection from hub %d, port %d.\n", ui8Hub, ui8Port);
+
+ //
+ // Look for a free slot in the device table.
+ //
+ for(ui32DevIndex = 1; ui32DevIndex <= MAX_USB_DEVICES; ui32DevIndex++)
+ {
+ if((g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags &
+ USBHDEV_FLAG_ALLOCATED) == 0)
+ {
+ //
+ // We found one. Set the state to ensure that it gets enumerated.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags =
+ USBHDEV_FLAG_ALLOCATED;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor->bLength = 0;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub = ui8Hub;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort = ui8Port;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed = ui32Speed;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength = 0;
+
+ //
+ // Set the state to ensure enumeration begins.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConnectedHub;
+
+ DEBUG_OUTPUT("Allocating device %d\n", ui32DevIndex);
+
+ //
+ // Pass the device index back to the hub driver.
+ //
+ return(ui32DevIndex);
+ }
+ }
+
+ //
+ // If we get here, there are device slots available so send back an invalid
+ // device index to tell the caller to ignore this device.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Called when a device is disconnected from a hub.
+//
+// \param ui32Index is the index of the USB controller to use.
+// \param ui32DevIndex is the device index for the USB device that was
+// disconnected.
+//
+//*****************************************************************************
+void
+USBHCDHubDeviceDisconnected(uint32_t ui32Index, uint32_t ui32DevIndex)
+{
+ //
+ // Debug sanity checks.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(ui32DevIndex && (ui32DevIndex <= MAX_USB_DEVICES));
+
+ DEBUG_OUTPUT("Disconnection from hub %d, port %d, device %d\n",
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort, ui32DevIndex);
+
+ //
+ // Set the device state to ensure that USBHCDMain cleans it up.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevDisconnected;
+}
+
+//*****************************************************************************
+//
+// This is the endpoint 0 interrupt handler.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDEnumHandler(void)
+{
+ uint32_t ui32EPStatus;
+ uint32_t ui32DataSize;
+
+ //
+ // Get the end point 0 status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
+
+ //
+ // If there was an error then go to the error state.
+ //
+ if(ui32EPStatus == USB_HOST_EP0_ERROR)
+ {
+ //
+ // Clear this status indicating that the status packet was
+ // received.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ USB_HOST_EP0_ERROR);
+ MAP_USBFIFOFlush(USB0_BASE, USB_EP_0, 0);
+
+ //
+ // Just go back to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateError;
+
+ return;
+ }
+
+ switch(g_sUSBHEP0State.iState)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
+ //
+ case eEP0StateStatus:
+ {
+ //
+ // Handle the case of a received status packet.
+ //
+ if(ui32EPStatus & (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS))
+ {
+ //
+ // Clear this status indicating that the status packet was
+ // received.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ (USB_HOST_EP0_RXPKTRDY |
+ USB_HOST_EP0_STATUS));
+ }
+
+ //
+ // Just go back to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ break;
+ }
+
+ //
+ // This state triggers a STATUS IN request from the device.
+ //
+ case eEP0StateStatusIN:
+ {
+ //
+ // Generate an IN request from the device.
+ //
+ MAP_USBHostRequestStatus(USB0_BASE);
+
+ //
+ // Change to the status phase and wait for the response.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatus;
+
+ break;
+ }
+
+ //
+ // In the IDLE state the code is waiting to receive data from the host.
+ //
+ case eEP0StateIdle:
+ {
+ break;
+ }
+
+ //
+ // Data is still being sent to the host so handle this in the
+ // EP0StateTx() function.
+ //
+ case eEP0StateSetupOUT:
+ {
+ //
+ // Send remaining data if necessary.
+ //
+ USBHCDEP0StateTx();
+
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint 0.
+ //
+ case eEP0StateSetupIN:
+ {
+ //
+ // Generate a new IN request to the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, USB_EP_0);
+
+ //
+ // Proceed to the RX state to receive the requested data.
+ //
+ g_sUSBHEP0State.iState = eEP0StateRx;
+
+ break;
+ }
+
+ //
+ // The endpoint remains in this state until all requested data has
+ // been received.
+ //
+ case eEP0StateRx:
+ {
+ //
+ // There was a stall on endpoint 0 so go back to the idle state
+ // as this command has been terminated.
+ //
+ if(ui32EPStatus & USB_HOST_EP0_RX_STALL)
+ {
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ //
+ // Clear the stalled state on endpoint 0.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ ui32EPStatus & USB_HOST_IN_STATUS);
+ break;
+ }
+
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ ui32DataSize = g_sUSBHEP0State.ui32BytesRemaining;
+ if(ui32DataSize > g_sUSBHEP0State.ui32MaxPacketSize)
+ {
+ //
+ // Don't send more than EP0_MAX_PACKET_SIZE bytes.
+ //
+ ui32DataSize = MAX_PACKET_SIZE_EP0;
+ }
+
+ if(ui32DataSize != 0)
+ {
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0,
+ g_sUSBHEP0State.pui8Data,
+ &ui32DataSize);
+ }
+
+ //
+ // Advance the pointer.
+ //
+ g_sUSBHEP0State.pui8Data += ui32DataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ g_sUSBHEP0State.ui32BytesRemaining -= ui32DataSize;
+
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, USB_EP_0);
+
+ //
+ // If there was not more than the maximum packet size bytes of data
+ // the this was a int16_t packet and indicates that this transfer
+ // is complete. If there were exactly
+ // g_sUSBHEP0State.ui32MaxPacketSize remaining then there still
+ // needs to be null packet sent before this transfer is complete.
+ //
+ if((ui32DataSize < g_sUSBHEP0State.ui32MaxPacketSize) ||
+ (g_sUSBHEP0State.ui32BytesRemaining == 0))
+ {
+ //
+ // Return to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatus;
+
+ //
+ // No more data.
+ //
+ g_sUSBHEP0State.pui8Data = 0;
+
+ //
+ // Send a null packet to acknowledge that all data was
+ // received.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_STATUS);
+ }
+ else
+ {
+ //
+ // Request more data.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, USB_EP_0);
+ }
+ break;
+ }
+
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case eEP0StateStall:
+ {
+ //
+ // Reset the global end point 0 state to IDLE.
+ //
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ break;
+ }
+
+ //
+ // Halt on an unknown state, but only in DEBUG builds.
+ //
+ default:
+ {
+ ASSERT(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending data on endpoint 0.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDEP0StateTx(void)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+
+ //
+ // In the TX state on endpoint 0.
+ //
+ g_sUSBHEP0State.iState = eEP0StateSetupOUT;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_sUSBHEP0State.ui32BytesRemaining;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ui32NumBytes > 64)
+ {
+ ui32NumBytes = 64;
+ }
+
+ //
+ // Save the pointer so that it can be passed to the USBEndpointDataPut()
+ // function.
+ //
+ pui8Data = (uint8_t *)g_sUSBHEP0State.pui8Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_sUSBHEP0State.ui32BytesRemaining -= ui32NumBytes;
+ g_sUSBHEP0State.pui8Data += ui32NumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32NumBytes);
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ui32NumBytes == 64)
+ {
+ //
+ // There is more data to send or exactly 64 bytes were sent, this
+ // means that there is either more data coming or a null packet needs
+ // to be sent to complete the transaction.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);
+ }
+ else
+ {
+ //
+ // Send the last bit of data.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);
+
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatusIN;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function returns the USB hub port for the requested device instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//!
+//! This function returns the USB hub port for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use the value for
+//! \e ui32Instance was passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function returns the USB hub port for
+//! the interface number specified by the \e ui32Interface parameter.
+//!
+//! \return The USB hub port for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevHubPort(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ if(ui32DevIndex == 0xff)
+ {
+ return(ui32DevIndex);
+ }
+
+ return(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB address for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//!
+//! This function returns the USB address for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB address for
+//! the interface number specified by the \e ui32Interface parameter.
+//!
+//! \return The USB address for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevAddress(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ if(ui32DevIndex == 0xff)
+ {
+ return(ui32DevIndex);
+ }
+
+ return(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB class for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB class.
+//!
+//! This function returns the USB class for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB class for
+//! the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! class for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB class for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevClass(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined class.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_CLASS_DEVICE);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface class.
+ //
+ return(psInterface->bInterfaceClass);
+ }
+
+ //
+ // No valid interface so return an undefined class.
+ //
+ return(USB_CLASS_DEVICE);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB subclass for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB subclass.
+//!
+//! This function returns the USB subclass for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB subclass
+//! for the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! subclass for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB subclass for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevSubClass(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined subclass.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_SUBCLASS_UNDEFINED);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface subclass.
+ //
+ return(psInterface->bInterfaceSubClass);
+ }
+
+ //
+ // No valid interface so return an undefined subclass.
+ //
+ return(USB_SUBCLASS_UNDEFINED);
+}
+
+//*****************************************************************************
+//
+//! This function returns the USB protocol for the requested device instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB protocol.
+//!
+//! This function returns the USB protocol for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB protocol
+//! for the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! protocol for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB protocol for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevProtocol(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined protocol.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_PROTOCOL_UNDEFINED);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface protocol.
+ //
+ return(psInterface->bInterfaceProtocol);
+ }
+
+ //
+ // No valid interface so return an undefined protocol.
+ //
+ return(USB_PROTOCOL_UNDEFINED);
+}
+
+//*****************************************************************************
+//
+//! This function sets one of the \b USBLIB_FEATURE_ requests.
+//!
+//! \param ui32Index is the index of the USB controller to access.
+//! \param ui32Feature is one of the \b USBLIB_FEATURE_ defines.
+//! \param pvFeature is a pointer to the data for the \b USBLIB_FEATURE
+//! request.
+//!
+//! This function sends the requested feature request to the USB library.
+//! Not all features are supported by all devices so see the documentation
+//! for the \b USBLIB_FEATURE_ to determine if the feature is supported.
+//!
+//! \return Returns \b true if the feature was set and \b false if the feature
+//! is not supported or could not be changed to the requested value.
+//
+//*****************************************************************************
+bool
+USBHCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature)
+{
+ bool bRetCode;
+ tLPMFeature *psLPMFeature;
+
+ bRetCode = true;
+
+ switch(ui32Feature)
+ {
+ case USBLIB_FEATURE_CPUCLK:
+ {
+ //
+ // Set the ticks per millisecond.
+ //
+ g_ui32Tickms = (*(uint32_t *)pvFeature / 3000);
+ break;
+ }
+ case USBLIB_FEATURE_LPM:
+ {
+ psLPMFeature = (tLPMFeature *)pvFeature;
+
+ if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ g_sUSBHCD.ui32Features |= USBLIB_FEATURE_LPM_EN;
+
+ if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_RMT_WAKE)
+ {
+ g_sUSBHCD.ui32Features |= USBLIB_FEATURE_LPM_RMT_WAKE;
+ }
+ g_sUSBHCD.ui32LPMHIRD = psLPMFeature->ui32HIRD;
+ }
+ else
+ {
+ psLPMFeature->ui32Features &= ~USBLIB_FEATURE_LPM_EN;
+ }
+ break;
+ }
+ case USBLIB_FEATURE_USBPLL:
+ {
+ //
+ // If the PLL rate is not evenly divisible by 60MHz then
+ // do not set it.
+ //
+ if((*(uint32_t *)pvFeature % 60000000) != 0)
+ {
+ bRetCode = false;
+ }
+ else
+ {
+ //
+ // Save the new PLL rate.
+ //
+ g_ui32PLLDiv = (*(uint32_t *)pvFeature / 60000000);
+ }
+ break;
+ }
+ case USBLIB_FEATURE_USBULPI:
+ {
+ //
+ // Save the ULPI support level.
+ //
+ g_ui32ULPISupport = *(uint32_t *)pvFeature;
+
+ break;
+ }
+ default:
+ {
+ bRetCode = false;
+ break;
+ }
+ }
+ return(bRetCode);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psDevice is the device to query.
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDLPMStatus(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Ret;
+
+ ASSERT(psDevice != 0);
+
+ //
+ // Should never have both USBHDEV_FLAG_LPMERROR and USBHDEV_FLAG_LPMPEND
+ // set at the same time.
+ //
+ ASSERT((psDevice->ui32Flags &
+ (USBHDEV_FLAG_LPMERROR | USBHDEV_FLAG_LPMPEND)) !=
+ (USBHDEV_FLAG_LPMERROR | USBHDEV_FLAG_LPMPEND));
+
+ //
+ // Default to no pending transfers or errors.
+ //
+ ui32Ret = USBHCD_LPM_AVAIL;
+
+ if(psDevice->ui32Flags & USBHDEV_FLAG_LPMERROR)
+ {
+ //
+ // An error occurred after the last call to send an LPM command.
+ //
+ ui32Ret = USBHCD_LPM_ERROR;
+ }
+ else if(psDevice->ui32Flags & USBHDEV_FLAG_LPMPEND)
+ {
+ //
+ // Still have a pending transfer.
+ //
+ ui32Ret = USBHCD_LPM_PENDING;
+ }
+
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! This function generates an LPM request for a device to enter L1 sleep
+//! state.
+//!
+//! \param psDevice is the device to query.
+//!
+//! This function sends a request to a device to enter the LPM L1 sleep state.
+//! The caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on another
+//! device this function will return \b USBHCD_LPM_PENDING or
+//! \b USBHCD_LPM_AVAIL if the LPM request was scheduled to be sent. The
+//! caller should check the USBHCDLPMStatus() function to determine if the
+//! request has completed.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHCDLPMSleep(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Ret;
+
+ ASSERT(psDevice != 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // If there is no current LPM pending then send the request.
+ //
+ if((g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM_PEND) ||
+ (psDevice->ui32Flags & USBHDEV_FLAG_LPMPEND))
+ {
+ ui32Ret = USBHCD_LPM_PENDING;
+ }
+ else
+ {
+ //
+ // New pending LPM transfer at the host controller level.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_LPM_PEND;
+
+ //
+ // New pending request and clear any previous error for this
+ // device in case it was already set.
+ //
+ psDevice->ui32Flags |= USBHDEV_FLAG_LPMPEND;
+ psDevice->ui32Flags &= ~USBHDEV_FLAG_LPMERROR;
+
+ USBHostLPMSend(USB0_BASE, psDevice->ui32Address, USB_EP_0);
+
+ ui32Ret = USBHCD_LPM_AVAIL;
+ }
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! This function generates an LPM request for a device to exit L1 sleep state.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function will start LPM resume signaling on the USB bus. This wakes
+//! all devices and is similar to USBHCDResume() call but is triggered by an
+//! LPM request.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDLPMResume(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ USBHostLPMResume(USB0_BASE);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhostpriv.h b/usblib/host/usbhostpriv.h
new file mode 100644
index 0000000..1128749
--- /dev/null
+++ b/usblib/host/usbhostpriv.h
@@ -0,0 +1,201 @@
+//*****************************************************************************
+//
+// usbhostpriv.h - Internal header file for USB host functions.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHOSTPRIV_H__
+#define __USBHOSTPRIV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The states a hub port can be in during device connection.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The port has no device connected.
+ //
+ ePortIdle,
+
+ //
+ // The port has a device present and is waiting for the enumeration
+ // sequence to begin.
+ //
+ ePortConnected,
+
+ //
+ // A device connection notification has been received and we have initiated
+ // a reset to the port. We are waiting for the reset to complete.
+ //
+ ePortResetActive,
+
+ //
+ // The Port reset has completed but now the hub is waiting the required
+ // 10ms before accessing the device.
+ //
+ ePortResetWait,
+
+ //
+ // A device is connected and the port has been reset. Control has been
+ // passed to the main host handling portion of USBLib to enumerate the
+ // device.
+ //
+ ePortActive,
+
+ //
+ // A device has completed enumeration.
+ //
+ ePortEnumerated,
+
+ //
+ // A device is attached to the port but enumeration failed.
+ //
+ ePortError
+}
+tHubPortState;
+
+//*****************************************************************************
+//
+// The list of valid event flags in the g_sUSBHCD.ui32EventEnables member
+// variable.
+//
+//*****************************************************************************
+#define USBHCD_EVFLAG_SOF 0x00000001
+#define USBHCD_EVFLAG_CONNECT 0x00000002
+#define USBHCD_EVFLAG_UNKCNCT 0x00000004
+#define USBHCD_EVFLAG_DISCNCT 0x00000008
+#define USBHCD_EVFLAG_PWRFAULT 0x00000010
+#define USBHCD_EVFLAG_PWRDIS 0x00000020
+#define USBHCD_EVFLAG_PWREN 0x00000040
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the information for devices
+// that are enumerated in the system. It is passed in to Open function of
+// USB host class drivers so that they can allocate any endpoints and parse
+// out other information that the device class needs to complete enumeration.
+//
+//*****************************************************************************
+struct tUSBHostDevice
+{
+ //
+ // The current device address for this device.
+ //
+ uint32_t ui32Address;
+
+ //
+ // The current interface for this device.
+ //
+ uint32_t ui32Interface;
+
+ //
+ // A flag used to record whether this is a low-speed or a full-speed
+ // device.
+ //
+ bool bLowSpeed;
+
+ //
+ // The USB connection speed for this device.
+ //
+ uint32_t ui32Speed;
+
+ //
+ // A flag indicating whether or not we have read the device's
+ // configuration descriptor yet.
+ //
+ bool bConfigRead;
+
+ //
+ // The hub number to which this device is attached.
+ //
+ uint8_t ui8Hub;
+
+ //
+ // The hub port number to which the device is attached.
+ //
+ uint8_t ui8HubPort;
+
+ //
+ // The device descriptor for this device.
+ //
+ tDeviceDescriptor sDeviceDescriptor;
+
+ //
+ // A pointer to the configuration descriptor for this device.
+ //
+ tConfigDescriptor *psConfigDescriptor;
+
+ //
+ // The size of the buffer allocated to psConfigDescriptor.
+ //
+ uint32_t ui32ConfigDescriptorSize;
+
+ //
+ // Internal flags used by the host controller driver.
+ //
+ uint32_t ui32Flags;
+};
+
+//*****************************************************************************
+//
+// Functions within the host controller that are called by the hub class driver
+//
+//*****************************************************************************
+extern uint32_t USBHCDHubDeviceConnected(uint32_t ui32Index, uint8_t ui8Hub,
+ uint8_t ui8Port, uint32_t ui32Speed);
+extern void USBHCDHubDeviceDisconnected(uint32_t ui32Index,
+ uint32_t ui32DevIndex);
+
+//*****************************************************************************
+//
+// Functions in the hub class driver that are called by the host controller.
+//
+//*****************************************************************************
+extern void USBHHubMain(void);
+extern void USBHHubInit(void);
+extern void USBHHubEnumerationComplete(uint8_t ui8Hub, uint8_t ui8Port);
+extern void USBHHubEnumerationError(uint8_t ui8Hub, uint8_t ui8Port);
+extern uint32_t USBHCDLPMSleep(tUSBHostDevice *psDevice);
+extern uint32_t USBHCDLPMStatus(tUSBHostDevice *psDevice);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHOSTPRIV_H__
diff --git a/usblib/host/usbhscsi.c b/usblib/host/usbhscsi.c
new file mode 100644
index 0000000..407dc2d
--- /dev/null
+++ b/usblib/host/usbhscsi.c
@@ -0,0 +1,777 @@
+//*****************************************************************************
+//
+// usbhscsi.c - USB host SCSI layer used by the USB host MSC driver.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/usbmsc.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhmsc.h"
+#include "usblib/host/usbhscsi.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the data verify tag passed between requests.
+//
+//*****************************************************************************
+#define CBW_TAG_VALUE 0x54231990
+
+//*****************************************************************************
+//
+//! This function is used to issue SCSI commands via USB.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param psSCSICmd is the SCSI command structure to send.
+//! \param pui8Data is pointer to the command data to be sent.
+//! \param pui32Size is the number of bytes is the number of bytes expected or
+//! sent by the command.
+//!
+//! This internal function is used to handle SCSI commands sent by other
+//! functions. It serves as a layer between the SCSI command and the USB
+//! interface being used to send the command. The \e pSCSI parameter contains
+//! the SCSI command to send. For commands that expect data back, the
+//! \e pui8Data is the buffer to store the data into and \e pui32Size is used
+//! to store the amount of data to request as well as used to indicate how many
+//! bytes were filled into the \e pui8Data buffer on return. For commands that
+//! are sending data, \e pui8Data is the data to be sent and \e pui32Size is
+//! the number of bytes to send.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+static uint32_t
+USBHSCSISendCommand(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ tMSCCBW *psSCSICmd, uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCSW sCmdStatus;
+ uint32_t ui32Bytes;
+
+ //
+ // Initialize the command status.
+ //
+ sCmdStatus.dCSWSignature = 0;
+ sCmdStatus.dCSWTag = 0;
+ sCmdStatus.bCSWStatus = SCSI_CMD_STATUS_FAIL;
+
+ //
+ // Set the CBW signature and tag.
+ //
+ psSCSICmd->dCBWSignature = CBW_SIGNATURE;
+ psSCSICmd->dCBWTag = CBW_TAG_VALUE;
+
+ //
+ // Set the size of the data to be returned by the device.
+ //
+ psSCSICmd->dCBWDataTransferLength = *pui32Size;
+
+ //
+ // Send the command.
+ //
+ ui32Bytes = USBHCDPipeWrite(ui32OutPipe, (uint8_t*)psSCSICmd,
+ sizeof(tMSCCBW));
+
+ //
+ // If no bytes went out then the command failed.
+ //
+ if(ui32Bytes == 0)
+ {
+ return(SCSI_CMD_STATUS_FAIL);
+ }
+
+ //
+ // Only request data if there is data to request.
+ //
+ if(psSCSICmd->dCBWDataTransferLength != 0)
+ {
+ //
+ // See if this is a read or a write.
+ //
+ if(psSCSICmd->bmCBWFlags & CBWFLAGS_DIR_IN)
+ {
+ //
+ // Read the data back.
+ //
+ *pui32Size = USBHCDPipeRead(ui32InPipe, pui8Data, *pui32Size);
+ }
+ else
+ {
+ //
+ // Write the data out.
+ //
+ *pui32Size = USBHCDPipeWrite(ui32OutPipe, pui8Data, *pui32Size);
+ }
+ }
+
+ //
+ // Get the status of the command.
+ //
+ ui32Bytes = USBHCDPipeRead(ui32InPipe, (uint8_t *)&sCmdStatus,
+ sizeof(tMSCCSW));
+
+
+ //
+ // If the status was invalid or did not have the correct signature then
+ // indicate a failure.
+ //
+ if((ui32Bytes == 0) || (sCmdStatus.dCSWSignature != CSW_SIGNATURE) ||
+ (sCmdStatus.dCSWTag != CBW_TAG_VALUE))
+ {
+ return(SCSI_CMD_STATUS_FAIL);
+ }
+
+ //
+ // Return the status.
+ //
+ return((uint32_t)sCmdStatus.bCSWStatus);
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI inquiry command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Inquiry command to a mass
+//! storage device. To allow for multiple devices, the \e ui32InPipe and
+//! \e ui32OutPipe parameters indicate which USB pipes to use for this call.
+//!
+//! \note The \e pui8Data buffer pointer should have at least
+//! \b SCSI_INQUIRY_DATA_SZ bytes of data or this function will overflow the
+//! buffer.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIInquiry(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // The number of bytes of data that the host expects to transfer on the
+ // Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during
+ // the execution of this command. If this field is zero, the device and
+ // the host shall transfer no data between the CBW and the associated CSW,
+ // and the device shall ignore the value of the Direction bit in
+ // bmCBWFlags.
+ //
+ *pui32Size = SCSI_INQUIRY_DATA_SZ;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // This is the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Send Inquiry command with no request for vital product data.
+ //
+ pui32Data[0] = SCSI_INQUIRY_CMD;
+
+ //
+ // Allocation length.
+ //
+ pui32Data[1] = SCSI_INQUIRY_DATA_SZ;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI read capacity command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Read Capacity command
+//! to a mass storage device that is connected. To allow for multiple devices,
+//! the \e ui32InPipe and \e ui32OutPipe parameters indicate which USB pipes to
+//! use for this call.
+//!
+//! \note The \e pui8Data buffer pointer should have at least
+//! \b SCSI_READ_CAPACITY_SZ bytes of data or this function will overflow the
+//! buffer.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIReadCapacity(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // Set the size of the command data.
+ //
+ *pui32Size = SCSI_READ_CAPACITY_SZ;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Only use the first byte and set it to the Read Capacity command. The
+ // rest are set to 0.
+ //
+ pui32Data[0] = SCSI_READ_CAPACITY;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI read capacities command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Read Capacities command
+//! to a mass storage device that is connected. To allow for multiple devices,
+//! the \e ui32InPipe and \e ui32OutPipe parameters indicate which USB pipes to
+//! use for this call.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIReadCapacities(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Only use the first byte and set it to the Read Capacity command. The
+ // rest are set to 0.
+ //
+ pui32Data[0] = SCSI_READ_CAPACITIES;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI Mode Sense(6) command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32Flags is a combination of flags defining the exact query that is
+//! to be made.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//!
+//! This function should be used to issue a SCSI Mode Sense(6) command
+//! to a mass storage device. To allow for multiple devices,the \e ui32InPipe
+//! and \e ui32OutPipe parameters indicate which USB pipes to use for this
+//! call. The call will return at most the number of bytes in the \e pui32Size
+//! parameter, however it can return less and change the \e pui32Size parameter
+//! to the number of valid bytes in the \e *pui32Size buffer.
+//!
+//! The \e ui32Flags parameter is a combination of the following three sets of
+//! definitions:
+//!
+//! One of the following values must be specified:
+//!
+//! - \b SCSI_MS_PC_CURRENT request for current settings.
+//! - \b SCSI_MS_PC_CHANGEABLE request for changeable settings.
+//! - \b SCSI_MS_PC_DEFAULT request for default settings.
+//! - \b SCSI_MS_PC_SAVED request for the saved values.
+//!
+//! One of these following values must also be specified to determine the page
+//! code for the request:
+//!
+//! - \b SCSI_MS_PC_VENDOR is the vendor specific page code.
+//! - \b SCSI_MS_PC_DISCO is the disconnect/reconnect page code.
+//! - \b SCSI_MS_PC_CONTROL is the control page code.
+//! - \b SCSI_MS_PC_LUN is the protocol specific LUN page code.
+//! - \b SCSI_MS_PC_PORT is the protocol specific port page code.
+//! - \b SCSI_MS_PC_POWER is the power condition page code.
+//! - \b SCSI_MS_PC_INFORM is the informational exceptions page code.
+//! - \b SCSI_MS_PC_ALL will request all pages codes supported by the device.
+//!
+//! The last value is optional and supports the following global flag:
+//! - \b SCSI_MS_DBD disables returning block descriptors.
+//!
+//! Example: Request for all current settings.
+//!
+//! \verbatim
+//! SCSIModeSense6(ui32InPipe, ui32OutPipe,
+//! SCSI_MS_PC_CURRENT | SCSI_MS_PC_ALL,
+//! pui8Data, pui32Size);
+//! \endverbatim
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIModeSense6(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32Flags, uint8_t *pui8Data,
+ uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Set the options for the Mode Sense Command (6).
+ //
+ pui32Data[0] = (SCSI_MODE_SENSE_6 | ui32Flags);
+ pui32Data[1] = (uint8_t)*pui32Size;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Test Unit Ready command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//!
+//! This function is used to issue a SCSI Test Unit Ready command to a device.
+//! This call will simply return the results of issuing this command.
+//!
+//! \return This function returns the results of the SCSI Test Unit Ready
+//! command. The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSITestUnitReady(uint32_t ui32InPipe, uint32_t ui32OutPipe)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t ui32Size;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // No data in this command.
+ //
+ ui32Size = 0;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Set the parameter options.
+ //
+ pui32Data[0] = SCSI_TEST_UNIT_READY;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, 0,
+ &ui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Request Sense command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//!
+//! This function is used to issue a SCSI Request Sense command to a device.
+//! It will return the data in the buffer pointed to by \e pui8Data. The
+//! parameter \e pui32Size should have the allocation size in bytes of the
+//! buffer pointed to by \e pui8Data.
+//!
+//! \return This function returns the results of the SCSI Request Sense
+//! command. The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIRequestSense(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Set the parameter options.
+ //
+ pui32Data[0] = SCSI_REQUEST_SENSE;
+ pui32Data[1] = 18;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Read(10) command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32LBA is the logical block address to read.
+//! \param pui8Data is the data buffer to return the data.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//! \param ui32NumBlocks is the number of contiguous blocks to read from the
+//! device.
+//!
+//! This function is used to issue a SCSI Read(10) command to a device. The
+//! \e ui32LBA parameter specifies the logical block address to read from the
+//! device. The data from this block will be returned in the buffer pointed to
+//! by \e pui8Data. The parameter \e pui32Size should indicate enough space to
+//! hold a full block size, or only the first \e pui32Size bytes of the LBA are
+//! returned.
+//!
+//! \return This function returns the results of the SCSI Read(10) command.
+//! The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIRead10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks)
+{
+ tMSCCBW sSCSICmd;
+ int32_t i32Idx;
+
+ //
+ // Zero out the response data.
+ //
+ for(i32Idx = 0; i32Idx < sizeof(sSCSICmd.CBWCB); i32Idx++)
+ {
+ sSCSICmd.CBWCB[i32Idx] = 0;
+ }
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 10;
+
+ //
+ // Set the parameter options.
+ //
+ sSCSICmd.CBWCB[0] = SCSI_READ_10;
+
+ //
+ // LBA starts at offset 2.
+ //
+ sSCSICmd.CBWCB[2] = (uint8_t)(ui32LBA >> 24);
+ sSCSICmd.CBWCB[3] = (uint8_t)(ui32LBA >> 16);
+ sSCSICmd.CBWCB[4] = (uint8_t)(ui32LBA >> 8);
+ sSCSICmd.CBWCB[5] = (uint8_t)ui32LBA;
+
+ //
+ // Transfer length in blocks starts at offset 7.
+ //
+ sSCSICmd.CBWCB[7] = (uint8_t)(ui32NumBlocks >> 8);
+ sSCSICmd.CBWCB[8] = (uint8_t)ui32NumBlocks;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Write(10) command to a device.
+//!
+//! This function is used to issue a SCSI Write(10) command to a device. The
+//! \e ui32LBA parameter specifies the logical block address on the device.
+//! The data to write to this block should be in the buffer pointed to by
+//! \e pui8Data parameter. The parameter \e pui32Size should indicate the
+//! amount of data to write to the specified LBA.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32LBA is the logical block address to read.
+//! \param pui8Data is the data buffer to write out.
+//! \param pui32Size is the size of the buffer.
+//! \param ui32NumBlocks is the number of contiguous blocks to write to the
+//! device.
+//!
+//! \return This function returns the results of the SCSI Write(10) command.
+//! The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIWrite10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_OUT;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 10;
+
+ //
+ // Set the parameter options.
+ //
+ sSCSICmd.CBWCB[0] = SCSI_WRITE_10;
+
+ //
+ // Clear the reserved field.
+ //
+ sSCSICmd.CBWCB[1] = 0;
+
+ //
+ // LBA starts at offset 2.
+ //
+ sSCSICmd.CBWCB[2] = (uint8_t)(ui32LBA >> 24);
+ sSCSICmd.CBWCB[3] = (uint8_t)(ui32LBA >> 16);
+ sSCSICmd.CBWCB[4] = (uint8_t)(ui32LBA >> 8);
+ sSCSICmd.CBWCB[5] = (uint8_t)ui32LBA;
+
+ //
+ // Clear the reserved field.
+ //
+ sSCSICmd.CBWCB[6] = 0;
+
+ //
+ // Set the transfer length in blocks.
+ // This also sets the Control value to 0 at offset 9.
+ //
+ sSCSICmd.CBWCB[7] = (ui32NumBlocks & 0xFF00) >> 8;
+
+ //
+ // The blocks go into is byte offset 8 or word address 2.
+ //
+ pui32Data[2] = (ui32NumBlocks & 0xFF);
+
+ //
+ // The blocks go into is byte offset 12 or word address 3.
+ //
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhscsi.h b/usblib/host/usbhscsi.h
new file mode 100644
index 0000000..29291e1
--- /dev/null
+++ b/usblib/host/usbhscsi.h
@@ -0,0 +1,87 @@
+//*****************************************************************************
+//
+// usbhscsi.h - Definitions for the USB host SCSI layer.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHSCSI_H__
+#define __USBHSCSI_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs exported by the USB SCSI layer.
+//
+//*****************************************************************************
+extern uint32_t USBHSCSIInquiry(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Buffer, uint32_t *pui32Size);
+extern uint32_t USBHSCSIReadCapacity(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size);
+extern uint32_t USBHSCSIReadCapacities(uint32_t ui32InPipe,
+ uint32_t ui32OutPipe, uint8_t *pui8Data,
+ uint32_t *pui32Size);
+extern uint32_t USBHSCSIModeSense6(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32Flags, uint8_t *pui8Data,
+ uint32_t *pui32Size);
+extern uint32_t USBHSCSITestUnitReady(uint32_t ui32InPipe,
+ uint32_t ui32OutPipe);
+extern uint32_t USBHSCSIRequestSense(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size);
+extern uint32_t USBHSCSIRead10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks);
+extern uint32_t USBHSCSIWrite10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHSCSI_H__
diff --git a/usblib/readme.txt b/usblib/readme.txt
new file mode 100644
index 0000000..54f56a3
--- /dev/null
+++ b/usblib/readme.txt
@@ -0,0 +1,21 @@
+This project will build the Tiva USB Library.
+
+-------------------------------------------------------------------------------
+
+Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+Software License Agreement
+
+Texas Instruments (TI) is supplying this software for use solely and
+exclusively on TI's microcontroller products. The software is owned by
+TI and/or its suppliers, and is protected under applicable copyright
+laws. You may not combine this software with "viral" open-source
+software in order to form a larger program.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, FOR ANY REASON WHATSOEVER.
+
+This is part of revision 2.1.0.12573 of the Tiva USB Library.
diff --git a/usblib/rvmdk/usblib.lib b/usblib/rvmdk/usblib.lib
new file mode 100644
index 0000000..56ffd6e
--- /dev/null
+++ b/usblib/rvmdk/usblib.lib
Binary files differ
diff --git a/usblib/usb-ids.h b/usblib/usb-ids.h
new file mode 100644
index 0000000..31f4ae4
--- /dev/null
+++ b/usblib/usb-ids.h
@@ -0,0 +1,57 @@
+//*****************************************************************************
+//
+// usb-ids.h - Definitions of VIDs and PIDs used by USB library.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBIDS_H__
+#define __USBIDS_H__
+
+//*****************************************************************************
+//
+// TI Vendor ID for devices that use VID as 0x1CBE.
+//
+//*****************************************************************************
+#define USB_VID_TI_1CBE 0x1cbe
+
+//*****************************************************************************
+//
+// Product IDs.
+//
+//*****************************************************************************
+#define USB_PID_MOUSE 0x0000
+#define USB_PID_KEYBOARD 0x0001
+#define USB_PID_SERIAL 0x0002
+#define USB_PID_BULK 0x0003
+#define USB_PID_SCOPE 0x0004
+#define USB_PID_MSC 0x0005
+#define USB_PID_AUDIO 0x0006
+#define USB_PID_COMP_SERIAL 0x0007
+#define USB_PID_COMP_AUDIO_HID 0x0008
+#define USB_PID_COMP_HID_SER 0x0009
+#define USB_PID_COMP_HID_DFU 0x000A
+#define USB_PID_DATA_LOGGER 0x000B
+#define USB_PID_COMP_HID_HID 0x000D
+#define USB_PID_GAMEPAD 0x000F
+#define USB_PID_LP_CGAMEPAD 0x0010
+#define USB_PID_DFU 0x00FF
+
+#endif /* __USBIDS_H__ */
diff --git a/usblib/usbaudio.h b/usblib/usbaudio.h
new file mode 100644
index 0000000..eee61bc
--- /dev/null
+++ b/usblib/usbaudio.h
@@ -0,0 +1,718 @@
+//*****************************************************************************
+//
+// usbaudio.h - Definitions used by Audio Class devices.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBAUDIO_H__
+#define __USBAUDIO_H__
+
+
+//*****************************************************************************
+//
+// Standard Audio descriptor sub types.
+//
+//*****************************************************************************
+#define USB_AI_UNDEFINED 0
+#define USB_AI_HEADER 1
+#define USB_AI_INPUT_TERMINAL 2
+#define USB_AI_OUTPUT_TERMINAL 3
+#define USB_AI_MIXER_UNIT 4
+#define USB_AI_SELECTOR_UNIT 5
+#define USB_AI_FEATURE_UNIT 6
+#define USB_AI_PROCESSING_UNIT 7
+#define USB_AI_EXTENSION_UNIT 8
+
+//*****************************************************************************
+//
+// Standard Audio Streaming Interface descriptor types.
+//
+//*****************************************************************************
+#define USB_AS_UNDEFINED 0
+#define USB_AS_GENERAL 1
+#define USB_AS_FORMAT_TYPE 2
+#define USB_AS_FORMAT_SPECIFIC 3
+
+//*****************************************************************************
+//
+// Standard USB terminal types used with audio terminal descriptors. These
+// are defined in the "Universal Serial Bus Device Class Definition for
+// Terminal Types" version 1.0 released March 18, 1998.
+//
+//*****************************************************************************
+#define USB_TTYPE_UNDEFINED 0x0100
+#define USB_TTYPE_STREAMING 0x0101
+#define USB_TTYPE_VENDOR 0x01ff
+
+#define USB_TTYPE_OUT_UNDEF 0x0300
+#define USB_TTYPE_OUT_SPEAKER 0x0301
+#define USB_TTYPE_OUT_HEADPHONE 0x0302
+#define USB_TTYPE_OUT_DESK_SPKR 0x0304
+#define USB_TTYPE_OUT_ROOM_SPKR 0x0305
+#define USB_TTYPE_OUT_COMM_SPKR 0x0306
+#define USB_TTYPE_OUT_LFE 0x0307
+
+#define USB_TTYPE_EXT_UNDEF 0x0600
+#define USB_TTYPE_EXT_ANALOG 0x0601
+#define USB_TTYPE_EXT_DIGITAL 0x0602
+#define USB_TTYPE_EXT_LINE 0x0603
+#define USB_TTYPE_EXT_LEGACY 0x0604
+#define USB_TTYPE_EXT_SPDIF 0x0605
+#define USB_TTYPE_EXT_1394_DA 0x0606
+#define USB_TTYPE_EXT_1394_DV 0x0607
+
+//*****************************************************************************
+//
+// Audio Interface Subclass Codes
+//
+//*****************************************************************************
+#define USB_ASC_UNDEFINED 0x00
+#define USB_ASC_AUDIO_CONTROL 0x01
+#define USB_ASC_AUDIO_STREAMING 0x02
+#define USB_ASC_MIDI_STREAMING 0x03
+
+//*****************************************************************************
+//
+// Audio Class-Specific Descriptor Types
+// (Table A-4)
+//
+//*****************************************************************************
+#define USB_ACSDT_UNDEFINED 0x20
+#define USB_ACSDT_DEVICE 0x21
+#define USB_ACSDT_CONFIGURATION 0x22
+#define USB_ACSDT_STRING 0x23
+#define USB_ACSDT_INTERFACE 0x24
+#define USB_ACSDT_ENDPOINT 0x25
+
+//*****************************************************************************
+//
+// Audio Class-Specific AC Interface Descriptor Subtypes
+// (Table A-5)
+//
+//*****************************************************************************
+#define USB_ACDSTYPE_UNDEFINED 0x00
+#define USB_ACDSTYPE_HEADER 0x01
+#define USB_ACDSTYPE_IN_TERMINAL 0x02
+#define USB_ACDSTYPE_OUT_TERMINAL 0x03
+#define USB_ACDSTYPE_MIXER_UNIT 0x04
+#define USB_ACDSTYPE_SELECTOR_UNIT 0x05
+#define USB_ACDSTYPE_FEATURE_UNIT 0x06
+#define USB_ACDSTYPE_PROCESSING_UNIT 0x07
+#define USB_ACDSTYPE_EXTENSION_UNIT 0x08
+
+//*****************************************************************************
+//
+// Audio Class-Specific AS Interface Descriptor Subtypes
+// (Table A-6)
+//
+//*****************************************************************************
+#define USB_ASDSTYPE_UNDEFINED 0x00
+#define USB_ASDSTYPE_GENERAL 0x01
+#define USB_ASDSTYPE_FORMAT_TYPE 0x02
+#define USB_ASDSTYPE_FORMAT_SPECIFIC 0x03
+
+//*****************************************************************************
+//
+// Audio Data Format Type I Codes.
+//
+//*****************************************************************************
+#define USB_ADF_UNDEFINED 0x0000
+#define USB_ADF_PCM 0x0001
+#define USB_ADF_PCM8 0x0002
+#define USB_ADF_IEEE_FLOAT 0x0003
+#define USB_ADF_ALAW 0x0004
+#define USB_ADF_MULAW 0x0005
+
+//*****************************************************************************
+//
+// Audio Format Type Codes
+//
+//*****************************************************************************
+#define USB_AF_TYPE_UNDEFINED 0x00
+#define USB_AF_TYPE_TYPE_I 0x01
+#define USB_AF_TYPE_TYPE_II 0x02
+#define USB_AF_TYPE_TYPE_III 0x03
+
+//*****************************************************************************
+//
+// Audio Class-Specific controls used with bmaControls values.
+//
+//*****************************************************************************
+#define USB_ACONTROL_MUTE 0x0001 // Mute
+#define USB_ACONTROL_VOLUME 0x0002 // Volume
+#define USB_ACONTROL_BASS 0x0004 // Bass
+#define USB_ACONTROL_MID 0x0008 // Mid
+#define USB_ACONTROL_TREBLE 0x0010 // Treble
+#define USB_ACONTROL_EQ 0x0020 // Graphic Equalizer
+#define USB_ACONTROL_AGC 0x0040 // Automatic Gain
+#define USB_ACONTROL_DELAY 0x0080 // Delay
+#define USB_ACONTROL_BASS_BOOST 0x0100 // Bass Boost
+#define USB_ACONTROL_LOUD 0x0200 // Loudness
+
+//*****************************************************************************
+//
+// Audio Class-Specific Output terminal types.
+//
+//*****************************************************************************
+#define USB_ATTYPE_UNDEFINED 0x0300 // Output Terminal, undefined Type.
+#define USB_ATTYPE_SPEAKER 0x0301 // A generic speaker.
+#define USB_ATTYPE_HEADPHONES 0x0302 // A head-mounted audio output device.
+#define USB_ATTYPE_HMD 0x0303 // The audio part of a VR head mounted
+ // display.
+#define USB_ATTYPE_SPEAKER_DT 0x0304 // Desktop or Monitor speaker(s).
+#define USB_ATTYPE_SPEAKER_RM 0x0305 // Larger room speaker(s).
+#define USB_ATTYPE_SPEAKER_COM 0x0306 // Communications Speaker (phone).
+#define USB_ATTYPE_SPEAKER_LFE 0x0307 // Speaker designed for low
+ // frequencies.
+
+//*****************************************************************************
+//
+// USB Audio channel configuration bits for wChannelConfig values.
+// wChannelConfig: a bit field that indicates which spatial locations are
+// present in the cluster. The bit allocations are as follows:
+//
+//*****************************************************************************
+#define USB_CHANNEL_L 0x0001 // Left Front (L)
+#define USB_CHANNEL_R 0x0002 // Right Front (R)
+#define USB_CHANNEL_C 0x0004 // Center Front (C)
+#define USB_CHANNEL_LFE 0x0008 // Low Frequency Enhancement (LFE)
+#define USB_CHANNEL_LS 0x0010 // Left Surround (LS)
+#define USB_CHANNEL_RS 0x0020 // Right Surround (RS)
+#define USB_CHANNEL_LC 0x0040 // Left of Center (LC)
+#define USB_CHANNEL_RC 0x0080 // Right of Center (RC)
+#define USB_CHANNEL_S 0x0100 // Surround (S)
+#define USB_CHANNEL_SL 0x0200 // Side Left (SL)
+#define USB_CHANNEL_SR 0x0400 // Side Right (SR)
+#define USB_CHANNEL_T 0x0800 // Top (T)
+
+//*****************************************************************************
+//
+// Endpoint attributes for Audio Class General type.
+//
+//*****************************************************************************
+#define USB_EP_ATTR_ACG_SAMPLING 0x01 // Sampling Frequency
+#define USB_EP_ATTR_ACG_PITCH 0x02 // Pitch
+#define USB_EP_ATTR_ACG_MAXPACKET 0x80 // MaxPacketsOnly
+
+//*****************************************************************************
+//
+// Indicates the units used for the wLockDelay field for Audio Class General
+// type.
+//
+//*****************************************************************************
+#define USB_EP_LOCKDELAY_UNDEF 0x00 // Undefined
+#define USB_EP_LOCKDELAY_MS 0x01 // Milliseconds
+#define USB_EP_LOCKDELAY_PCM 0x02 // Decoded PCM samples
+
+//*****************************************************************************
+//
+// Audio Class-Specific Request Codes
+//
+//*****************************************************************************
+#define USB_AC_SET_CUR 0x01
+#define USB_AC_SET_MIN 0x02
+#define USB_AC_SET_MAX 0x03
+#define USB_AC_SET_RES 0x04
+#define USB_AC_SET_MEM 0x05
+#define USB_AC_GET_CUR 0x81
+#define USB_AC_GET_MIN 0x82
+#define USB_AC_GET_MAX 0x83
+#define USB_AC_GET_RES 0x84
+#define USB_AC_GET_MEM 0x85
+#define USB_AC_GET_STAT 0xff
+
+#define USB_CS_CONTROL_M 0xff00
+#define USB_CS_CHANNEL_M 0x00ff
+
+//*****************************************************************************
+//
+// Endpoint Control Selectors
+//
+//*****************************************************************************
+#define EP_CONTROL_UNDEFINED 0x0000
+#define SAMPLING_FREQ_CONTROL 0x0100
+#define PITCH_CONTROL 0x0200
+
+//*****************************************************************************
+//
+// Feature Unit Control Selectors
+//
+//*****************************************************************************
+#define FU_CONTROL_UNDEFINED 0x0000
+#define MUTE_CONTROL 0x0100
+#define VOLUME_CONTROL 0x0200
+#define BASS_CONTROL 0x0300
+#define MID_CONTROL 0x0400
+#define TREBLE_CONTROL 0x0500
+#define EQUALIZER_CONTROL 0x0600
+#define AUTOMATIC_GAIN_CONTROL 0x0700
+#define DELAY_CONTROL 0x0800
+#define BASS_BOOST_CONTROL 0x0900
+#define LOUDNESS_CONTROL 0x0A00
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requires a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+//! This structure describes the Class-Specific Audio Class Interface Header
+//! Descriptor as defined in Universal Serial Bus Device Class Definition
+//! for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_DSUBTYPE_HEADER for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Audio Device Class Specification Release Number in Binary-Coded
+ //! Decimal.
+ //
+ uint16_t bcdADC;
+
+ //
+ //! Total number of bytes returned for the class-specific AudioControl
+ //! interface descriptor. Includes the combined length of this descriptor
+ //! header and all Unit and Terminal descriptors.
+ //
+ uint16_t wTotai32Length;
+
+ //
+ //! The number of AudioStreaming and MIDIStreaming interfaces in the Audio
+ //! Interface Collection to which this AudioControl interface belongs.
+ //
+ uint8_t bInCollection;
+
+ //
+ //! Interface number of the first AudioStreaming or MIDIStreaming interface
+ //! in the Collection.
+ //
+ uint8_t baInterfaceNr;
+}
+PACKED tACHeader;
+
+//*****************************************************************************
+//
+// These are the possible bits set in the tACInputTerminal.wChannelConfig
+// value.
+//
+//*****************************************************************************
+#define USB_AC_CC_LEFT 0x0001
+#define USB_AC_CC_RIGHT 0x0002
+#define USB_AC_CC_CENTER 0x0004
+#define USB_AC_CC_LFE 0x0008
+#define USB_AC_CC_LEFTSURROUND 0x0010
+#define USB_AC_CC_RIGHTSURROUND 0x0020
+#define USB_AC_CC_LEFT_CENTER 0x0040
+#define USB_AC_CC_RIGHT_CENTER 0x0080
+#define USB_AC_CC_SURROUND 0x0100
+#define USB_AC_CC_SIDE_LEFT 0x0200
+#define USB_AC_CC_SIDE_RIGHT 0x0400
+#define USB_AC_CC_TOP 0x0800
+
+//*****************************************************************************
+//
+//! This structure describes the Feature Unit Descriptor as defined in
+//! Universal Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_DSUBTYPE_IN_TERM for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Constant uniquely identifying the Unit within the audio function. This
+ //! value is used in all requests to address this Unit.
+ //
+ uint8_t bUnitID;
+
+ //
+ //! ID of the Unit or Terminal to which this Feature Unit is connected.
+ //
+ uint8_t bSourceID;
+
+ //
+ //! ID of the Output Terminal to which this Input Terminal is associated.
+ //
+ uint8_t bControlSize;
+
+ //
+ //! A bit set to 1 indicates that the mentioned Control is supported for
+ //! a given channel. See the USB_FU_* defines for the bit definitions.
+ //! This actually an array of elements of size bControlSize so be
+ //! careful when using this value directly.
+ //
+ uint16_t bmaControls;
+}
+PACKED tACFeatureUnit;
+
+//*****************************************************************************
+//
+//! This structure describes the Output Terminal Descriptor as defined in
+//! Universal Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_DSUBTYPE_OUT_TERM for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Constant uniquely identifying the Terminal within the audio function.
+ //! This value is used in all requests to address this Terminal.
+ //
+ uint8_t bTerminalID;
+
+ //
+ //! Constant characterizing the type of Terminal. See USB Audio Terminal
+ //! Types.
+ //
+ uint16_t wTerminalType;
+
+ //
+ //! Constant, identifying the Input Terminal to which this Output Terminal
+ //! is associated.
+ //
+ uint8_t bAssocTerminal;
+
+ //
+ //! ID of the Unit or Terminal to which this Terminal is connected.
+ //
+ uint8_t bSourceID;
+
+ //
+ //! Index of a string descriptor, describing the Output Terminal.
+ //
+ uint8_t iTerminal;
+}
+PACKED tACOutputTerminal;
+
+//*****************************************************************************
+//
+//! This structure describes the Input Terminal Descriptor as defined in
+//! Universal Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_DSUBTYPE_OUT_TERM for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Constant uniquely identifying the Terminal within the audio function.
+ //! This value is used in all requests to address this Terminal.
+ //
+ uint8_t bTerminalID;
+
+ //
+ //! Constant characterizing the type of Terminal. See USB Audio Terminal
+ //! Types.
+ //
+ uint16_t wTerminalType;
+
+ //
+ //! Constant, identifying the Input Terminal to which this Output Terminal
+ //! is associated.
+ //
+ uint8_t bAssocTerminal;
+
+ //
+ //! Number of logical output channels in the Terminal's output audio
+ //! channel cluster.
+ //
+ uint8_t bNrChannels;
+
+ //
+ //! Describes the spatial location of the logical channels.
+ //
+ uint16_t wChannelConfig;
+
+ //
+ //! Index of a string descriptor, describing the name of the first logical
+ //! channel.
+ //
+ uint8_t iChannelNames;
+
+ //
+ //! Index of a string descriptor, describing the Output Terminal.
+ //
+ uint8_t iTerminal;
+}
+PACKED tACInputTerminal;
+
+//*****************************************************************************
+//
+//! This structure describes the Mixer Descriptor as defined in Universal
+//! Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_AI_MIXER_UNIT for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Constant uniquely identifying the Unit within the audio function. This
+ //! value is used in all requests to address this Unit.
+ //
+ uint8_t bUnitID;
+
+ //
+ //! Number of Input Pins of this Unit.
+ //
+ uint8_t bNrInPins;
+
+ //
+ //! ID of the Unit or Terminal to which the first Input Pin of this Mixer
+ //! Unit is connected.
+ //
+ uint8_t baSourceID;
+}
+PACKED tACMixer;
+
+//*****************************************************************************
+//
+//! This structure describes the Selector Descriptor as defined in Universal
+//! Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_AI_MIXER_UNIT for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! Constant uniquely identifying the Unit within the audio function. This
+ //! value is used in all requests to address this Unit.
+ //
+ uint8_t bUnitID;
+
+ //
+ //! Number of Input Pins of this Unit.
+ //
+ uint8_t bNrInPins;
+
+ //
+ //! ID of the Unit or Terminal to which the first Input Pin of this Mixer
+ //! Unit is connected.
+ //
+ uint8_t baSourceID;
+}
+PACKED tACSelector;
+
+//*****************************************************************************
+//
+//! This structure describes the Output Terminal Descriptor as defined in
+//! Universal Serial Bus Device Class Definition for Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_DSUBTYPE_GENERAL for the header.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! The Terminal ID of the Terminal to which the endpoint of this
+ //! interface is connected.
+ //
+ uint8_t bTerminalLink;
+
+ //
+ //! Delay introduced by the data path. Expressed in number of frames.
+ //
+ uint8_t bDelay;
+
+ //
+ //! The Audio Data Format that has to be used to communicate with this
+ //! interface.
+ //
+ uint16_t wFormatTag;
+}
+PACKED tACGeneral;
+
+//*****************************************************************************
+//
+//! This structure describes the Type I Audio format descriptors defined in
+//! USB Audio Devices Release 1.0.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_CS_INTERFACE (36).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! This will be USB_AS_FORMAT_TYPE.
+ //
+ uint8_t bDescriptorSubtype;
+
+ //
+ //! This will be USB_AS_FORMAT_TYPE_I.
+ //
+ uint8_t bFormatType;
+
+ //
+ //! Number of channels on this streaming interface.
+ //
+ uint8_t bNrChannels;
+
+ //
+ //! Number of bytes per audio sub-frame or channel.
+ //
+ uint8_t bSubFrameSize;
+
+ //
+ //! Number of bits per sample.
+ //
+ uint8_t bBitResolution;
+
+ //
+ //! Number of sample rates that are supported.
+ //
+ uint8_t bSamFreqType;
+
+ //
+ //! Number of bits per sample.
+ //
+ uint8_t tSamFreq;
+}
+PACKED tASFormat;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+#endif
+
diff --git a/usblib/usbbuffer.c b/usblib/usbbuffer.c
new file mode 100644
index 0000000..acc74e3
--- /dev/null
+++ b/usblib/usbbuffer.c
@@ -0,0 +1,1192 @@
+//*****************************************************************************
+//
+// usbbuffer.c - USB buffer object.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_buffer_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Workspace variables required by each buffer instance. This structure is
+// overlaid on the pvWorkspace memory provided in the tUSBBuffer structure
+// passed to USBBufferInit().
+//
+//*****************************************************************************
+typedef struct
+{
+ tUSBRingBufObject sRingBuf;
+ uint32_t ui32LastSent;
+ uint32_t ui32Flags;
+}
+tUSBBufferVars;
+
+//*****************************************************************************
+//
+// Flags which may be set in the tUSBBufferVars ui32Flags field.
+//
+//*****************************************************************************
+#define USB_BUFFER_FLAG_SEND_ZLP 0x00000001
+
+//*****************************************************************************
+//
+// Schedule the next packet transmission to the host if data remains to be
+// sent.
+//
+// \param psBuffer points to the buffer from which a packet transmission is
+// to be scheduled.
+//
+// This function checks to determine whether the lower layer is capable of
+// accepting a new packet for transmission and, if so, schedules the next
+// packet transmission if data remains in the buffer.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+ScheduleNextTransmission(const tUSBBuffer *psBuffer)
+{
+ tUSBBufferVars *psBufVars;
+ uint32_t ui32Packet, ui32Space, ui32Total, ui32Sent;
+
+ //
+ // Get a pointer to our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Ask the lower layer if it has space to accept another packet of data.
+ //
+ ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
+
+ //
+ // If we were returned something other than zero, we can write that number
+ // of bytes to the lower layer.
+ //
+ if(ui32Packet)
+ {
+ //
+ // How much contiguous data do we have in the buffer?
+ //
+ ui32Space = USBRingBufContigUsed(&psBufVars->sRingBuf);
+
+ //
+ // How much total data do we have in the buffer?
+ //
+ ui32Total = USBRingBufUsed(&psBufVars->sRingBuf);
+
+ //
+ // How much data will we be sending as a result of this call?
+ //
+ ui32Sent = (ui32Packet < ui32Total) ? ui32Packet : ui32Total;
+
+ //
+ // Write the contiguous bytes to the lower layer assuming there is
+ // something to send.
+ //
+ if(ui32Space)
+ {
+ //
+ // There is data available to send. Update our state to indicate
+ // the amount we will be sending in this packet.
+ //
+ psBufVars->ui32LastSent = ui32Sent;
+
+ //
+ // Determine the maximum sized block we can send in this transfer.
+ //
+ ui32Space = (ui32Space < ui32Packet) ? ui32Space : ui32Packet;
+ //
+ // Call the lower layer to send the new packet. If the current
+ // data spans the buffer wrap, tell the lower layer that it can
+ // expect a second call to fill the whole packet before it
+ // transmits it.
+ //
+ psBuffer->pfnTransfer(psBuffer->pvHandle,
+ (psBufVars->sRingBuf.pui8Buf +
+ psBufVars->sRingBuf.ui32ReadIndex),
+ ui32Space,
+ (((ui32Space < ui32Packet) &&
+ (ui32Space < ui32Total)) ? false : true));
+
+ //
+ // Do we need to send a second part to fill out the packet? This
+ // will occur if the current packet spans the buffer wrap.
+ //
+ if((ui32Space < ui32Packet) && (ui32Space < ui32Total))
+ {
+ //
+ // The packet straddled the wrap. How much space remains in
+ // the packet?
+ //
+ ui32Packet -= ui32Space;
+
+ //
+ // How much data can we actually send?
+ //
+ ui32Space = ui32Total - ui32Space;
+ ui32Space = (ui32Space > ui32Packet) ? ui32Packet : ui32Space;
+
+ psBuffer->pfnTransfer(psBuffer->pvHandle,
+ psBufVars->sRingBuf.pui8Buf, ui32Space,
+ true);
+ }
+ }
+ else
+ {
+ //
+ // There is no data to send. Did we last send a full packet?
+ //
+ if(psBufVars->ui32LastSent == ui32Packet)
+ {
+ //
+ // Yes - if necessary, send a zero-length packet back to the
+ // host to complete the last transaction.
+ //
+ if(psBufVars->ui32Flags & USB_BUFFER_FLAG_SEND_ZLP)
+ {
+ psBufVars->ui32LastSent = 0;
+ psBuffer->pfnTransfer(psBuffer->pvHandle,
+ psBufVars->sRingBuf.pui8Buf, 0,
+ true);
+ }
+ }
+ }
+
+ //
+ // Don't update the ring buffer read index yet. We do this once we are
+ // sure the packet was correctly transmitted.
+ //
+ }
+}
+
+//*****************************************************************************
+//
+// Handles USB_EVENT_RX_AVAILABLE for a receive buffer.
+//
+// \param psBuffer points to the buffer which is receiving the event.
+// \param ui32Size is the size reported in the event.
+// \param pui8Data is the pointer provided in the event.
+//
+// This function is responsible for reading data from the lower layer into
+// the buffer or, if we had previously passed a section of the buffer to the
+// lower layer for it to write into directly, updating the buffer write pointer
+// to add the new data to the buffer.
+//
+// If the pointer provided is NULL, we call the low level pfnTransfer function
+// to get the new data. If the pointer is not NULL and not within the existing
+// ring buffer, we copy the data directly from the pointer to the buffer and
+// return the number of bytes read.
+//
+// \return Returns the number of bytes read from the lower layer.
+//
+//*****************************************************************************
+static uint32_t
+HandleRxAvailable(tUSBBuffer *psBuffer, uint32_t ui32Size, uint8_t *pui8Data)
+{
+ tUSBBufferVars *psBufVars;
+ uint32_t ui32Avail, ui32Read, ui32Packet, ui32RetCount;
+
+ //
+ // Get a pointer to our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Has the data already been read into memory?
+ //
+ if(pui8Data)
+ {
+ //
+ // Yes - is it already in our ring buffer?
+ //
+ if((pui8Data >= psBuffer->pui8Buffer) &&
+ (pui8Data < psBuffer->pui8Buffer + psBuffer->ui32BufferSize))
+ {
+ //
+ // The data is already in our ring buffer so merely update the
+ // write pointer to add the new data.
+ //
+ USBRingBufAdvanceWrite(&psBufVars->sRingBuf, ui32Size);
+
+ //
+ // In this case, we pass back 0 to indicate that the lower layer
+ // doesn't need to make any buffer pointer updates.
+ //
+ ui32RetCount = 0;
+ }
+ else
+ {
+ //
+ // The data is not within our buffer so we need to copy it into
+ // the buffer.
+ //
+ // How much space does the buffer have available?
+ //
+ ui32Avail = USBRingBufFree(&psBufVars->sRingBuf);
+
+ //
+ // How much should we copy?
+ //
+ ui32Read = (ui32Avail < ui32Size) ? ui32Avail : ui32Size;
+
+ //
+ // Copy the data into the buffer.
+ //
+ USBRingBufWrite(&psBufVars->sRingBuf, pui8Data, ui32Read);
+
+ //
+ // We need to return the number of bytes we read in this case
+ // since the buffer supplied to us was owned by the lower layer and
+ // it may need to update its read pointer.
+ //
+ ui32RetCount = ui32Read;
+ }
+ }
+ else
+ {
+ //
+ // We were passed a NULL pointer so the low level driver has not read
+ // the data into memory yet. We need to call the transfer function to
+ // get the packet.
+ //
+ // How big is the packet that we need to receive?
+ //
+ ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
+
+ //
+ // How much contiguous space do we have in the buffer?
+ //
+ ui32Avail = USBRingBufContigFree(&psBufVars->sRingBuf);
+
+ //
+ // Get as much of the packet as we can in the available space.
+ //
+ ui32Read = psBuffer->pfnTransfer(psBuffer->pvHandle,
+ (psBufVars->sRingBuf.pui8Buf +
+ psBufVars->sRingBuf.ui32WriteIndex),
+ ui32Avail, true);
+
+ //
+ // Advance the ring buffer write pointer to add our new data.
+ //
+ if(ui32Read)
+ {
+ USBRingBufAdvanceWrite(&psBufVars->sRingBuf, ui32Read);
+ }
+
+ //
+ // Did we get the whole packet?
+ //
+ if(ui32Read < ui32Packet)
+ {
+ //
+ // No - how much space do we have in the buffer?
+ //
+ ui32Avail = USBRingBufContigFree(&psBufVars->sRingBuf);
+
+ //
+ // If there is any space left, read as much of the remainder of
+ // the packet as we can.
+ //
+ if(ui32Avail)
+ {
+ ui32Packet =
+ psBuffer->pfnTransfer(psBuffer->pvHandle,
+ (psBufVars->sRingBuf.pui8Buf +
+ psBufVars->sRingBuf.ui32WriteIndex),
+ ui32Avail, true);
+
+ //
+ // Update the write pointer after we read more data into the
+ // buffer.
+ //
+ if(ui32Packet)
+ {
+ USBRingBufAdvanceWrite(&psBufVars->sRingBuf, ui32Packet);
+ }
+ }
+ }
+
+ //
+ // We need to return 0 in this case to indicate that the lower layer
+ // need not perform any buffer maintenance as a result of the callback.
+ //
+ ui32RetCount = 0;
+ }
+
+ //
+ // How much data do we have in the buffer?
+ //
+ ui32Avail = USBRingBufUsed(&psBufVars->sRingBuf);
+
+ //
+ // Pass the event on to the client with the current read pointer and
+ // available data size. The client is expected to understand the ring
+ // structure and be able to deal with wrap if it wants to read the data
+ // directly from the buffer.
+ //
+ ui32Read = psBuffer->pfnCallback(psBuffer->pvCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Avail,
+ (psBufVars->sRingBuf.pui8Buf +
+ psBufVars->sRingBuf.ui32ReadIndex));
+
+ //
+ // If the client read anything from the buffer, update the read pointer.
+ //
+ USBRingBufAdvanceRead(&psBufVars->sRingBuf, ui32Read);
+
+ //
+ // Return the correct value to the low level driver.
+ //
+ return(ui32RetCount);
+}
+
+//*****************************************************************************
+//
+// Handles USB_EVENT_DATA_REMAINING for a receive buffer.
+//
+// \param psBuffer points to the buffer which is receiving the event.
+//
+// This function determines the total number of bytes of data that remain
+// unprocessed in the client and buffer and reports this back to the caller.
+//
+// \return Returns the number of bytes remaining to be processed.
+//
+//*****************************************************************************
+static uint32_t
+HandleDataRemaining(tUSBBuffer *psBuffer)
+{
+ uint32_t ui32BufData, ui32ClientData;
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Get a pointer to our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // How much data does the client currently have buffered?
+ //
+ ui32ClientData = psBuffer->pfnCallback(psBuffer->pvCBData,
+ USB_EVENT_DATA_REMAINING, 0,
+ (void *)0);
+
+ //
+ // How much data do we have in the buffer?
+ //
+ ui32BufData = USBRingBufUsed(&psBufVars->sRingBuf);
+
+ //
+ // Return the total number of bytes of unprocessed data to the lower layer.
+ //
+ return(ui32BufData + ui32ClientData);
+}
+
+//*****************************************************************************
+//
+// Handles USB_EVENT_TX_COMPLETE for a transmit buffer.
+//
+// \param psBuffer points to the buffer which is receiving the event.
+// \param ui32Size is the number of bytes that have been transmitted and
+// acknowledged.
+//
+// This function informs us that data written to the lower layer from a
+// transmit buffer has been successfully transmitted. We use this to update
+// the buffer read pointer and attempt to schedule the next transmission if
+// data remains in the buffer.
+//
+// \return Returns the number of bytes remaining to be processed.
+//
+//*****************************************************************************
+static uint32_t
+HandleTxComplete(tUSBBuffer *psBuffer, uint32_t ui32Size)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Get a pointer to our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Update the transmit buffer read pointer to remove the data that has
+ // now been transmitted.
+ //
+ USBRingBufAdvanceRead(&psBufVars->sRingBuf, ui32Size);
+
+ //
+ // Try to schedule the next packet transmission if data remains to be
+ // sent.
+ //
+ ScheduleNextTransmission(psBuffer);
+
+ //
+ // The return code from this event is ignored.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Handles USB_EVENT_REQUEST_BUFFER for a receive buffer.
+//
+// \param psBuffer points to the buffer which is receiving the event.
+// \param ui32Size is the size of the buffer requested.
+// \param ppui8Buffer is a pointer which is to be written with a pointer to
+// the returned buffer.
+//
+// This function is called by a low level driver that wishes to receive data
+// automatically and write it directly to a memory buffer, either using
+// software or DMA prior to issuing USB_EVENT_RX_AVAILABLE. The event is sent
+// in advance of receiving data to provide storage for whatever is received
+// next.
+//
+// If we have a contiguous block of space in the buffer of at least ui32Size
+// bytes immediately in front of the current write pointer, we pass this back
+// otherwise we send NULL indicating that the next packet should be notified
+// using a standard USB_EVENT_RX_AVAILABLE event without being received
+// automatically. Note that the USB_EVENT_REQUEST_BUFFER protocol allows us to
+// return less than \e ui32Size bytes if we know how much data is expected next
+// but this is not possible here since the USBBuffer knows nothing about the
+// protocol whose data it is handling.
+//
+// \return Returns the number of bytes remaining to be processed.
+//
+//*****************************************************************************
+static uint32_t
+HandleRequestBuffer(tUSBBuffer *psBuffer, uint32_t ui32Size,
+ uint8_t **ppui8Buffer)
+{
+ tUSBBufferVars *psBufVars;
+ uint32_t ui32Space;
+
+ //
+ // Get a pointer to our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // How much contiguous space do we have available?
+ //
+ ui32Space = USBRingBufContigFree(&psBufVars->sRingBuf);
+
+ //
+ // Is there enough space available to satisfy the request?
+ //
+ if(ui32Space >= ui32Size)
+ {
+ //
+ // Yes - return the current write pointer
+ //
+ *ppui8Buffer = psBufVars->sRingBuf.pui8Buf +
+ psBufVars->sRingBuf.ui32WriteIndex;
+ return(ui32Size);
+ }
+ else
+ {
+ //
+ // We do not have enough contiguous space following the current write
+ // pointer to satisfy the request so do not provide a buffer.
+ //
+ *ppui8Buffer = (uint8_t *)0;
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes a USB buffer object to be used with a given USB controller and
+//! device or host class driver.
+//!
+//! \param psBuffer points to a structure containing information on the buffer
+//! memory to be used and the underlying device or host class driver whose data
+//! is to be buffered. This structure must remain accessible for as long as
+//! the buffer is in use.
+//!
+//! This function is used to initialize a USB buffer object and insert it
+//! into the function and callback interfaces between an underlying driver
+//! and the application. The caller supplies information on both the RAM
+//! to be used to buffer data, the type of buffer to be created (transmit or
+//! receive) and the functions to be called in the lower layer to transfer
+//! data to or from the USB controller.
+//!
+//! \return Returns the original buffer structure pointer if successful or
+//! NULL if an error is detected.
+//
+//*****************************************************************************
+const tUSBBuffer *
+USBBufferInit(const tUSBBuffer *psBuffer)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer && psBuffer->pvWorkspace && psBuffer->pui8Buffer &&
+ psBuffer->ui32BufferSize && psBuffer->pfnAvailable &&
+ psBuffer->pfnTransfer && psBuffer->pfnCallback);
+
+ //
+ // Get a pointer to the buffer workspace and initialize the variables it
+ // contains.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+ psBufVars->ui32Flags = 0;
+ USBRingBufInit(&psBufVars->sRingBuf, psBuffer->pui8Buffer,
+ psBuffer->ui32BufferSize);
+
+ //
+ // If all is well, return the same pointer we were originally passed.
+ //
+ return(psBuffer);
+}
+
+//*****************************************************************************
+//
+//! Enables or disables zero-length packet insertion.
+//!
+//! \param psBuffer is the pointer to the buffer instance whose information
+//! is being queried.
+//! \param bSendZLP is \b true to send zero-length packets or \b false to
+//! prevent them from being sent.
+//!
+//! This function allows the use of zero-length packets to be controlled by
+//! an application. In cases where the USB buffer has sent a full (64 byte)
+//! packet and then discovers that the transmit buffer is empty, the default
+//! behavior is to do nothing. Some protocols, however, require that a zero-
+//! length packet be inserted to signal the end of the data. When using such
+//! a protocol, this function should be called with \e bSendZLP set to \b true
+//! to enable the desired behavior.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer, bool bSendZLP)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Set the flag telling us whether or not to send a zero-length packet
+ // after sending a 64 bytes packet and finding no more data to send.
+ //
+ if(bSendZLP)
+ {
+ //
+ // Enable ZLP transmission.
+ //
+ psBufVars->ui32Flags |= USB_BUFFER_FLAG_SEND_ZLP;
+ }
+ else
+ {
+ //
+ // Disable ZLP transmission.
+ //
+ psBufVars->ui32Flags &= ~ USB_BUFFER_FLAG_SEND_ZLP;
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the current ring buffer indices for this USB buffer.
+//!
+//! \param psBuffer is the pointer to the buffer instance whose information
+//! is being queried.
+//! \param psRingBuf is a pointer to storage that will be written with the
+//! current ring buffer control structure for this USB buffer.
+//!
+//! This function is provided to aid a client wishing to write data directly
+//! into the USB buffer rather than using the USBBufferWrite() function. This
+//! may be necessary to control when the USBBuffer starts transmission of a
+//! large block of data, for example.
+//!
+//! A transmit buffer will immediately send a new packet on any call to
+//! USBBufferWrite() if the underlying layer indicates that a transmission can
+//! be started. In some cases this is not desirable and a client may wish to
+//! wishes to write more data to the buffer in advance of starting transmission
+//! to the lower layer. In such cases, this function may be called to retrieve
+//! the current ring buffer indices and the buffer accessed directly. Once the
+//! client has written all data it wishes to send, it should call function
+//! USBBufferDataWritten() to indicate that transmission may begin.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBufferInfoGet(const tUSBBuffer *psBuffer, tUSBRingBufObject *psRingBuf)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer && psRingBuf);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Copy the current ring buffer settings to the clients storage.
+ //
+ psRingBuf->pui8Buf = psBufVars->sRingBuf.pui8Buf;
+ psRingBuf->ui32ReadIndex = psBufVars->sRingBuf.ui32ReadIndex;
+ psRingBuf->ui32Size = psBufVars->sRingBuf.ui32ReadIndex;
+ psRingBuf->ui32WriteIndex = psBufVars->sRingBuf.ui32WriteIndex;
+}
+
+//*****************************************************************************
+//
+//! Indicates that a client has written data directly into the buffer and
+//! wishes to start transmission.
+//!
+//! \param psBuffer is the pointer to the buffer instance into which data has
+//! been written.
+//! \param ui32Length is the number of bytes of data that the client has
+//! written.
+//!
+//! This function updates the USB buffer write pointer and starts transmission
+//! of the data in the buffer assuming the lower layer is ready to receive a
+//! new packet. The function is provided to aid a client wishing to write
+//! data directly into the USB buffer rather than using the USBBufferWrite()
+//! function. This may be necessary to control when the USB buffer starts
+//! transmission of a large block of data, for example.
+//!
+//! A transmit buffer will immediately send a new packet on any call to
+//! USBBufferWrite() if the underlying layer indicates that a transmission can
+//! be started. In some cases this is not desirable and a client may wish to
+//! write more data to the buffer in advance of starting transmission
+//! to the lower layer. In such cases, USBBufferInfoGet() may be called to
+//! retrieve the current ring buffer indices and the buffer accessed directly.
+//! Once the client has written all data it wishes to send (taking care to
+//! handle the ring buffer wrap), it should call this function to indicate that
+//! transmission may begin.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBufferDataWritten(const tUSBBuffer *psBuffer, uint32_t ui32Length)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Advance the ring buffer write pointer to include the newly written
+ // data.
+ //
+ if(ui32Length)
+ {
+ USBRingBufAdvanceWrite(&psBufVars->sRingBuf, ui32Length);
+ }
+
+ //
+ // Try to schedule a new packet transmission.
+ //
+ ScheduleNextTransmission(psBuffer);
+}
+
+//*****************************************************************************
+//
+//! Indicates that a client has read data directly out of the buffer.
+//!
+//! \param psBuffer is the pointer to the buffer instance from which data has
+//! been read.
+//! \param ui32Length is the number of bytes of data that the client has read.
+//!
+//! This function updates the USB buffer read pointer to remove data that
+//! the client has read directly rather than via a call to USBBufferRead().
+//! The function is provided to aid a client wishing to minimize data copying.
+//! To read directly from the buffer, a client must call USBBufferInfoGet() to
+//! retrieve the current buffer inpsBufVarsdices. With this information, the
+//! data following the current read index can be read. Once the client has
+//! processed much data as it needs, USBBufferDataRemoved() must be called to
+//! advance the read pointer past the data that has been read and free up that
+//! section of the buffer. The client must take care to correctly handle the
+//! wrap point if accessing the buffer directly.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBufferDataRemoved(const tUSBBuffer *psBuffer, uint32_t ui32Length)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Advance the ring buffer write pointer to include the newly written
+ // data.
+ //
+ if(ui32Length)
+ {
+ USBRingBufAdvanceRead(&psBufVars->sRingBuf, ui32Length);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the callback pointer supplied to clients of this buffer.
+//!
+//! \param psBuffer is the pointer to the buffer instance whose callback data
+//! is to be changed.
+//! \param pvCBData is the pointer the client wishes to receive on all future
+//! callbacks from this buffer.
+//!
+//! This function sets the callback pointer which this buffer will supply
+//! to clients as the \e pvCBData parameter in all future calls to the
+//! event callback.
+//!
+//! \note If this function is to be used, the application must ensure that the
+//! tUSBBuffer structure used to describe this buffer is held in RAM rather
+//! than flash. The \e pvCBData value passed is written directly into this
+//! structure.
+//!
+//! \return Returns the previous callback pointer set for the buffer.
+//
+//*****************************************************************************
+void *
+USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData)
+{
+ void *pvOldData;
+
+ //
+ // Keep a copy of the old callback data.
+ //
+ pvOldData = psBuffer->pvCBData;
+
+ //
+ // Replace the callback data with the new value.
+ //
+ psBuffer->pvCBData = pvCBData;
+
+ //
+ // Give the caller the old value back.
+ //
+ return(pvOldData);
+}
+
+//*****************************************************************************
+//
+//! Writes a block of data to the transmit buffer and queues it for
+//! transmission to the USB controller.
+//!
+//! \param psBuffer points to the pointer instance into which data is to be
+//! written.
+//! \param pui8Data points to the first byte of data which is to be written.
+//! \param ui32Length is the number of bytes of data to write to the buffer.
+//!
+//! This function copies the supplied data into the transmit buffer. The
+//! transmit buffer data will be packetized according to the constraints
+//! imposed by the lower layer in use and sent to the USB controller as soon as
+//! possible. Once a packet is transmitted and acknowledged, a
+//! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback
+//! indicating the number of bytes that have been sent from the buffer.
+//!
+//! Attempts to send more data than there is space for in the transmit buffer
+//! will result in fewer bytes than expected being written. The value returned
+//! by the function indicates the actual number of bytes copied to the buffer.
+//!
+//! \return Returns the number of bytes actually written.
+//
+//*****************************************************************************
+uint32_t
+USBBufferWrite(const tUSBBuffer *psBuffer, const uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Space;
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer && pui8Data);
+ ASSERT(psBuffer->bTransmitBuffer == true);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // How much space is left in the buffer?
+ //
+ ui32Space = USBRingBufFree(&psBufVars->sRingBuf);
+
+ //
+ // How many bytes will we write?
+ //
+ ui32Length = (ui32Length > ui32Space) ? ui32Space : ui32Length;
+
+ //
+ // Write the data to the buffer.
+ //
+ if(ui32Length)
+ {
+ USBRingBufWrite(&psBufVars->sRingBuf, pui8Data, ui32Length);
+ }
+
+ //
+ // Try to transmit the next packet to the host.
+ //
+ ScheduleNextTransmission(psBuffer);
+
+ //
+ // Tell the caller how many bytes we wrote to the buffer.
+ //
+ return(ui32Length);
+}
+
+//*****************************************************************************
+//
+//! Flushes a USB buffer, discarding any data that it contains.
+//!
+//! \param psBuffer is the pointer to the buffer instance which is to be
+//! flushed.
+//!
+//! This function discards all data currently in the supplied buffer without
+//! processing (transmitting it via the USB controller or passing it to the
+//! client depending upon the buffer mode).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBufferFlush(const tUSBBuffer *psBuffer)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Flush the ring buffer.
+ //
+ USBRingBufFlush(&psBufVars->sRingBuf);
+}
+
+//*****************************************************************************
+//
+//! Reads a block of data from a USB receive buffer into storage supplied by
+//! the caller.
+//!
+//! \param psBuffer is the pointer to the buffer instance from which data is
+//! to be read.
+//! \param pui8Data points to a buffer into which the received data will be
+//! written.
+//! \param ui32Length is the size of the buffer pointed to by pui8Data.
+//!
+//! This function reads up to \e ui32Length bytes of data received from the USB
+//! host into the supplied application buffer. If the receive buffer
+//! contains fewer than \e ui32Length bytes of data, the data that is present
+//! will be copied and the return code will indicate the actual number of bytes
+//! copied to \e pui8Data.
+//!
+//! \return Returns the number of bytes of data read.
+//
+//*****************************************************************************
+uint32_t
+USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ tUSBBufferVars *psBufVars;
+ uint32_t ui32Avail, ui32Read;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer && pui8Data && ui32Length);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // How much data is in the buffer?
+ //
+ ui32Avail = USBRingBufUsed(&psBufVars->sRingBuf);
+
+ //
+ // Determine how many bytes we can actually read.
+ //
+ ui32Read = (ui32Avail < ui32Length) ? ui32Avail : ui32Length;
+
+ //
+ // Read the data from the buffer assuming there is some to read.
+ //
+ if(ui32Read)
+ {
+ USBRingBufRead(&psBufVars->sRingBuf, pui8Data, ui32Read);
+ }
+
+ //
+ // Tell the caller how many bytes we wrote to their buffer.
+ //
+ return(ui32Read);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes of data available in the buffer.
+//!
+//! \param psBuffer is the pointer to the buffer instance which is to be
+//! queried.
+//!
+//! This function may be used to determine the number of bytes of data in a
+//! buffer. For a receive buffer, this indicates the number of bytes that the
+//! client can read from the buffer using USBBufferRead(). For a transmit
+//! buffer, this indicates the amount of data that remains to be sent to the
+//! USB controller.
+//!
+//! \return Returns the number of bytes of data in the buffer.
+//
+//*****************************************************************************
+uint32_t
+USBBufferDataAvailable(const tUSBBuffer *psBuffer)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Return the amount of data in the buffer.
+ //
+ return(USBRingBufUsed(&psBufVars->sRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Returns the number of free bytes in the buffer.
+//!
+//! \param psBuffer is the pointer to the buffer instance which is to be
+//! queried.
+//!
+//! This function returns the number of free bytes in the buffer. For a
+//! transmit buffer, this indicates the maximum number of bytes that can be
+//! passed on a call to USBBufferWrite() and accepted for transmission. For a
+//! receive buffer, it indicates the number of bytes that can be read from the
+//! USB controller before the buffer will be full.
+//!
+//! \return Returns the number of free bytes in the buffer.
+//
+//*****************************************************************************
+uint32_t
+USBBufferSpaceAvailable(const tUSBBuffer *psBuffer)
+{
+ tUSBBufferVars *psBufVars;
+
+ //
+ // Check parameter validity.
+ //
+ ASSERT(psBuffer);
+
+ //
+ // Get our workspace variables.
+ //
+ psBufVars = psBuffer->pvWorkspace;
+
+ //
+ // Return the amount of space available in the buffer.
+ //
+ return(USBRingBufFree(&psBufVars->sRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Called by the USB buffer to notify the client of asynchronous events.
+//!
+//! \param pvCBData is the client-supplied callback pointer associated with
+//! this buffer instance.
+//! \param ui32Event is the identifier of the event being sent. This will be
+//! a general event identifier of the form \b USBD_EVENT_xxxx or a device
+//! class-dependent event of the form \b USBD_CDC_EVENT_xxx or
+//! \b USBD_HID_EVENT_xxx.
+//! \param ui32MsgValue is an event-specific parameter value.
+//! \param pvMsgData is an event-specific data pointer.
+//!
+//! This function is the USB buffer event handler that applications should
+//! register with the USB device class driver as the callback for the channel
+//! which is to be buffered using this buffer.
+//!
+//! \note This function will never be called by an application. It is the
+//! handler that allows the USB buffer to be inserted above the device class
+//! driver or host pipe driver and below the application to offer buffering
+//! support.
+//!
+//! \return The return value is dependent upon the event being processed.
+//
+//*****************************************************************************
+uint32_t
+USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
+ uint32_t ui32MsgValue, void *pvMsgData)
+{
+ tUSBBuffer *psBuffer;
+
+ //
+ // Get our instance data pointers from the callback data.
+ //
+ psBuffer = (tUSBBuffer *)pvCBData;
+ ASSERT(psBuffer);
+
+ //
+ // Which event have we been sent?
+ //
+ switch(ui32Event)
+ {
+ //
+ // Data is available from the lower layer.
+ //
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // This event is only relevant to us if we are a receive buffer.
+ //
+ if(!psBuffer->bTransmitBuffer)
+ {
+ return(HandleRxAvailable(psBuffer, ui32MsgValue, pvMsgData));
+ }
+ break;
+ }
+
+ //
+ // We are being asked how much data remains to be processed.
+ //
+ case USB_EVENT_DATA_REMAINING:
+ {
+ return(HandleDataRemaining(psBuffer));
+ }
+
+ //
+ // A previous transmission has completed.
+ //
+ case USB_EVENT_TX_COMPLETE:
+ {
+ //
+ // This event is only relevant to us if we are a transmit buffer.
+ //
+ if(psBuffer->bTransmitBuffer)
+ {
+ //
+ // Handle the message then drop out of the switch so that the
+ // event is echoed to the layer above.
+ //
+ HandleTxComplete(psBuffer, ui32MsgValue);
+ }
+ break;
+ }
+
+ //
+ // We are being asked to provide a buffer into which the next packet
+ // can be received.
+ //
+ case USB_EVENT_REQUEST_BUFFER:
+ {
+ //
+ // This event is only relevant to us if we are a receive buffer.
+ //
+ if(!psBuffer->bTransmitBuffer)
+ {
+ return(HandleRequestBuffer(psBuffer, ui32MsgValue, pvMsgData));
+ }
+ break;
+ }
+
+ //
+ // All other events are merely passed through to the client.
+ //
+ default:
+ {
+ break;
+ }
+ }
+
+ //
+ // If we drop out of the switch, we need to pass the event on to the client
+ // unmodified and return the relevant return code back to the lower layer.
+ //
+ return(psBuffer->pfnCallback(psBuffer->pvCBData, ui32Event, ui32MsgValue,
+ pvMsgData));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbcdc.h b/usblib/usbcdc.h
new file mode 100644
index 0000000..a59ac91
--- /dev/null
+++ b/usblib/usbcdc.h
@@ -0,0 +1,947 @@
+//*****************************************************************************
+//
+// usbhid.h - Definitions used by Communication Device Class devices.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Note: This header contains definitions related to the USB Communication
+// Device Class specification. The header is complete for ACM model
+// devices but request and notification definitions specific to other
+// modem types, ISDN, ATM and Ethernet are currently incomplete or
+// omitted.
+//
+//*****************************************************************************
+
+#ifndef __USBCDC_H__
+#define __USBCDC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cdc_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Generic macros to read an 8-bit, 16-bit or 32-bit value from a character
+// pointer.
+//
+//*****************************************************************************
+#define BYTE(pui8Data) (*(uint8_t *)(pui8Data))
+#define SHORT(pui8Data) (*(uint16_t *)(pui8Data))
+#define LONG(pui8Data) (*(uint32_t *)(pui8Data))
+
+//*****************************************************************************
+//
+// USB CDC subclass codes. Used in interface descriptor, bInterfaceClass
+//
+//*****************************************************************************
+#define USB_CDC_SUBCLASS_DIRECT_LINE_MODEL \
+ 0x01
+#define USB_CDC_SUBCLASS_ABSTRACT_MODEL \
+ 0x02
+#define USB_CDC_SUBCLASS_TELEPHONE_MODEL \
+ 0x03
+#define USB_CDC_SUBCLASS_MULTI_CHANNEL_MODEL \
+ 0x04
+#define USB_CDC_SUBCLASS_CAPI_MODEL \
+ 0x05
+#define USB_CDC_SUBCLASS_ETHERNET_MODEL \
+ 0x06
+#define USB_CDC_SUBCLASS_ATM_MODEL \
+ 0x07
+
+//*****************************************************************************
+//
+// USB CDC control interface protocols. Used in control interface descriptor,
+// bInterfaceProtocol
+//
+//*****************************************************************************
+#define USB_CDC_PROTOCOL_NONE 0x00
+#define USB_CDC_PROTOCOL_V25TER 0x01
+#define USB_CDC_PROTOCOL_VENDOR 0xFF
+
+//*****************************************************************************
+//
+// USB CDC data interface protocols. Used in data interface descriptor,
+// bInterfaceProtocol
+//
+//*****************************************************************************
+#define USB_CDC_PROTOCOL_NONE 0x00
+#define USB_CDC_PROTOCOL_I420 0x30
+#define USB_CDC_PROTOCOL_TRANSPARENT \
+ 0x32
+#define USB_CDC_PROTOCOL_Q921M 0x50
+#define USB_CDC_PROTOCOL_Q921 0x51
+#define USB_CDC_PROTOCOL_Q921TM 0x52
+#define USB_CDC_PROTOCOL_V42BIS 0x90
+#define USB_CDC_PROTOCOL_Q921EURO \
+ 0x91
+#define USB_CDC_PROTOCOL_V120 0x92
+#define USB_CDC_PROTOCOL_CAPI20 0x93
+#define USB_CDC_PROTOCOL_HOST_DRIVER \
+ 0xFD
+#define USB_CDC_PROTOCOL_CDC_SPEC \
+ 0xFE
+#define USB_CDC_PROTOCOL_VENDOR 0xFF
+
+//*****************************************************************************
+//
+// Functional descriptor definitions
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Functional descriptor types
+//
+//*****************************************************************************
+#define USB_CDC_CS_INTERFACE 0x24
+#define USB_CDC_CS_ENDPOINT 0x25
+
+//*****************************************************************************
+//
+// Functional descriptor subtypes
+//
+//*****************************************************************************
+#define USB_CDC_FD_SUBTYPE_HEADER \
+ 0x00
+#define USB_CDC_FD_SUBTYPE_CALL_MGMT \
+ 0x01
+#define USB_CDC_FD_SUBTYPE_ABSTRACT_CTL_MGMT \
+ 0x02
+#define USB_CDC_FD_SUBTYPE_DIRECT_LINE_MGMT \
+ 0x03
+#define USB_CDC_FD_SUBTYPE_TELEPHONE_RINGER \
+ 0x04
+#define USB_CDC_FD_SUBTYPE_LINE_STATE_CAPS \
+ 0x05
+#define USB_CDC_FD_SUBTYPE_UNION \
+ 0x06
+#define USB_CDC_FD_SUBTYPE_COUNTRY \
+ 0x07
+#define USB_CDC_FD_SUBTYPE_TELEPHONE_MODES \
+ 0x08
+#define USB_CDC_FD_SUBTYPE_USB_TERMINAL \
+ 0x09
+#define USB_CDC_FD_SUBTYPE_NETWORK_TERMINAL \
+ 0x0A
+#define USB_CDC_FD_SUBTYPE_PROTOCOL_UNIT \
+ 0x0B
+#define USB_CDC_FD_SUBTYPE_EXTENSION_UNIT \
+ 0x0C
+#define USB_CDC_FD_SUBTYPE_MULTI_CHANNEL_MGMT \
+ 0x0D
+#define USB_CDC_FD_SUBTYPE_CAPI_MGMT \
+ 0x0E
+#define USB_CDC_FD_SUBTYPE_ETHERNET \
+ 0x0F
+#define USB_CDC_FD_SUBTYPE_ATM 0x10
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_CALL_MGMT, Header functional descriptor, bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_CALL_MGMT_VIA_DATA \
+ 0x02
+#define USB_CDC_CALL_MGMT_HANDLED \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_ABSTRACT_CTL_MGMT, Abstract Control Management functional
+// descriptor, bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_ACM_SUPPORTS_NETWORK_CONNECTION \
+ 0x08
+#define USB_CDC_ACM_SUPPORTS_SEND_BREAK \
+ 0x04
+#define USB_CDC_ACM_SUPPORTS_LINE_PARAMS \
+ 0x02
+#define USB_CDC_ACM_SUPPORTS_COMM_FEATURE \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_DIRECT_LINE_MGMT, Direct Line Management functional
+// descriptor, bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_DLM_NEEDS_EXTRA_PULSE_SETUP \
+ 0x04
+#define USB_CDC_DLM_SUPPORTS_AUX \
+ 0x02
+#define USB_CDC_DLM_SUPPORTS_PULSE \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_TELEPHONE_MODES, Telephone Operational Modes functional
+// descriptor, bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_TELEPHONE_SUPPORTS_COMPUTER \
+ 0x04
+#define USB_CDC_TELEPHONE_SUPPORTS_STANDALONE \
+ 0x02
+#define USB_CDC_TELEPHONE_SUPPORTS_SIMPLE \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_LINE_STATE_CAPS, Telephone Call and Line State Reporting
+// Capabilities descriptor
+//
+//*****************************************************************************
+#define USB_CDC_LINE_STATE_CHANGES_NOTIFIED \
+ 0x20
+#define USB_CDC_LINE_STATE_REPORTS_DTMF \
+ 0x10
+#define USB_CDC_LINE_STATE_REPORTS_DIST_RING \
+ 0x08
+#define USB_CDC_LINE_STATE_REPORTS_CALLERID \
+ 0x04
+#define USB_CDC_LINE_STATE_REPORTS_BUSY \
+ 0x02
+#define USB_CDC_LINE_STATE_REPORTS_INT_DIALTONE \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_USB_TERMINAL, USB Terminal functional descriptor,
+// bmOptions
+//
+//*****************************************************************************
+#define USB_CDC_TERMINAL_NO_WRAPPER_USED \
+ 0x00
+#define USB_CDC_TERMINAL_WRAPPER_USED \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_MULTI_CHANNEL_MGMT, Multi-Channel Management functional
+// descriptor, bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_MCM_SUPPORTS_SET_UNIT_PARAM \
+ 0x04
+#define USB_CDC_MCM_SUPPORTS_CLEAR_UNIT_PARAM \
+ 0x02
+#define USB_CDC_MCM_UNIT_PARAMS_NON_VOLATILE \
+ 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_CAPI_MGMT, CAPI Control Management functional descriptor,
+// bmCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_CAPI_INTELLIGENT \
+ 0x01
+#define USB_CDC_CAPI_SIMPLE 0x00
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_ETHERNET, Ethernet Networking functional descriptor,
+// bmEthernetStatistics
+//
+//*****************************************************************************
+#define USB_CDC_ETHERNET_XMIT_OK \
+ 0x01000000
+#define USB_CDC_ETHERNET_RCV_OK 0x02000000
+#define USB_CDC_ETHERNET_XMIT_ERROR \
+ 0x04000000
+#define USB_CDC_ETHERNET_RCV_ERROR \
+ 0x08000000
+#define USB_CDC_ETHERNET_RCV_NO_BUFFER \
+ 0x10000000
+#define USB_CDC_ETHERNET_DIRECTED_BYTES_XMIT \
+ 0x20000000
+#define USB_CDC_ETHERNET_DIRECTED_FRAMES_XMIT \
+ 0x40000000
+#define USB_CDC_ETHERNET_MULTICAST_BYTES_XMIT \
+ 0x80000000
+#define USB_CDC_ETHERNET_MULTICAST_FRAMES_XMIT \
+ 0x00010000
+#define USB_CDC_ETHERNET_BROADCAST_BYTES_XMIT \
+ 0x00020000
+#define USB_CDC_ETHERNET_BROADCAST_FRAMES_XMIT \
+ 0x00040000
+#define USB_CDC_ETHERNET_DIRECTED_BYTES_RCV \
+ 0x00080000
+#define USB_CDC_ETHERNET_DIRECTED_FRAMES_RCV \
+ 0x00100000
+#define USB_CDC_ETHERNET_MULTICAST_BYTES_RCV \
+ 0x00200000
+#define USB_CDC_ETHERNET_MULTICAST_FRAMES_RCV \
+ 0x00400000
+#define USB_CDC_ETHERNET_BROADCAST_BYTES_RCV \
+ 0x00800000
+#define USB_CDC_ETHERNET_BROADCAST_FRAMES_RCV \
+ 0x00000100
+#define USB_CDC_ETHERNET_RCV_CRC_ERROR \
+ 0x00000200
+#define USB_CDC_ETHERNET_TRANSMIT_QUEUE_LENGTH \
+ 0x00000400
+#define USB_CDC_ETHERNET_RCV_ERROR_ALIGNMENT \
+ 0x00000800
+#define USB_CDC_ETHERNET_XMIT_ONE_COLLISION \
+ 0x00001000
+#define USB_CDC_ETHERNET_XMIT_MORE_COLLISIONS \
+ 0x00002000
+#define USB_CDC_ETHERNET_XMIT_DEFERRED \
+ 0x00004000
+#define USB_CDC_ETHERNET_XMIT_MAX_COLLISIONS \
+ 0x00008000
+#define USB_CDC_ETHERNET_RCV_OVERRUN \
+ 0x00000001
+#define USB_CDC_ETHERNET_XMIT_UNDERRUN \
+ 0x00000002
+#define USB_CDC_ETHERNET_XMIT_HEARTBEAT_FAILURE \
+ 0x00000004
+#define USB_CDC_ETHERNET_XMIT_TIMES_CRS_LOST \
+ 0x00000010
+
+//*****************************************************************************
+//
+// USB_CDC_FD_SUBTYPE_ATM, ATM Networking functional descriptor,
+// bmDataCapabilities
+//
+//*****************************************************************************
+#define USB_CDC_ATM_TYPE_3 0x08
+#define USB_CDC_ATM_TYPE_2 0x04
+#define USB_CDC_ATM_TYPE_1 0x02
+
+//*****************************************************************************
+//
+// bmATMDeviceStatistics
+//
+//*****************************************************************************
+#define USB_CDC_ATM_VC_US_CELLS_SENT \
+ 0x10
+#define USB_CDC_ATM_VC_US_CELLS_RECEIVED \
+ 0x08
+#define USB_CDC_ATM_DS_CELLS_HEC_ERR_CORRECTED \
+ 0x04
+#define USB_CDC_ATM_US_CELLS_SENT \
+ 0x02
+#define USB_CDC_ATM_US_CELLS_RECEIVED \
+ 0x01
+
+//*****************************************************************************
+//
+// Management Element Requests (provided in tUSBRequest.bRequest)
+//
+//*****************************************************************************
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND \
+ 0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE \
+ 0x01
+#define USB_CDC_SET_COMM_FEATURE \
+ 0x02
+#define USB_CDC_GET_COMM_FEATURE \
+ 0x03
+#define USB_CDC_CLEAR_COMM_FEATURE \
+ 0x04
+#define USB_CDC_SET_AUX_LINE_STATE \
+ 0x10
+#define USB_CDC_SET_HOOK_STATE 0x11
+#define USB_CDC_PULSE_SETUP 0x12
+#define USB_CDC_SEND_PULSE 0x13
+#define USB_CDC_SET_PULSE_TIME 0x14
+#define USB_CDC_RING_AUX_JACK 0x15
+#define USB_CDC_SET_LINE_CODING 0x20
+#define USB_CDC_GET_LINE_CODING 0x21
+#define USB_CDC_SET_CONTROL_LINE_STATE \
+ 0x22
+#define USB_CDC_SEND_BREAK 0x23
+#define USB_CDC_SET_RINGER_PARMS \
+ 0x30
+#define USB_CDC_GET_RINGER_PARMS \
+ 0x31
+#define USB_CDC_SET_OPERATION_PARMS \
+ 0x32
+#define USB_CDC_GET_OPERATION_PARMS \
+ 0x33
+#define USB_CDC_SET_LINE_PARMS 0x34
+#define USB_CDC_GET_LINE_PARMS 0x35
+#define USB_CDC_DIAL_DIGITS 0x36
+#define USB_CDC_SET_UNIT_PARAMETER \
+ 0x37
+#define USB_CDC_GET_UNIT_PARAMETER \
+ 0x38
+#define USB_CDC_CLEAR_UNIT_PARAMETER \
+ 0x39
+#define USB_CDC_GET_PROFILE 0x3A
+#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS \
+ 0x40
+#define USB_CDC_SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER \
+ 0x41
+#define USB_CDC_GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER \
+ 0x42
+#define USB_CDC_SET_ETHERNET_PACKET_FILTER \
+ 0x43
+#define USB_CDC_GET_ETHERNET_STATISTIC \
+ 0x44
+#define USB_CDC_SET_ATM_DATA_FORMAT \
+ 0x50
+#define USB_CDC_GET_ATM_DEVICE_STATISTICS \
+ 0x51
+#define USB_CDC_SET_ATM_DEFAULT_VC \
+ 0x52
+#define USB_CDC_GET_ATM_VC_STATISTICS \
+ 0x53
+
+//*****************************************************************************
+//
+// In cases where a request defined above results in the return of a fixed size
+// data block, the following group of labels define the size of that block. In
+// each of these cases, an access macro is also provided to write the response
+// data into an appropriately-sized array of 8-bit characters.
+//
+//*****************************************************************************
+#define USB_CDC_SIZE_COMM_FEATURE \
+ 2
+#define USB_CDC_SIZE_LINE_CODING \
+ 7
+#define USB_CDC_SIZE_RINGER_PARMS \
+ 4
+#define USB_CDC_SIZE_OPERATION_PARMS \
+ 2
+#define USB_CDC_SIZE_UNIT_PARAMETER \
+ 2
+#define USB_CDC_SIZE_PROFILE 64
+#define USB_CDC_SIZE_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER \
+ 2
+#define USB_CDC_SIZE_ETHERNET_STATISTIC \
+ 4
+#define USB_CDC_SIZE_ATM_DEVICE_STATISTICS \
+ 4
+#define USB_CDC_SIZE_ATM_VC_STATISTICS \
+ 4
+#define USB_CDC_SIZE_LINE_PARMS \
+ 10
+
+//*****************************************************************************
+//
+// NB: USB_CDC_SIZE_LINE_PARAMS assumes only a single call. For multiple
+// calls, add 4 bytes per additional call.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// USB_CDC_GET_COMM_FEATURE & USB_CDC_SET_COMM_FEATURE
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// wValue (Feature Selector)
+//
+//*****************************************************************************
+#define USB_CDC_ABSTRACT_STATE 0x0001
+#define USB_CDC_COUNTRY_SETTING 0x0002
+
+//*****************************************************************************
+//
+// Data when feature selector is USB_DCD_ABSTRACT_STATE
+//
+//*****************************************************************************
+#define USB_CDC_ABSTRACT_CALL_DATA_MULTIPLEXED \
+ 0x0002
+#define USB_CDC_ABSTRACT_ENDPOINTS_IDLE \
+ 0x0001
+
+//*****************************************************************************
+//
+// Macros to populate the response data buffer (whose size in bytes is defined
+// by USB_CDC_SIZE_COMM_FEATURE).
+//
+//*****************************************************************************
+#define SetResponseCommFeature(pi8Buf, ui16Data) \
+ do \
+ { \
+ (*(uint16_t *)(pi8Buf)) = ui16Data; \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// USB_CDC_SET_AUX_LINE_STATE, wValue
+//
+//*****************************************************************************
+#define USB_CDC_AUX_DISCONNECT 0x0000
+#define USB_CDC_AUX_CONNECT 0x0001
+
+//*****************************************************************************
+//
+// USB_CDC_SET_HOOK_STATE, wValue
+//
+//*****************************************************************************
+#define USB_CDC_ON_HOOK 0x0000
+#define USB_CDC_OFF_HOOK 0x0001
+#define USB_CDC_SNOOPING 0x0002
+
+//*****************************************************************************
+//
+// USB_CDC_GET_LINE_CODING
+//
+//*****************************************************************************
+#define USB_CDC_STOP_BITS_1 0x00
+#define USB_CDC_STOP_BITS_1_5 0x01
+#define USB_CDC_STOP_BITS_2 0x02
+
+#define USB_CDC_PARITY_NONE 0x00
+#define USB_CDC_PARITY_ODD 0x01
+#define USB_CDC_PARITY_EVEN 0x02
+#define USB_CDC_PARITY_MARK 0x03
+#define USB_CDC_PARITY_SPACE 0x04
+
+//*****************************************************************************
+//
+// Macro to populate the response data buffer (whose size in bytes is defined
+// by USB_CDC_SIZE_LINE_CODING).
+//
+//*****************************************************************************
+#define SetResponseLineCoding(pi8Buf, ui8Rate, ui8Stop, ui8Parity, \
+ ui8Databits) \
+ do \
+ { \
+ (*(uint32_t *)(pi8Buf)) = ui8Rate; \
+ (*((uint8_t *)(pi8Buf) + 4)) = ui8Stop; \
+ (*((uint8_t *)(pi8Buf) + 5)) = ui8Parity; \
+ (*((uint8_t *)(pi8Buf) + 6)) = ui8Databits; \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// USB_CDC_SET_CONTROL_LINE_STATE, wValue
+//
+//*****************************************************************************
+#define USB_CDC_DEACTIVATE_CARRIER \
+ 0x00
+#define USB_CDC_ACTIVATE_CARRIER \
+ 0x02
+#define USB_CDC_DTE_NOT_PRESENT 0x00
+#define USB_CDC_DTE_PRESENT 0x01
+
+//*****************************************************************************
+//
+// USB_CDC_SET_RINGER_PARMS, USB_CDC_GET_RINGER_PARMS and
+// USB_CDC_GET_LINE_PARMS (ui32RingerBmp)
+//
+//*****************************************************************************
+#define USB_CDC_RINGER_EXISTS 0x80000000
+#define USB_CDC_RINGER_DOES_NOT_EXIST \
+ 0x00000000
+
+//*****************************************************************************
+//
+// Macro to populate the response data buffer to USB_CDC_GET_RINGER_PARMS.
+// Parameter buf points to a buffer of size USB_CDC_SIZE_RINGER_PARMS bytes.
+//
+//*****************************************************************************
+#define SetResponseRingerParms(pi8Buf, ui8Pattern, ui8Volume, ui32Exists) \
+ do \
+ { \
+ *(uint32_t *)(pi8Buf) = ((ui8Pattern) + \
+ ((ui8Volume & 0xFF) << 8) + \
+ (ui32Exists & USB_CDC_RINGER_EXISTS)); \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// Macros to extract fields from the USB_CDC_SET_RINGER_PARMS data
+//
+//*****************************************************************************
+#define GetRingerVolume(pi8Data) \
+ (BYTE((pi8Data) + 1))
+#define GetRingerPattern(pi8Data) \
+ (BYTE(pi8Data))
+#define GetRingerExists(pi8Data) \
+ ((LONG(pi8Data)) & USB_CDC_RINGER_EXISTS)
+
+//*****************************************************************************
+//
+// USB_CDC_SET_OPERATION_PARMS, wValue
+//
+//*****************************************************************************
+#define USB_CDC_SIMPLE_MODE 0x0000
+#define USB_CDC_STANDALONE_MODE 0x0001
+#define USB_CDC_HOST_CENTRIC_MODE \
+ 0x0002
+
+//*****************************************************************************
+//
+// Macro to populate the response data buffer to USB_CDC_GET_OPERATION_PARMS.
+// Parameter buf points to a buffer of size USB_CDC_SIZE_OPERATION_PARMS
+// bytes.
+//
+//*****************************************************************************
+#define SetResponseOperationParms(pi8Bbuf, ui16Data) \
+ do \
+ { \
+ WORD(pi8Buf) = ui16Data; \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// USB_CDC_SET_LINE_PARMS, wParam - Line State Change
+//
+//*****************************************************************************
+#define USB_CDC_DROP_ACTIVE_CALL \
+ 0x0000
+#define USB_CDC_START_NEW_CALL 0x0001
+#define USB_CDC_APPLY_RINGING 0x0002
+#define USB_CDC_REMOVE_RINGING 0x0003
+#define USB_CDC_SWITCH_CALL 0x0004
+
+//*****************************************************************************
+//
+// Line state bitmap in USB_CDC_GET_LINE_PARMS response
+//
+//*****************************************************************************
+#define USB_CDC_LINE_IS_ACTIVE 0x80000000
+#define USB_CDC_LINE_IS_IDLE 0x00000000
+#define USB_CDC_LINE_NO_ACTIVE_CALL \
+ 0x000000FF
+
+#define USB_CDC_CALL_ACTIVE 0x80000000
+
+//*****************************************************************************
+//
+// Call state value definitions
+//
+//*****************************************************************************
+#define USB_CDC_CALL_IDLE 0x00000000
+#define USB_CDC_CALL_TYPICAL_DIALTONE \
+ 0x00000001
+#define USB_CDC_CALL_INTERRUPTED_DIALTONE \
+ 0x00000002
+#define USB_CDC_CALL_DIALING 0x00000003
+#define USB_CDC_CALL_RINGBACK 0x00000004
+#define USB_CDC_CALL_CONNECTED 0x00000005
+#define USB_CDC_CALL_INCOMING 0x00000006
+
+//*****************************************************************************
+//
+// Call state change value definitions
+//
+//*****************************************************************************
+#define USB_CDC_CALL_STATE_IDLE 0x01
+#define USB_CDC_CALL_STATE_DIALING \
+ 0x02
+#define USB_CDC_CALL_STATE_RINGBACK \
+ 0x03
+#define USB_CDC_CALL_STATE_CONNECTED \
+ 0x04
+#define USB_CDC_CALL_STATE_INCOMING \
+ 0x05
+
+//*****************************************************************************
+//
+// Extra byte of data describing the connection type for
+// USB_CDC_CALL_STATE_CONNECTED.
+//
+//*****************************************************************************
+#define USB_CDC_VOICE 0x00
+#define USB_CDC_ANSWERING_MACHINE \
+ 0x01
+#define USB_CDC_FAX 0x02
+#define USB_CDC_MODEM 0x03
+#define USB_CDC_UNKNOWN 0xFF
+
+//*****************************************************************************
+//
+// Macro to extract call index from request in cases where wParam is
+// USB_CDC_SWITCH_CALL.
+//
+//*****************************************************************************
+#define GetCallIndex(pi8Data) (BYTE(pi8Data))
+
+//*****************************************************************************
+//
+// Macro to populate the CallState entries in response to request
+// USB_CDC_GET_LINE_PARMS. The ui8Index parameter is a zero based index
+// indicating which call entry in the pi8Buf response buffer to fill in. Note
+// that pi8Buf points to the first byte of the buffer (the wLength field).
+//
+//*****************************************************************************
+#define SetResponseCallState(pi8Buf, ui8Index, ui32Active, ui8StateChange, \
+ ui8State) \
+ do \
+ { \
+ (LONG((uint8_t *)(pi8Buf) + (10 + (4 * (ui8Index))))) = \
+ (((ui32Active) & USB_CDC_CALL_IS_ACTIVE) + \
+ (((ui8StateChange) & 0xFF) << 8) + \
+ ((ui8State) & 0xFF)); \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// Macro to populate the response data buffer (whose size in bytes is defined
+// by USB_CDC_SIZE_LINE_PARMS). Note that this macro only populates fields for
+// a single call. If multiple calls are being managed, additional 4 byte
+// fields must be appended to provide call state for each call after the first.
+// This may be done using the SetResponseCallState macro with the appropriate
+// call index supplied.
+//
+//*****************************************************************************
+#define SetResponseLineParms(pi8Buf, ui16Length, \
+ ui8RingPattern, ui8RingVolume, ui32RingExists, \
+ ui32LineActive, ui8LineCallIndex, \
+ ui32CallActive, ui8CallStateChange, \
+ ui8CallState) \
+ do \
+ { \
+ (WORD(pi8Buf)) = ui16Length; \
+ SetResponseRingerParams(((uint8_t *)(pi8Buf) + 2), \
+ ui8RingPattern, ui8RingVolume, \
+ ui32RingExists); \
+ (LONG((uint8_t *)(pi8Buf) + 6)) = \
+ (((ui32LineActive) & USB_CDC_LINE_IS_ACTIVE) + \
+ ((ui8LineCallIndex) & 0xFF)) ; \
+ SetResponseCallState(pi8Buf, 0, ui32CallActive, \
+ ui8CallStateChange, ui8CallState); \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// Notification Element definitions
+//
+//*****************************************************************************
+#define USB_CDC_NOTIFY_NETWORK_CONNECTION \
+ 0x00
+#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE \
+ 0x01
+#define USB_CDC_NOTIFY_AUX_JACK_HOOK_STATE \
+ 0x08
+#define USB_CDC_NOTIFY_RING_DETECT \
+ 0x09
+#define USB_CDC_NOTIFY_SERIAL_STATE \
+ 0x20
+#define USB_CDC_NOTIFY_CALL_STATE_CHANGE \
+ 0x28
+#define USB_CDC_NOTIFY_LINE_STATE_CHANGE \
+ 0x29
+#define USB_CDC_NOTIFY_CONNECTION_SPEED_CHANGE \
+ 0x2A
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_NETWORK_CONNECTION, wValue
+//
+//*****************************************************************************
+#define USB_CDC_NETWORK_DISCONNECTED \
+ 0x0000
+#define USB_CDC_NETWORK_CONNECTED \
+ 0x0001
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_AUX_JACK_HOOK_STATE, wValue
+//
+//*****************************************************************************
+#define USB_CDC_AUX_JACK_ON_HOOK \
+ 0x0000
+#define USB_CDC_AUX_JACK_OFF_HOOK \
+ 0x0001
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_SERIAL_STATE, Data
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Number of bytes of data returned alongside this notification.
+//
+//*****************************************************************************
+#define USB_CDC_NOTIFY_SERIAL_STATE_SIZE \
+ 2
+
+#define USB_CDC_SERIAL_STATE_OVERRUN \
+ 0x0040
+#define USB_CDC_SERIAL_STATE_PARITY \
+ 0x0020
+#define USB_CDC_SERIAL_STATE_FRAMING \
+ 0x0010
+#define USB_CDC_SERIAL_STATE_RING_SIGNAL \
+ 0x0008
+#define USB_CDC_SERIAL_STATE_BREAK \
+ 0x0004
+#define USB_CDC_SERIAL_STATE_TXCARRIER \
+ 0x0002
+#define USB_CDC_SERIAL_STATE_RXCARRIER \
+ 0x0001
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_CALL_STATE_CHANGE, wValue
+//
+// Call state values are defined above in the group beginning
+// USB_CDC_CALL_STATE_IDLE. Note that the data returned alongside this
+// notification are heavily dependent upon the call state being reported so no
+// specific lengths or access macros are provided here.
+//
+// Macro to construct the correct wValue for this notification given a state
+// and call index.
+//
+//*****************************************************************************
+#define SetNotifyCallStatewValue(pi16Result, ui8CallState, ui8Index) \
+ do \
+ { \
+ (WORD(pi16Result)) = (((ui8CallState) & 0xFF) + \
+ (((ui8Index) & 0xFF) << 8)); \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_LINE_STATE_CHANGE, wValue
+//
+// Note that the data returned alongside this notification are heavily
+// dependent upon the call state being reported so no specific lengths or
+// access macros are provided here.
+//
+//*****************************************************************************
+#define USB_CDC_LINE_STATE_IDLE 0x0000
+#define USB_CDC_LINE_STATE_HOLD 0x0001
+#define USB_CDC_LINE_STATE_OFF_HOOK \
+ 0x0002
+#define USB_CDC_LINE_STATE_ON_HOOK \
+ 0x0003
+
+//*****************************************************************************
+//
+// USB_CDC_NOTIFY_CONNECTION_SPEED_CHANGE, Data
+//
+// Macro to populate the 8 byte data structure returned alongside this
+// notification.
+//
+//*****************************************************************************
+#define SetNotifyConnectionSpeedChange(pi8Buf, ui32USBitRate, ui32DSBitRate) \
+ do \
+ { \
+ LONG(pi8Buf) = ui32USBitRate; \
+ LONG((uint8_t *)(pi8Buf) + 4) = ui32DSBitRate; \
+ } \
+ while(0)
+
+//*****************************************************************************
+//
+// Packed structure definitions for request/response data blocks
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requires a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+//! USB_CDC_GET/SET_LINE_CODING request-specific data.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The data terminal rate in bits per second.
+ //
+ uint32_t ui32Rate;
+
+ //
+ //! The number of stop bits. Valid values are USB_CDC_STOP_BITS_1,
+ //! USB_CDC_STOP_BITS_1_5 or USB_CDC_STOP_BITS_2
+ //
+ uint8_t ui8Stop;
+
+ //
+ //! The parity setting. Valid values are USB_CDC_PARITY_NONE,
+ //! USB_CDC_PARITY_ODD, USB_CDC_PARITY_EVEN, USB_CDC_PARITY_MARK and
+ //! USB_CDC_PARITY_SPACE.
+ //
+ uint8_t ui8Parity;
+
+ //
+ //! The number of data bits per character. Valid values are 5, 6, 7 and 8
+ //! in this implementation.
+ //
+ uint8_t ui8Databits;
+}
+PACKED tLineCoding;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBCDC_H__
diff --git a/usblib/usbdesc.c b/usblib/usbdesc.c
new file mode 100644
index 0000000..ac88082
--- /dev/null
+++ b/usblib/usbdesc.c
@@ -0,0 +1,480 @@
+//*****************************************************************************
+//
+// usbdesc.c - USB descriptor parsing functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+
+//*****************************************************************************
+//
+// Assumptions:
+// ------------
+//
+// The following assumptions are made in this module. From reading chapter 9
+// of the USB 2.0 specification, these appear to be perfectly valid.
+//
+// 1. The interface number, bInterfaceNumber in the interface descriptor, is
+// a zero based index and takes values between 0 and
+// (pConfigDescriptor->bNumInterfaces - 1) inclusive.
+// 2. Similarly, the alternate setting number, bAlternateSetting in the
+// interface descriptor, is a zero based index.
+// 3. Interface descriptors are ordered by interface number in the
+// configuration descriptor.
+// 4. If alternate settings are available for an interface, the interface
+// descriptors are ordered by alternate setting value bAlternateSetting.
+// 5. Although the endpoints associated with a given interface must follow
+// their associated interface descriptor, it is possible for other,
+// device specific descriptors to be found between an interface descriptor
+// and its endpoints or between endpoint descriptors for the same
+// interface.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup general_usblib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Determines the number of individual descriptors of a particular type within
+//! a supplied buffer.
+//!
+//! \param psDesc points to the first byte of a block of standard USB
+//! descriptors.
+//! \param ui32Size is the number of bytes of descriptor data found at pointer
+//! \e psDesc.
+//! \param ui32Type identifies the type of descriptor that is to be counted.
+//! If the value is \b USB_DESC_ANY, the function returns the total number of
+//! descriptors regardless of type.
+//!
+//! This function can be used to count the number of descriptors of a
+//! particular type within a block of descriptors. The caller can provide a
+//! specific type value which the function matches against the second byte of
+//! each descriptor or, alternatively, can specify \b USB_DESC_ANY to have the
+//! function count all descriptors regardless of their type.
+//!
+//! \return Returns the number of descriptors found in the supplied block of
+//! data.
+//
+//*****************************************************************************
+uint32_t
+USBDescGetNum(tDescriptorHeader *psDesc, uint32_t ui32Size,
+ uint32_t ui32Type)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32TotLength;
+ uint32_t ui32Count;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = psDesc;
+ ui32TotLength = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(ui32TotLength < ui32Size)
+ {
+ //
+ // Does this descriptor match the type passed (if a specific type
+ // has been specified)?
+ //
+ if((ui32Type == USB_DESC_ANY) ||
+ (psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF)))
+ {
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui32TotLength += (uint32_t)psDescCheck->bLength;
+ psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
+ }
+
+ //
+ // Return the descriptor count to the caller.
+ //
+ return(ui32Count);
+}
+
+//*****************************************************************************
+//
+//! Determines the number of individual descriptors of a particular type within
+//! a supplied buffer.
+//!
+//! \param psDesc points to the first byte of a block of standard USB
+//! descriptors.
+//! \param ui32Size is the number of bytes of descriptor data found at pointer
+//! \e psDesc.
+//! \param ui32Type identifies the type of descriptor that is to be found. If
+//! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th
+//! descriptor regardless of type.
+//! \param ui32Index is the zero based index of the descriptor whose pointer is
+//! to be returned. For example, passing value 1 in \e ui32Index returns the
+//! second matching descriptor.
+//!
+//! Return a pointer to the n-th descriptor of a particular type found in the
+//! block of \e ui32Size bytes starting at \e psDesc.
+//!
+//! \return Returns a pointer to the header of the required descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tDescriptorHeader *
+USBDescGet(tDescriptorHeader *psDesc, uint32_t ui32Size,
+ uint32_t ui32Type, uint32_t ui32Index)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32TotLength;
+ uint32_t ui32Count;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = psDesc;
+ ui32TotLength = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(ui32TotLength < ui32Size)
+ {
+ //
+ // Does this descriptor match the type passed (if a specific type
+ // has been specified)?
+ //
+ if((ui32Type == USB_DESC_ANY) ||
+ (psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF)))
+ {
+ //
+ // We found a matching descriptor. If our count matches the
+ // supplied index, we are done so return the pointer.
+ //
+ if(ui32Count == ui32Index)
+ {
+ return(psDescCheck);
+ }
+
+ //
+ // We have not found enough descriptors yet to satisfy the supplied
+ // index so increment our count and continue.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui32TotLength += (uint32_t)psDescCheck->bLength;
+ psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
+ }
+
+ //
+ // If we get here, we reached the end of the data without finding the
+ // required descriptor. Return NULL.
+ //
+ return((tDescriptorHeader *)0);
+}
+
+//*****************************************************************************
+//
+//! Determines the number of different alternate configurations for a given
+//! interface within a configuration descriptor.
+//!
+//! \param psConfig points to the first byte of a standard USB configuration
+//! descriptor.
+//! \param ui8InterfaceNumber is the interface number for which the number of
+//! alternate configurations is to be counted.
+//!
+//! This function can be used to count the number of alternate settings for a
+//! specific interface within a configuration.
+//!
+//! \return Returns the number of alternate versions of the specified interface
+//! or 0 if the interface number supplied cannot be found in the config
+//! descriptor.
+//
+//*****************************************************************************
+uint32_t
+USBDescGetNumAlternateInterfaces(tConfigDescriptor *psConfig,
+ uint8_t ui8InterfaceNumber)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32TotLength;
+ uint32_t ui32Count;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig;
+ ui32TotLength = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
+ {
+ //
+ // Is this an interface descriptor with the required interface number?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // Yes - increment our count.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui32TotLength += (uint32_t)psDescCheck->bLength;
+ psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
+ }
+
+ //
+ // Return the descriptor count to the caller.
+ //
+ return(ui32Count);
+}
+
+//*****************************************************************************
+//
+//! Returns a pointer to the n-th interface descriptor in a config descriptor
+//! with the supplied interface number.
+//!
+//! \param psConfig points to the first byte of a standard USB configuration
+//! descriptor.
+//! \param ui8InterfaceNumber is the interface number of the descriptor that is
+//! being queried.
+//! \param ui32Index is the zero based index of the descriptor to return.
+//!
+//! This function returns a pointer to the n-th interface descriptor in the
+//! supplied configuration which has the requested interface number. It may be
+//! used by a client to retrieve the descriptors for each alternate setting
+//! of a given interface within the configuration passed.
+//!
+//! \return Returns a pointer to the n-th interface descriptor with interface
+//! number as specified or NULL of this descriptor does not exist.
+//
+//*****************************************************************************
+static tInterfaceDescriptor *
+USBDescGetAlternateInterface(tConfigDescriptor *psConfig,
+ uint8_t ui8InterfaceNumber,
+ uint32_t ui32Index)
+{
+ tDescriptorHeader *psDescCheck;
+ uint32_t ui32TotLength;
+ uint32_t ui32Count;
+
+ //
+ // Set up for our descriptor counting loop.
+ //
+ psDescCheck = (tDescriptorHeader *)psConfig;
+ ui32TotLength = 0;
+ ui32Count = 0;
+
+ //
+ // Keep looking through the supplied data until we reach the end.
+ //
+ while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
+ {
+ //
+ // Does this descriptor match the type passed (if a specific type
+ // has been specified)?
+ //
+ if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
+ (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
+ ui8InterfaceNumber))
+ {
+ //
+ // This is an interface descriptor for interface
+ // ui8InterfaceNumber. Determine if this is the n-th one we have
+ // found and, if so, return its pointer.
+ //
+ if(ui32Count == ui32Index)
+ {
+ //
+ // Found it - return the pointer.
+ //
+ return((tInterfaceDescriptor *)psDescCheck);
+ }
+
+ //
+ // Increment our count of matching descriptors found and go back
+ // to look for another since we have not yet reached the n-th
+ // match.
+ //
+ ui32Count++;
+ }
+
+ //
+ // Move on to the next descriptor.
+ //
+ ui32TotLength += (uint32_t)psDescCheck->bLength;
+ psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck);
+ }
+
+ //
+ // If we drop out the end of the loop, we did not find the requested
+ // descriptor so return NULL.
+ //
+ return((tInterfaceDescriptor *)0);
+}
+
+//*****************************************************************************
+//
+//! Returns a pointer to the n-th interface descriptor in a configuration
+//! descriptor that applies to the supplied alternate setting number.
+//!
+//! \param psConfig points to the first byte of a standard USB configuration
+//! descriptor.
+//! \param ui32Index is the zero based index of the interface that is to be
+//! found. If \e ui32Alt is set to a value other than \b USB_DESC_ANY, this
+//! will be equivalent to the interface number being searched for.
+//! \param ui32Alt is the alternate setting number which is to be
+//! searched for. If this value is \b USB_DESC_ANY, the alternate setting
+//! is ignored and all interface descriptors are considered in the search.
+//!
+//! Return a pointer to the n-th interface descriptor found in the supplied
+//! configuration descriptor. If \e ui32Alt is not \b USB_DESC_ANY, only
+//! interface descriptors which are part of the supplied alternate setting are
+//! considered in the search otherwise all interface descriptors are
+//! considered.
+//!
+//! Note that, although alternate settings can be applied on an interface-by-
+//! interface basis, the number of interfaces offered is fixed for a given
+//! config descriptor. Hence, this function will correctly find the unique
+//! interface descriptor for that interface's alternate setting number
+//! \e ui32Alt if \e ui32Index is set to the required interface number and
+//! \e ui32Alt is set to a valid alternate setting number for that interface.
+//!
+//! \return Returns a pointer to the required interface descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tInterfaceDescriptor *
+USBDescGetInterface(tConfigDescriptor *psConfig, uint32_t ui32Index,
+ uint32_t ui32Alt)
+{
+ //
+ // If we are being told to ignore the alternate configuration, this boils
+ // down to a very simple query.
+ //
+ if(ui32Alt == USB_DESC_ANY)
+ {
+ //
+ // Return the ui32Index-th interface descriptor we find in the
+ // configuration descriptor.
+ //
+ return((tInterfaceDescriptor *)USBDescGet(
+ (tDescriptorHeader *)psConfig,
+ (uint32_t)psConfig->wTotalLength,
+ USB_DTYPE_INTERFACE, ui32Index));
+ }
+ else
+ {
+ //
+ // In this case, a specific alternate setting number is required.
+ // Given that interface numbers are zero based indices, we can
+ // pass the supplied ui32Index parameter directly as the interface
+ // number to USBDescGetAlternateInterface to retrieve the requested
+ // interface descriptor pointer.
+ //
+ return(USBDescGetAlternateInterface(psConfig, ui32Index, ui32Alt));
+ }
+}
+
+//*****************************************************************************
+//
+//! Return a pointer to the n-th endpoint descriptor in the supplied
+//! interface descriptor.
+//!
+//! \param psInterface points to the first byte of a standard USB interface
+//! descriptor.
+//! \param ui32Index is the zero based index of the endpoint that is to be
+//! found.
+//! \param ui32Size contains the maximum number of bytes that the function may
+//! search beyond \e psInterface while looking for the requested endpoint
+//! descriptor.
+//!
+//! Return a pointer to the n-th endpoint descriptor found in the supplied
+//! interface descriptor. If the \e ui32Index parameter is invalid (greater
+//! than or equal to the bNumEndpoints field of the interface descriptor) or
+//! the endpoint cannot be found within \e ui32Size bytes of the interface
+//! descriptor pointer, the function will return NULL.
+//!
+//! Note that, although the USB 2.0 specification states that endpoint
+//! descriptors must follow the interface descriptor that they relate to, it
+//! also states that device specific descriptors should follow any standard
+//! descriptor that they relate to. As a result, we cannot assume that each
+//! interface descriptor will be followed by nothing but an ordered list of
+//! its own endpoints and, hence, the function needs to be provided \e ui32Size
+//! to limit the search range.
+//!
+//! \return Returns a pointer to the requested endpoint descriptor if
+//! found or NULL otherwise.
+//
+//*****************************************************************************
+tEndpointDescriptor *
+USBDescGetInterfaceEndpoint(tInterfaceDescriptor *psInterface,
+ uint32_t ui32Index, uint32_t ui32Size)
+{
+ //
+ // Is the index passed valid?
+ //
+ if(ui32Index >= psInterface->bNumEndpoints)
+ {
+ //
+ // It's out of bounds so return a NULL.
+ //
+ return((tEndpointDescriptor *)0);
+ }
+ else
+ {
+ //
+ // Endpoint index is valid so find the descriptor.
+ //
+ return((tEndpointDescriptor *)USBDescGet(
+ (tDescriptorHeader *)psInterface,
+ ui32Size, USB_DTYPE_ENDPOINT, ui32Index));
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbdfu.h b/usblib/usbdfu.h
new file mode 100644
index 0000000..9bde75d
--- /dev/null
+++ b/usblib/usbdfu.h
@@ -0,0 +1,504 @@
+//*****************************************************************************
+//
+// usbdfu.h - Definitions related to the USB Device Firmware Upgrade class.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBDFU_H__
+#define __USBDFU_H__
+
+//*****************************************************************************
+//
+// DFU attributes as published in the functional descriptor.
+//
+//*****************************************************************************
+#define DFU_ATTR_WILL_DETACH 0x08
+#define DFU_ATTR_MANIFEST_TOLERANT \
+ 0x04
+#define DFU_ATTR_CAN_UPLOAD 0x02
+#define DFU_ATTR_CAN_DOWNLOAD 0x01
+
+//*****************************************************************************
+//
+// The states that the DFU device can be in. These values are reported to
+// the host in response to a USBD_DFU_REQUEST_GETSTATE request.
+//
+//*****************************************************************************
+typedef enum
+{
+ eDFUStateAppIdle = 0,
+ eDFUStateAppDetach,
+ eDFUStateIdle,
+ eDFUStateDnloadSync,
+ eDFUStateDnBusy,
+ eDFUStateDnloadIdle,
+ eDFUStateManifestSync,
+ eDFUStateManifest,
+ eDFUStateManifestWaitReset,
+ eDFUStateUploadIdle,
+ eDFUStateError
+}
+tDFUState;
+
+//*****************************************************************************
+//
+// The current error status of the DFU device. These values are reported to
+// the host in response to a USBD_DFU_REQUEST_GETSTATUS request.
+//
+//*****************************************************************************
+typedef enum
+{
+ eDFUStatusOk = 0,
+ eDFUStatusErrTarget,
+ eDFUStatusErrFile,
+ eDFUStatusErrWrite,
+ eDFUStatusErrErase,
+ eDFUStatusErrCheckErased,
+ eDFUStatusErrProg,
+ eDFUStatusErrVerify,
+ eDFUStatusErrAddress,
+ eDFUStatusErrNotDone,
+ eDFUStatusErrFirmware,
+ eDFUStatusErrVendor,
+ eDFUStatusErrUSBR,
+ eDFUStatusErrPOR,
+ eDFUStatusErrUnknown,
+ eDFUStatusErrStalledPkt
+}
+tDFUStatus;
+
+//*****************************************************************************
+//
+// The descriptor type for the DFU functional descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_FUNC_DESCRIPTOR_TYPE \
+ 0x21
+
+//*****************************************************************************
+//
+// The subclass identifier for DFU as reported to the host in the
+// bInterfaceSubClass field of the DFU interface descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_SUBCLASS 0x01
+
+//*****************************************************************************
+//
+// The protocol identifier for DFU as reported to the host in the
+// bInterfaceProtocol field of the DFU interface descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_PROTOCOL 0x02
+#define USB_DFU_RUNTIME_PROTOCOL \
+ 0x01
+
+//*****************************************************************************
+//
+// DFU class-specific request identifiers.
+//
+//*****************************************************************************
+#define USBD_DFU_REQUEST_DETACH 0
+#define USBD_DFU_REQUEST_DNLOAD 1
+#define USBD_DFU_REQUEST_UPLOAD 2
+#define USBD_DFU_REQUEST_GETSTATUS \
+ 3
+#define USBD_DFU_REQUEST_CLRSTATUS \
+ 4
+#define USBD_DFU_REQUEST_GETSTATE \
+ 5
+#define USBD_DFU_REQUEST_ABORT 6
+
+//*****************************************************************************
+//
+// Request 1KB blocks from the host. This value is published in the USB
+// functional descriptor.
+//
+//*****************************************************************************
+#define DFU_TRANSFER_SIZE 1024
+
+//*****************************************************************************
+//
+// USBLib-specific request identifier. This is used to determine whether
+// the target device supports our DFU command protocol. It is expected that
+// a device not supporting our extensions will stall this request. This
+// request is only supported while the DFU device is in eDFUStateIdle.
+//
+// An IN request containing the following parameters will result in the device
+// sending back a tDFUQueryTivaProtocol structure indicating that
+// USBLib extensions are supported. The actual values in wValue and wIndex
+// have no meaning other than to act as markers in the unlikely event that
+// another DFU device also chooses to use request ID 0x42 for some other
+// purpose.
+//
+// wValue - 0x23(REQUEST_TIVA_VALUE)
+// wIndex - Interface number
+// wLength - sizeof(tDFUQueryTivaProtocol)
+//
+//*****************************************************************************
+#define USBD_DFU_REQUEST_TIVA 0x42
+#define REQUEST_TIVA_VALUE 0x23
+
+#define DFU_PROTOCOL_TIVA_MARKER \
+ 0x4C4D
+#define DFU_PROTOCOL_TIVA_VERSION_1 \
+ 0x0001
+
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+// The structure sent to the host when a valid USBD_DFU_REQUEST_TIVA is
+// received while the DFU device is in idle state.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The protocol marker(DFU_PROTOCOL_TIVA_MARKER)
+ //
+ uint16_t ui16Marker;
+
+ //
+ // The protocol version(DFU_PROTOCOL_TIVA_VERSION_1)
+ //
+ uint16_t ui16Version;
+}
+PACKED tDFUQueryTivaProtocol;
+
+//*****************************************************************************
+//
+// Structure sent to the host in response to USBD_DFU_REQUEST_GETSTATUS.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t bStatus;
+ uint8_t bwPollTimeout[3];
+ uint8_t bState;
+ uint8_t iString;
+}
+PACKED tDFUGetStatusResponse;
+
+//*****************************************************************************
+//
+// Firmware Download Commands
+//
+// The data passed on a USBD_DFU_REQUEST_DNLOAD request is comprised of a
+// header which instructs the boot loader how to interpret the block and
+// block-specific data. The following definitions relate to the download
+// block headers.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Supported command identifiers
+//
+//*****************************************************************************
+#define DFU_CMD_PROG 0x01
+#define DFU_CMD_READ 0x02
+#define DFU_CMD_CHECK 0x03
+#define DFU_CMD_ERASE 0x04
+#define DFU_CMD_INFO 0x05
+#define DFU_CMD_BIN 0x06
+#define DFU_CMD_RESET 0x07
+
+//*****************************************************************************
+//
+// Generic download command header.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Command identifier.
+ //
+ uint8_t ui8Command;
+
+ //
+ // Command-specific data elements.
+ //
+ uint8_t pui8Data[7];
+}
+PACKED tDFUDownloadHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_PROG command.
+//
+// This command is used to program a section of the flash with the binary data
+// which immediately follows the header. The start address of the data is
+// expressed as a 1KB block number so 0 would represent the bottom of flash
+// (which, incidentally, the USB boot loader will not let you program) and 0x10
+// would represent address 16KB or 16384 (0x4000). The ui32Length field
+// contains the total number of bytes of data in the following programming
+// operation. The DFU device will not look for any command header on following
+// USBD_DFU_REQUEST_DNLOAD requests until the operation is completed or
+// aborted.
+//
+// By using this protocol, the DFU_CMD_PROG command header may be used as a
+// simple header on the binary files to be sent to the DFU device for
+// programming. If we enforce the requirement that the DFU_CMD_PROG header is
+// applied to each USBD_DFU_REQUEST_DNLOAD (one per block), this means that the
+// host-side DFU application must be aware of the underlying protocol and
+// insert these headers dynamically during programming operations. This could
+// be handled by post processing the binary to insert the headers at the
+// appropriate points but this would then tie the binary structure to the
+// chosen transfer size and break the operation if the transfer size were to
+// change in the future.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // DFU_CMD_PROG
+ //
+ uint8_t ui8Command;
+
+ //
+ // Reserved - set to 0x00.
+ //
+ uint8_t ui8Reserved;
+
+ //
+ // Block start address / 1024
+ //
+ uint16_t ui16StartAddr;
+
+ //
+ // Total length, in bytes, of following data for the complete download
+ // operation.
+ //
+ uint32_t ui32Length;
+}
+PACKED tDFUDownloadProgHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_READ and DFU_CMD_CHECK commands.
+//
+// This command may be used to set the address range whose content will be
+// returned on subsequent USBD_DFU_REQUEST_UPLOAD requests from the host.
+//
+// To read back a the contents of a region of flash, the host should send
+// USBD_DFU_REQUEST_DNLOAD with ui8Command DFU_CMD_READ, ui16StartAddr set to
+// the 1KB block start address and ui32Length set to the number of bytes to
+// read. The host should then send one or more USBD_DFU_REQUEST_UPLOAD
+// requests to receive the current flash contents from the configured
+// addresses. Data returned will include an 8 byte DFU_CMD_PROG prefix
+// structure unless the prefix has been disabled by sending a DFU_CMD_BIN
+// command with the bBinary parameter set to 1.
+//
+// To check that a region of flash is erased, the DFU_CMD_CHECK command should
+// be sent with ui16StartAddr and ui32Length set to describe the region to
+// check. The host should then send a USBD_DFU_REQUEST_GETSTATUS. If the
+// erase check was successful, the returned bStatus value will be STATUS_OK,
+// otherwise it will be STATUS_ERR_CHECK_ERASED. Note that ui32Length passed
+// must be a multiple of 4. If this is not the case, the value will be
+// truncated before the check is performed.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // DFU_CMD_READ or DFU_CMD_CHECK
+ //
+ uint8_t ui8Command;
+
+ //
+ // Reserved - write to 0
+ //
+ uint8_t ui8Reserved;
+
+ //
+ // Block start address / 1024
+ //
+ uint16_t ui16StartAddr;
+
+ //
+ // The number of bytes of data to read back or check.
+ //
+ uint32_t ui32Length;
+}
+PACKED tDFUDownloadReadCheckHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_ERASE command.
+//
+// This command may be used to erase a number of flash blocks. The address of
+// the first block to be erased is passed in ui16StartAddr with ui16NumBlocks
+// containing the number of blocks to be erased from this address. The block
+// size of the device may be determined using the DFU_CMD_INFO command.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // DFU_CMD_ERASE
+ //
+ uint8_t ui8Command;
+
+ //
+ // Reserved - set to 0.
+ //
+ uint8_t ui8Reserved;
+
+ //
+ // Block start address / 1024
+ //
+ uint16_t ui16StartAddr;
+
+ //
+ // The number of blocks to erase.
+ //
+ uint16_t ui16NumBlocks;
+
+ //
+ // Reserved - set to 0.
+ //
+ uint8_t pui8Reserved2[2];
+}
+PACKED tDFUDownloadEraseHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_INFO command.
+//
+// This command may be used to query information about the connected device.
+// After sending the command, the information is returned on the next
+// USBD_DFU_REQUEST_UPLOAD request.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // DFU_CMD_INFO
+ //
+ uint8_t ui8Command;
+
+ //
+ // Reserved - set to 0.
+ //
+ uint8_t pui8Reserved[7];
+}
+PACKED tDFUDownloadInfoHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_BIN command.
+//
+// This command may be used to set the format of uploaded data. By default,
+// images read using USBD_DFU_REQUEST_UPLOAD are formatted with the appropriate
+// header to allow the same image to be flashed back to the device and have it
+// located at the address from which it originated. This is a requirement of
+// the DFU class specification (section 6.2 "the uploaded image must be
+// usable in a subsequent download") but may not be helpful in some cases where
+// the application wishes to receive only the binary image from flash. To
+// instruct the DFU device to omit the position and size header, send this
+// command with the bBinary field set to \b true prior to issuing a
+// USBD_DFU_REQUEST_UPLOAD for image data. The format choice remains in effect
+// until the command is sent once again with bBinary set to \b false.
+//
+// Note that the format choice affects only image data sent and not responses
+// read via USBD_DFU_REQUEST_UPLOAD following USBLib-specific commands such
+// as DFU_CMD_INFO.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // DFU_CMD_BIN
+ //
+ uint8_t ui8Command;
+
+ //
+ // Set to true to omit image header or false to include it (the default).
+ //
+ uint8_t ui8Binary;
+
+ //
+ // Reserved - set to 0.
+ //
+ uint8_t pui8Reserved[6];
+}
+PACKED tDFUDownloadBinHeader;
+
+//*****************************************************************************
+//
+// The DFU_CMD_RESET command uses a tDFUDownloadHeader structure since
+// only the ui8Command field is important. This command causes an immediate
+// reset of the the target board.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Payload returned in response to the DFU_CMD_INFO command.
+//!
+//! This is structure is returned in response to the first
+//! USBD_DFU_REQUEST_UPLOAD request following a DFU_CMD_INFO command.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The size of a flash block in bytes.
+ //
+ uint16_t ui16FlashBlockSize;
+
+ //
+ //! The number of blocks of flash in the device. Total flash size is
+ //! ui16NumFlashBlocks * ui16FlashBlockSize.
+ //
+ uint16_t ui16NumFlashBlocks;
+
+ //
+ //! Information on the part number, family, version and package as
+ //! read from SYSCTL register DID1.
+ //
+ uint32_t ui32PartInfo;
+
+ //
+ //! Information on the part class and revision as read from SYSCTL DID0.
+ //
+ uint32_t ui32ClassInfo;
+
+ //
+ //! Address 1 byte above the highest location the boot loader can access.
+ //
+ uint32_t ui32FlashTop;
+
+ //
+ //! Lowest address the boot loader can write or erase.
+ //
+ uint32_t ui32AppStartAddr;
+}
+PACKED tDFUDeviceInfo;
+
+#ifdef ewarm
+#pragma pack()
+#endif
+
+#endif // __USBDFU_H__
diff --git a/usblib/usbdma.c b/usblib/usbdma.c
new file mode 100644
index 0000000..4ae9e2b
--- /dev/null
+++ b/usblib/usbdma.c
@@ -0,0 +1,1453 @@
+//*****************************************************************************
+//
+// usbdma.c - USB Library DMA handling functions.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_udma.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rtos_bindings.h"
+#include "driverlib/usb.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/udma.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_dma_api Internal USB DMA functions
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// There are two sets of functions in this file, one is used with uDMA while
+// the other is used with USB controllers with an integrated DMA controller.
+// The functions with the IDMA prefix are for the integrated DMA controller and
+// the functions that are specific to the uDMA controller are prefixed with
+// uDMA. Any common functions are have just the DMA prefix.
+//
+//*****************************************************************************
+static tUSBDMAInstance g_psUSBDMAInst[1];
+
+//*****************************************************************************
+//
+// Macros used to determine if a uDMA endpoint configuration is used for
+// receive or transmit.
+//
+//*****************************************************************************
+#define UDMAConfigIsRx(ui32Config) \
+ ((ui32Config & UDMA_SRC_INC_NONE) == UDMA_SRC_INC_NONE)
+#define UDMAConfigIsTx(ui32Config) \
+ ((ui32Config & UDMA_DEST_INC_NONE) == UDMA_DEST_INC_NONE)
+
+//*****************************************************************************
+//
+// USBLibDMAChannelStatus() for USB controllers that use the uDMA for DMA.
+//
+//*****************************************************************************
+static uint32_t
+uDMAUSBChannelStatus(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ uint32_t ui32Status;
+
+ //
+ // Initialize the current status to no events.
+ //
+ ui32Status = USBLIBSTATUS_DMA_IDLE;
+
+ //
+ // Check if there is a pending DMA transfer.
+ //
+ if(psUSBDMAInst->ui32Complete & (1 << (ui32Channel - 1)))
+ {
+ //
+ // Return that the DMA transfer has completed and clear the
+ // DMA pending flag.
+ //
+ ui32Status = USBLIBSTATUS_DMA_COMPLETE;
+ }
+ else if(psUSBDMAInst->ui32Pending & (1 << (ui32Channel - 1)))
+ {
+ //
+ // DMA transfer is still pending.
+ //
+ ui32Status = USBLIBSTATUS_DMA_PENDING;
+ }
+ else
+ {
+ //
+ // DMA transfer is still pending.
+ //
+ ui32Status = USBLIBSTATUS_DMA_IDLE;
+ }
+
+ return(ui32Status);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelStatus() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static uint32_t
+iDMAUSBChannelStatus(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ uint32_t ui32Status;
+
+ //
+ // Initialize the current status to no events.
+ //
+ ui32Status = USBLIBSTATUS_DMA_IDLE;
+
+ //
+ // Check if an error has occurred.
+ //
+ if(USBDMAChannelStatus(psUSBDMAInst->ui32Base, ui32Channel) ==
+ USB_DMA_STATUS_ERROR)
+ {
+ ui32Status = USBLIBSTATUS_DMA_ERROR;
+ }
+ //
+ // Otherwise check if there a pending DMA transfer has completed.
+ //
+ else if(psUSBDMAInst->ui32Complete & (1 << (ui32Channel - 1)))
+ {
+ //
+ // Return that the DMA transfer has completed and clear the
+ // DMA pending flag.
+ //
+ ui32Status = USBLIBSTATUS_DMA_COMPLETE;
+ }
+ else if(psUSBDMAInst->ui32Pending & (1 << (ui32Channel - 1)))
+ {
+ //
+ // DMA transfer is still pending.
+ //
+ ui32Status = USBLIBSTATUS_DMA_PENDING;
+ }
+ else
+ {
+ //
+ // DMA Channel is idle.
+ //
+ ui32Status = USBLIBSTATUS_DMA_IDLE;
+ }
+
+ return(ui32Status);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAIntStatus() for USB controllers that use uDMA.
+//
+//*****************************************************************************
+static uint32_t
+uDMAUSBIntStatus(tUSBDMAInstance *psUSBDMAInst)
+{
+ uint32_t ui32Status, ui32Pending;
+ int32_t i32Channel;
+
+ //
+ // Initialize the current status to no events.
+ //
+ ui32Status = 0;
+
+ //
+ // No pending interrupts by default.
+ //
+ ui32Status = 0;
+
+ //
+ // Save the pending channels.
+ //
+ ui32Pending = psUSBDMAInst->ui32Pending;
+
+ //
+ // Loop through channels to find out if any pending DMA transfers have
+ // completed.
+ //
+ for(i32Channel = 0; i32Channel < USB_MAX_DMA_CHANNELS; i32Channel++)
+ {
+ //
+ // If pending and stopped then the DMA completed.
+ //
+ if((ui32Pending & 1) &&
+ (MAP_uDMAChannelModeGet(i32Channel) == UDMA_MODE_STOP))
+ {
+ ui32Status |= (1 << i32Channel);
+ }
+ ui32Pending >>= 1;
+
+ //
+ // Done if this is zero.
+ //
+ if(ui32Pending == 0)
+ {
+ break;
+ }
+ }
+
+ return(ui32Status);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAIntStatus() for USB controllers with an integrated DMA controller.
+//
+//*****************************************************************************
+static uint32_t
+iDMAUSBIntStatus(tUSBDMAInstance *psUSBDMAInst)
+{
+ //
+ // Read the current DMA status, unfortunately this clears the
+ // pending interrupt status.
+ //
+ return(USBDMAChannelIntStatus(psUSBDMAInst->ui32Base));
+}
+
+//*****************************************************************************
+//
+// USBLibDMAIntStatusClear() for USB controllers that use uDMA for DMA or have
+// an integrated DMA controller.
+//
+//*****************************************************************************
+static void
+DMAUSBIntStatusClear(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Status)
+{
+ //
+ // Clear out the requested interrupts. Since the USB interface does not
+ // have a true interrupt clear, this clears the current completed
+ // status for the requested channels.
+ //
+ psUSBDMAInst->ui32Complete &= ~ui32Status;
+
+ return;
+}
+
+//*****************************************************************************
+//
+// USBLibDMAIntHandler() for USB controllers that use uDMA for DMA or have an
+// integrated DMA controller.
+//
+//*****************************************************************************
+static void
+DMAUSBIntHandler(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32DMAIntStatus)
+{
+ uint32_t ui32Channel;
+
+ if(ui32DMAIntStatus == 0)
+ {
+ return;
+ }
+
+ //
+ // Determine if the uDMA is used or the USB DMA controller.
+ //
+ for(ui32Channel = 0; ui32Channel < USB_MAX_DMA_CHANNELS; ui32Channel++)
+ {
+ //
+ // Mark any pending interrupts as completed.
+ //
+ if(ui32DMAIntStatus & 1)
+ {
+ psUSBDMAInst->ui32Pending &= ~(1 << ui32Channel);
+ psUSBDMAInst->ui32Complete |= (1 << ui32Channel);
+ }
+
+ //
+ // Check the next channel.
+ //
+ ui32DMAIntStatus >>= 1;
+
+ //
+ // Break if there are no more pending DMA interrupts.
+ //
+ if(ui32DMAIntStatus == 0)
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelEnable() for USB controllers that use uDMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBChannelEnable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ uint32_t ui32IntEnabled;
+
+ //
+ // Save if the interrupt was enabled or not.
+ //
+ ui32IntEnabled = IntIsEnabled(psUSBDMAInst->ui32IntNum);
+
+ //
+ // Disable the USB interrupt if it was enabled.
+ //
+ if(ui32IntEnabled)
+ {
+ OS_INT_DISABLE(psUSBDMAInst->ui32IntNum);
+ }
+
+ //
+ // Mark this channel as pending and not complete.
+ //
+ psUSBDMAInst->ui32Pending |= (1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+
+ //
+ // Enable DMA for the endpoint.
+ //
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ MAP_USBEndpointDMAEnable(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_DEV_OUT | USB_EP_HOST_IN);
+ }
+ else
+ {
+ MAP_USBEndpointDMAEnable(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_DEV_IN | USB_EP_HOST_OUT);
+ }
+
+ //
+ // Enable the DMA in the uDMA controller.
+ //
+ MAP_uDMAChannelEnable(ui32Channel - 1);
+
+ //
+ // Enable the USB interrupt if it was enabled before.
+ //
+ if(ui32IntEnabled)
+ {
+ OS_INT_ENABLE(psUSBDMAInst->ui32IntNum);
+ }
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelEnable() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBChannelEnable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ uint32_t ui32IntEnabled;
+
+ //
+ // Save if the interrupt was enabled or not.
+ //
+ ui32IntEnabled = IntIsEnabled(psUSBDMAInst->ui32IntNum);
+
+ //
+ // Disable the USB interrupt if it was enabled.
+ //
+ if(ui32IntEnabled)
+ {
+ OS_INT_DISABLE(psUSBDMAInst->ui32IntNum);
+ }
+
+ //
+ // Mark this channel as pending and not complete.
+ //
+ psUSBDMAInst->ui32Pending |= (1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+
+ //
+ // Enable the interrupt for this DMA channel.
+ //
+ USBDMAChannelIntEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+
+ //
+ // Enable the DMA channel.
+ //
+ USBDMAChannelEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+
+ //
+ // Enable the USB interrupt if it was enabled before.
+ //
+ if(ui32IntEnabled)
+ {
+ OS_INT_ENABLE(psUSBDMAInst->ui32IntNum);
+ }
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelDisable() for USB controllers that use uDMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBChannelDisable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // Disable DMA for the endpoint.
+ //
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_DEV_OUT);
+ }
+ else
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_DEV_IN);
+ }
+
+ //
+ // Disable the DMA channel in the uDMA controller.
+ //
+ MAP_uDMAChannelDisable(ui32Channel - 1);
+
+ //
+ // Clear out any pending or complete flag set for this DMA channel.
+ //
+ psUSBDMAInst->ui32Pending &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelDisable() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBChannelDisable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // Disable the DMA channel.
+ //
+ USBDMAChannelDisable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+
+ //
+ // Disable the interrupt for this DMA channel.
+ //
+ USBDMAChannelIntDisable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+
+ //
+ // Clear out any pending or complete flag set for this DMA channel.
+ //
+ psUSBDMAInst->ui32Pending &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelIntEnable() for USB controllers that use uDMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBChannelIntEnable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // There is no way to Enable channel interrupts when using uDMA.
+ //
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelIntEnable() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBChannelIntEnable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // Enable the interrupt for this DMA channel.
+ //
+ USBDMAChannelIntEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelIntDisable() for USB controllers that use uDMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBChannelIntDisable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // There is no way to Disable channel interrupts when using uDMA.
+ //
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelIntDisable() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBChannelIntDisable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ //
+ // Disable the interrupt for this DMA channel.
+ //
+ USBDMAChannelIntDisable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+}
+
+//*****************************************************************************
+//
+// USBLibDMATransfer() for USB controllers that use the uDMA controller.
+//
+//*****************************************************************************
+static uint32_t
+uDMAUSBTransfer(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ void *pvBuffer, uint32_t ui32Size)
+{
+ void *pvFIFO;
+ uint32_t uluDMAChannel;
+ uint32_t ui32PacketCount;
+ uint32_t ui32TransferCount;
+
+ if((ui32Size < 64) || ((uint32_t)pvBuffer & 0x3))
+ {
+ return(0);
+ }
+
+ //
+ // Mark this channel as pending and not complete.
+ //
+ psUSBDMAInst->ui32Pending |= (1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+
+ //
+ // Save the pointer to the data and the byte count.
+ //
+ psUSBDMAInst->ppui32Data[ui32Channel - 1] = pvBuffer;
+ psUSBDMAInst->pui32Count[ui32Channel - 1] = ui32Size;
+
+ //
+ // Need the address of the FIFO.
+ //
+ pvFIFO = (void *)USBFIFOAddrGet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1]);
+
+ //
+ // Calculate the uDMA channel for this RX channel.
+ //
+ uluDMAChannel = UDMA_CHANNEL_USBEP1RX + ui32Channel - 1;
+
+ ui32TransferCount = ui32Size;
+
+ if((psUSBDMAInst->pui32Config[ui32Channel - 1] & UDMA_SIZE_32) ==
+ UDMA_SIZE_32)
+ {
+ ui32TransferCount >>= 2;
+ }
+ else if((psUSBDMAInst->pui32Config[ui32Channel - 1] & UDMA_SIZE_32) ==
+ UDMA_SIZE_32)
+ {
+ ui32TransferCount >>= 1;
+ }
+
+ //
+ // If source increment is none this is an RX transfer.
+ //
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ MAP_uDMAChannelTransferSet(uluDMAChannel, UDMA_MODE_BASIC, pvFIFO,
+ pvBuffer, ui32TransferCount);
+ }
+ else
+ {
+ MAP_uDMAChannelTransferSet(uluDMAChannel, UDMA_MODE_BASIC, pvBuffer,
+ pvFIFO, ui32TransferCount);
+ }
+
+ //
+ // Set the mode based on the size of the transfer. More than one
+ // packet requires mode 1.
+ //
+ if(ui32Size > psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1])
+ {
+ //
+ // Calculate the number of packets required for this transfer.
+ //
+ ui32PacketCount = ((ui32Size /
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1]));
+
+ //
+ // Set the packet count so that the last packet does not generate
+ // another IN request.
+ //
+ USBEndpointPacketCountSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ ui32PacketCount);
+
+ //
+ // Configure the USB endpoint in mode 1 for this DMA transfer.
+ //
+ USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel - 1]);
+ }
+ else
+ {
+ //
+ // Configure the USB endpoint in mode 0 for this DMA transfer.
+ //
+ USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel -1]);
+ }
+
+ //
+ // Enable the uDMA channel to start the transfer
+ //
+ uDMAUSBChannelEnable(psUSBDMAInst, ui32Channel);
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+// USBLibDMATransfer() for USB controllers with an integrated DMA controller.
+//
+//*****************************************************************************
+static uint32_t
+iDMAUSBTransfer(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ void *pvBuffer, uint32_t ui32Size)
+{
+ uint32_t ui32PacketCount;
+
+ if((uint32_t)pvBuffer & 0x3)
+ {
+ return(0);
+ }
+
+ //
+ // Mark this channel as pending and not complete.
+ //
+ psUSBDMAInst->ui32Pending |= (1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+
+ //
+ // Save the pointer to the data and the byte count.
+ //
+ psUSBDMAInst->ppui32Data[ui32Channel - 1] = pvBuffer;
+ psUSBDMAInst->pui32Count[ui32Channel - 1] = ui32Size;
+
+ //
+ // Set the address.
+ //
+ USBDMAChannelAddressSet(psUSBDMAInst->ui32Base, ui32Channel - 1, pvBuffer);
+
+ //
+ // Set the number of transfers.
+ //
+ USBDMAChannelCountSet(psUSBDMAInst->ui32Base, ui32Channel - 1, ui32Size);
+
+ //
+ // Set the mode based on the size of the transfer. More than one
+ // packet requires mode 1.
+ //
+ if(ui32Size > psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1])
+ {
+ //
+ // Calculate the number of packets required for this transfer.
+ //
+ ui32PacketCount = ui32Size /
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1];
+
+ if(ui32Size % psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1])
+ {
+ ui32PacketCount += 1;
+ }
+
+ USBEndpointPacketCountSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ ui32PacketCount);
+
+ //
+ // Configure the USB DMA controller for mode 1.
+ //
+ USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel - 1]);
+
+ USBDMAChannelConfigSet(psUSBDMAInst->ui32Base, ui32Channel - 1,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32Config[ui32Channel - 1] |
+ USB_DMA_CFG_MODE_1);
+
+ //
+ // Enable DMA on the endpoint.
+ //
+ if(psUSBDMAInst->pui32Config[ui32Channel - 1] & USB_DMA_CFG_DIR_TX)
+ {
+ //
+ // Make sure that DMA is enabled on the endpoint.
+ //
+ MAP_USBEndpointDMAEnable(
+ psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_HOST_OUT);
+ }
+ else
+ {
+ //
+ // Make sure that DMA is enabled on the endpoint.
+ //
+ MAP_USBEndpointDMAEnable(
+ psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_HOST_IN);
+ }
+
+ //
+ // Enable the DMA channel.
+ //
+ USBDMAChannelEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+ }
+ else
+ {
+ //
+ // Configure the USB DMA controller for mode 0.
+ //
+ USBEndpointDMAConfigSet(psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel -1]);
+
+ USBDMAChannelConfigSet(psUSBDMAInst->ui32Base, ui32Channel -1,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ psUSBDMAInst->pui32Config[ui32Channel - 1] |
+ USB_DMA_CFG_MODE_0);
+
+ //
+ // In mode 0 only enable DMA transfer for mode 0.
+ //
+ if(psUSBDMAInst->pui32Config[ui32Channel - 1] & USB_DMA_CFG_DIR_TX)
+ {
+ //
+ // Make sure that DMA is enabled on the endpoint.
+ //
+ MAP_USBEndpointDMAEnable(
+ psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_HOST_OUT);
+ //
+ // Enable the DMA channel.
+ //
+ USBDMAChannelEnable(psUSBDMAInst->ui32Base, ui32Channel - 1);
+ }
+ else
+ {
+ //
+ // Make sure that DMA is disabled on the endpoint, it will
+ // be enabled when the endpoint interrupt occurs.
+ //
+ MAP_USBEndpointDMADisable(
+ psUSBDMAInst->ui32Base,
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1],
+ USB_EP_HOST_IN);
+
+ }
+ }
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelAllocate() for USB controllers that use uDMA for DMA.
+//
+//*****************************************************************************
+static uint32_t
+uDMAUSBChannelAllocate(tUSBDMAInstance *psUSBDMAInst, uint8_t ui8Endpoint,
+ uint32_t ui32MaxPacketSize, uint32_t ui32Config)
+{
+ uint32_t ui32Channel;
+
+ //
+ // The DMA channels are organized in pairs on this controller and the
+ // transmit channels are 1, 3, and 5 while receive are 0, 2, and 4.
+ //
+ if(ui32Config & USB_DMA_EP_RX)
+ {
+ ui32Channel = 0;
+ }
+ else
+ {
+ ui32Channel = 1;
+ }
+
+ //
+ // Search for an available DMA channel to use.
+ //
+ for(; ui32Channel < USB_MAX_DMA_CHANNELS_0; ui32Channel += 2)
+ {
+ //
+ // If the current endpoint value is zero then this channel is
+ // available.
+ //
+ if(psUSBDMAInst->pui8Endpoint[ui32Channel] == 0)
+ {
+ //
+ // Save the endpoint for this DMA channel.
+ //
+ psUSBDMAInst->pui8Endpoint[ui32Channel] = ui8Endpoint;
+
+ //
+ // Save the maximum packet size for the endpoint.
+ //
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel] = ui32MaxPacketSize;
+
+ //
+ // Set the channel configuration based on the direction.
+ //
+ if(ui32Config & USB_DMA_EP_RX)
+ {
+ psUSBDMAInst->pui32Config[ui32Channel] =
+ UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
+ UDMA_ARB_64;
+
+ //
+ // If in device mode and Isochronous.
+ //
+ if(((ui32Config & USB_DMA_EP_HOST) == 0) &&
+ ((ui32Config & USB_DMA_EP_TYPE_M) == USB_DMA_EP_TYPE_ISOC))
+ {
+ //
+ // USB_EP_AUTO_REQUEST is required for device
+ // Isochronous endpoints.
+ //
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] =
+ USB_EP_DMA_MODE_0 |
+ USB_EP_AUTO_REQUEST |
+ USB_EP_HOST_IN;
+ }
+ else
+ {
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] =
+ USB_EP_DMA_MODE_0 |
+ USB_EP_AUTO_CLEAR |
+ USB_EP_HOST_IN;
+ }
+
+ //
+ // Do not set auto request in device mode unless it is an
+ // isochronous endpoint.
+ //
+ if(((ui32Config & USB_DMA_EP_HOST) == 0) &&
+ ((ui32Config & USB_DMA_EP_TYPE_M) != USB_DMA_EP_TYPE_ISOC))
+ {
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] =
+ USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_IN |
+ USB_EP_AUTO_CLEAR;
+ }
+ else
+ {
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] =
+ USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_IN |
+ USB_EP_AUTO_REQUEST |
+ USB_EP_AUTO_CLEAR;
+ }
+ }
+ else
+ {
+ psUSBDMAInst->pui32Config[ui32Channel] =
+ UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
+ UDMA_ARB_64;
+
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] = USB_EP_DMA_MODE_0 |
+ USB_EP_HOST_OUT;
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] = USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_OUT |
+ USB_EP_AUTO_SET;
+ }
+
+ //
+ // Map the uDMA channel to the given endpoint.
+ //
+ MAP_USBEndpointDMAChannel(psUSBDMAInst->ui32Base, ui8Endpoint,
+ ui32Channel);
+
+ //
+ // Clear out the attributes on this channel.
+ //
+ MAP_uDMAChannelAttributeDisable(ui32Channel, UDMA_ATTR_ALL);
+
+ //
+ // Configure the uDMA channel for the pipe
+ //
+ MAP_uDMAChannelControlSet(ui32Channel,
+ psUSBDMAInst->pui32Config[ui32Channel]);
+
+ if(ui32Config & USB_DMA_EP_RX)
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base, ui8Endpoint,
+ USB_EP_DEV_OUT);
+ }
+ else
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base, ui8Endpoint,
+ USB_EP_DEV_IN);
+ }
+
+ //
+ // Outside of this function all channels are 1 based as
+ // zero is not a valid channel.
+ //
+ return(ui32Channel + 1);
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelAllocate() for USB controllers with an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static uint32_t
+iDMAUSBChannelAllocate(tUSBDMAInstance *psUSBDMAInst, uint8_t ui8Endpoint,
+ uint32_t ui32MaxPacketSize, uint32_t ui32Config)
+{
+ uint32_t ui32Channel;
+
+ //
+ // Search for an available DMA channel to use.
+ //
+ for(ui32Channel = 0; ui32Channel < USB_MAX_DMA_CHANNELS_0; ui32Channel++)
+ {
+ //
+ // If the current endpoint value is zero then this channel is
+ // available.
+ //
+ if(psUSBDMAInst->pui8Endpoint[ui32Channel] == 0)
+ {
+ //
+ // Clear out the attributes on this channel.
+ //
+ USBDMAChannelDisable(psUSBDMAInst->ui32Base, ui32Channel);
+
+ //
+ // Save the endpoint for this DMA channel.
+ //
+ psUSBDMAInst->pui8Endpoint[ui32Channel] = ui8Endpoint;
+
+ //
+ // Save the maximum packet size for the endpoint.
+ //
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel] = ui32MaxPacketSize;
+
+ //
+ // Assign the endpoint to the channel and set the direction.
+ //
+ if(ui32Config & USB_DMA_EP_RX)
+ {
+ psUSBDMAInst->pui32Config[ui32Channel] =
+ USB_DMA_CFG_DIR_RX |
+ USB_DMA_CFG_BURST_NONE |
+ USB_DMA_CFG_INT_EN;
+
+ //
+ // If in device mode and Isochronous.
+ //
+ if(((ui32Config & USB_DMA_EP_HOST) == 0) &&
+ ((ui32Config & USB_DMA_EP_TYPE_M) == USB_DMA_EP_TYPE_ISOC))
+ {
+ //
+ // USB_EP_AUTO_REQUEST is required for device
+ // Isochronous endpoints.
+ //
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] =
+ USB_EP_DMA_MODE_0 |
+ USB_EP_AUTO_REQUEST |
+ USB_EP_HOST_IN;
+ }
+ else
+ {
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] =
+ USB_EP_DMA_MODE_0 |
+ USB_EP_AUTO_CLEAR |
+ USB_EP_HOST_IN;
+ }
+
+ //
+ // Do not set auto request in device mode unless it is an
+ // isochronous endpoint.
+ //
+ if(((ui32Config & USB_DMA_EP_HOST) == 0) &&
+ ((ui32Config & USB_DMA_EP_TYPE_M) != USB_DMA_EP_TYPE_ISOC))
+ {
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] =
+ USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_IN |
+ USB_EP_AUTO_CLEAR;
+ }
+ else
+ {
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] =
+ USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_IN |
+ USB_EP_AUTO_REQUEST |
+ USB_EP_AUTO_CLEAR;
+ }
+ }
+ else
+ {
+ psUSBDMAInst->pui32Config[ui32Channel] =
+ USB_DMA_CFG_DIR_TX |
+ USB_DMA_CFG_BURST_NONE |
+ USB_DMA_CFG_INT_EN;
+
+ psUSBDMAInst->pui32EPDMAMode0[ui32Channel] =
+ USB_EP_DMA_MODE_0 |
+ USB_EP_HOST_OUT;
+ psUSBDMAInst->pui32EPDMAMode1[ui32Channel] =
+ USB_EP_DMA_MODE_1 |
+ USB_EP_HOST_OUT |
+ USB_EP_AUTO_SET;
+ }
+
+ //
+ // Outside of this function all channels are 1 based as
+ // zero is not a valid channel.
+ //
+ return(ui32Channel + 1);
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAChannelRelease() for USB controllers that use uDMA for DMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBChannelRelease(tUSBDMAInstance *psUSBDMAInst, uint8_t ui32Channel)
+{
+ ASSERT(ui32Channel < USB_MAX_DMA_CHANNELS_0);
+
+ //
+ // Clear out the attributes on this channel.
+ //
+ MAP_uDMAChannelAttributeDisable(ui32Channel - 1, UDMA_ATTR_ALL);
+
+ if(psUSBDMAInst->pui8Endpoint[ui32Channel] & USB_DMA_EP_RX)
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base,
+ (psUSBDMAInst->pui8Endpoint[ui32Channel] & ~USB_DMA_EP_RX),
+ USB_EP_DEV_OUT);
+ }
+ else
+ {
+ MAP_USBEndpointDMADisable(psUSBDMAInst->ui32Base,
+ (psUSBDMAInst->pui8Endpoint[ui32Channel] & ~USB_DMA_EP_RX),
+ USB_EP_DEV_IN);
+ }
+
+ //
+ // Clear out the state for this endpoint.
+ //
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1] = 0;
+ psUSBDMAInst->pui32Config[ui32Channel - 1] = 0;
+ psUSBDMAInst->ui32Pending &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1] = 0;
+}
+
+//*****************************************************************************
+//
+// DMAChannelRelease() for USB controllers with an integrated DMA controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBChannelRelease(tUSBDMAInstance *psUSBDMAInst, uint8_t ui32Channel)
+{
+ ASSERT(ui32Channel < USB_MAX_DMA_CHANNELS);
+
+ //
+ // Clear out the attributes on this channel.
+ //
+ USBDMAChannelDisable(psUSBDMAInst->ui32Base, ui32Channel);
+
+ //
+ // Clear out the state for this endpoint.
+ //
+ psUSBDMAInst->pui8Endpoint[ui32Channel - 1] = 0;
+ psUSBDMAInst->pui32Config[ui32Channel - 1] = 0;
+ psUSBDMAInst->ui32Pending &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->ui32Complete &= ~(1 << (ui32Channel - 1));
+ psUSBDMAInst->pui32MaxPacketSize[ui32Channel - 1] = 0;
+}
+
+//*****************************************************************************
+//
+// USBLibDMAUnitSizeSet() for USB controllers that use uDMA for DMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBUnitSizeSet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ uint32_t ui32BitSize)
+{
+ uint32_t ui32Value;
+
+ ASSERT((ui32BitSize == 8) || (ui32BitSize == 16) || (ui32BitSize == 32));
+
+ ASSERT(ui32Channel < USB_MAX_DMA_CHANNELS_0);
+
+ if(ui32BitSize == 8)
+ {
+ ui32Value = UDMA_SIZE_8;
+
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ //
+ // Receive increments destination and not source.
+ //
+ ui32Value |= UDMA_DST_INC_8 | UDMA_SRC_INC_NONE;
+ }
+ else
+ {
+ //
+ // Transmit increments source and not destination.
+ //
+ ui32Value |= UDMA_SRC_INC_8 | UDMA_DST_INC_NONE;
+ }
+ }
+ else if(ui32BitSize == 16)
+ {
+ ui32Value = UDMA_SIZE_16;
+
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ //
+ // Receive increments destination and not source.
+ //
+ ui32Value |= UDMA_DST_INC_16 | UDMA_SRC_INC_NONE;
+ }
+ else
+ {
+ //
+ // Transmit increments source and not destination.
+ //
+ ui32Value |= UDMA_SRC_INC_16 | UDMA_DST_INC_NONE;
+ }
+ }
+ else
+ {
+ ui32Value = UDMA_SIZE_32;
+
+ if(UDMAConfigIsRx(psUSBDMAInst->pui32Config[ui32Channel - 1]))
+ {
+ //
+ // Receive increments destination and not source.
+ //
+ ui32Value |= (UDMA_DST_INC_32 | UDMA_SRC_INC_NONE);
+ }
+ else
+ {
+ //
+ // Transmit increments source and not destination.
+ //
+ ui32Value |= (UDMA_SRC_INC_32 | UDMA_DST_INC_NONE);
+ }
+ }
+
+ //
+ // Keep the current arbitration size and or in the size.
+ //
+ psUSBDMAInst->pui32Config[ui32Channel - 1] &= 0x00ffffff;
+ psUSBDMAInst->pui32Config[ui32Channel - 1] |= ui32Value;
+ MAP_uDMAChannelControlSet(ui32Channel - 1,
+ psUSBDMAInst->pui32Config[ui32Channel - 1]);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAUnitSizeSet() for USB controllers that have an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBUnitSizeSet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ uint32_t ui32BitSize)
+{
+}
+
+//*****************************************************************************
+//
+// USBLibDMAArbSizeSet() for USB controllers that use uDMA for DMA.
+//
+//*****************************************************************************
+static void
+uDMAUSBArbSizeSet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ uint32_t ui32ArbSize)
+{
+ uint32_t ui32Value;
+
+ ASSERT(ui32Channel < USB_MAX_DMA_CHANNELS_0);
+
+ //
+ // Get the arbitration size value.
+ //
+ if(ui32ArbSize == 2)
+ {
+ ui32Value = UDMA_ARB_2;
+ }
+ else if(ui32ArbSize == 4)
+ {
+ ui32Value = UDMA_ARB_4;
+ }
+ else if(ui32ArbSize == 8)
+ {
+ ui32Value = UDMA_ARB_8;
+ }
+ else if(ui32ArbSize == 16)
+ {
+ ui32Value = UDMA_ARB_16;
+ }
+ else if(ui32ArbSize == 32)
+ {
+ ui32Value = UDMA_ARB_32;
+ }
+ else if(ui32ArbSize == 64)
+ {
+ ui32Value = UDMA_ARB_64;
+ }
+ else if(ui32ArbSize == 128)
+ {
+ ui32Value = UDMA_ARB_128;
+ }
+ else if(ui32ArbSize == 256)
+ {
+ ui32Value = UDMA_ARB_256;
+ }
+ else
+ {
+ //
+ // Default to arbitration size of 1.
+ //
+ ui32Value = UDMA_ARB_1;
+ }
+
+ //
+ // Keep the current size and or in the new arbitration size.
+ //
+ psUSBDMAInst->pui32Config[ui32Channel - 1] &= 0xff000000;
+ psUSBDMAInst->pui32Config[ui32Channel - 1] |= ui32Value;
+
+ //
+ // Set the uDMA channel control, remember its channel starts at 0 and
+ // not 1.
+ //
+ MAP_uDMAChannelControlSet(ui32Channel - 1,
+ psUSBDMAInst->pui32Config[ui32Channel - 1]);
+}
+
+//*****************************************************************************
+//
+// USBLibDMAArbSizeSet() for USB controllers that have an integrated DMA
+// controller.
+//
+//*****************************************************************************
+static void
+iDMAUSBArbSizeSet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ uint32_t ui32ArbSize)
+{
+}
+
+//*****************************************************************************
+//
+// USBLibDMAStatus() for USB controllers that use uDMA for DMA or have an
+// integrated DMA controller.
+//
+//*****************************************************************************
+static uint32_t
+DMAUSBStatus(tUSBDMAInstance *psUSBDMAInst)
+{
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to return the current DMA pointer for a given
+//! DMA channel.
+//!
+//! \param psUSBDMAInst is a generic instance pointer that can be used to
+//! distinguish between different hardware instances.
+//! \param ui32Channel is the DMA channel number for this request.
+//!
+//! This function returns the address that is in use by the DMA channel passed
+//! in via the \e ui32Channel parameter. This is not the real-time pointer,
+//! but the starting address of the DMA transfer for this DMA channel.
+//!
+//! \return The current DMA address for the given DMA channel.
+//
+//*****************************************************************************
+void *
+USBLibDMAAddrGet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ return(psUSBDMAInst->ppui32Data[ui32Channel - 1]);
+}
+
+//*****************************************************************************
+//
+//! This function is used to return the current DMA transfer size for a given
+//! DMA channel.
+//!
+//! \param psUSBDMAInst is a generic instance pointer that can be used to
+//! distinguish between different hardware instances.
+//! \param ui32Channel is the DMA channel number for this request.
+//!
+//! This function returns the DMA transfer size that is in use by the DMA
+//! channel passed in via the \e ui32Channel parameter.
+//!
+//! \return The current DMA transfer size for the given DMA channel.
+//
+//*****************************************************************************
+uint32_t
+USBLibDMASizeGet(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
+{
+ return(psUSBDMAInst->pui32Count[ui32Channel - 1]);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize the DMA interface for a USB instance.
+//!
+//! \param ui32Index is the index of the USB controller for this instance.
+//!
+//! This function performs any initialization and configuration of the DMA
+//! portions of the USB controller. This function returns a pointer that
+//! is used with the remaining USBLibDMA APIs or the function returns zero
+//! if the requested controller cannot support DMA. If this function is called
+//! when already initialized it will not reinitialize the DMA controller and
+//! will instead return the previously initialized DMA instance.
+//!
+//! \return A pointer to use with USBLibDMA APIs.
+//
+//*****************************************************************************
+tUSBDMAInstance *
+USBLibDMAInit(uint32_t ui32Index)
+{
+ uint32_t ui32Channel;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Make sure that the DMA has not already been initialized.
+ //
+ if(g_psUSBDMAInst[0].ui32Base == USB0_BASE)
+ {
+ return(&g_psUSBDMAInst[0]);
+ }
+
+ //
+ // Save the base address of the USB controller.
+ //
+ g_psUSBDMAInst[0].ui32Base = USB0_BASE;
+
+ //
+ // Save the interrupt number for the USB controller.
+ //
+ g_psUSBDMAInst[0].ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // Initialize the function pointers.
+ //
+ g_psUSBDMAInst[0].pfnArbSizeSet = uDMAUSBArbSizeSet;
+ g_psUSBDMAInst[0].pfnChannelAllocate = uDMAUSBChannelAllocate;
+ g_psUSBDMAInst[0].pfnChannelDisable = uDMAUSBChannelDisable;
+ g_psUSBDMAInst[0].pfnChannelEnable = uDMAUSBChannelEnable;
+ g_psUSBDMAInst[0].pfnChannelIntEnable = uDMAUSBChannelIntEnable;
+ g_psUSBDMAInst[0].pfnChannelIntDisable = uDMAUSBChannelIntDisable;
+ g_psUSBDMAInst[0].pfnChannelRelease = uDMAUSBChannelRelease;
+ g_psUSBDMAInst[0].pfnChannelStatus = uDMAUSBChannelStatus;
+ g_psUSBDMAInst[0].pfnIntHandler = DMAUSBIntHandler;
+ g_psUSBDMAInst[0].pfnIntStatus = uDMAUSBIntStatus;
+ g_psUSBDMAInst[0].pfnIntStatusClear = DMAUSBIntStatusClear;
+ g_psUSBDMAInst[0].pfnStatus = DMAUSBStatus;
+ g_psUSBDMAInst[0].pfnTransfer = uDMAUSBTransfer;
+ g_psUSBDMAInst[0].pfnUnitSizeSet = uDMAUSBUnitSizeSet;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_psUSBDMAInst[0].ui32IntNum = INT_USB0_TM4C129;
+ }
+
+ //
+ // Initialize the function pointers for the integrated USB DMA controller.
+ //
+ if(USBControllerVersion(g_psUSBDMAInst[0].ui32Base) == USB_CONTROLLER_VER_1)
+ {
+ g_psUSBDMAInst[0].pfnArbSizeSet = iDMAUSBArbSizeSet;
+ g_psUSBDMAInst[0].pfnChannelAllocate = iDMAUSBChannelAllocate;
+ g_psUSBDMAInst[0].pfnChannelStatus = iDMAUSBChannelStatus;
+ g_psUSBDMAInst[0].pfnIntStatus = iDMAUSBIntStatus;
+ g_psUSBDMAInst[0].pfnChannelIntEnable = iDMAUSBChannelIntEnable;
+ g_psUSBDMAInst[0].pfnChannelIntDisable = iDMAUSBChannelIntDisable;
+ g_psUSBDMAInst[0].pfnTransfer = iDMAUSBTransfer;
+ g_psUSBDMAInst[0].pfnChannelRelease = iDMAUSBChannelRelease;
+ g_psUSBDMAInst[0].pfnChannelEnable = iDMAUSBChannelEnable;
+ g_psUSBDMAInst[0].pfnChannelDisable = iDMAUSBChannelDisable;
+ g_psUSBDMAInst[0].pfnUnitSizeSet = iDMAUSBUnitSizeSet;
+ }
+
+ //
+ // Clear out the endpoint and the current configuration.
+ //
+ for(ui32Channel = 0; ui32Channel < USB_MAX_DMA_CHANNELS; ui32Channel++)
+ {
+ g_psUSBDMAInst[0].pui8Endpoint[ui32Channel] = 0;
+ g_psUSBDMAInst[0].pui32Config[ui32Channel] = 0;
+ g_psUSBDMAInst[0].ui32Pending = 0;
+ g_psUSBDMAInst[0].ui32Complete = 0;
+ }
+ return(&g_psUSBDMAInst[0]);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbhid.h b/usblib/usbhid.h
new file mode 100644
index 0000000..b89a24f
--- /dev/null
+++ b/usblib/usbhid.h
@@ -0,0 +1,667 @@
+//*****************************************************************************
+//
+// usbhid.h - Definitions used by HID class devices and hosts.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHID_H__
+#define __USBHID_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup hid_device_class_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// HID Interface descriptor Subclasses.
+//
+//*****************************************************************************
+#define USB_HID_SCLASS_NONE 0x00
+#define USB_HID_SCLASS_BOOT 0x01
+
+//*****************************************************************************
+//
+// USB Interface descriptor HID protocols.
+//
+//*****************************************************************************
+#define USB_HID_PROTOCOL_NONE 0
+#define USB_HID_PROTOCOL_KEYB 1
+#define USB_HID_PROTOCOL_MOUSE 2
+
+//*****************************************************************************
+//
+// HID Class descriptor types.
+//
+//*****************************************************************************
+#define USB_HID_DTYPE_HID 0x21
+#define USB_HID_DTYPE_REPORT 0x22
+#define USB_HID_DTYPE_PHYSICAL 0x23
+
+//*****************************************************************************
+//
+// HID USB requests.
+//
+//*****************************************************************************
+#define USBREQ_GET_REPORT 0x01
+#define USBREQ_GET_IDLE 0x02
+#define USBREQ_GET_PROTOCOL 0x03
+#define USBREQ_SET_REPORT 0x09
+#define USBREQ_SET_IDLE 0x0a
+#define USBREQ_SET_PROTOCOL 0x0b
+
+//*****************************************************************************
+//
+// GET_REPORT or SET_REPORT Definitions.
+//
+//*****************************************************************************
+#define USB_HID_REPORT_IN 0x01
+#define USB_HID_REPORT_OUTPUT 0x02
+#define USB_HID_REPORT_FEATURE 0x03
+
+//*****************************************************************************
+//
+// GET_PROTOCOL or SET_PROTOCOL Definitions.
+//
+//*****************************************************************************
+#define USB_HID_PROTOCOL_BOOT 0
+#define USB_HID_PROTOCOL_REPORT 1
+
+//*****************************************************************************
+//
+// Report Values used with the Report macros.
+//
+//*****************************************************************************
+#define USB_HID_GENERIC_DESKTOP 0x01
+#define USB_HID_BUTTONS 0x09
+#define USB_HID_X 0x30
+#define USB_HID_Y 0x31
+#define USB_HID_Z 0x32
+#define USB_HID_RX 0x33
+#define USB_HID_RY 0x34
+#define USB_HID_RZ 0x35
+
+#define USB_HID_POINTER 0x01
+#define USB_HID_MOUSE 0x02
+#define USB_HID_JOYSTICK 0x04
+#define USB_HID_GAME_PAD 0x05
+#define USB_HID_KEYBOARD 0x06
+
+#define USB_HID_PHYSICAL 0x00
+#define USB_HID_APPLICATION 0x01
+#define USB_HID_LOGICAL 0x02
+
+#define USB_HID_USAGE_POINTER 0x0109
+#define USB_HID_USAGE_BUTTONS 0x0509
+#define USB_HID_USAGE_LEDS 0x0508
+#define USB_HID_USAGE_KEYCODES 0x0507
+
+//*****************************************************************************
+//
+// HID mouse button definitions as used in the first byte of the output report
+// used in the BIOS mouse protocol.
+//
+//*****************************************************************************
+#define HID_MOUSE_BUTTON_1 0x01
+#define HID_MOUSE_BUTTON_2 0x02
+#define HID_MOUSE_BUTTON_3 0x04
+
+//*****************************************************************************
+//
+// HID Keyboard LED definitions as used in the first byte of the output report
+// used in the BIOS keyboard protocol.
+//
+//*****************************************************************************
+#define HID_KEYB_NUM_LOCK 0x01
+#define HID_KEYB_CAPS_LOCK 0x02
+#define HID_KEYB_SCROLL_LOCK 0x04
+#define HID_KEYB_COMPOSE 0x08
+#define HID_KEYB_KANA 0x10
+
+//*****************************************************************************
+//
+// HID Keyboard key modifiers as provided in the first byte of the input report
+// used in the BIOS keyboard protocol.
+//
+//*****************************************************************************
+#define HID_KEYB_LEFT_CTRL 0x01
+#define HID_KEYB_LEFT_SHIFT 0x02
+#define HID_KEYB_LEFT_ALT 0x04
+#define HID_KEYB_LEFT_GUI 0x08
+#define HID_KEYB_RIGHT_CTRL 0x10
+#define HID_KEYB_RIGHT_SHIFT 0x20
+#define HID_KEYB_RIGHT_ALT 0x40
+#define HID_KEYB_RIGHT_GUI 0x80
+
+//*****************************************************************************
+//
+// A subset of the HID keyboard usage IDs.
+//
+//*****************************************************************************
+#define HID_KEYB_USAGE_RESERVED 0x00
+#define HID_KEYB_USAGE_ROLLOVER 0x01
+#define HID_KEYB_USAGE_A 0x04
+#define HID_KEYB_USAGE_B 0x05
+#define HID_KEYB_USAGE_C 0x06
+#define HID_KEYB_USAGE_D 0x07
+#define HID_KEYB_USAGE_E 0x08
+#define HID_KEYB_USAGE_F 0x09
+#define HID_KEYB_USAGE_G 0x0A
+#define HID_KEYB_USAGE_H 0x0B
+#define HID_KEYB_USAGE_I 0x0C
+#define HID_KEYB_USAGE_J 0x0D
+#define HID_KEYB_USAGE_K 0x0E
+#define HID_KEYB_USAGE_L 0x0F
+#define HID_KEYB_USAGE_M 0x10
+#define HID_KEYB_USAGE_N 0x11
+#define HID_KEYB_USAGE_O 0x12
+#define HID_KEYB_USAGE_P 0x13
+#define HID_KEYB_USAGE_Q 0x14
+#define HID_KEYB_USAGE_R 0x15
+#define HID_KEYB_USAGE_S 0x16
+#define HID_KEYB_USAGE_T 0x17
+#define HID_KEYB_USAGE_U 0x18
+#define HID_KEYB_USAGE_V 0x19
+#define HID_KEYB_USAGE_W 0x1A
+#define HID_KEYB_USAGE_X 0x1B
+#define HID_KEYB_USAGE_Y 0x1C
+#define HID_KEYB_USAGE_Z 0x1D
+#define HID_KEYB_USAGE_1 0x1E
+#define HID_KEYB_USAGE_2 0x1F
+#define HID_KEYB_USAGE_3 0x20
+#define HID_KEYB_USAGE_4 0x21
+#define HID_KEYB_USAGE_5 0x22
+#define HID_KEYB_USAGE_6 0x23
+#define HID_KEYB_USAGE_7 0x24
+#define HID_KEYB_USAGE_8 0x25
+#define HID_KEYB_USAGE_9 0x26
+#define HID_KEYB_USAGE_0 0x27
+#define HID_KEYB_USAGE_ENTER 0x28
+#define HID_KEYB_USAGE_ESCAPE 0x29
+#define HID_KEYB_USAGE_BACKSPACE \
+ 0x2A
+#define HID_KEYB_USAGE_TAB 0x2B
+#define HID_KEYB_USAGE_SPACE 0x2C
+#define HID_KEYB_USAGE_MINUS 0x2D
+#define HID_KEYB_USAGE_EQUAL 0x2E
+#define HID_KEYB_USAGE_LBRACKET 0x2F
+#define HID_KEYB_USAGE_RBRACKET 0x30
+#define HID_KEYB_USAGE_BSLASH 0x31
+#define HID_KEYB_USAGE_SEMICOLON \
+ 0x33
+#define HID_KEYB_USAGE_FQUOTE 0x34
+#define HID_KEYB_USAGE_BQUOTE 0x35
+#define HID_KEYB_USAGE_COMMA 0x36
+#define HID_KEYB_USAGE_PERIOD 0x37
+#define HID_KEYB_USAGE_FSLASH 0x38
+#define HID_KEYB_USAGE_CAPSLOCK 0x39
+#define HID_KEYB_USAGE_F1 0x3A
+#define HID_KEYB_USAGE_F2 0x3B
+#define HID_KEYB_USAGE_F3 0x3C
+#define HID_KEYB_USAGE_F4 0x3D
+#define HID_KEYB_USAGE_F5 0x3E
+#define HID_KEYB_USAGE_F6 0x3F
+#define HID_KEYB_USAGE_F7 0x40
+#define HID_KEYB_USAGE_F8 0x41
+#define HID_KEYB_USAGE_F9 0x42
+#define HID_KEYB_USAGE_F10 0x43
+#define HID_KEYB_USAGE_F11 0x44
+#define HID_KEYB_USAGE_F12 0x45
+#define HID_KEYB_USAGE_SCROLLOCK \
+ 0x47
+#define HID_KEYB_USAGE_PAGE_UP 0x4B
+#define HID_KEYB_USAGE_PAGE_DOWN \
+ 0x4E
+#define HID_KEYB_USAGE_RIGHT_ARROW \
+ 0x4F
+#define HID_KEYB_USAGE_LEFT_ARROW \
+ 0x50
+#define HID_KEYB_USAGE_DOWN_ARROW \
+ 0x51
+#define HID_KEYB_USAGE_UP_ARROW 0x52
+#define HID_KEYB_USAGE_NUMLOCK 0x53
+#define HID_KEYB_USAGE_KEYPAD_SLASH \
+ 0x54
+#define HID_KEYB_USAGE_KEYPAD_STAR \
+ 0x55
+#define HID_KEYB_USAGE_KEYPAD_MINUS \
+ 0x56
+#define HID_KEYB_USAGE_KEYPAD_PLUS \
+ 0x57
+#define HID_KEYB_USAGE_KEPAD_ENTER \
+ 0x58
+#define HID_KEYB_USAGE_KEYPAD_1 0x59
+#define HID_KEYB_USAGE_KEYPAD_2 0x5A
+#define HID_KEYB_USAGE_KEYPAD_3 0x5B
+#define HID_KEYB_USAGE_KEYPAD_4 0x5C
+#define HID_KEYB_USAGE_KEYPAD_5 0x5D
+#define HID_KEYB_USAGE_KEYPAD_6 0x5E
+#define HID_KEYB_USAGE_KEYPAD_7 0x5F
+#define HID_KEYB_USAGE_KEYPAD_8 0x60
+#define HID_KEYB_USAGE_KEYPAD_9 0x61
+#define HID_KEYB_USAGE_KEYPAD_0 0x62
+#define HID_KEYB_USAGE_KEPAD_PERIOD \
+ 0x63
+
+//*****************************************************************************
+//
+// HID descriptor country codes (most of these are described as "countries" in
+// the HID specification even though they are really languages).
+//
+//*****************************************************************************
+#define USB_HID_COUNTRY_NONE 0x00
+#define USB_HID_COUNTRY_ARABIC 0x01
+#define USB_HID_COUNTRY_BELGIAN 0x02
+#define USB_HID_COUNTRY_CANADA_BI \
+ 0x03
+#define USB_HID_COUNTRY_CANADA_FR \
+ 0x04
+#define USB_HID_COUNTRY_CZECH_REPUBLIC \
+ 0x05
+#define USB_HID_COUNTRY_DANISH 0x06
+#define USB_HID_COUNTRY_FINNISH 0x07
+#define USB_HID_COUNTRY_FRENCH 0x08
+#define USB_HID_COUNTRY_GERMAN 0x09
+#define USB_HID_COUNTRY_GREEK 0x0A
+#define USB_HID_COUNTRY_HEBREW 0x0B
+#define USB_HID_COUNTRY_HUNGARY 0x0C
+#define USB_HID_COUNTRY_INTERNATIONAL_ISO \
+ 0x0D
+#define USB_HID_COUNTRY_ITALIAN 0x0E
+#define USB_HID_COUNTRY_JAPAN_KATAKANA \
+ 0x0F
+#define USB_HID_COUNTRY_KOREAN 0x10
+#define USB_HID_COUNTRY_LATIN_AMERICAN \
+ 0x11
+#define USB_HID_COUNTRY_NETHERLANDS \
+ 0x12
+#define USB_HID_COUNTRY_NORWEGIAN \
+ 0x13
+#define USB_HID_COUNTRY_PERSIAN 0x14
+#define USB_HID_COUNTRY_POLAND 0x15
+#define USB_HID_COUNTRY_PORTUGUESE \
+ 0x16
+#define USB_HID_COUNTRY_RUSSIA 0x17
+#define USB_HID_COUNTRY_SLOVAKIA \
+ 0x18
+#define USB_HID_COUNTRY_SPANISH 0x19
+#define USB_HID_COUNTRY_SWEDISH 0x1A
+#define USB_HID_COUNTRY_SWISS_FRENCH \
+ 0x1B
+#define USB_HID_COUNTRY_SWISS_GERMAN \
+ 0x1C
+#define USB_HID_COUNTRY_SWITZERLAND \
+ 0x1D
+#define USB_HID_COUNTRY_TAIWAN 0x1E
+#define USB_HID_COUNTRY_TURKISH_Q \
+ 0x1F
+#define USB_HID_COUNTRY_UK 0x20
+#define USB_HID_COUNTRY_US 0x21
+#define USB_HID_COUNTRY_YUGOSLAVIA \
+ 0x22
+#define USB_HID_COUNTRY_TURKISH_F \
+ 0x23
+
+//*****************************************************************************
+//
+// Data flags used in Input item tags within report descriptors.
+//
+//*****************************************************************************
+#define USB_HID_INPUT_DATA 0x0000
+#define USB_HID_INPUT_CONSTANT 0x0001
+#define USB_HID_INPUT_ARRAY 0x0000
+#define USB_HID_INPUT_VARIABLE 0x0002
+#define USB_HID_INPUT_ABS 0x0000
+#define USB_HID_INPUT_RELATIVE 0x0004
+#define USB_HID_INPUT_NOWRAP 0x0000
+#define USB_HID_INPUT_WRAP 0x0008
+#define USB_HID_INPUT_LINEAR 0x0000
+#define USB_HID_INPUT_NONLINEAR 0x0010
+#define USB_HID_INPUT_PREFER 0x0000
+#define USB_HID_INPUT_NONPREFER 0x0020
+#define USB_HID_INPUT_NONULL 0x0000
+#define USB_HID_INPUT_NULL 0x0040
+#define USB_HID_INPUT_BITF 0x0100
+#define USB_HID_INPUT_BYTES 0x0000
+
+//*****************************************************************************
+//
+// Data flags used in Feature item tags within report descriptors.
+//
+//*****************************************************************************
+#define USB_HID_FEATURE_DATA 0x0000
+#define USB_HID_FEATURE_CONSTANT \
+ 0x0001
+#define USB_HID_FEATURE_ARRAY 0x0000
+#define USB_HID_FEATURE_VARIABLE \
+ 0x0002
+#define USB_HID_FEATURE_ABS 0x0000
+#define USB_HID_FEATURE_RELATIVE \
+ 0x0004
+#define USB_HID_FEATURE_NOWRAP 0x0000
+#define USB_HID_FEATURE_WRAP 0x0008
+#define USB_HID_FEATURE_LINEAR 0x0000
+#define USB_HID_FEATURE_NONLINEAR \
+ 0x0010
+#define USB_HID_FEATURE_PREFER 0x0000
+#define USB_HID_FEATURE_NONPREFER \
+ 0x0020
+#define USB_HID_FEATURE_NONULL 0x0000
+#define USB_HID_FEATURE_NULL 0x0040
+#define USB_HID_FEATURE_BITF 0x0100
+#define USB_HID_FEATURE_BYTES 0x0000
+
+//*****************************************************************************
+//
+// Data flags used in Output item tags within report descriptors.
+//
+//*****************************************************************************
+#define USB_HID_OUTPUT_DATA 0x0000
+#define USB_HID_OUTPUT_CONSTANT 0x0001
+#define USB_HID_OUTPUT_ARRAY 0x0000
+#define USB_HID_OUTPUT_VARIABLE 0x0002
+#define USB_HID_OUTPUT_ABS 0x0000
+#define USB_HID_OUTPUT_RELATIVE 0x0004
+#define USB_HID_OUTPUT_NOWRAP 0x0000
+#define USB_HID_OUTPUT_WRAP 0x0008
+#define USB_HID_OUTPUT_LINEAR 0x0000
+#define USB_HID_OUTPUT_NONLINEAR \
+ 0x0010
+#define USB_HID_OUTPUT_PREFER 0x0000
+#define USB_HID_OUTPUT_NONPREFER \
+ 0x0020
+#define USB_HID_OUTPUT_NONULL 0x0000
+#define USB_HID_OUTPUT_NULL 0x0040
+#define USB_HID_OUTPUT_BITF 0x0100
+#define USB_HID_OUTPUT_BYTES 0x0000
+
+//*****************************************************************************
+//
+// Physical descriptor bias values.
+//
+//*****************************************************************************
+#define USB_HID_BIAS_NOT_APPLICABLE \
+ 0x00
+#define USB_HID_BIAS_RIGHT_HAND 0x01
+#define USB_HID_BIAS_LEFT_HAND 0x02
+#define USB_HID_BIAS_BOTH_HANDS 0x03
+#define USB_HID_BIAS_EITHER_HAND \
+ 0x04
+
+//*****************************************************************************
+//
+// Physical descriptor designator values.
+//
+//*****************************************************************************
+#define USB_HID_DESIGNATOR_NONE 0x00
+#define USB_HID_DESIGNATOR_HAND 0x01
+#define USB_HID_DESIGNATOR_EYEBALL \
+ 0x02
+#define USB_HID_DESIGNATOR_EYEBROW \
+ 0x03
+#define USB_HID_DESIGNATOR_EYELID \
+ 0x04
+#define USB_HID_DESIGNATOR_EAR 0x05
+#define USB_HID_DESIGNATOR_NOSE 0x06
+#define USB_HID_DESIGNATOR_MOUTH \
+ 0x07
+#define USB_HID_DESIGNATOR_UPPER_LIP \
+ 0x08
+#define USB_HID_DESIGNATOR_LOWER_LIP \
+ 0x09
+#define USB_HID_DESIGNATOR_JAW 0x0A
+#define USB_HID_DESIGNATOR_NECK 0x0B
+#define USB_HID_DESIGNATOR_UPPER_ARM \
+ 0x0C
+#define USB_HID_DESIGNATOR_ELBOW \
+ 0x0D
+#define USB_HID_DESIGNATOR_FOREARM \
+ 0x0E
+#define USB_HID_DESIGNATOR_WRIST \
+ 0x0F
+#define USB_HID_DESIGNATOR_PALM 0x10
+#define USB_HID_DESIGNATOR_THUMB \
+ 0x11
+#define USB_HID_DESIGNATOR_INDEX_FINGER \
+ 0x12
+#define USB_HID_DESIGNATOR_MIDDLE_FINGER \
+ 0x13
+#define USB_HID_DESIGNATOR_RING_FINGER \
+ 0x14
+#define USB_HID_DESIGNATOR_LITTLE_FINGER \
+ 0x15
+#define USB_HID_DESIGNATOR_HEAD 0x16
+#define USB_HID_DESIGNATOR_SHOULDER \
+ 0x17
+#define USB_HID_DESIGNATOR_HIP 0x18
+#define USB_HID_DESIGNATOR_WAIST \
+ 0x19
+#define USB_HID_DESIGNATOR_THIGH \
+ 0x1A
+#define USB_HID_DESIGNATOR_KNEE 0x1B
+#define USB_HID_DESIGNATOR_CALF 0x1C
+#define USB_HID_DESIGNATOR_ANKLE \
+ 0x1D
+#define USB_HID_DESIGNATOR_FOOT 0x1E
+#define USB_HID_DESIGNATOR_HEEL 0x1F
+#define USB_HID_DESIGNATOR_BALL_OF_FOOT \
+ 0x20
+#define USB_HID_DESIGNATOR_BIG_TOE \
+ 0x21
+#define USB_HID_DESIGNATOR_SECOND_TOE \
+ 0x22
+#define USB_HID_DESIGNATOR_THIRD_TOE \
+ 0x23
+#define USB_HID_DESIGNATOR_FOURTH_TOE \
+ 0x24
+#define USB_HID_DESIGNATOR_LITTLE_TOE \
+ 0x25
+#define USB_HID_DESIGNATOR_BROW 0x26
+#define USB_HID_DESIGNATOR_CHEEK \
+ 0x27
+
+//*****************************************************************************
+//
+// Physical descriptor qualifier values.
+//
+//*****************************************************************************
+#define USB_HID_QUALIFIER_NOT_APPLICABLE \
+ (0x00 << 5)
+#define USB_HID_QUALIFIER_RIGHT (0x01 << 5)
+#define USB_HID_QUALIFIER_LEFT (0x02 << 5)
+#define USB_HID_QUALIFIER_BOTH (0x03 << 5)
+#define USB_HID_QUALIFIER_EITHER \
+ (0x04 << 5)
+#define USB_HID_QUALIFIER_CENTER \
+ (0x05 << 5)
+
+//*****************************************************************************
+//
+// This is the maximum value for a usage code.
+//
+//*****************************************************************************
+#define USBH_HID_MAX_USAGE 256
+#define USBH_HID_CAPS_ARRAY_SZ (USBH_HID_MAX_USAGE/sizeof(uint32_t))
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requires a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+//! The class descriptor information structure is used to announce the presence
+//! of HID-specific class descriptors within the HID descriptor.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The type of HID class descriptor. This will be \b USB_HID_DTYPE_REPORT
+ //! or \b USB_HID_DTYPE_PHYSICAL.
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The total length of the HID class descriptor.
+ //
+ uint16_t wDescriptorLength;
+}
+PACKED tHIDClassDescriptorInfo;
+
+//*****************************************************************************
+//
+//! The HID descriptor is inserted following the interface descriptor and
+//! before the endpoint descriptors for a HID class device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a HID descriptor, this will be
+ //! \b USB_HID_DTYPE_HID.
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! A BCD value identifying the HID Class specification release supported
+ //! by the device. For version 1.11, for example, this value would be
+ //! 0x0111.
+ //
+ uint16_t bcdHID;
+
+ //
+ //! The country code for which this hardware is localized or 0 if no
+ //! localization has been performed. Valid country (or language) codes are
+ //! in labels of the form \b USB_HID_COUNTRY_xxx.
+ uint8_t bCountryCode;
+
+ //
+ //! The number of class-specific descriptors that exist for this device.
+ //! This indicates the number of class descriptor information structures
+ //! that are appended to this structure and must be at least 1 (since all
+ //! HID devices must publish at least 1 report descriptor).
+ //
+ uint8_t bNumDescriptors;
+
+ //
+ //! A table announcing each of the class-specific descriptors that this
+ //! device publishes. The actual number of entries in the array is given
+ //! by the bNumDescriptors field.
+ //
+ tHIDClassDescriptorInfo sClassDescriptor[1];
+}
+PACKED tHIDDescriptor;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+//! This structure defines the mapping of USB usage identifiers to printable
+//! characters. The structure has three members that hold this information.
+//! The ui8BytesPerChar, indicates the number of bytes per character in
+//! the table. The pui32CapsLock array holds a packed bit array of usage
+//! identifiers that can be modified by the Caps Lock key. The pCharMapping
+//! array is treated as a double indexed array with two "columns". In the case
+//! of a single byte character it is treated as pairs of 8 bit values for
+//! unshifted and shifted values. In the case of a double byte characters it
+//! is treated as pairs of 16 bit values.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Number of bytes per character in the pCharMapping table of this
+ //! structure.
+ //
+ uint8_t ui8BytesPerChar;
+
+ //
+ //! This is a packed bitmasked structure with a one bit flags that
+ //! indicates if the corresponding Usage ID is affected by the Caps Lock
+ //! key.
+ //
+ uint32_t pui32CapsLock[USBH_HID_CAPS_ARRAY_SZ];
+
+ //
+ //! This is the indexed table of Usage ID to character value. It must be
+ //! at least ui8BytesPerChar * 2 * \b USBH_HID_MAX_USAGE bytes in size as
+ //! it is treated as a double indexed array.
+ //
+ void *pvCharMapping;
+}
+tHIDKeyboardUsageTable;
+
+//*****************************************************************************
+//
+// The US Keyboard mapping used by USB keyboard usage ID to character mapping.
+//
+//*****************************************************************************
+extern const tHIDKeyboardUsageTable g_sUSKeyboardMap;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHID_H__
diff --git a/usblib/usbkeyboardmap.c b/usblib/usbkeyboardmap.c
new file mode 100644
index 0000000..ae5fd20
--- /dev/null
+++ b/usblib/usbkeyboardmap.c
@@ -0,0 +1,145 @@
+//*****************************************************************************
+//
+// usbkeyboardmap.c - This file holds the table to enable USB keyboard usage
+// identifiers to be mapped to printable characters.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/usbhid.h"
+
+//*****************************************************************************
+//
+// This is the array that hold the unshifted and shifted ASCII character for
+// each usage ID.
+//
+//*****************************************************************************
+const uint8_t g_pui8KeyBoardMap[USBH_HID_MAX_USAGE][2] =
+{
+//
+// Usage ID to character mapping Usage ID CAPS Lock
+//
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 0 - 3 0
+ {'a', 'A'}, {'b', 'B'}, {'c', 'C'}, {'d', 'D'}, // 4 - 7 f
+ {'e', 'E'}, {'f', 'F'}, {'g', 'G'}, {'h', 'H'}, // 8 - 11 f
+ {'i', 'I'}, {'j', 'J'}, {'k', 'K'}, {'l', 'L'}, // 12 - 15 f
+ {'m', 'M'}, {'n', 'N'}, {'o', 'O'}, {'p', 'P'}, // 16 - 19 f
+ {'q', 'Q'}, {'r', 'R'}, {'s', 'S'}, {'t', 'T'}, // 20 - 23 f
+ {'u', 'U'}, {'v', 'V'}, {'w', 'W'}, {'x', 'X'}, // 24 - 27 f
+ {'y', 'Y'}, {'z', 'Z'}, {'1', '!'}, {'2', '@'}, // 28 - 31 3
+
+ {'3', '#'}, {'4', '$'}, {'5', '%'}, {'6', '^'}, // 32 - 35 0
+ {'7', '&'}, {'8', '*'}, {'9', '('}, {'0', ')'}, // 36 - 39 0
+ {'\n', '\n'}, {0, 0}, {0, 0}, {'\t', '\t'}, // 40 - 43 0
+ {' ', ' '}, {'-', '_'}, {'=', '+'}, {'[', '{'}, // 44 - 47 0
+ {']', '}'}, {'\\', '|'},{'`', '~'}, {';', ':'}, // 48 - 51 0
+ {'\'', '"'}, {'`', '~'}, {',', '<'}, {'.', '>'},// 52 - 55 0
+ {'/', '?'}, {0, 0}, {0, 0}, {0, 0}, // 56 - 59 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 60 - 63 0
+
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 64 - 67 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 68 - 71 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 72 - 75 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 76 - 79 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 80 - 83 0
+ {'/', '/'}, {'*', '*'}, {'-', '-'}, {'+', '+'}, // 84 - 87 0
+ {'\n', '\n'}, {'1', 0}, {'2', 0}, {'3', 0}, // 88 - 91 0
+ {'4', 0}, {'5', 0}, {'6', 0}, {'7', 0}, // 92 - 95 0
+
+ {'8', 0}, {'9', 0}, {'0', 0}, {'.', 0}, // 96 - 99 0
+ {'\\', '|'},{0, 0}, {0, 0}, {'=', '+'}, // 100 - 103 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 104 - 107 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 108 - 111 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 112 - 115 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 116 - 119 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 120 - 123 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 124 - 127 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 128 - 131 0
+
+ {0, 0}, {',', ','}, {'=', '='}, {0, 0}, // 132 - 135 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 136 - 139 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 140 - 143 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 144 - 147 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 148 - 151 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 152 - 155 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 156 - 159 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 160 - 163 0
+
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 164 - 167 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 168 - 171 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 172 - 175 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 174 - 179 0
+ {0, 0}, {0, 0}, {'(', '('}, {')', ')'}, // 180 - 183 0
+ {'{', '{'}, {'}', '}'}, {'\t', '\t'}, {0, 0}, // 184 - 187 0
+ {'A', 'A'}, {'B', 'B'}, {'C', 'C'}, {'D', 'D'}, // 188 - 191 0
+ {'E', 'E'}, {'F', 'F'}, {0, 0}, {'^', '^'}, // 192 - 195 0
+
+ {'%', '%'}, {'<', '<'}, {'>', '>'}, {'&', '&'}, // 196 - 199 0
+ {'&', '&'}, {'|', '|'}, {'|', '|'}, {':', ':'}, // 200 - 203 0
+ {'#', '#'}, {' ', ' '}, {'@', '@'}, {'!', '!'}, // 204 - 207 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 208 - 211 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 212 - 215 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 216 - 219 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 220 - 223 0
+
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 224 - 227 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 228 - 231 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 232 - 235 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 236 - 239 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 240 - 243 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 244 - 247 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 248 - 251 0
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}, // 252 - 255 0
+};
+
+//*****************************************************************************
+//
+// This is the structure that defines the mapping of USB usage IDs to ASCII
+// values for printing.
+//
+//*****************************************************************************
+const tHIDKeyboardUsageTable g_sUSKeyboardMap =
+{
+ //
+ // One byte per character.
+ //
+ 1,
+ //
+ // Packed bit array of usages codes that are effected by Caps Lock state.
+ //
+ {
+ 0x3ffffff0, // Alpha characters are only one affected by CAPS LOCK
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ },
+ //
+ // The large table of the direct mapping of usage id's to ascii characters.
+ //
+ (void *)g_pui8KeyBoardMap
+};
diff --git a/usblib/usblib.ewp b/usblib/usblib.ewp
new file mode 100644
index 0000000..70afea7
--- /dev/null
+++ b/usblib/usblib.ewp
@@ -0,0 +1,860 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<project>
+ <fileVersion>1</fileVersion>
+ <configuration>
+ <name>Debug</name>
+ <toolchain>
+ <name>ARM</name>
+ </toolchain>
+ <debug>1</debug>
+ <settings>
+ <name>General</name>
+ <archiveVersion>3</archiveVersion>
+ <data>
+ <version>14</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>ExePath</name>
+ <state>ewarm\Exe</state>
+ </option>
+ <option>
+ <name>ObjPath</name>
+ <state>ewarm\Obj</state>
+ </option>
+ <option>
+ <name>ListPath</name>
+ <state>ewarm\List</state>
+ </option>
+ <option>
+ <name>Variant</name>
+ <version>19</version>
+ <state>39</state>
+ </option>
+ <option>
+ <name>GEndianMode</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Input variant</name>
+ <version>1</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Input description</name>
+ <state>Full formatting.</state>
+ </option>
+ <option>
+ <name>Output variant</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Output description</name>
+ <state>Full formatting.</state>
+ </option>
+ <option>
+ <name>GOutputBinary</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>FPU</name>
+ <version>2</version>
+ <state>5</state>
+ </option>
+ <option>
+ <name>OGCoreOrChip</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GRuntimeLibSelect</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GRuntimeLibSelectSlave</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>RTDescription</name>
+ <state>To be used with the normal configuration of the C/C++ runtime library. No locale interface, C locale, no file descriptor support, no multibytes in printf and scanf, and no hex floats in strtod.</state>
+ </option>
+ <option>
+ <name>RTConfigPath</name>
+ <state>$TOOLKIT_DIR$\INC\DLib_Config_Normal.h</state>
+ </option>
+ <option>
+ <name>OGProductVersion</name>
+ <state>5.11.0.50579</state>
+ </option>
+ <option>
+ <name>OGLastSavedByProductVersion</name>
+ <state>5.11.0.50579</state>
+ </option>
+ <option>
+ <name>GeneralMisraRules</name>
+ <version>0</version>
+ <state>1000111110110101101110011100111111101110011011000101110111101101100111111111111100110011111001110111001111111111111111111111111</state>
+ </option>
+ <option>
+ <name>GeneralEnableMisra</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>GeneralMisraVerbose</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OGChipSelectEditMenu</name>
+ <state>TM4C1230C3PM TexasInstruments TM4C1230C3PM</state>
+ </option>
+ <option>
+ <name>GenLowLevelInterface</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GEndianModeBE</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OGBufferedTerminalOutput</name>
+ <state>0</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>ICCARM</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>19</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>CCDefines</name>
+ <state>ewarm</state>
+ </option>
+ <option>
+ <name>CCPreprocFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCPreprocComments</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCPreprocLine</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCMnemonics</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCMessages</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListAssFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListAssSource</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCEnableRemarks</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCDiagSuppress</name>
+ <state>Pa050</state>
+ </option>
+ <option>
+ <name>CCDiagRemark</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCDiagWarning</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCDiagError</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCObjPrefix</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCAllowList</name>
+ <version>1</version>
+ <state>1111111</state>
+ </option>
+ <option>
+ <name>CCDebugInfo</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IEndianMode</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IExtraOptionsCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IExtraOptions</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCLangConformance</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCSignedPlainChar</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCRequirePrototypes</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCMultibyteSupport</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCDiagWarnAreErr</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCCompilerRuntimeInfo</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IFpuProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OutputFile</name>
+ <state>$FILE_BNAME$.o</state>
+ </option>
+ <option>
+ <name>CCLangSelect</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCLibConfigHeader</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>PreInclude</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CompilerMisraRules</name>
+ <version>0</version>
+ <state>1000111110110101101110011100111111101110011011000101110111101101100111111111111100110011111001110111001111111111111111111111111</state>
+ </option>
+ <option>
+ <name>CompilerMisraOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCIncludePath2</name>
+ <state>$PROJ_DIR$\..</state>
+ </option>
+ <option>
+ <name>CCStdIncCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCStdIncludePath</name>
+ <state>$TOOLKIT_DIR$\INC\</state>
+ </option>
+ <option>
+ <name>CCCodeSection</name>
+ <state>.text</state>
+ </option>
+ <option>
+ <name>IInterwork2</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IProcessorMode2</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCOptLevel</name>
+ <state>3</state>
+ </option>
+ <option>
+ <name>CCOptStrategy</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCOptLevelSlave</name>
+ <state>3</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>AARM</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>7</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>AObjPrefix</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AEndian</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>ACaseSensitivity</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>MacroChars</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnEnable</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnWhat</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnOne</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AWarnRange1</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AWarnRange2</name>
+ <state></state>
+ </option>
+ <option>
+ <name>ADebug</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AltRegisterNames</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ADefines</name>
+ <state>ewarm</state>
+ </option>
+ <option>
+ <name>AList</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AListHeader</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AListing</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>Includes</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MacDefs</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MacExps</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>MacExec</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OnlyAssed</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MultiLine</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>PageLengthCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>PageLength</name>
+ <state>80</state>
+ </option>
+ <option>
+ <name>TabSpacing</name>
+ <state>8</state>
+ </option>
+ <option>
+ <name>AXRef</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefDefines</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefInternal</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefDual</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AFpuProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AOutputFile</name>
+ <state>$FILE_BNAME$.o</state>
+ </option>
+ <option>
+ <name>AMultibyteSupport</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ALimitErrorsCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ALimitErrorsEdit</name>
+ <state>100</state>
+ </option>
+ <option>
+ <name>AIgnoreStdInclude</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AStdIncludes</name>
+ <state>$TOOLKIT_DIR$\INC\</state>
+ </option>
+ <option>
+ <name>AUserIncludes</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AExtraOptionsCheckV2</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AExtraOptionsV2</name>
+ <state></state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>OBJCOPY</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>1</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>OOCOutputFormat</name>
+ <version>1</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OCOutputOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OOCOutputFile</name>
+ <state>usblib.srec</state>
+ </option>
+ <option>
+ <name>OOCCommandLineProducer</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OOCObjCopyEnable</name>
+ <state>0</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>CUSTOM</name>
+ <archiveVersion>3</archiveVersion>
+ <data>
+ <extensions></extensions>
+ <cmdline></cmdline>
+ </data>
+ </settings>
+ <settings>
+ <name>BICOMP</name>
+ <archiveVersion>0</archiveVersion>
+ <data/>
+ </settings>
+ <settings>
+ <name>BUILDACTION</name>
+ <archiveVersion>1</archiveVersion>
+ <data>
+ <prebuild></prebuild>
+ <postbuild></postbuild>
+ </data>
+ </settings>
+ <settings>
+ <name>ILINK</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>5</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>IlinkLibIOConfig</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>XLinkMisraHandler</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkInputFileSlave</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkOutputFile</name>
+ <state>usblib.out</state>
+ </option>
+ <option>
+ <name>IlinkDebugInfoEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkKeepSymbols</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinaryFile</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinarySymbol</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinarySegment</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinaryAlign</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkDefines</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkConfigDefines</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkMapFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogInitialization</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogModule</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogSection</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogVeneer</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkIcfOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkIcfFile</name>
+ <state>lnk0t.icf</state>
+ </option>
+ <option>
+ <name>IlinkIcfFileSlave</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkEnableRemarks</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkSuppressDiags</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsRem</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsWarn</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsErr</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkWarningsAreErrors</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkUseExtraOptions</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkExtraOptions</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkLowLevelInterfaceSlave</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkAutoLibEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkAdditionalLibs</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkOverrideProgramEntryLabel</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkProgramEntryLabelSelect</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkProgramEntryLabel</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkNXPLPCChecksum</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>DoFill</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>FillerByte</name>
+ <state>0xFF</state>
+ </option>
+ <option>
+ <name>FillerStart</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>FillerEnd</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>CrcSize</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcAlign</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcAlgo</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcPoly</name>
+ <state>0x11021</state>
+ </option>
+ <option>
+ <name>CrcCompl</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CrcBitOrder</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CrcInitialValue</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>DoCrc</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkBE8Slave</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkBufferedTerminalOutput</name>
+ <state>1</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>IARCHIVE</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>0</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>IarchiveInputs</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IarchiveOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IarchiveOutput</name>
+ <state>$PROJ_DIR$\ewarm\Exe\usblib.a</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>BILINK</name>
+ <archiveVersion>0</archiveVersion>
+ <data/>
+ </settings>
+ </configuration>
+ <group>
+ <name>Source</name>
+ <file>
+ <name>$PROJ_DIR$\usbbuffer.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdaudio.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdbulk.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdcdc.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdcdesc.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdcomp.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdconfig.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbddfu-rt.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdenum.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbdesc.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdhandler.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdhid.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdhidgamepad.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdhidkeyb.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdhidmouse.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbdma.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\device\usbdmsc.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhaudio.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhhid.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhhidkeyboard.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhhidmouse.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhhub.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhmsc.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhostenum.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\host\usbhscsi.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbkeyboardmap.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbmode.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbringbuf.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbtick.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\usbulpi.c</name>
+ </file>
+ </group>
+</project>
diff --git a/usblib/usblib.h b/usblib/usblib.h
new file mode 100644
index 0000000..3c96a19
--- /dev/null
+++ b/usblib/usblib.h
@@ -0,0 +1,1951 @@
+//*****************************************************************************
+//
+// usblib.h - Main header file for the USB Library.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBLIB_H__
+#define __USBLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// This is the maximum number of devices we can support when in host mode and
+// using a hub. By default, we support up to 4 devices (plus 1 internally for
+// the hub itself).
+//
+//*****************************************************************************
+#ifndef MAX_USB_DEVICES
+#define MAX_USB_DEVICES 5
+#endif
+
+//*****************************************************************************
+//
+// This is the maximum number of endpoints supported by the usblib.
+//
+//*****************************************************************************
+#ifndef USBLIB_NUM_EP
+#define USBLIB_NUM_EP 8 // Number of supported endpoints.
+#endif
+
+//*****************************************************************************
+//
+// The following macro allows compiler-independent syntax to be used to
+// define packed structures. A typical structure definition using these
+// macros will look similar to the following example:
+//
+// #ifdef ewarm
+// #pragma pack(1)
+// #endif
+//
+// typedef struct _PackedStructName
+// {
+// uint32_t ui32FirstField;
+// int8_t i8CharMember;
+// uint16_t ui16Short;
+// }
+// PACKED tPackedStructName;
+//
+// #ifdef ewarm
+// #pragma pack()
+// #endif
+//
+// The conditional blocks related to ewarm include the #pragma pack() lines
+// only if the IAR Embedded Workbench compiler is being used. Unfortunately,
+// it is not possible to emit a #pragma from within a macro definition so this
+// must be done explicitly.
+//
+//*****************************************************************************
+#if defined(ccs) || \
+ defined(codered) || \
+ defined(gcc) || \
+ defined(rvmdk) || \
+ defined(__ARMCC_VERSION) || \
+ defined(sourcerygxx)
+#define PACKED __attribute__ ((packed))
+#elif defined(ewarm)
+#define PACKED
+#else
+#error Unrecognized COMPILER!
+#endif
+//*****************************************************************************
+//
+// Assorted language IDs from the document "USB_LANGIDs.pdf" provided by the
+// USB Implementers' Forum (Version 1.0).
+//
+//*****************************************************************************
+#define USB_LANG_CHINESE_PRC 0x0804 // Chinese (PRC)
+#define USB_LANG_CHINESE_TAIWAN 0x0404 // Chinese (Taiwan)
+#define USB_LANG_EN_US 0x0409 // English (United States)
+#define USB_LANG_EN_UK 0x0809 // English (United Kingdom)
+#define USB_LANG_EN_AUS 0x0C09 // English (Australia)
+#define USB_LANG_EN_CA 0x1009 // English (Canada)
+#define USB_LANG_EN_NZ 0x1409 // English (New Zealand)
+#define USB_LANG_FRENCH 0x040C // French (Standard)
+#define USB_LANG_GERMAN 0x0407 // German (Standard)
+#define USB_LANG_HINDI 0x0439 // Hindi
+#define USB_LANG_ITALIAN 0x0410 // Italian (Standard)
+#define USB_LANG_JAPANESE 0x0411 // Japanese
+#define USB_LANG_KOREAN 0x0412 // Korean
+#define USB_LANG_ES_TRAD 0x040A // Spanish (Traditional)
+#define USB_LANG_ES_MODERN 0x0C0A // Spanish (Modern)
+#define USB_LANG_SWAHILI 0x0441 // Swahili (Kenya)
+#define USB_LANG_URDU_IN 0x0820 // Urdu (India)
+#define USB_LANG_URDU_PK 0x0420 // Urdu (Pakistan)
+
+//*****************************************************************************
+//
+//! \addtogroup usbchap9_src
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Note:
+//
+// Structure definitions which are derived directly from the USB specification
+// use field names from the specification. Since a somewhat different version
+// of Hungarian prefix notation is used from the standard, beware of making
+// assumptions about field sizes based on the field prefix when using
+// these structures. Of particular note is the difference in the meaning of
+// the 'i' prefix. In USB structures, this indicates a single byte index
+// whereas in other code, this is an integer or enumeration variable.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requires a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+// Definitions related to standard USB device requests (sections 9.3 & 9.4)
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The standard USB request header as defined in section 9.3 of the USB 2.0
+//! specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Determines the type and direction of the request.
+ //
+ uint8_t bmRequestType;
+
+ //
+ //! Identifies the specific request being made.
+ //
+ uint8_t bRequest;
+
+ //
+ //! Word-sized field that varies according to the request.
+ //
+ uint16_t wValue;
+
+ //
+ //! Word-sized field that varies according to the request; typically used
+ //! to pass an index or offset.
+ //
+ uint16_t wIndex;
+
+ //
+ //! The number of bytes to transfer if there is a data stage to the
+ //! request.
+ //
+ uint16_t wLength;
+
+}
+PACKED tUSBRequest;
+
+//*****************************************************************************
+//
+// The following defines are used with the bmRequestType member of tUSBRequest.
+//
+// Request types have 3 bit fields:
+// 4:0 - Is the recipient type.
+// 6:5 - Is the request type.
+// 7 - Is the direction of the request.
+//
+//*****************************************************************************
+#define USB_RTYPE_DIR_IN 0x80
+#define USB_RTYPE_DIR_OUT 0x00
+
+#define USB_RTYPE_TYPE_M 0x60
+#define USB_RTYPE_VENDOR 0x40
+#define USB_RTYPE_CLASS 0x20
+#define USB_RTYPE_STANDARD 0x00
+
+#define USB_RTYPE_RECIPIENT_M 0x1f
+#define USB_RTYPE_OTHER 0x03
+#define USB_RTYPE_ENDPOINT 0x02
+#define USB_RTYPE_INTERFACE 0x01
+#define USB_RTYPE_DEVICE 0x00
+
+//*****************************************************************************
+//
+// Standard USB requests IDs used in the bRequest field of tUSBRequest.
+//
+//*****************************************************************************
+#define USBREQ_GET_STATUS 0x00
+#define USBREQ_CLEAR_FEATURE 0x01
+#define USBREQ_SET_FEATURE 0x03
+#define USBREQ_SET_ADDRESS 0x05
+#define USBREQ_GET_DESCRIPTOR 0x06
+#define USBREQ_SET_DESCRIPTOR 0x07
+#define USBREQ_GET_CONFIG 0x08
+#define USBREQ_SET_CONFIG 0x09
+#define USBREQ_GET_INTERFACE 0x0a
+#define USBREQ_SET_INTERFACE 0x0b
+#define USBREQ_SYNC_FRAME 0x0c
+
+//*****************************************************************************
+//
+// Data returned from a USBREQ_GET_STATUS request to a device.
+//
+//*****************************************************************************
+#define USB_STATUS_SELF_PWR 0x0001 // Currently self powered.
+#define USB_STATUS_BUS_PWR 0x0000 // Currently bus-powered.
+#define USB_STATUS_PWR_M 0x0001 // Mask for power mode.
+#define USB_STATUS_REMOTE_WAKE 0x0002 // Remote wake-up is currently enabled.
+
+//*****************************************************************************
+//
+// Feature Selectors (tUSBRequest.wValue) passed on USBREQ_CLEAR_FEATURE and
+// USBREQ_SET_FEATURE.
+//
+//*****************************************************************************
+#define USB_FEATURE_EP_HALT 0x0000 // Endpoint halt feature.
+#define USB_FEATURE_REMOTE_WAKE 0x0001 // Remote wake feature, device only.
+#define USB_FEATURE_TEST_MODE 0x0002 // Test mode
+
+//*****************************************************************************
+//
+// Endpoint Selectors (tUSBRequest.wIndex) passed on USBREQ_CLEAR_FEATURE,
+// USBREQ_SET_FEATURE and USBREQ_GET_STATUS.
+//
+//*****************************************************************************
+#define USB_REQ_EP_NUM_M 0x007F
+#define USB_REQ_EP_DIR_M 0x0080
+#define USB_REQ_EP_DIR_IN 0x0080
+#define USB_REQ_EP_DIR_OUT 0x0000
+
+//*****************************************************************************
+//
+// Standard USB descriptor types. These values are passed in the upper bytes
+// of tUSBRequest.wValue on USBREQ_GET_DESCRIPTOR and also appear in the
+// bDescriptorType field of standard USB descriptors.
+//
+//*****************************************************************************
+#define USB_DTYPE_DEVICE 1
+#define USB_DTYPE_CONFIGURATION 2
+#define USB_DTYPE_STRING 3
+#define USB_DTYPE_INTERFACE 4
+#define USB_DTYPE_ENDPOINT 5
+#define USB_DTYPE_DEVICE_QUAL 6
+#define USB_DTYPE_OSPEED_CONF 7
+#define USB_DTYPE_INTERFACE_PWR 8
+#define USB_DTYPE_OTG 9
+#define USB_DTYPE_INTERFACE_ASC 11
+#define USB_DTYPE_CS_INTERFACE 36
+#define USB_DTYPE_HUB 41
+
+//*****************************************************************************
+//
+// Definitions related to USB descriptors (sections 9.5 & 9.6)
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure describes a generic descriptor header. These fields are to
+//! be found at the beginning of all valid USB descriptors.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor (including this length byte) expressed
+ //! in bytes.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type identifier of the descriptor whose information follows. For
+ //! standard descriptors, this field could contain, for example,
+ //! USB_DTYPE_DEVICE to identify a device descriptor or USB_DTYPE_ENDPOINT
+ //! to identify an endpoint descriptor.
+ //
+ uint8_t bDescriptorType;
+}
+PACKED tDescriptorHeader;
+
+//*****************************************************************************
+//
+//! This structure describes the USB device descriptor as defined in USB
+//! 2.0 specification section 9.6.1.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All device descriptors are
+ //! 18 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a device descriptor, this will be
+ //! USB_DTYPE_DEVICE (1).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The USB Specification Release Number in BCD format. For USB 2.0, this
+ //! will be 0x0200.
+ //
+ uint16_t bcdUSB;
+
+ //
+ //! The device class code.
+ //
+ uint8_t bDeviceClass;
+
+ //
+ //! The device subclass code. This value qualifies the value found in the
+ //! bDeviceClass field.
+ //
+ uint8_t bDeviceSubClass;
+
+ //
+ //! The device protocol code. This value is qualified by the values of
+ //! bDeviceClass and bDeviceSubClass.
+ //
+ uint8_t bDeviceProtocol;
+
+ //
+ //! The maximum packet size for endpoint zero. Valid values are 8, 16, 32
+ //! and 64.
+ //
+ uint8_t bMaxPacketSize0;
+
+ //
+ //! The device Vendor ID (VID) as assigned by the USB-IF.
+ //
+ uint16_t idVendor;
+
+ //
+ //! The device Product ID (PID) as assigned by the manufacturer.
+ //
+ uint16_t idProduct;
+
+ //
+ //! The device release number in BCD format.
+ //
+ uint16_t bcdDevice;
+
+ //
+ //! The index of a string descriptor describing the manufacturer.
+ //
+ uint8_t iManufacturer;
+
+ //
+ //! The index of a string descriptor describing the product.
+ //
+ uint8_t iProduct;
+
+ //
+ //! The index of a string descriptor describing the device's serial
+ //! number.
+ //
+ uint8_t iSerialNumber;
+
+ //
+ //! The number of possible configurations offered by the device. This
+ //! field indicates the number of distinct configuration descriptors that
+ //! the device offers.
+ //
+ uint8_t bNumConfigurations;
+}
+PACKED tDeviceDescriptor;
+
+//*****************************************************************************
+//
+// USB Device Class codes used in the tDeviceDescriptor.bDeviceClass field.
+// Definitions for the bDeviceSubClass and bDeviceProtocol fields are device
+// specific and can be found in the appropriate device class header files.
+//
+//*****************************************************************************
+#define USB_CLASS_DEVICE 0x00
+#define USB_CLASS_AUDIO 0x01
+#define USB_CLASS_CDC 0x02
+#define USB_CLASS_HID 0x03
+#define USB_CLASS_PHYSICAL 0x05
+#define USB_CLASS_IMAGE 0x06
+#define USB_CLASS_PRINTER 0x07
+#define USB_CLASS_MASS_STORAGE 0x08
+#define USB_CLASS_HUB 0x09
+#define USB_CLASS_CDC_DATA 0x0a
+#define USB_CLASS_SMART_CARD 0x0b
+#define USB_CLASS_SECURITY 0x0d
+#define USB_CLASS_VIDEO 0x0e
+#define USB_CLASS_HEALTHCARE 0x0f
+#define USB_CLASS_DIAG_DEVICE 0xdc
+#define USB_CLASS_WIRELESS 0xe0
+#define USB_CLASS_MISC 0xef
+#define USB_CLASS_APP_SPECIFIC 0xfe
+#define USB_CLASS_VEND_SPECIFIC 0xff
+#define USB_CLASS_EVENTS 0xffffffff
+
+//*****************************************************************************
+//
+// Generic values for undefined subclass and protocol.
+//
+//*****************************************************************************
+#define USB_SUBCLASS_UNDEFINED 0x00
+#define USB_PROTOCOL_UNDEFINED 0x00
+
+//*****************************************************************************
+//
+// The following are the miscellaneous subclass values.
+//
+//*****************************************************************************
+#define USB_MISC_SUBCLASS_SYNC 0x01
+#define USB_MISC_SUBCLASS_COMMON \
+ 0x02
+
+//*****************************************************************************
+//
+// These following are miscellaneous protocol values.
+//
+//*****************************************************************************
+#define USB_MISC_PROTOCOL_IAD 0x01
+
+//*****************************************************************************
+//
+// These following are hub protocol values.
+//
+//*****************************************************************************
+#define USB_HUB_PROTOCOL_FS 0x00
+#define USB_HUB_PROTOCOL_SINGLE 0x01
+#define USB_HUB_PROTOCOL_MULTI 0x02
+
+//*****************************************************************************
+//
+//! This structure describes the USB device qualifier descriptor as defined in
+//! the USB 2.0 specification, section 9.6.2.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All device qualifier
+ //! descriptors are 10 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a device descriptor, this will be
+ //! USB_DTYPE_DEVICE_QUAL (6).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The USB Specification Release Number in BCD format. For USB 2.0, this
+ //! will be 0x0200.
+ //
+ uint16_t bcdUSB;
+
+ //
+ //! The device class code.
+ //
+ uint8_t bDeviceClass;
+
+ //
+ //! The device subclass code. This value qualifies the value found in the
+ //! bDeviceClass field.
+ //
+ uint8_t bDeviceSubClass;
+
+ //
+ //! The device protocol code. This value is qualified by the values of
+ //! bDeviceClass and bDeviceSubClass.
+ //
+ uint8_t bDeviceProtocol;
+
+ //
+ //! The maximum packet size for endpoint zero when operating at a speed
+ //! other than high speed.
+ //
+ uint8_t bMaxPacketSize0;
+
+ //
+ //! The number of other-speed configurations supported.
+ //
+ uint8_t bNumConfigurations;
+
+ //
+ //! Reserved for future use. Must be set to zero.
+ //
+ uint8_t bReserved;
+}
+PACKED tDeviceQualifierDescriptor;
+
+//*****************************************************************************
+//
+//! This structure describes the USB configuration descriptor as defined in
+//! USB 2.0 specification section 9.6.3. This structure also applies to the
+//! USB other speed configuration descriptor defined in section 9.6.4.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All configuration descriptors
+ //! are 9 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a configuration descriptor, this will
+ //! be USB_DTYPE_CONFIGURATION (2).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The total length of data returned for this configuration. This
+ //! includes the combined length of all descriptors (configuration,
+ //! interface, endpoint and class- or vendor-specific) returned for this
+ //! configuration.
+ //
+ uint16_t wTotalLength;
+
+ //
+ //! The number of interface supported by this configuration.
+ //
+ uint8_t bNumInterfaces;
+
+ //
+ //! The value used as an argument to the SetConfiguration standard request
+ //! to select this configuration.
+ //
+ uint8_t bConfigurationValue;
+
+ //
+ //! The index of a string descriptor describing this configuration.
+ //
+ uint8_t iConfiguration;
+
+ //
+ //! Attributes of this configuration.
+ //
+ uint8_t bmAttributes;
+
+ //
+ //! The maximum power consumption of the USB device from the bus in this
+ //! configuration when the device is fully operational. This is expressed
+ //! in units of 2mA so, for example, 100 represents 200mA.
+ //
+ uint8_t bMaxPower;
+}
+PACKED tConfigDescriptor;
+
+//*****************************************************************************
+//
+// Flags used in constructing the value assigned to the field
+// tConfigDescriptor.bmAttributes. Note that bit 7 is reserved and must be set
+// to 1.
+//
+//*****************************************************************************
+#define USB_CONF_ATTR_PWR_M 0xC0
+
+#define USB_CONF_ATTR_SELF_PWR 0xC0
+#define USB_CONF_ATTR_BUS_PWR 0x80
+#define USB_CONF_ATTR_RWAKE 0xA0
+
+//*****************************************************************************
+//
+//! This structure describes the USB interface descriptor as defined in USB
+//! 2.0 specification section 9.6.5.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All interface descriptors
+ //! are 9 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an interface descriptor, this will
+ //! be USB_DTYPE_INTERFACE (4).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The number of this interface. This is a zero based index into the
+ //! array of concurrent interfaces supported by this configuration.
+ //
+ uint8_t bInterfaceNumber;
+
+ //
+ //! The value used to select this alternate setting for the interface
+ //! defined in bInterfaceNumber.
+ //
+ uint8_t bAlternateSetting;
+
+ //
+ //! The number of endpoints used by this interface (excluding endpoint
+ //! zero).
+ //
+ uint8_t bNumEndpoints;
+
+ //
+ //! The interface class code as assigned by the USB-IF.
+ //
+ uint8_t bInterfaceClass;
+
+ //
+ //! The interface subclass code as assigned by the USB-IF.
+ //
+ uint8_t bInterfaceSubClass;
+
+ //
+ //! The interface protocol code as assigned by the USB-IF.
+ //
+ uint8_t bInterfaceProtocol;
+
+ //
+ //! The index of a string descriptor describing this interface.
+ //
+ uint8_t iInterface;
+}
+PACKED tInterfaceDescriptor;
+
+//*****************************************************************************
+//
+//! This structure describes the USB endpoint descriptor as defined in USB
+//! 2.0 specification section 9.6.6.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All endpoint descriptors
+ //! are 7 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For an endpoint descriptor, this will
+ //! be USB_DTYPE_ENDPOINT (5).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The address of the endpoint. This field contains the endpoint number
+ //! ORed with flag USB_EP_DESC_OUT or USB_EP_DESC_IN to indicate the
+ //! endpoint direction.
+ //
+ uint8_t bEndpointAddress;
+
+ //
+ //! The endpoint transfer type, USB_EP_ATTR_CONTROL, USB_EP_ATTR_ISOC,
+ //! USB_EP_ATTR_BULK or USB_EP_ATTR_INT and, if isochronous, additional
+ //! flags indicating usage type and synchronization method.
+ //
+ uint8_t bmAttributes;
+
+ //
+ //! The maximum packet size this endpoint is capable of sending or
+ //! receiving when this configuration is selected. For high speed
+ //! isochronous or interrupt endpoints, bits 11 and 12 are used to
+ //! pass additional information.
+ //
+ uint16_t wMaxPacketSize;
+
+ //
+ //! The polling interval for data transfers expressed in frames or
+ //! micro frames depending upon the operating speed.
+ //
+ uint8_t bInterval;
+}
+PACKED tEndpointDescriptor;
+
+//*****************************************************************************
+//
+// Flags used in constructing the value assigned to the field
+// tEndpointDescriptor.bEndpointAddress.
+//
+//*****************************************************************************
+#define USB_EP_DESC_OUT 0x00
+#define USB_EP_DESC_IN 0x80
+#define USB_EP_DESC_NUM_M 0x0f
+
+//*****************************************************************************
+//
+// Mask used to extract the maximum packet size (in bytes) from the
+// wMaxPacketSize field of the endpoint descriptor.
+//
+//*****************************************************************************
+#define USB_EP_MAX_PACKET_COUNT_M \
+ 0x07FF
+
+//*****************************************************************************
+//
+// Endpoint attributes used in tEndpointDescriptor.bmAttributes.
+//
+//*****************************************************************************
+#define USB_EP_ATTR_CONTROL 0x00
+#define USB_EP_ATTR_ISOC 0x01
+#define USB_EP_ATTR_BULK 0x02
+#define USB_EP_ATTR_INT 0x03
+#define USB_EP_ATTR_TYPE_M 0x03
+
+#define USB_EP_ATTR_ISOC_M 0x0c
+#define USB_EP_ATTR_ISOC_NOSYNC 0x00
+#define USB_EP_ATTR_ISOC_ASYNC 0x04
+#define USB_EP_ATTR_ISOC_ADAPT 0x08
+#define USB_EP_ATTR_ISOC_SYNC 0x0c
+#define USB_EP_ATTR_USAGE_M 0x30
+#define USB_EP_ATTR_USAGE_DATA 0x00
+#define USB_EP_ATTR_USAGE_FEEDBACK \
+ 0x10
+#define USB_EP_ATTR_USAGE_IMPFEEDBACK \
+ 0x20
+
+//*****************************************************************************
+//
+//! This structure describes the USB string descriptor for index 0 as defined
+//! in USB 2.0 specification section 9.6.7. Note that the number of language
+//! IDs is variable and can be determined by examining bLength. The number of
+//! language IDs present in the descriptor is given by ((bLength - 2) / 2).
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. This value will vary
+ //! depending upon the number of language codes provided in the descriptor.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a string descriptor, this will be
+ //! USB_DTYPE_STRING (3).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The language code (LANGID) for the first supported language. Note that
+ //! this descriptor may support multiple languages, in which case, the
+ //! number of elements in the wLANGID array will increase and bLength will
+ //! be updated accordingly.
+ //
+ uint16_t wLANGID[1];
+}
+PACKED tString0Descriptor;
+
+//*****************************************************************************
+//
+//! This structure describes the USB string descriptor for all string indexes
+//! other than 0 as defined in USB 2.0 specification section 9.6.7.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. This value will be 2 greater
+ //! than the number of bytes comprising the UNICODE string that the
+ //! descriptor contains.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a string descriptor, this will be
+ //! USB_DTYPE_STRING (3).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The first byte of the UNICODE string. This string is not NULL
+ //! terminated. Its length (in bytes) can be computed by subtracting 2
+ //! from the value in the bLength field.
+ //
+ uint8_t bString;
+}
+PACKED tStringDescriptor;
+
+//*****************************************************************************
+//
+//! Write a 16-bit value to a USB descriptor block.
+//!
+//! \param ui16Value is the 16-bit value to write to the descriptor.
+//!
+//! This helper macro is used in descriptor definitions to write two-byte
+//! values. Since the configuration descriptor contains all interface and
+//! endpoint descriptors in a contiguous block of memory, these descriptors are
+//! typically defined using an array of bytes rather than as packed structures.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define USBShort(ui16Value) (ui16Value & 0xff), (ui16Value >> 8)
+
+//*****************************************************************************
+//
+//! Write a 24-bit value to a USB descriptor block.
+//!
+//! \param ui32Value is the 24-bit value that to write to the descriptor.
+//!
+//! This helper macro is used in descriptor definitions to write three-byte
+//! values. Since the configuration descriptor contains all interface and
+//! endpoint descriptors in a contiguous block of memory, these descriptors are
+//! typically defined using an array of bytes rather than as packed structures.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define USB3Byte(ui32Value) (ui32Value & 0xff), \
+ ((ui32Value >> 8) & 0xff), \
+ ((ui32Value >> 16) & 0xff)
+
+//*****************************************************************************
+//
+//! Write a 32-bit value to a USB descriptor block.
+//!
+//! \param ui32Value is the 32-bit value that to write to the descriptor.
+//!
+//! This helper macro is used in descriptor definitions to write four-byte
+//! values. Since the configuration descriptor contains all interface and
+//! endpoint descriptors in a contiguous block of memory, these descriptors are
+//! typically defined using an array of bytes rather than as packed structures.
+//!
+//! \return Not a function.
+//
+//*****************************************************************************
+#define USBLong(ui32Value) (ui32Value & 0xff), \
+ ((ui32Value >> 8) & 0xff), \
+ ((ui32Value >> 16) & 0xff), \
+ ((ui32Value >> 24) & 0xff)
+
+//*****************************************************************************
+//
+//! Traverse to the next USB descriptor in a block.
+//!
+//! \param ptr points to the first byte of a descriptor in a block of
+//! USB descriptors.
+//!
+//! This macro aids in traversing lists of descriptors by returning a pointer
+//! to the next descriptor in the list given a pointer to the current one.
+//!
+//! \return Returns a pointer to the next descriptor in the block following
+//! \e ptr.
+//!
+//*****************************************************************************
+#define NEXT_USB_DESCRIPTOR(ptr) \
+ (tDescriptorHeader *)(((uint8_t *)(ptr)) + \
+ *((uint8_t *)(ptr)))
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// Close the usbchap9_src Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup device_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Function prototype for any standard USB request.
+//
+//*****************************************************************************
+typedef void (* tStdRequest)(void *pvInstance, tUSBRequest *pUSBRequest);
+
+//*****************************************************************************
+//
+// Data callback for receiving data from an endpoint.
+//
+//*****************************************************************************
+typedef void (* tInfoCallback)(void *pvInstance, uint32_t ui32Info);
+
+//*****************************************************************************
+//
+// Callback made to indicate that an interface alternate setting change has
+// occurred.
+//
+//*****************************************************************************
+typedef void (* tInterfaceCallback)(void *pvInstance, uint8_t ui8InterfaceNum,
+ uint8_t ui8AlternateSetting);
+
+//*****************************************************************************
+//
+// Generic interrupt handler callbacks.
+//
+//*****************************************************************************
+typedef void (* tUSBIntHandler)(void *pvInstance);
+
+//*****************************************************************************
+//
+// Interrupt handler callbacks that have status information.
+//
+//*****************************************************************************
+typedef void (* tUSBEPIntHandler)(void *pvInstance, uint32_t ui32Status);
+
+//*****************************************************************************
+//
+//! Generic handler callbacks that are used when the callers needs to call into
+//! an instance of class.
+//
+//*****************************************************************************
+typedef void (* tUSBDeviceHandler)(void *pvInstance, uint32_t ui32Request,
+ void *pvRequestData);
+
+//*****************************************************************************
+//
+//! USB event handler functions used during enumeration and operation of the
+//! device stack.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This callback is made whenever the USB host requests a non-standard
+ //! descriptor from the device.
+ //
+ tStdRequest pfnGetDescriptor;
+
+ //
+ //! This callback is made whenever the USB host makes a non-standard
+ //! request.
+ //
+ tStdRequest pfnRequestHandler;
+
+ //
+ //! This callback is made in response to a SetInterface request from the
+ //! host.
+ //
+ tInterfaceCallback pfnInterfaceChange;
+
+ //
+ //! This callback is made in response to a SetConfiguration request from
+ //! the host.
+ //
+ tInfoCallback pfnConfigChange;
+
+ //
+ //! This callback is made when data has been received following to a call
+ //! to USBDCDRequestDataEP0.
+ //
+ tInfoCallback pfnDataReceived;
+
+ //
+ //! This callback is made when data has been transmitted following a call
+ //! to USBDCDSendDataEP0.
+ //
+ tInfoCallback pfnDataSent;
+
+ //
+ //! This callback is made when a USB reset is detected.
+ //
+ tUSBIntHandler pfnResetHandler;
+
+ //
+ //! This callback is made when the bus has been inactive long enough to
+ //! trigger a suspend condition.
+ //
+ tUSBIntHandler pfnSuspendHandler;
+
+ //
+ //! This is called when resume signaling is detected.
+ //
+ tUSBIntHandler pfnResumeHandler;
+
+ //
+ //! This callback is made when the device is disconnected from the USB bus.
+ //
+ tUSBIntHandler pfnDisconnectHandler;
+
+ //
+ //! This callback is made to inform the device of activity on all endpoints
+ //! other than endpoint zero.
+ //
+ tUSBEPIntHandler pfnEndpointHandler;
+
+ //
+ //! This generic handler is provided to allow requests based on
+ //! a given instance to be passed into a device. This is commonly used
+ //! by a top level composite device that is using multiple instances of
+ //! a class.
+ //
+ tUSBDeviceHandler pfnDeviceHandler;
+}
+tCustomHandlers;
+
+//*****************************************************************************
+//
+//! This structure defines a contiguous block of data which contains a group
+//! of descriptors that form part of a configuration descriptor for a device.
+//! It is assumed that a config section contains only whole descriptors. It is
+//! not valid to split a single descriptor across multiple sections.
+//!
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The number of bytes of descriptor data pointed to by pui8Data.
+ //
+ uint16_t ui16Size;
+
+ //
+ //! A pointer to a block of data containing an integral number of
+ //! USB descriptors which form part of a larger configuration descriptor.
+ //
+ const uint8_t *pui8Data;
+}
+tConfigSection;
+
+//*****************************************************************************
+//
+//! This is the top level structure defining a USB device configuration
+//! descriptor. A configuration descriptor contains a collection of device-
+//! specific descriptors in addition to the basic config, interface and
+//! endpoint descriptors. To allow flexibility in constructing the
+//! configuration, the descriptor is described in terms of a list of data
+//! blocks. The first block must contain the configuration descriptor itself
+//! and the following blocks are appended to this in order to produce the
+//! full descriptor sent to the host in response to a GetDescriptor request
+//! for the configuration descriptor.
+//!
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The number of sections comprising the full descriptor for this
+ //! configuration.
+ //
+ uint8_t ui8NumSections;
+
+ //
+ //! A pointer to an array of ui8NumSections section pointers which must
+ //! be concatenated to form the configuration descriptor.
+ //
+ const tConfigSection * const *psSections;
+}
+tConfigHeader;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup general_usblib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Predeclare of the DMA instance structure.
+//
+//*****************************************************************************
+typedef struct tUSBDMAInstance tUSBDMAInstance;
+
+//*****************************************************************************
+//
+// USB descriptor parsing functions found in usbdesc.c
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The USB_DESC_ANY label is used as a wild card in several of the descriptor
+//! parsing APIs to determine whether or not particular search criteria should
+//! be ignored.
+//
+//*****************************************************************************
+#define USB_DESC_ANY 0xFFFFFFFF
+
+extern uint32_t USBDescGetNum(tDescriptorHeader *psDesc, uint32_t ui32Size,
+ uint32_t ui32Type);
+extern tDescriptorHeader *USBDescGet(tDescriptorHeader *psDesc,
+ uint32_t ui32Size, uint32_t ui32Type,
+ uint32_t ui32Index);
+extern uint32_t
+ USBDescGetNumAlternateInterfaces(tConfigDescriptor *psConfig,
+ uint8_t ui8InterfaceNumber);
+extern tInterfaceDescriptor *USBDescGetInterface(tConfigDescriptor *psConfig,
+ uint32_t ui32Index,
+ uint32_t ui32AltCfg);
+extern tEndpointDescriptor *
+ USBDescGetInterfaceEndpoint(tInterfaceDescriptor *psInterface,
+ uint32_t ui32Index, uint32_t ui32Size);
+
+//*****************************************************************************
+//
+//! The operating mode required by the USB library client. This type is used
+//! by applications which wish to be able to switch between host and device
+//! modes by calling the USBStackModeSet() API.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! Operate in USB device mode with active monitoring of VBUS and the
+ //! ID pin must be pulled to a logic high value.
+ //
+ eUSBModeDevice = 0,
+
+ //
+ //! Operate in USB host mode with active monitoring of VBUS and the ID pin
+ //! must be pulled to a logic low value.
+ //
+ eUSBModeHost,
+
+ //
+ //! Operate as an On-The-Go device which requires both VBUS and ID to be
+ //! connected directly to the USB controller from the USB connector.
+ //
+ eUSBModeOTG,
+
+ //
+ //! A marker indicating that no USB mode has yet been set by the
+ //! application.
+ //
+ eUSBModeNone,
+
+ //
+ //! Force host mode so that the VBUS and ID pins are not used or monitored
+ //! by the USB controller.
+ //
+ eUSBModeForceHost,
+
+ //
+ //! Forcing device mode so that the VBUS and ID pins are not used or
+ //! monitored by the USB controller.
+ //
+ eUSBModeForceDevice,
+}
+tUSBMode;
+
+//*****************************************************************************
+//
+// A pointer to a USB mode callback function. This function is called by the
+// USB library to indicate to the application which operating mode it should
+// use, host or device.
+//
+//*****************************************************************************
+typedef void (*tUSBModeCallback)(uint32_t ui32Index, tUSBMode iMode);
+
+//*****************************************************************************
+//
+//! USB callback function.
+//!
+//! \param pvCBData is the callback pointer associated with the instance
+//! generating the callback. This is a value provided by the client during
+//! initialization of the instance making the callback.
+//! \param ui32Event is the identifier of the asynchronous event which is being
+//! notified to the client.
+//! \param ui32MsgParam is an event-specific parameter.
+//! \param pvMsgData is an event-specific data pointer.
+//!
+//! A function pointer provided to the USB layer by the application
+//! which will be called to notify it of all asynchronous events relating to
+//! data transmission or reception. This callback is used by device class
+//! drivers and host pipe functions.
+//!
+//! \return Returns an event-dependent value.
+//
+//*****************************************************************************
+typedef uint32_t (* tUSBCallback)(void *pvCBData, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData);
+
+//*****************************************************************************
+//
+// Error sources reported via USB_EVENT_ERROR.
+//
+//*****************************************************************************
+
+//
+//! The host received an invalid PID in a transaction.
+//
+#define USBERR_HOST_IN_PID_ERROR \
+ 0x01000000
+
+//
+//! The host did not receive a response from a device.
+//
+#define USBERR_HOST_IN_NOT_COMP 0x00100000
+
+//
+//! The host received a stall on an IN endpoint.
+//
+#define USBERR_HOST_IN_STALL 0x00400000
+
+//
+//! The host detected a CRC or bit-stuffing error (isochronous mode).
+//
+#define USBERR_HOST_IN_DATA_ERROR \
+ 0x00080000
+
+//
+//! The host received NAK on an IN endpoint for longer than the specified
+//! timeout period (interrupt, bulk and control modes).
+//
+#define USBERR_HOST_IN_NAK_TO 0x00080000
+
+//
+//! The host failed to communicate with a device via an IN endpoint.
+//
+#define USBERR_HOST_IN_ERROR 0x00040000
+
+//
+//! The host receive FIFO is full.
+//
+#define USBERR_HOST_IN_FIFO_FULL \
+ 0x00020000
+//
+//! The host received NAK on an OUT endpoint for longer than the specified
+//! timeout period (bulk, interrupt and control modes).
+//
+#define USBERR_HOST_OUT_NAK_TO 0x00000080
+
+//
+//! The host did not receive a response from a device (isochronous mode).
+//
+#define USBERR_HOST_OUT_NOT_COMP \
+ 0x00000080
+
+//
+//! The host received a stall on an OUT endpoint.
+//
+#define USBERR_HOST_OUT_STALL 0x00000020
+
+//
+//! The host failed to communicate with a device via an OUT endpoint.
+//
+#define USBERR_HOST_OUT_ERROR 0x00000004
+
+//
+//! The host received NAK on endpoint 0 for longer than the configured
+//! timeout.
+//
+#define USBERR_HOST_EP0_NAK_TO 0x00000080
+
+//
+//! The host failed to communicate with a device via an endpoint zero.
+//
+#define USBERR_HOST_EP0_ERROR 0x00000010
+
+//
+//! The device detected a CRC error in received data.
+//
+#define USBERR_DEV_RX_DATA_ERROR \
+ 0x00080000
+
+//
+//! The device was unable to receive a packet from the host since the receive
+//! FIFO is full.
+//
+#define USBERR_DEV_RX_OVERRUN 0x00040000
+
+//
+//! The device receive FIFO is full.
+//
+#define USBERR_DEV_RX_FIFO_FULL 0x00020000
+
+//*****************************************************************************
+//
+// Close the general_usblib_api Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_events
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure is used to return generic event based information to an
+//! application. The following events are currently supported:
+//! USB_EVENT_CONNECTED, USB_EVENT_DISCONNECTED, USB_EVENT_POWER_FAULT,
+//! USB_EVENT_POWER_FAULT, USB_EVENT_POWER_ENABLE,
+//! USB_EVENT_POWER_DISABLE and USB_EVENT_SOF.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! One of the USB_EVENT_ values.
+ //
+ uint32_t ui32Event;
+
+ //
+ //! The caller supplied instance value that is passed to event handlers.
+ //
+ uint32_t ui32Instance;
+}
+tEventInfo;
+
+//*****************************************************************************
+//
+// Base identifiers for groups of USB events. These are used by both the
+// device class drivers and host layer.
+//
+// USB_CLASS_EVENT_BASE is the lowest identifier that should be used for
+// a class-specific event. Individual event bases are defined for each
+// of the supported device class drivers. Events with IDs between
+// USB_EVENT_BASE and USB_CLASS_EVENT_BASE are reserved for stack use.
+//
+//*****************************************************************************
+#define USB_EVENT_BASE 0x0000
+#define USB_CLASS_EVENT_BASE 0x8000
+
+//*****************************************************************************
+//
+// Event base identifiers for the various device classes supported in host
+// and device modes.
+// The first 0x800 values of a range are reserved for the device specific
+// messages and the second 0x800 values of a range are used for the host
+// specific messages for a given class.
+//
+//*****************************************************************************
+#define USBD_CDC_EVENT_BASE (USB_CLASS_EVENT_BASE + 0)
+#define USBD_HID_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x1000)
+#define USBD_HID_KEYB_EVENT_BASE \
+ (USBD_HID_EVENT_BASE + 0x100)
+#define USBD_BULK_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x2000)
+#define USBD_MSC_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x3000)
+#define USBD_AUDIO_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x4000)
+#define USBD_DFU_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x5000)
+
+#define USBH_CDC_EVENT_BASE (USBD_CDC_EVENT_BASE + 0x800)
+#define USBH_HID_EVENT_BASE (USBD_HID_EVENT_BASE + 0x800)
+#define USBH_BULK_EVENT_BASE (USBD_BULK_EVENT_BASE + 0x800)
+#define USBH_MSC_EVENT_BASE (USBD_MSC_EVENT_BASE + 0x800)
+#define USBH_AUDIO_EVENT_BASE (USBD_AUDIO_EVENT_BASE + 0x800)
+
+//*****************************************************************************
+//
+// General events supported by device classes and host pipes.
+//
+//*****************************************************************************
+
+//
+//! The device is now attached to a USB host and ready to begin sending
+//! and receiving data (used by device classes only).
+//
+#define USB_EVENT_CONNECTED (USB_EVENT_BASE + 0)
+
+//
+//! The device has been disconnected from the USB host (used by device classes
+//! only).
+//!
+//! \note In device mode, the USB_EVENT_DISCONNECTED will not be reported if
+//! the MCU's PB1/USB0VBUS pin is connected to a fixed +5 Volts rather than
+//! directly to the VBUS pin on the USB connector.
+//
+#define USB_EVENT_DISCONNECTED (USB_EVENT_BASE + 1)
+
+//
+//! Data has been received and is in the buffer provided or is ready to be
+//! read from the FIFO. If the \e pvMsgData value is 0 then the
+//! \e ui32MsgParam value contains the amount of data in bytes ready to be read
+//! from the device. If the \e pvMsgData value is not 0 then \e pvMsgData is
+//! a pointer to the data that was read and \e ui32MsgParam is the number of
+//! valid bytes in the array pointed to by \e pvMsgData.
+//
+#define USB_EVENT_RX_AVAILABLE (USB_EVENT_BASE + 2)
+
+//
+//! This event is sent by a lower layer to inquire about the amount of
+//! unprocessed data buffered in the layers above. It is used in cases
+//! where a low level driver needs to ensure that all preceding data has
+//! been processed prior to performing some action or making some notification.
+//! Clients receiving this event should return the number of bytes of data
+//! that are unprocessed or 0 if no outstanding data remains.
+//
+#define USB_EVENT_DATA_REMAINING \
+ (USB_EVENT_BASE + 3)
+
+//
+//! This event is sent by a lower layer supporting DMA to request a buffer in
+//! which the next received packet may be stored. The \e ui32MsgValue
+//! parameter indicates the maximum size of packet that can be received in this
+//! channel and \e pvMsgData points to storage which should be written with the
+//! returned buffer pointer. The return value from the callback should be the
+//! size of the buffer allocated (which may be less than the maximum size
+//! passed in \e ui32MsgValue if the client knows that fewer bytes are expected
+//! to be received) or 0 if no buffer is being returned.
+//
+#define USB_EVENT_REQUEST_BUFFER \
+ (USB_EVENT_BASE + 4)
+
+//
+//! Data has been sent and acknowledged. If this event is received via the
+//! USB buffer callback, the \e ui32MsgValue parameter indicates the number of
+//! bytes from the transmit buffer that have been successfully transmitted
+//! and acknowledged.
+//
+#define USB_EVENT_TX_COMPLETE (USB_EVENT_BASE + 5)
+
+//
+//! An error has been reported on the channel or pipe. The \e ui32MsgValue
+//! parameter indicates the source(s) of the error and is the logical OR
+//! combination of "USBERR_" flags defined below.
+//
+#define USB_EVENT_ERROR (USB_EVENT_BASE + 6)
+
+//
+//! The bus has entered suspend state.
+//
+#define USB_EVENT_SUSPEND (USB_EVENT_BASE + 7)
+
+//
+//! The bus has left suspend state.
+//
+#define USB_EVENT_RESUME (USB_EVENT_BASE + 8)
+
+//
+//! A scheduler event has occurred.
+//
+#define USB_EVENT_SCHEDULER (USB_EVENT_BASE + 9)
+//
+//! A device or host has detected a stall condition.
+//
+#define USB_EVENT_STALL (USB_EVENT_BASE + 10)
+
+//
+//! The host detected a power fault condition.
+//
+#define USB_EVENT_POWER_FAULT (USB_EVENT_BASE + 11)
+
+//
+//! The controller has detected a A-Side cable and needs power applied This is
+//! only generated on OTG parts if automatic power control is disabled.
+//
+#define USB_EVENT_POWER_ENABLE (USB_EVENT_BASE + 12)
+
+//
+//! The controller needs power removed, This is only generated on OTG parts
+//! if automatic power control is disabled.
+//
+#define USB_EVENT_POWER_DISABLE (USB_EVENT_BASE + 13)
+
+//
+//! This define is used with a device class's pfnDeviceHandler handler function
+//! to indicate that the USB library has changed the interface number. This
+//! event is typically due to the class being included in a composite device.
+//!
+//! The \e pvInstance is a pointer to an instance of the device being accessed.
+//!
+//! The \e ui32Request is USB_EVENT_COMP_IFACE_CHANGE.
+//!
+//! The \e pvRequestData is a pointer to a two byte array where the first value
+//! is the old interface number and the second is the new interface number.
+//
+#define USB_EVENT_COMP_IFACE_CHANGE \
+ (USB_EVENT_BASE + 14)
+
+//
+//! This define is used with a device class's pfnDeviceHandler handler function
+//! to indicate that the USB library has changed the endpoint number. This
+//! event is typically due to the class being included in a composite device.
+//!
+//! The \e pvInstance is a pointer to an instance of the device being accessed.
+//!
+//! The \e ui32Request is USB_EVENT_COMP_EP_CHANGE.
+//!
+//! The \e pvRequestData is a pointer to a two byte array where the first value
+//! is the old endpoint number and the second is the new endpoint number. The
+//! endpoint numbers should be exactly as USB specification defines them and
+//! bit 7 set indicates an IN endpoint and bit 7 clear indicates an OUT
+//! endpoint.
+//
+#define USB_EVENT_COMP_EP_CHANGE \
+ (USB_EVENT_BASE + 15)
+
+//
+//! This define is used with a device class's pfnDeviceHandler handler function
+//! to indicate that the USB library has changed the string index number for a
+//! string. This event is typically due to the class being included in a
+//! composite device.
+//!
+//! The \e pvInstance is a pointer to an instance of the device being accessed.
+//!
+//! The \e ui32Request is USB_EVENT_COMP_STR_CHANGE.
+//!
+//! The \e pvRequestData is a pointer to a two byte array where the first value
+//! is the old string index and the second is the new string index.
+//
+#define USB_EVENT_COMP_STR_CHANGE \
+ (USB_EVENT_BASE + 16)
+
+//
+//! This define is used with a device class's pfnDeviceHandler handler function
+//! to indicate that the USB library has changed the configuration descriptor.
+//! This allows the class to make final adjustments to the configuration
+//! descriptor. This event is typically due to the class being included in a
+//! composite device.
+//!
+//! The \e pvInstance is a pointer to an instance of the device being accessed.
+//!
+//! The \e ui32Request is USB_EVENT_COMP_CONFIG.
+//!
+//! The \e pvRequestData is a pointer to the beginning of the configuration
+//! descriptor for the device instance.
+//
+#define USB_EVENT_COMP_CONFIG (USB_EVENT_BASE + 17)
+
+//
+//! An unknown device is now attached to a USB host. This value is only valid
+//! for the generic event handler and not other device handlers. It is
+//! useful for applications that want to know when an unknown device is
+//! connected and what the class is of the unknown device.
+//!
+//! The \e ui32Instance is the device instance for the unknown device.
+//
+#define USB_EVENT_UNKNOWN_CONNECTED \
+ (USB_EVENT_BASE + 18)
+
+//
+//! A start of frame event has occurred. This event is disabled by default
+//! and must be enabled via a call from the application to USBHCDEventEnable().
+//
+#define USB_EVENT_SOF (USB_EVENT_BASE + 19)
+
+//
+//! This event occurs when a device enters LPM sleep mode.
+//
+#define USB_EVENT_LPM_SLEEP (USB_EVENT_BASE + 20)
+
+//
+//! This event occurs when a device is resumed from LPM sleep mode.
+//
+#define USB_EVENT_LPM_RESUME (USB_EVENT_BASE + 21)
+
+//
+//! This event occurs when a device has responded with a NYET to an LPM request
+//! because LPM responses were disabled.
+//
+#define USB_EVENT_LPM_ERROR (USB_EVENT_BASE + 22)
+
+//*****************************************************************************
+//
+// Close the usblib_events Doxygen group.
+//! @}
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+//! \addtogroup usblib_buffer_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! A function pointer type which describes either a class driver packet read
+//! or packet write function (both have the same prototype) to the USB
+//! buffer object.
+//
+//*****************************************************************************
+typedef uint32_t (* tUSBPacketTransfer)(void *pvHandle, uint8_t *pi8Data,
+ uint32_t ui32Length, bool bLast);
+
+//*****************************************************************************
+//
+//! A function pointer type which describes either a class driver transmit
+//! or receive packet available function (both have the same prototype) to the
+//! USB buffer object.
+//!
+//! \param pvHandle is the handle of the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+typedef uint32_t (* tUSBPacketAvailable)(void *pvHandle);
+
+//*****************************************************************************
+//
+//! The number of bytes of workspace that each USB buffer object requires.
+//! This workspace memory is provided to the buffer on USBBufferInit() in
+//! the \e pvWorkspace field of the \e tUSBBuffer structure.
+//
+//*****************************************************************************
+#define USB_BUFFER_WORKSPACE_SIZE \
+ 24
+//*****************************************************************************
+//
+// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This feature setting enables or disables LPM support in the USB library in
+//! either host or device mode depending on if the USBHCDFeatureSet() or
+//! USBDCDFeatureSet() is called. If no action is taken the default behavior of
+//! USB library is to not support LPM transactions. The \e pvFeature value
+//! is a pointer to a 32-bit value containing the a logical OR of the following
+//! values:
+//!
+//! - \b USBLIB_FEATURE_LPM_EN is used to enable LPM support in host or device
+//! mode.
+//! - \b USBLIB_FEATURE_LPM_DIS(default) is used to disable LPM support in host
+//! or device mode.
+//! - \b USBLIB_FEATURE_LPM_RMT_WAKE is used to enable remote wake from an
+//! LPM suspended state.
+//!
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_LPM 0x00000001
+
+//*****************************************************************************
+//
+// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
+// for \b USBLIB_FEATURE_LPM feature requests.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_LPM_RMT_WAKE \
+ 0x00000002
+#define USBLIB_FEATURE_LPM_EN 0x00000001
+#define USBLIB_FEATURE_LPM_DIS 0x00000000
+
+//*****************************************************************************
+//
+//! This feature setting allows an application to inform the USB library of the
+//! current processor speed that is can use for internal timing when the frame
+//! counter is not yet running. The \e pvFeature is a pointer to a 32-bit
+//! value that holds the processor frequency in Hz.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_CPUCLK 0x00000002
+
+//*****************************************************************************
+//
+//! This feature setting allows an application to inform the USB library of the
+//! current USB PLL rate in cases where the USB library needs this information
+//! for internal configuration. If this feature is not set, then default rate
+//! for the USB PLL is 480MHz. The \e pvFeature is a pointer to an 32-bit
+//! value that holds the USB PLL speed in Hz. If the application needs to use
+//! an external USB clock the PLL value should be set to zero. This is used
+//! when connecting to an external USB phy which is providing the 60-MHz clock.
+//!
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_USBPLL 0x00000003
+
+//*****************************************************************************
+//!
+//! This feature setting allows an application to disable or configure and
+//! enable the ULPI features in the USB library. If this feature is not set,
+//! the default behavior is to not support ULPI operation. The \e pvFeature is
+//! a pointer to an 32-bit value that holds the USB ULPI configuration. The
+//! following are the valid settings for this feature:
+//!
+//! - USBLIB_FEATURE_ULPI_NONE disables all ULPI support.
+//! - USBLIB_FEATURE_ULPI_HS enable ULPI with high speed support.
+//! - USBLIB_FEATURE_ULPI_FS enable ULPI with full speed support.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_USBULPI 0x00000004
+
+//*****************************************************************************
+//
+// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
+// for \b USBLIB_FEATURE_USBULPI feature requests.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_ULPI_NONE \
+ 0x00000000
+#define USBLIB_FEATURE_ULPI_HS 0x00000010
+#define USBLIB_FEATURE_ULPI_FS 0x00000020
+
+//*****************************************************************************
+//
+//! This feature setting enables or disables various power settings in the USB
+//! library in either host or device mode depending on if the
+//! USBHCDFeatureSet() or USBDCDFeatureSet() is called. The \e pvFeature value
+//! is a pointer to a 32-bit value containing the a logical OR of the following
+//! values:
+//!
+//! - \b USBLIB_FEATURE_POWER_BUS - USB device mode is bus powered(default).
+//! - \b USBLIB_FEATURE_POWER_SELF - USB device mode is self powered.
+//! - \b USBLIB_FEATURE_REMOTE_WAKE - Enable USB remote wake feature.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_POWER 0x00000005
+
+//*****************************************************************************
+//
+// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
+// for \b USBLIB_FEATURE_POWER feature requests.
+//
+//*****************************************************************************
+#define USBLIB_FEATURE_POWER_SELF \
+ 0x00000001
+#define USBLIB_FEATURE_POWER_BUS \
+ 0x00000000
+#define USBLIB_FEATURE_REMOTE_WAKE \
+ 0x00000002
+
+//*****************************************************************************
+//
+// The structure used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
+// to set feature enables and resume timing parameter.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint32_t ui32HIRD;
+ uint32_t ui32Features;
+}
+tLPMFeature;
+
+//*****************************************************************************
+//
+//! The structure used by the application to initialize a buffer object that
+//! will provide buffered access to either a transmit or receive channel.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! This field sets the mode of the buffer. If true, the buffer
+ //! operates as a transmit buffer and supports calls to USBBufferWrite
+ //! by the client. If false, the buffer operates as a receive buffer
+ //! and supports calls to USBBufferRead.
+ //
+ bool bTransmitBuffer;
+
+ //
+ //! A pointer to the callback function which will be called to notify
+ //! the application of all asynchronous events related to the operation
+ //! of the buffer.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ //! A pointer that the buffer will pass back to the client in the
+ //! first parameter of all callbacks related to this instance.
+ //
+ void *pvCBData;
+
+ //
+ //! The function which should be called to transmit a packet of data
+ //! in transmit mode or receive a packet in receive mode.
+ //
+ tUSBPacketTransfer pfnTransfer;
+
+ //
+ //! The function which should be called to determine if the endpoint is
+ //! ready to accept a new packet for transmission in transmit mode or
+ //! to determine the size of the buffer required to read a packet in
+ //! receive mode.
+ //
+ tUSBPacketAvailable pfnAvailable;
+
+ //
+ //! The handle to pass to the low level function pointers
+ //! provided in the pfnTransfer and pfnAvailable members. For USB device
+ //! use, this is the psDevice parameter required by the relevant device
+ //! class driver APIs. For USB host use, this is the pipe identifier
+ //! returned by USBHCDPipeAlloc.
+ //
+ void *pvHandle;
+
+ //
+ //! A pointer to memory to be used as the ring buffer for this
+ //! instance.
+ //
+ uint8_t *pui8Buffer;
+
+ //
+ //! The size, in bytes, of the buffer pointed to by pi8Buffer.
+ //
+ uint32_t ui32BufferSize;
+
+ //
+ //! A pointer to USB_BUFFER_WORKSPACE_SIZE bytes of RAM that the buffer
+ //! object can use for workspace.
+ //
+ void *pvWorkspace;
+}
+tUSBBuffer;
+
+//*****************************************************************************
+//
+//! The structure used for encapsulating all the items associated with a
+//! ring buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The ring buffer size.
+ //
+ uint32_t ui32Size;
+
+ //
+ //! The ring buffer write index.
+ //
+ volatile uint32_t ui32WriteIndex;
+
+ //
+ //! The ring buffer read index.
+ //
+ volatile uint32_t ui32ReadIndex;
+
+ //
+ //! The ring buffer.
+ //
+ uint8_t *pui8Buf;
+}
+tUSBRingBufObject;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// USB buffer API function prototypes.
+//
+//*****************************************************************************
+extern const tUSBBuffer *USBBufferInit(const tUSBBuffer *psBuffer);
+extern void USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer,
+ bool bSendZLP);
+extern void USBBufferInfoGet(const tUSBBuffer *psBuffer,
+ tUSBRingBufObject *psRingBuf);
+extern void *USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData);
+extern uint32_t USBBufferWrite(const tUSBBuffer *psBuffer,
+ const uint8_t *pui8Data, uint32_t ui32Length);
+extern void USBBufferDataWritten(const tUSBBuffer *psBuffer,
+ uint32_t ui32Length);
+extern void USBBufferDataRemoved(const tUSBBuffer *psBuffer,
+ uint32_t ui32Length);
+extern void USBBufferFlush(const tUSBBuffer *psBuffer);
+extern uint32_t USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
+ uint32_t ui32Length);
+extern uint32_t USBBufferDataAvailable(const tUSBBuffer *psBuffer);
+extern uint32_t USBBufferSpaceAvailable(const tUSBBuffer *psBuffer);
+extern uint32_t USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
+ uint32_t ui32MsgValue, void *pvMsgData);
+extern bool USBRingBufFull(tUSBRingBufObject *psUSBRingBuf);
+extern bool USBRingBufEmpty(tUSBRingBufObject *psUSBRingBuf);
+extern void USBRingBufFlush(tUSBRingBufObject *psUSBRingBuf);
+extern uint32_t USBRingBufUsed(tUSBRingBufObject *psUSBRingBuf);
+extern uint32_t USBRingBufFree(tUSBRingBufObject *psUSBRingBuf);
+extern uint32_t USBRingBufContigUsed(tUSBRingBufObject *psUSBRingBuf);
+extern uint32_t USBRingBufContigFree(tUSBRingBufObject *psUSBRingBuf);
+extern uint32_t USBRingBufSize(tUSBRingBufObject *psUSBRingBuf);
+extern uint8_t USBRingBufReadOne(tUSBRingBufObject *psUSBRingBuf);
+extern void USBRingBufRead(tUSBRingBufObject *psUSBRingBuf,
+ uint8_t *pui8Data, uint32_t ui32Length);
+extern void USBRingBufWriteOne(tUSBRingBufObject *psUSBRingBuf,
+ uint8_t ui8Data);
+extern void USBRingBufWrite(tUSBRingBufObject *psUSBRingBuf,
+ const uint8_t *pui8Data, uint32_t ui32Length);
+extern void USBRingBufAdvanceWrite(tUSBRingBufObject *psUSBRingBuf,
+ uint32_t ui32NumBytes);
+extern void USBRingBufAdvanceRead(tUSBRingBufObject *psUSBRingBuf,
+ uint32_t ui32NumBytes);
+extern void USBRingBufInit(tUSBRingBufObject *psUSBRingBuf,
+ uint8_t *pui8Buf, uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Mode selection and dual mode interrupt steering functions.
+//
+//*****************************************************************************
+extern void USBStackModeSet(uint32_t ui32Index, tUSBMode iUSBMode,
+ tUSBModeCallback pfnCallback);
+extern void USBDualModeInit(uint32_t ui32Index);
+extern void USBDualModeTerm(uint32_t ui32Index);
+extern void USBOTGMain(uint32_t ui32MsTicks);
+extern void USBOTGPollRate(uint32_t ui32Index, uint32_t ui32PollRate);
+extern void USBOTGModeInit(uint32_t ui32Index, uint32_t ui32PollRate,
+ void *pHostData, uint32_t ui32HostDataSize);
+extern void USBOTGModeTerm(uint32_t ui32Index);
+extern void USB0OTGModeIntHandler(void);
+extern bool USBOTGFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature);
+extern void USB0DualModeIntHandler(void);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBLIB_H__
diff --git a/usblib/usblib.uvopt b/usblib/usblib.uvopt
new file mode 100644
index 0000000..0f71b15
--- /dev/null
+++ b/usblib/usblib.uvopt
@@ -0,0 +1,650 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<ProjectOpt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_opt.xsd">
+
+ <SchemaVersion>1.0</SchemaVersion>
+
+ <Header>### uVision Project, (C) Keil Software</Header>
+
+ <Extensions>
+ <cExt>*.c</cExt>
+ <aExt>*.s*; *.src; *.a*</aExt>
+ <oExt>*.obj</oExt>
+ <lExt>*.lib</lExt>
+ <tExt>*.txt; *.h; *.inc</tExt>
+ <pExt>*.plm</pExt>
+ <CppX>*.cpp</CppX>
+ </Extensions>
+
+ <DaveTm>
+ <dwLowDateTime>0</dwLowDateTime>
+ <dwHighDateTime>0</dwHighDateTime>
+ </DaveTm>
+
+ <Target>
+ <TargetName>usblib</TargetName>
+ <ToolsetNumber>0x4</ToolsetNumber>
+ <ToolsetName>ARM-ADS</ToolsetName>
+ <TargetOption>
+ <CLKADS>8000000</CLKADS>
+ <OPTTT>
+ <gFlags>1</gFlags>
+ <BeepAtEnd>1</BeepAtEnd>
+ <RunSim>1</RunSim>
+ <RunTarget>0</RunTarget>
+ </OPTTT>
+ <OPTHX>
+ <HexSelection>1</HexSelection>
+ <FlashByte>65535</FlashByte>
+ <HexRangeLowAddress>0</HexRangeLowAddress>
+ <HexRangeHighAddress>0</HexRangeHighAddress>
+ <HexOffset>0</HexOffset>
+ </OPTHX>
+ <OPTLEX>
+ <PageWidth>79</PageWidth>
+ <PageLength>66</PageLength>
+ <TabStop>8</TabStop>
+ <ListingPath>.\rvmdk\</ListingPath>
+ </OPTLEX>
+ <ListingPage>
+ <CreateCListing>1</CreateCListing>
+ <CreateAListing>1</CreateAListing>
+ <CreateLListing>1</CreateLListing>
+ <CreateIListing>0</CreateIListing>
+ <AsmCond>1</AsmCond>
+ <AsmSymb>1</AsmSymb>
+ <AsmXref>0</AsmXref>
+ <CCond>1</CCond>
+ <CCode>0</CCode>
+ <CListInc>0</CListInc>
+ <CSymb>0</CSymb>
+ <LinkerCodeListing>0</LinkerCodeListing>
+ </ListingPage>
+ <OPTXL>
+ <LMap>1</LMap>
+ <LComments>1</LComments>
+ <LGenerateSymbols>1</LGenerateSymbols>
+ <LLibSym>1</LLibSym>
+ <LLines>1</LLines>
+ <LLocSym>1</LLocSym>
+ <LPubSym>1</LPubSym>
+ <LXref>0</LXref>
+ <LExpSel>0</LExpSel>
+ </OPTXL>
+ <OPTFL>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <IsCurrentTarget>1</IsCurrentTarget>
+ </OPTFL>
+ <CpuCode>255</CpuCode>
+ <Books>
+ <Book>
+ <Number>0</Number>
+ <Title>Data Sheet</Title>
+ <Path>DATASHTS\Luminary\TM4C1230C3PM.PDF</Path>
+ </Book>
+ </Books>
+ <DllOpt>
+ <SimDllName>SARMCM3.DLL</SimDllName>
+ <SimDllArguments>-MPU</SimDllArguments>
+ <SimDlgDllName>DCM.DLL</SimDlgDllName>
+ <SimDlgDllArguments>-pCM4</SimDlgDllArguments>
+ <TargetDllName>SARMCM3.DLL</TargetDllName>
+ <TargetDllArguments>-MPU</TargetDllArguments>
+ <TargetDlgDllName>TCM.DLL</TargetDlgDllName>
+ <TargetDlgDllArguments>-pCM4</TargetDlgDllArguments>
+ </DllOpt>
+ <DebugOpt>
+ <uSim>1</uSim>
+ <uTrg>0</uTrg>
+ <sLdApp>1</sLdApp>
+ <sGomain>1</sGomain>
+ <sRbreak>1</sRbreak>
+ <sRwatch>1</sRwatch>
+ <sRmem>1</sRmem>
+ <sRfunc>1</sRfunc>
+ <sRbox>1</sRbox>
+ <tLdApp>1</tLdApp>
+ <tGomain>0</tGomain>
+ <tRbreak>1</tRbreak>
+ <tRwatch>1</tRwatch>
+ <tRmem>1</tRmem>
+ <tRfunc>0</tRfunc>
+ <tRbox>1</tRbox>
+ <sRunDeb>0</sRunDeb>
+ <sLrtime>0</sLrtime>
+ <nTsel>3</nTsel>
+ <sDll></sDll>
+ <sDllPa></sDllPa>
+ <sDlgDll></sDlgDll>
+ <sDlgPa></sDlgPa>
+ <sIfile></sIfile>
+ <tDll></tDll>
+ <tDllPa></tDllPa>
+ <tDlgDll></tDlgDll>
+ <tDlgPa></tDlgPa>
+ <tIfile></tIfile>
+ <pMon>BIN\lmidk-agdi.dll</pMon>
+ </DebugOpt>
+ <TargetDriverDllRegistry>
+ <SetRegEntry>
+ <Number>0</Number>
+ <Key>lmidk-agdi</Key>
+ <Name>-O4622 -S3 -FO29</Name>
+ </SetRegEntry>
+ </TargetDriverDllRegistry>
+ <DebugFlag>
+ <trace>0</trace>
+ <periodic>1</periodic>
+ <aLwin>0</aLwin>
+ <aCover>0</aCover>
+ <aSer1>0</aSer1>
+ <aSer2>0</aSer2>
+ <aPa>0</aPa>
+ <viewmode>0</viewmode>
+ <vrSel>0</vrSel>
+ <aSym>0</aSym>
+ <aTbox>0</aTbox>
+ <AscS1>0</AscS1>
+ <AscS2>0</AscS2>
+ <AscS3>0</AscS3>
+ <aSer3>0</aSer3>
+ <eProf>0</eProf>
+ <aLa>0</aLa>
+ <aPa1>0</aPa1>
+ <AscS4>0</AscS4>
+ <aSer4>0</aSer4>
+ <StkLoc>0</StkLoc>
+ <TrcWin>0</TrcWin>
+ <newCpu>0</newCpu>
+ <uProt>0</uProt>
+ </DebugFlag>
+ <LintExecutable></LintExecutable>
+ <LintConfigFile></LintConfigFile>
+ </TargetOption>
+ </Target>
+
+ <Group>
+ <GroupName>Source</GroupName>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <cbSel>0</cbSel>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>1</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbbuffer.c</PathWithFileName>
+ <FilenameWithoutPath>usbbuffer.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>2</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdaudio.c</PathWithFileName>
+ <FilenameWithoutPath>usbdaudio.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>3</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdbulk.c</PathWithFileName>
+ <FilenameWithoutPath>usbdbulk.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>4</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdcdc.c</PathWithFileName>
+ <FilenameWithoutPath>usbdcdc.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>5</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdcdesc.c</PathWithFileName>
+ <FilenameWithoutPath>usbdcdesc.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>6</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdcomp.c</PathWithFileName>
+ <FilenameWithoutPath>usbdcomp.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>7</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdconfig.c</PathWithFileName>
+ <FilenameWithoutPath>usbdconfig.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>8</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbddfu-rt.c</PathWithFileName>
+ <FilenameWithoutPath>usbddfu-rt.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>9</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdenum.c</PathWithFileName>
+ <FilenameWithoutPath>usbdenum.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>10</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbdesc.c</PathWithFileName>
+ <FilenameWithoutPath>usbdesc.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>11</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdhandler.c</PathWithFileName>
+ <FilenameWithoutPath>usbdhandler.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>12</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdhid.c</PathWithFileName>
+ <FilenameWithoutPath>usbdhid.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>13</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdhidgamepad.c</PathWithFileName>
+ <FilenameWithoutPath>usbdhidgamepad.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>14</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdhidkeyb.c</PathWithFileName>
+ <FilenameWithoutPath>usbdhidkeyb.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>15</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdhidmouse.c</PathWithFileName>
+ <FilenameWithoutPath>usbdhidmouse.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>16</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbdma.c</PathWithFileName>
+ <FilenameWithoutPath>usbdma.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>17</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\device\usbdmsc.c</PathWithFileName>
+ <FilenameWithoutPath>usbdmsc.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>18</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhaudio.c</PathWithFileName>
+ <FilenameWithoutPath>usbhaudio.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>19</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhhid.c</PathWithFileName>
+ <FilenameWithoutPath>usbhhid.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>20</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhhidkeyboard.c</PathWithFileName>
+ <FilenameWithoutPath>usbhhidkeyboard.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>21</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhhidmouse.c</PathWithFileName>
+ <FilenameWithoutPath>usbhhidmouse.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>22</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhhub.c</PathWithFileName>
+ <FilenameWithoutPath>usbhhub.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>23</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhmsc.c</PathWithFileName>
+ <FilenameWithoutPath>usbhmsc.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>24</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhostenum.c</PathWithFileName>
+ <FilenameWithoutPath>usbhostenum.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>25</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\host\usbhscsi.c</PathWithFileName>
+ <FilenameWithoutPath>usbhscsi.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>26</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbkeyboardmap.c</PathWithFileName>
+ <FilenameWithoutPath>usbkeyboardmap.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>27</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbmode.c</PathWithFileName>
+ <FilenameWithoutPath>usbmode.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>28</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbringbuf.c</PathWithFileName>
+ <FilenameWithoutPath>usbringbuf.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>29</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbtick.c</PathWithFileName>
+ <FilenameWithoutPath>usbtick.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>30</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\usbulpi.c</PathWithFileName>
+ <FilenameWithoutPath>usbulpi.c</FilenameWithoutPath>
+ </File>
+ </Group>
+
+ <Group>
+ <GroupName>Documentation</GroupName>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <cbSel>0</cbSel>
+ <File>
+ <GroupNumber>2</GroupNumber>
+ <FileNumber>31</FileNumber>
+ <FileType>5</FileType>
+ <tvExp>0</tvExp>
+ <Focus>1</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>1</TopLine>
+ <CurrentLine>1</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\readme.txt</PathWithFileName>
+ <FilenameWithoutPath>readme.txt</FilenameWithoutPath>
+ <WindowPosition>
+ <length>44</length>
+ <flags>0</flags>
+ <showCmd>1</showCmd>
+ <MinPosition>
+ <xPos>-1</xPos>
+ <yPos>-1</yPos>
+ </MinPosition>
+ <MaxPosition>
+ <xPos>-1</xPos>
+ <yPos>-1</yPos>
+ </MaxPosition>
+ <NormalPosition>
+ <Top>0</Top>
+ <Left>0</Left>
+ <Right>729</Right>
+ <Bottom>300</Bottom>
+ </NormalPosition>
+ </WindowPosition>
+ </File>
+ </Group>
+
+ <MDIGroups>
+ <Orientation>1</Orientation>
+ <ActiveMDIGroup>0</ActiveMDIGroup>
+ <MDIGroup>
+ <Size>100</Size>
+ <ActiveTab>0</ActiveTab>
+ <Documents>
+ <Doc>
+ <Name>.\readme.txt</Name>
+ <ColumnNumber>0</ColumnNumber>
+ <TopLine>1</TopLine>
+ <CurrentLine>1</CurrentLine>
+ </Doc>
+ </Documents>
+ </MDIGroup>
+ </MDIGroups>
+
+</ProjectOpt>
diff --git a/usblib/usblib.uvproj b/usblib/usblib.uvproj
new file mode 100644
index 0000000..e71fe93
--- /dev/null
+++ b/usblib/usblib.uvproj
@@ -0,0 +1,555 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
+
+ <SchemaVersion>1.1</SchemaVersion>
+
+ <Header>### uVision Project, (C) Keil Software</Header>
+
+ <Targets>
+ <Target>
+ <TargetName>usblib</TargetName>
+ <ToolsetNumber>0x4</ToolsetNumber>
+ <ToolsetName>ARM-ADS</ToolsetName>
+ <TargetOption>
+ <TargetCommonOption>
+ <Device>TM4C1230C3PM</Device>
+ <Vendor>Texas Instruments</Vendor>
+ <Cpu>IRAM(0x20000000-0x20002FFF) IROM(0-0x7FFF) CLOCK(8000000) CPUTYPE("Cortex-M4") FPU2</Cpu>
+ <FlashUtilSpec></FlashUtilSpec>
+ <StartupFile>"STARTUP\Luminary\Startup.s" ("Luminary Startup Code")</StartupFile>
+ <FlashDriverDll>UL2CM3(-O207 -S0 -C0 -FO7 -FD20000000 -FC800 -FN1 -FF0LM4F_32 -FS00 -FL08000)</FlashDriverDll>
+ <DeviceId>5919</DeviceId>
+ <RegisterFile>LM4Fxxxx.H</RegisterFile>
+ <MemoryEnv></MemoryEnv>
+ <Cmp></Cmp>
+ <Asm></Asm>
+ <Linker></Linker>
+ <OHString></OHString>
+ <InfinionOptionDll></InfinionOptionDll>
+ <SLE66CMisc></SLE66CMisc>
+ <SLE66AMisc></SLE66AMisc>
+ <SLE66LinkerMisc></SLE66LinkerMisc>
+ <SFDFile>SFD\Luminary\TM4C1230C3PM.SFR</SFDFile>
+ <UseEnv>0</UseEnv>
+ <BinPath></BinPath>
+ <IncludePath></IncludePath>
+ <LibPath></LibPath>
+ <RegisterFilePath>Luminary\</RegisterFilePath>
+ <DBRegisterFilePath>Luminary\</DBRegisterFilePath>
+ <TargetStatus>
+ <Error>0</Error>
+ <ExitCodeStop>0</ExitCodeStop>
+ <ButtonStop>0</ButtonStop>
+ <NotGenerated>0</NotGenerated>
+ <InvalidFlash>1</InvalidFlash>
+ </TargetStatus>
+ <OutputDirectory>.\rvmdk\</OutputDirectory>
+ <OutputName>usblib</OutputName>
+ <CreateExecutable>0</CreateExecutable>
+ <CreateLib>1</CreateLib>
+ <CreateHexFile>0</CreateHexFile>
+ <DebugInformation>1</DebugInformation>
+ <BrowseInformation>1</BrowseInformation>
+ <ListingPath>.\rvmdk\</ListingPath>
+ <HexFormatSelection>1</HexFormatSelection>
+ <Merge32K>0</Merge32K>
+ <CreateBatchFile>0</CreateBatchFile>
+ <BeforeCompile>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </BeforeCompile>
+ <BeforeMake>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </BeforeMake>
+ <AfterMake>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </AfterMake>
+ <SelectedForBatchBuild>0</SelectedForBatchBuild>
+ <SVCSIdString></SVCSIdString>
+ </TargetCommonOption>
+ <CommonProperty>
+ <UseCPPCompiler>0</UseCPPCompiler>
+ <RVCTCodeConst>0</RVCTCodeConst>
+ <RVCTZI>0</RVCTZI>
+ <RVCTOtherData>0</RVCTOtherData>
+ <ModuleSelection>0</ModuleSelection>
+ <IncludeInBuild>1</IncludeInBuild>
+ <AlwaysBuild>0</AlwaysBuild>
+ <GenerateAssemblyFile>0</GenerateAssemblyFile>
+ <AssembleAssemblyFile>0</AssembleAssemblyFile>
+ <PublicsOnly>0</PublicsOnly>
+ <StopOnExitCode>3</StopOnExitCode>
+ <CustomArgument></CustomArgument>
+ <IncludeLibraryModules></IncludeLibraryModules>
+ </CommonProperty>
+ <DllOption>
+ <SimDllName>SARMCM3.DLL</SimDllName>
+ <SimDllArguments>-MPU</SimDllArguments>
+ <SimDlgDll>DCM.DLL</SimDlgDll>
+ <SimDlgDllArguments>-pCM4</SimDlgDllArguments>
+ <TargetDllName>SARMCM3.DLL</TargetDllName>
+ <TargetDllArguments>-MPU</TargetDllArguments>
+ <TargetDlgDll>TCM.DLL</TargetDlgDll>
+ <TargetDlgDllArguments>-pCM4</TargetDlgDllArguments>
+ </DllOption>
+ <DebugOption>
+ <OPTHX>
+ <HexSelection>1</HexSelection>
+ <HexRangeLowAddress>0</HexRangeLowAddress>
+ <HexRangeHighAddress>0</HexRangeHighAddress>
+ <HexOffset>0</HexOffset>
+ <Oh166RecLen>16</Oh166RecLen>
+ </OPTHX>
+ <Simulator>
+ <UseSimulator>1</UseSimulator>
+ <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+ <RunToMain>1</RunToMain>
+ <RestoreBreakpoints>1</RestoreBreakpoints>
+ <RestoreWatchpoints>1</RestoreWatchpoints>
+ <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+ <RestoreFunctions>1</RestoreFunctions>
+ <RestoreToolbox>1</RestoreToolbox>
+ <LimitSpeedToRealTime>0</LimitSpeedToRealTime>
+ </Simulator>
+ <Target>
+ <UseTarget>0</UseTarget>
+ <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+ <RunToMain>0</RunToMain>
+ <RestoreBreakpoints>1</RestoreBreakpoints>
+ <RestoreWatchpoints>1</RestoreWatchpoints>
+ <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+ <RestoreFunctions>0</RestoreFunctions>
+ <RestoreToolbox>1</RestoreToolbox>
+ </Target>
+ <RunDebugAfterBuild>0</RunDebugAfterBuild>
+ <TargetSelection>3</TargetSelection>
+ <SimDlls>
+ <CpuDll></CpuDll>
+ <CpuDllArguments></CpuDllArguments>
+ <PeripheralDll></PeripheralDll>
+ <PeripheralDllArguments></PeripheralDllArguments>
+ <InitializationFile></InitializationFile>
+ </SimDlls>
+ <TargetDlls>
+ <CpuDll></CpuDll>
+ <CpuDllArguments></CpuDllArguments>
+ <PeripheralDll></PeripheralDll>
+ <PeripheralDllArguments></PeripheralDllArguments>
+ <InitializationFile></InitializationFile>
+ <Driver>BIN\lmidk-agdi.dll</Driver>
+ </TargetDlls>
+ </DebugOption>
+ <Utilities>
+ <Flash1>
+ <UseTargetDll>1</UseTargetDll>
+ <UseExternalTool>0</UseExternalTool>
+ <RunIndependent>0</RunIndependent>
+ <UpdateFlashBeforeDebugging>0</UpdateFlashBeforeDebugging>
+ <Capability>1</Capability>
+ <DriverSelection>4097</DriverSelection>
+ </Flash1>
+ <Flash2>BIN\lmidk-agdi.dll</Flash2>
+ <Flash3></Flash3>
+ <Flash4></Flash4>
+ </Utilities>
+ <TargetArmAds>
+ <ArmAdsMisc>
+ <GenerateListings>0</GenerateListings>
+ <asHll>1</asHll>
+ <asAsm>1</asAsm>
+ <asMacX>1</asMacX>
+ <asSyms>1</asSyms>
+ <asFals>1</asFals>
+ <asDbgD>1</asDbgD>
+ <asForm>1</asForm>
+ <ldLst>0</ldLst>
+ <ldmm>1</ldmm>
+ <ldXref>1</ldXref>
+ <BigEnd>0</BigEnd>
+ <AdsALst>0</AdsALst>
+ <AdsACrf>0</AdsACrf>
+ <AdsANop>0</AdsANop>
+ <AdsANot>0</AdsANot>
+ <AdsLLst>0</AdsLLst>
+ <AdsLmap>0</AdsLmap>
+ <AdsLcgr>0</AdsLcgr>
+ <AdsLsym>0</AdsLsym>
+ <AdsLszi>0</AdsLszi>
+ <AdsLtoi>0</AdsLtoi>
+ <AdsLsun>0</AdsLsun>
+ <AdsLven>0</AdsLven>
+ <AdsLsxf>0</AdsLsxf>
+ <RvctClst>0</RvctClst>
+ <GenPPlst>0</GenPPlst>
+ <AdsCpuType>"Cortex-M4"</AdsCpuType>
+ <RvctDeviceName></RvctDeviceName>
+ <mOS>0</mOS>
+ <uocRom>0</uocRom>
+ <uocRam>0</uocRam>
+ <hadIROM>1</hadIROM>
+ <hadIRAM>1</hadIRAM>
+ <hadXRAM>0</hadXRAM>
+ <uocXRam>0</uocXRam>
+ <RvdsVP>2</RvdsVP>
+ <hadIRAM2>0</hadIRAM2>
+ <hadIROM2>0</hadIROM2>
+ <StupSel>8</StupSel>
+ <useUlib>1</useUlib>
+ <EndSel>0</EndSel>
+ <uLtcg>0</uLtcg>
+ <RoSelD>3</RoSelD>
+ <RwSelD>3</RwSelD>
+ <CodeSel>0</CodeSel>
+ <OptFeed>0</OptFeed>
+ <NoZi1>0</NoZi1>
+ <NoZi2>0</NoZi2>
+ <NoZi3>0</NoZi3>
+ <NoZi4>0</NoZi4>
+ <NoZi5>0</NoZi5>
+ <Ro1Chk>0</Ro1Chk>
+ <Ro2Chk>0</Ro2Chk>
+ <Ro3Chk>0</Ro3Chk>
+ <Ir1Chk>1</Ir1Chk>
+ <Ir2Chk>0</Ir2Chk>
+ <Ra1Chk>0</Ra1Chk>
+ <Ra2Chk>0</Ra2Chk>
+ <Ra3Chk>0</Ra3Chk>
+ <Im1Chk>1</Im1Chk>
+ <Im2Chk>0</Im2Chk>
+ <OnChipMemories>
+ <Ocm1>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm1>
+ <Ocm2>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm2>
+ <Ocm3>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm3>
+ <Ocm4>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm4>
+ <Ocm5>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm5>
+ <Ocm6>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm6>
+ <IRAM>
+ <Type>0</Type>
+ <StartAddress>0x20000000</StartAddress>
+ <Size>0x3000</Size>
+ </IRAM>
+ <IROM>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x8000</Size>
+ </IROM>
+ <XRAM>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </XRAM>
+ <OCR_RVCT1>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT1>
+ <OCR_RVCT2>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT2>
+ <OCR_RVCT3>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT3>
+ <OCR_RVCT4>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x8000</Size>
+ </OCR_RVCT4>
+ <OCR_RVCT5>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT5>
+ <OCR_RVCT6>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT6>
+ <OCR_RVCT7>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT7>
+ <OCR_RVCT8>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT8>
+ <OCR_RVCT9>
+ <Type>0</Type>
+ <StartAddress>0x20000000</StartAddress>
+ <Size>0x3000</Size>
+ </OCR_RVCT9>
+ <OCR_RVCT10>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT10>
+ </OnChipMemories>
+ <RvctStartVector></RvctStartVector>
+ </ArmAdsMisc>
+ <Cads>
+ <interw>0</interw>
+ <Optim>3</Optim>
+ <oTime>1</oTime>
+ <SplitLS>0</SplitLS>
+ <OneElfS>1</OneElfS>
+ <Strict>0</Strict>
+ <EnumInt>0</EnumInt>
+ <PlainCh>0</PlainCh>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <wLevel>2</wLevel>
+ <uThumb>0</uThumb>
+ <VariousControls>
+ <MiscControls>--c99</MiscControls>
+ <Define>rvmdk </Define>
+ <Undefine></Undefine>
+ <IncludePath>..;</IncludePath>
+ </VariousControls>
+ </Cads>
+ <Aads>
+ <interw>1</interw>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <thumb>0</thumb>
+ <SplitLS>0</SplitLS>
+ <SwStkChk>0</SwStkChk>
+ <NoWarn>0</NoWarn>
+ <VariousControls>
+ <MiscControls></MiscControls>
+ <Define></Define>
+ <Undefine></Undefine>
+ <IncludePath></IncludePath>
+ </VariousControls>
+ </Aads>
+ <LDads>
+ <umfTarg>0</umfTarg>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <noStLib>0</noStLib>
+ <RepFail>1</RepFail>
+ <useFile>0</useFile>
+ <TextAddressRange>0x00000000</TextAddressRange>
+ <DataAddressRange>0x20000000</DataAddressRange>
+ <ScatterFile></ScatterFile>
+ <IncludeLibs></IncludeLibs>
+ <IncludeLibsPath></IncludeLibsPath>
+ <Misc></Misc>
+ <LinkerInputFile></LinkerInputFile>
+ <DisabledWarnings></DisabledWarnings>
+ </LDads>
+ </TargetArmAds>
+ </TargetOption>
+ <Groups>
+ <Group>
+ <GroupName>Source</GroupName>
+ <Files>
+ <File>
+ <FileName>usbbuffer.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbbuffer.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdaudio.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdaudio.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdbulk.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdbulk.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdcdc.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdcdc.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdcdesc.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdcdesc.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdcomp.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdcomp.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdconfig.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdconfig.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbddfu-rt.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbddfu-rt.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdenum.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdenum.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdesc.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbdesc.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdhandler.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdhandler.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdhid.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdhid.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdhidgamepad.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdhidgamepad.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdhidkeyb.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdhidkeyb.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdhidmouse.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdhidmouse.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdma.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbdma.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbdmsc.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\device\usbdmsc.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhaudio.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhaudio.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhhid.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhhid.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhhidkeyboard.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhhidkeyboard.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhhidmouse.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhhidmouse.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhhub.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhhub.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhmsc.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhmsc.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhostenum.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhostenum.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbhscsi.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\host\usbhscsi.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbkeyboardmap.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbkeyboardmap.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbmode.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbmode.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbringbuf.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbringbuf.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbtick.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbtick.c</FilePath>
+ </File>
+ <File>
+ <FileName>usbulpi.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\usbulpi.c</FilePath>
+ </File>
+ </Files>
+ </Group>
+ <Group>
+ <GroupName>Documentation</GroupName>
+ <Files>
+ <File>
+ <FileName>readme.txt</FileName>
+ <FileType>5</FileType>
+ <FilePath>.\readme.txt</FilePath>
+ </File>
+ </Files>
+ </Group>
+ </Groups>
+ </Target>
+ </Targets>
+
+</Project>
diff --git a/usblib/usblibpriv.h b/usblib/usblibpriv.h
new file mode 100644
index 0000000..51359f7
--- /dev/null
+++ b/usblib/usblibpriv.h
@@ -0,0 +1,529 @@
+//*****************************************************************************
+//
+// usblibpriv.h - Private header file used to share internal variables and
+// function prototypes between the various modules in the USB
+// library. This header MUST NOT be used by application code.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBLIBPRIV_H__
+#define __USBLIBPRIV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_dma_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Internal interrupt handlers called from the main vectors in device and
+// host mode.
+//
+//*****************************************************************************
+extern void USBDeviceIntHandlerInternal(uint32_t ui32Index,
+ uint32_t ui32Status);
+extern void USBHostIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status);
+
+//*****************************************************************************
+//
+// The maximum number of tick handlers that can be registered in a system.
+//
+//*****************************************************************************
+#define MAX_USB_TICK_HANDLERS 6
+
+//*****************************************************************************
+//
+// This value defines the number of SOF ticks that must pass before a call
+// is made to InternalUSBStartOfFrameTick. The value 5 ensures that the
+// function is called every 5 milliseconds assuming that SOF interrupts are
+// enabled and SOF is present.
+//
+//*****************************************************************************
+#define USB_SOF_TICK_DIVIDE 5
+
+//*****************************************************************************
+//
+// Tick handler function pointer type.
+//
+//*****************************************************************************
+typedef void(* tUSBTickHandler)(void *pvInstance, uint32_t ui32TicksmS);
+
+//*****************************************************************************
+//
+// Internal functions use to initialize the tick handler and register tick
+// callbacks.
+//
+//*****************************************************************************
+extern void InternalUSBTickInit(void);
+extern void InternalUSBTickReset(void);
+extern int32_t InternalUSBRegisterTickHandler(tUSBTickHandler pfnHandler,
+ void *pvInstance);
+extern void InternalUSBStartOfFrameTick(uint32_t ui32TicksmS);
+extern void InternalUSBHCDSendEvent(uint32_t ui32Index, tEventInfo *psEvent,
+ uint32_t ui32EvFlag);
+
+//*****************************************************************************
+//
+// g_ui32CurrentUSBTick holds the elapsed time in milliseconds since the
+// tick module was first initialized based on calls to the function
+// InternalUSBStartOfFrameTick. The granularity is USB_SOF_TICK_DIVIDE
+// milliseconds.
+//
+//*****************************************************************************
+extern uint32_t g_ui32CurrentUSBTick;
+
+//*****************************************************************************
+//
+// g_ui32USBSOFCount is a global counter for Start of Frame interrupts. It is
+// incremented by the low level device- or host-mode interrupt handlers.
+//
+//*****************************************************************************
+extern uint32_t g_ui32USBSOFCount;
+
+//*****************************************************************************
+//
+// InternalUSBGetTime is a macro which will return the system time in
+// milliseconds as calculated based on calls to the function
+// InternalUSBStartOfFrameTick. The granularity is USB_SOF_TICK_DIVIDE
+// milliseconds.
+//
+// Currently, this merely returns the value of a global variable.
+//
+//*****************************************************************************
+#define InternalUSBGetTime() g_ui32CurrentUSBTick
+
+//*****************************************************************************
+//
+// Macros to convert between USB controller base address and an index. These
+// are currently trivial but are included to allow for the possibility of
+// supporting more than one controller in the future.
+//
+//*****************************************************************************
+#define USBBaseToIndex(BaseAddr)(0)
+#define USBIndexToBase(Index) (USB0_BASE)
+
+//
+// Maximum number of channels for Type 0 USB controllers.
+//
+#define USB_MAX_DMA_CHANNELS_0 6
+
+//
+// Maximum number of channels for all other USB controllers.
+//
+#define USB_MAX_DMA_CHANNELS 8
+
+//*****************************************************************************
+//
+// Values returned by the USBLibDMAChannelStatus() function.
+//
+//*****************************************************************************
+#define USBLIBSTATUS_DMA_IDLE 0x00000000
+#define USBLIBSTATUS_DMA_COMPLETE \
+ 0x00000001
+#define USBLIBSTATUS_DMA_ERROR 0x00000002
+#define USBLIBSTATUS_DMA_PENDING \
+ 0x00000004
+
+//*****************************************************************************
+//
+// DMA endpoint types used with the USBLibDMAChannelAllocate() function.
+//
+//*****************************************************************************
+#define USB_DMA_EP_RX 0x00000080
+#define USB_DMA_EP_TX 0x00000000
+#define USB_DMA_EP_HOST 0x00000040
+#define USB_DMA_EP_DEVICE 0x00000000
+#define USB_DMA_EP_TYPE_CTRL 0x00000000
+#define USB_DMA_EP_TYPE_ISOC 0x00000001
+#define USB_DMA_EP_TYPE_BULK 0x00000002
+#define USB_DMA_EP_TYPE_INT 0x00000003
+#define USB_DMA_EP_TYPE_M 0x00000003
+
+//*****************************************************************************
+//
+// This is the internal instance data for the DMA functions and should not
+// be modified outside the usbdma.c file.
+//
+//*****************************************************************************
+struct tUSBDMAInstance
+{
+ uint32_t ui32Base;
+
+ uint32_t ui32IntNum;
+
+ uint32_t pui32Config[USB_MAX_DMA_CHANNELS];
+
+ uint32_t pui32MaxPacketSize[USB_MAX_DMA_CHANNELS];
+
+ uint32_t *ppui32Data[USB_MAX_DMA_CHANNELS];
+
+ uint32_t pui32Count[USB_MAX_DMA_CHANNELS];
+
+ uint8_t pui8Endpoint[USB_MAX_DMA_CHANNELS];
+
+ uint32_t pui32EPDMAMode0[USB_MAX_DMA_CHANNELS];
+
+ uint32_t pui32EPDMAMode1[USB_MAX_DMA_CHANNELS];
+
+ uint32_t ui32Pending;
+
+ uint32_t ui32Complete;
+
+ void (* pfnArbSizeSet)(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
+ uint32_t ui32ArbSize);
+ uint32_t (* pfnChannelAllocate)(tUSBDMAInstance *psUSBDMAInst,
+ uint8_t ui8Endpoint,
+ uint32_t ui32MaxPacketSize,
+ uint32_t ui32Config);
+ void (* pfnChannelEnable)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+ void (* pfnChannelDisable)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+ void (* pfnChannelRelease)(tUSBDMAInstance *psUSBDMAInst,
+ uint8_t ui8Endpoint);
+ uint32_t (* pfnChannelStatus)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+ void (* pfnChannelIntDisable)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+ void (* pfnChannelIntEnable)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+ void (* pfnIntHandler)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Status);
+ uint32_t (* pfnIntStatus)(tUSBDMAInstance *psUSBDMAInst);
+ void (* pfnIntStatusClear)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Status);
+ uint32_t (* pfnStatus)(tUSBDMAInstance *psUSBDMAInst);
+ uint32_t (* pfnTransfer)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel, void *pvBuffer,
+ uint32_t ui32Size);
+ void (* pfnUnitSizeSet)(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel,
+ uint32_t ui32BitSize);
+};
+
+//*****************************************************************************
+//
+// These are the USB libraries DMA functions.
+//
+//*****************************************************************************
+extern tUSBDMAInstance * USBLibDMAInit(uint32_t ui32Index);
+extern void * USBLibDMAAddrGet(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+extern uint32_t USBLibDMASizeGet(tUSBDMAInstance *psUSBDMAInst,
+ uint32_t ui32Channel);
+
+//*****************************************************************************
+//
+//! This function returns the current DMA status for a given DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel number used to retrieve the DMA
+//! status.
+//!
+//! This function returns the current status of a DMA transfer on a given
+//! DMA channel. The DMA channel is specified by the \e ui32Channel parameter.
+//!
+//! \return This function returns one of the \b USBLIBSTATUS_DMA_* values.
+//
+//*****************************************************************************
+#define USBLibDMAChannelStatus(psUSBDMAInst, ui32Channel) \
+ psUSBDMAInst->pfnChannelStatus(psUSBDMAInst, ui32Channel)
+
+//*****************************************************************************
+//
+//! This function is used to return any global status information for USB DMA.
+//!
+//! \param psUSBDMAInst is a generic instance pointer that can be used to
+//! distinguish between different hardware instances.
+//!
+//! This function performs returns the global status for the USB DMA
+//! interface.
+//!
+//! \return Always returns 0.
+//
+//*****************************************************************************
+#define USBLibDMAStatus(psUSBDMAInst) psUSBDMAInst->pfnStatus(psUSBDMAInst)
+
+//*****************************************************************************
+//
+//! This function returns the current DMA interrupt status.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//!
+//! This function returns the interrupt status for all DMA channels. The value
+//! returned is a per channel interrupt mapping with the DMA channels mapped
+//! into bits 0-31 by channel number with channel 1 starting at bit 0.
+//!
+//! \note This function does not return an endpoint interrupt status, but the
+//! interrupt status for the DMA interface used with the USB controller.
+//!
+//! \return This function returns the pending DMA interrupts.
+//
+//*****************************************************************************
+#define USBLibDMAIntStatus(psUSBDMAInst) \
+ psUSBDMAInst->pfnIntStatus(psUSBDMAInst)
+
+//*****************************************************************************
+//
+//! This function clears the requested DMA interrupt status.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Status contains the interrupts to clear.
+//!
+//! This function clears the current DMA interrupt status for the
+//! controller specified by the \e ui32Instance parameter. The \e ui32Status
+//! value has the same format as the value returned from the
+//! USBLibDMAIntStatus() function which is a per channel interrupt mapping.
+//! The DMA channels are mapped into bits 0-31 by channel number with channel 1
+//!starting at bit 0.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAIntStatusClear(psUSBDMAInst, ui32Status) \
+ psUSBDMAInst->pfnIntStatusClear(psUSBDMAInst, ui32Status)
+
+//*****************************************************************************
+//
+//! This function enables DMA for a given channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel to enable.
+//!
+//! This function enables DMA on the channel number passed in the
+//! \e ui32Channel parameter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAChannelEnable(psUSBDMAInst, ui32Channel) \
+ psUSBDMAInst->pfnChannelEnable(psUSBDMAInst, ui32Channel)
+
+//*****************************************************************************
+//
+//! This function disables DMA for a given DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel to disable.
+//!
+//! This function disables DMA on the channel number passed in the
+//!\e ui32Channel parameter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAChannelDisable(psUSBDMAInst, ui32Channel) \
+ psUSBDMAInst->pfnChannelDisable(psUSBDMAInst, ui32Channel)
+
+//*****************************************************************************
+//
+//! This function is configures a USB transfer on a given DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel to use.
+//! \param pvBuffer is a pointer to the buffer to use for the transfer.
+//! \param ui32Size is the size of the data to be transferred in bytes.
+//!
+//! This function is called to configure a transfer using the USB
+//! controller depending on the parameters. The \e ui32Channel parameter
+//! holds the channel number to use for this transfer which must have already
+//! been allocated with a call to the USBLibDMAChannelAllocate() function. The
+//! transaction is configured to transfer \e ui32Size bytes to/from the buffer
+//! held in the \e pvBuffer pointer.
+//!
+//! \return This function returns the number of bytes scheduled to be
+//! transferred.
+//
+//*****************************************************************************
+#define USBLibDMATransfer(psUSBDMAInst, ui32Channel, pvBuffer, ui32Size) \
+ psUSBDMAInst->pfnTransfer(psUSBDMAInst, ui32Channel, \
+ pvBuffer, ui32Size)
+
+//*****************************************************************************
+//
+//! This function is called by the USB interrupt handler.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Status is the DMA interrupt status.
+//!
+//! This function is called by the USB interrupt handler to allow the DMA
+//! interface to handle interrupts outside of the context of the normal USB
+//! interrupt handler. The \e ui32Status is the current DMA interrupt status
+//! at the time of the USB interrupt. Since some DMA controller interrupts are
+//! cleared automatically when read, this value must be retrieved by calling
+//! the USBLibDMAIntStatus() function and passed into this function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAIntHandler(psUSBDMAInst, ui32Status) \
+ psUSBDMAInst->pfnIntHandler(psUSBDMAInst, ui32Status)
+
+//*****************************************************************************
+//
+//! This function is used to assign a DMA channel to an endpoint.
+//!
+//! \param psUSBDMAInst is the DMA instance data for a USB controller.
+//! \param ui8Endpoint is the endpoint number to assign a DMA channel.
+//! \param ui32MaxPacketSize is the maximum packet size for the endpoint
+//! assigned that is being assigned to the DMA channel.
+//! \param ui32Config are the basic configuration options for the DMA channel.
+//!
+//! This function assigns a DMA channel to a given endpoint. The
+//! \e ui8Endpoint parameter is the zero based endpoint number that is assigned
+//! a DMA channel. The \e ui32Config parameter contains any configuration
+//! options for the DMA channel. The current options include the following:
+//! - \b USB_DMA_EP_TX - this request is for a transmit DMA channel.
+//! - \b USB_DMA_EP_RX - this request is for a receive DMA channel.
+//!
+//! \note The maximum number of available DMA channels to endpoints varies
+//! between devices.
+//!
+//! \return Zero or the DMA channel assigned to the endpoint.
+//
+//*****************************************************************************
+#define USBLibDMAChannelAllocate(psUSBDMAInst, ui8Endpoint, ui32MaxPacketSize,\
+ ui32Config) \
+ psUSBDMAInst->pfnChannelAllocate(psUSBDMAInst, \
+ ui8Endpoint, \
+ ui32MaxPacketSize, \
+ ui32Config)
+
+//*****************************************************************************
+//
+//! This function is used to free a DMA channel that was assigned to an
+//! endpoint.
+//!
+//! \param psUSBDMAInst is the DMA instance data for a USB controller.
+//! \param ui8Endpoint is the DMA channel number to free up.
+//!
+//! This function frees up a DMA channel that was allocated to an endpoint
+//! by the USBLibDMAChannelAllocate() function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAChannelRelease(psUSBDMAInst, ui8Endpoint) \
+ psUSBDMAInst->pfnChannelRelease(psUSBDMAInst, ui8Endpoint)
+
+//*****************************************************************************
+//
+//! This function is used to set the individual transfer size of a DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA instance data for a USB controller.
+//! \param ui32Channel is the DMA channel number to modify.
+//! \param ui32BitSize is the individual transfer size in bits(8, 16 or 32).
+//!
+//! This function configures the individual transfer size of the DMA channel
+//! provided in the \e ui32Channel parameter. The \e ui32Channel must already
+//! be allocated to an endpoint by calling the USBLibDMAChannelAllocate()
+//! function. The \e ui32BitSize parameter should be on of the following
+//! values: 8, 16 or 32.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAUnitSizeSet(psUSBDMAInst, ui32Channel, ui32BitSize) \
+ psUSBDMAInst->pfnUnitSizeSet(psUSBDMAInst, ui32Channel, \
+ ui32BitSize);
+
+//*****************************************************************************
+//
+//! This function is used to set the arbitration size for a DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA instance data for a USB controller.
+//! \param ui32Channel is the DMA channel number to modify.
+//! \param ui32ArbSize is the transfer arbitration size in bytes.
+//!
+//! This function configures the individual transfer size of the DMA channel
+//! provided in the \e ui32Channel parameter. The \e ui32Channel must already
+//! be allocated to an endpoint by calling the USBLibDMAChannelAllocate()
+//! function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAArbSizeSet(psUSBDMAInst, ui32Channel, ui32ArbSize) \
+ psUSBDMAInst->pfnArbSizeSet(psUSBDMAInst, ui32Channel, \
+ ui32ArbSize);
+
+//*****************************************************************************
+//
+//! This function enables the DMA interrupt for a given channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel interrupt to enable.
+//!
+//! This function enables DMA interrupt on the channel number passed in the
+//! \e ui32Channel parameter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAChannelIntEnable(psUSBDMAInst, ui32Channel) \
+ psUSBDMAInst->pfnChannelIntEnable(psUSBDMAInst, ui32Channel)
+
+//*****************************************************************************
+//
+//! This function disables DMA interrupt for a given DMA channel.
+//!
+//! \param psUSBDMAInst is the DMA structure pointer for this instance.
+//! \param ui32Channel is the DMA channel interrupt to disable.
+//!
+//! This function disables the DMA interrupt on the channel number passed in
+//! the \e ui32Channel parameter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#define USBLibDMAChannelIntDisable(psUSBDMAInst, ui32Channel) \
+ psUSBDMAInst->pfnChannelIntDisable(psUSBDMAInst, ui32Channel)
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif // __USBLIBPRIV_H__
diff --git a/usblib/usbmode.c b/usblib/usbmode.c
new file mode 100644
index 0000000..3d95c11
--- /dev/null
+++ b/usblib/usbmode.c
@@ -0,0 +1,1180 @@
+//*****************************************************************************
+//
+// usbmode.c - Functions related to dual mode USB device/host operation.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_usb.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/device/usbdevice.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup general_usblib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The following label defines interrupts that we will always pass to the host
+// interrupt handler even if we are in dual mode and not yet sure of which
+// mode we are operating in.
+//
+//*****************************************************************************
+#define USB_HOST_INTS (USB_INTCTRL_VBUS_ERR)
+
+//*****************************************************************************
+//
+// Global variable indicating which mode of operation the application has
+// requested.
+//
+//*****************************************************************************
+volatile tUSBMode g_iUSBMode = eUSBModeNone;
+
+//*****************************************************************************
+//
+// The default and the current polling rate for the USB OTG library.
+//
+//*****************************************************************************
+volatile uint32_t g_ui32PollRate;
+
+//*****************************************************************************
+//
+// The current time remaining in milliseconds before checking the cable
+// connection.
+//
+//*****************************************************************************
+volatile uint32_t g_ui32WaitTicks = 0;
+
+//*****************************************************************************
+//
+// This enum holds the various states that we can be in while performing
+// USB mode checking. This involves use of the OTG session request to poll
+// the USB ID pin to determine whether a device or a host is connected.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // No checking is currently pending.
+ //
+ eUSBOTGModeIdle,
+
+ //
+ // Waiting on ID mode detection.
+ //
+ eUSBOTGModeWaitID,
+
+ //
+ // Waiting for next poll interval.
+ //
+ eUSBOTGModeWait,
+
+ //
+ // Now in B-side wait for connect.
+ //
+ eUSBOTGModeBWaitCon,
+
+ //
+ // Now in A-side device mode.
+ //
+ eUSBOTGModeBDevice,
+
+ //
+ // Now in A-side host mode.
+ //
+ eUSBOTGModeAHost,
+}
+tUSBOTGState;
+
+volatile tUSBOTGState g_eOTGModeState;
+
+//*****************************************************************************
+//
+// Global variable indicating whether we are currently operating in host or
+// device mode if the user has requested Dual mode operation.
+//
+//*****************************************************************************
+static volatile tUSBMode g_iDualMode = eUSBModeNone;
+
+static void USBOTGRemovePower(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// Global variable holding a pointer to the callback function which will be
+// called when the USB mode changes between device and host.
+//
+//*****************************************************************************
+static tUSBModeCallback g_pfnUSBModeCallback;
+
+//*****************************************************************************
+//
+// This function is used to handle switching between host, device and
+// unconfigured modes.
+//
+// \param iUSBMode is one of eUSBModeHost, eUSBModeDevice, or eUSBModeNone.
+//
+// Based on the current state held in g_iDualMode variable this function will
+// handle the transition of the mode of operation in OTG mode and calling
+// the callback function if it is present.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBOTGSetMode(tUSBMode iUSBMode)
+{
+ if((g_iDualMode != iUSBMode) || (g_iDualMode == eUSBModeNone))
+ {
+ //
+ // If going from host mode to unconfigured mode then remove power.
+ //
+ if((g_iDualMode == eUSBModeHost) && (iUSBMode == eUSBModeNone))
+ {
+ //
+ // Take the steps to remove power in the of host mode OTG.
+ //
+ USBOTGRemovePower(0);
+ }
+
+ //
+ // If going from device mode to unconfigured mode then end the current
+ // session.
+ //
+ if((g_iDualMode == eUSBModeDevice) && (iUSBMode == eUSBModeNone))
+ {
+ //
+ // End the current session.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+ }
+
+ //
+ // Reset the delay whenever returning to eUSBModeNone.
+ //
+ if(iUSBMode == eUSBModeNone)
+ {
+ g_ui32WaitTicks = g_ui32PollRate;
+ }
+
+ //
+ // Do we have a mode change callback installed?
+ //
+ if((g_pfnUSBModeCallback) && (g_iDualMode != iUSBMode))
+ {
+ //
+ // Inform the callback of the new operating mode.
+ //
+ g_pfnUSBModeCallback(0, iUSBMode);
+ }
+
+ //
+ // Save the new mode.
+ //
+ g_iDualMode = iUSBMode;
+ }
+}
+
+//*****************************************************************************
+//
+//! Allows dual mode application to switch between USB device and host modes
+//! and provides a method to force the controller into the desired mode.
+//!
+//! \param ui32Index specifies the USB controller whose mode of operation is to
+//! be set. This parameter must be set to 0.
+//! \param iUSBMode indicates the mode that the application wishes to operate
+//! in. Valid values are \b eUSBModeDevice to operate as a USB device and
+//! \b eUSBModeHost to operate as a USB host.
+//! \param pfnCallback is a pointer to a function which the USB library will
+//! call each time the mode is changed to indicate the new operating mode. In
+//! cases where \e iUSBMode is set to either \b eUSBModeDevice or
+//! \b eUSBModeHost, the callback will be made immediately to allow the
+//! application to perform any host or device specific initialization.
+//!
+//! This function allows a USB application that can operate in host
+//! or device mode to indicate to the USB stack the mode that it wishes to
+//! use. The caller is responsible for cleaning up the interface and removing
+//! itself from the bus prior to making this call and reconfiguring afterwards.
+//! The \e pfnCallback function can be a NULL(0) value to indicate that no
+//! notification is required.
+//!
+//! For successful dual mode mode operation, an application must register
+//! USB0DualModeIntHandler() as the interrupt handler for the USB0 interrupt.
+//! This handler is responsible for steering interrupts to the device or host
+//! stack depending upon the chosen mode. Devices which do not require dual
+//! mode capability should register either \e USB0DeviceIntHandler() or
+//! \e USB0HostIntHandler() instead. Registering \e USB0DualModeIntHandler()
+//! for a single mode application will result in an application binary larger
+//! than required since library functions for both USB operating modes will be
+//! included even though only one mode is required.
+//!
+//! Single mode applications (those offering exclusively USB device or USB
+//! host functionality) are only required to call this function if they need to
+//! force the mode of the controller to Host or Device mode. This is usually
+//! in the event that the application needs to reused the USBVBUS and/or USBID
+//! pins as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBStackModeSet(uint32_t ui32Index, tUSBMode iUSBMode,
+ tUSBModeCallback pfnCallback)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Remember the mode so that we can steer the interrupts appropriately.
+ //
+ g_iUSBMode = iUSBMode;
+
+ //
+ // Remember the callback pointer.
+ //
+ g_pfnUSBModeCallback = pfnCallback;
+
+ //
+ // If we are being asked to be either a host or device, we will not be
+ // trying to auto-detect the mode so make the callback immediately.
+ //
+ if((iUSBMode == eUSBModeDevice) || (iUSBMode == eUSBModeHost))
+ {
+ //
+ // Make sure that a callback was provided.
+ //
+ if(g_pfnUSBModeCallback)
+ {
+ g_pfnUSBModeCallback(0, iUSBMode);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Steers USB interrupts from controller to the correct handler in the USB
+//! stack.
+//!
+//! This interrupt handler is used in applications which require to operate
+//! in both host and device mode. It steers the USB hardware interrupt to the
+//! correct handler in the USB stack depending upon the current operating mode
+//! of the application, USB device or host.
+//!
+//! For successful dual mode operation, an application must register
+//! USB0DualModeIntHandler() in the CPU vector table as the interrupt handler
+//! for the USB0 interrupt. This handler is responsible for steering
+//! interrupts to the device or host stack depending upon the chosen mode.
+//!
+//! \note Devices which do not require dual mode capability should register
+//! either USB0DeviceIntHandler() or USB0HostIntHandler() instead. Registering
+//! USB0DualModeIntHandler() for a single mode application will result in an
+//! application binary larger than required since library functions for both
+//! USB operating modes will be included even though only one mode is actually
+//! required.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0DualModeIntHandler(void)
+{
+ uint32_t ui32Status;
+
+ //
+ // Read the USB interrupt status.
+ //
+ ui32Status = USBIntStatusControl(USB0_BASE);
+
+ //
+ // Pass through the subset of interrupts that we always want
+ // the host stack to see regardless of whether or not we
+ // are actually in host mode at this point.
+ //
+ if(ui32Status & USB_HOST_INTS)
+ {
+ //
+ // Call the host's interrupt handler.
+ //
+ USBHostIntHandlerInternal(0, ui32Status & USB_HOST_INTS);
+
+ //
+ // We have already processed these interrupts so clear them
+ // from the status.
+ //
+ ui32Status &= ~USB_HOST_INTS;
+ }
+
+ //
+ // Steer the interrupt to the appropriate handler within the stack
+ // depending upon our current operating mode. Note that we need to pass
+ // the ui32Status parameter since the USB interrupt register is
+ // clear-on-read.
+ //
+ switch(g_iUSBMode)
+ {
+ case eUSBModeNone:
+ {
+ //
+ // No mode is set yet so we have no idea what to do. Just ignore
+ // the interrupt.
+ //
+ break;
+ }
+
+ //
+ // Operating in pure host mode.
+ //
+ case eUSBModeHost:
+ {
+ //
+ // Call the host interrupt handler if there is anything still to
+ // process.
+ //
+ USBHostIntHandlerInternal(0, ui32Status);
+
+ break;
+ }
+
+ //
+ // Operating in pure device mode.
+ //
+ case eUSBModeDevice:
+ {
+ //
+ // Call the device interrupt handler.
+ //
+ USBDeviceIntHandlerInternal(0, ui32Status);
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group general_usblib_api.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup dualmode_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Initializes the USB controller for dual mode operation.
+//!
+//! \param ui32Index specifies the USB controller that is to be initialized for
+//! dual mode operation. This parameter must be set to 0.
+//!
+//! This function initializes the USB controller hardware into a state
+//! suitable for dual mode operation. Applications may use this function to
+//! ensure that the controller is in a neutral state and able to receive
+//! appropriate interrupts before host or device mode is chosen using a call
+//! to USBStackModeSet().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDualModeInit(uint32_t ui32Index)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Configure the End point 0.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | USB_EP_SPEED_FULL |
+ USB_EP_HOST_OUT));
+
+ //
+ // Enable USB Interrupts.
+ //
+ MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
+ USB_INTCTRL_DISCONNECT |
+ USB_INTCTRL_SESSION |
+ USB_INTCTRL_BABBLE |
+ USB_INTCTRL_CONNECT |
+ USB_INTCTRL_RESUME |
+ USB_INTCTRL_SUSPEND |
+ USB_INTCTRL_VBUS_ERR);
+
+ //
+ // Enable all endpoint interrupts.
+ //
+ MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Initialize the USB tick module.
+ //
+ InternalUSBTickInit();
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_psDCDInst[0].ui32IntNum);
+ //
+ // Turn on session request to enable ID pin checking.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+
+ //
+ // Initialize the power configuration.
+ //
+ USBHostPwrConfig(USB0_BASE, USBHCDPowerConfigGet(ui32Index));
+
+ //
+ // If power enable is automatic then then USBHostPwrEnable() has to be
+ // called to allow the USB controller to control the power enable pin.
+ //
+ if(USBHCDPowerAutomatic(ui32Index))
+ {
+ //
+ // This will not turn on power but instead will allow the USB
+ // controller to turn on power when needed.
+ //
+ USBHostPwrEnable(USB0_BASE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the USB controller to the default mode when in dual mode operation.
+//!
+//! \param ui32Index specifies the USB controller whose dual mode operation is
+//! to be ended. This parameter must be set to 0.
+//!
+//! Applications using both host and device modes may call this function to
+//! disable interrupts in preparation for shutdown or a change of operating
+//! mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBDualModeTerm(uint32_t ui32Index)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_psDCDInst[0].ui32IntNum);
+
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group dualmode_api.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_otg
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Returns the USB controller to and inactive state when in OTG mode
+//! operation.
+//!
+//! \param ui32Index specifies the USB controller to end OTG mode operations.
+//!
+//! Applications using OTG mode may call this function to disable interrupts
+//! in preparation for shutdown or a change of operating mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBOTGModeTerm(uint32_t ui32Index)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_psDCDInst[0].ui32IntNum);
+
+ //
+ // Disable all control interrupts.
+ //
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+
+ //
+ // Disable all endpoint interrupts.
+ //
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Set the mode to none if it is not already.
+ //
+ USBOTGSetMode(eUSBModeNone);
+}
+
+//*****************************************************************************
+//
+//! Initializes the USB controller for OTG mode operation.
+//!
+//! \param ui32Index specifies the USB controller that is to be initialized for
+//! OTG mode operation.
+//! \param ui32PollingRate is the rate in milliseconds to poll the controller
+//! for changes in mode.
+//! \param pvPool is a pointer to the data to use as a memory pool for this
+//! controller.
+//! \param ui32PoolSize is the size in bytes of the buffer passed in as
+//! \e pvPool.
+//!
+//! This function initializes the USB controller hardware into a state
+//! suitable for OTG mode operation. Applications must use this function to
+//! ensure that the controller is in a neutral state and able to receive
+//! appropriate interrupts before host or device mode is chosen by OTG
+//! negotiation. The \e ui32PollingRate parameter is used to set the rate at
+//! which the USB library will poll the controller to determine the mode. This
+//! has the most effect on how quickly the USB library will detect changes when
+//! going to host mode. The parameters \e pvPool and \e ui32PoolSize are
+//! passed on to the USB host library functions to provide memory for the USB
+//! library when it is acting as a host. Any device and host initialization
+//! should have been called before calling this function to prevent the USB
+//! library from attempting to run in device or host mode before the USB
+//! library is fully configured.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBOTGModeInit(uint32_t ui32Index, uint32_t ui32PollingRate,
+ void *pvPool, uint32_t ui32PoolSize)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // This should never be called if not in OTG mode.
+ //
+ ASSERT(g_iUSBMode == eUSBModeOTG);
+
+ //
+ // Force OTG mode in all cases since anything else is invalid, but a DEBUG
+ // build will still ASSERT above if this value is incorrect.
+ //
+ g_iUSBMode = eUSBModeOTG;
+
+ //
+ // Remember that we have not yet determined whether we are device or
+ // host.
+ //
+ g_iDualMode = eUSBModeNone;
+
+ //
+ // Set the default polling rate.
+ //
+ g_ui32PollRate = ui32PollingRate;
+
+ //
+ // Enable the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Initialize the host controller stack.
+ //
+ USBHCDInit(ui32Index, pvPool, ui32PoolSize);
+
+ //
+ // Configure the End point 0.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | USB_EP_SPEED_FULL |
+ USB_EP_HOST_OUT));
+
+ //
+ // Enable control interrupts.
+ //
+ MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
+ USB_INTCTRL_DISCONNECT |
+ USB_INTCTRL_SESSION |
+ USB_INTCTRL_BABBLE |
+ USB_INTCTRL_CONNECT |
+ USB_INTCTRL_RESUME |
+ USB_INTCTRL_SUSPEND |
+ USB_INTCTRL_VBUS_ERR |
+ USB_INTCTRL_MODE_DETECT |
+ USB_INTCTRL_SOF);
+
+ //
+ // Make sure the mode OTG mode and not forced device or host.
+ //
+ USBOTGMode(USB0_BASE);
+
+ //
+ // Enable all endpoint interrupts.
+ //
+ MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Initialize the power configuration.
+ //
+ USBHCDPowerConfigSet(ui32Index, USBHCDPowerConfigGet(ui32Index));
+
+ //
+ // If power enable is automatic then then USBHostPwrEnable() has to be
+ // called to allow the USB controller to control the power enable pin.
+ //
+ if(USBHCDPowerAutomatic(ui32Index))
+ {
+ //
+ // This will not turn on power but instead will allow the USB
+ // controller to turn on power when needed.
+ //
+ USBHostPwrEnable(USB0_BASE);
+ }
+
+ //
+ // Enable the USB interrupt.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ OS_INT_ENABLE(INT_USB0_TM4C129);
+ }
+ else
+ {
+ OS_INT_ENABLE(INT_USB0_TM4C123);
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the steps required to remove power in OTG mode.
+//
+// \param ui32Index specifies which USB controller should remove power.
+//
+// This function will perform the steps required to remove power from the USB
+// bus as required by the OTG specification. This call will first issue a
+// bus suspend followed by clearing the current session and then removing
+// power.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBOTGRemovePower(uint32_t ui32Index)
+{
+ tEventInfo sEvent;
+
+ //
+ // Do suspend signaling.
+ //
+ USBHostSuspend(USB0_BASE);
+
+ //
+ // End the session in either device or host mode.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+
+ //
+ // Check if the controller is automatically applying power or not.
+ //
+ if(USBHCDPowerAutomatic(ui32Index) == 0)
+ {
+ //
+ // Call the registered event driver to allow it to disable power.
+ //
+ sEvent.ui32Event = USB_EVENT_POWER_DISABLE;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWRDIS);
+ }
+}
+
+//*****************************************************************************
+//
+//! This call sets the USB OTG controllers poll rate when checking for the mode
+//! of the controller.
+//!
+//! \param ui32Index specifies which USB controller to set the polling rate.
+//! \param ui32PollRate is the rate in milliseconds to poll for changes in the
+//! controller mode.
+//!
+//! This function is called to set the USB OTG libraries polling rate when
+//! checking the status of the cable. The \e ui32PollRate value used sets the
+//! rate in milliseconds that the USB OTG library will poll the cable to see
+//! if the controller should enter host mode. This value has no effect on
+//! device detection rate as the controller will detect being connected to a
+//! host controller automatically. The \e ui32PollRate can be set to 0 to
+//! disable polling. The USB OTG library can still function with the polling
+//! rate set to zero, however it will fail to detect host mode properly when no
+//! device is present at the end of the USB OTG B side of the cable.
+//!
+//! \note This function should only be called on devices that support OTG
+//! functionality.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBOTGPollRate(uint32_t ui32Index, uint32_t ui32PollRate)
+{
+ //
+ // Save the timeout.
+ //
+ g_ui32PollRate = ui32PollRate;
+}
+
+//*****************************************************************************
+//
+//! Handles OTG mode changes and also steers other USB interrupts from
+//! the controller to the correct handler in the USB stack.
+//!
+//! This interrupt handler is used in applications which require to operate
+//! in both host and device mode using OTG. When in host or device mode, it
+//! steers the USB hardware interrupt to the correct handler in the USB stack
+//! depending upon the current operating mode. It also handles other OTG
+//! related interrupt events.
+//!
+//! For successful OTG mode operation, an application must register
+//! USB0OTGModeIntHandler() in the CPU vector table as the interrupt handler
+//! for the USB0 interrupt.
+//!
+//! \note This interrupt handler should only be used on controllers that
+//! support OTG functionality.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0OTGModeIntHandler(void)
+{
+ uint32_t ui32Status;
+ tEventInfo sEvent;
+
+ //
+ // Read the USB interrupt status.
+ //
+ ui32Status = USBIntStatusControl(USB0_BASE);
+
+ //
+ // Check if this was an mode detect interrupt and under manual power
+ // control.
+ //
+ if((ui32Status & USB_INTCTRL_MODE_DETECT) &&
+ (USBHCDPowerAutomatic(0) == 0))
+ {
+ uint32_t ui32Mode;
+
+ ui32Mode = USBModeGet(USB0_BASE);
+
+ switch(ui32Mode)
+ {
+ //
+ // Device is on the A side of the cable and power needs to be
+ // applied.
+ //
+ case USB_OTG_MODE_ASIDE_NPWR:
+ case USB_OTG_MODE_ASIDE_SESS:
+ case USB_OTG_MODE_ASIDE_AVAL:
+ {
+ //
+ // Since power is not automatically enabled, call the
+ // registered event handler to allow the application to turn
+ // on power.
+ //
+ sEvent.ui32Event = USB_EVENT_POWER_ENABLE;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWREN);
+
+ break;
+ }
+
+ //
+ // Device is on the B side of the cable and powered.
+ //
+ case USB_OTG_MODE_BSIDE_DEV:
+ {
+ //
+ // Now in device mode on the B side of the cable and will wait
+ // for a connect before becoming a device.
+ //
+ g_eOTGModeState = eUSBOTGModeBWaitCon;
+
+ break;
+ }
+
+ //
+ // Any other mode detect indicates eUSBModeNone.
+ //
+ default:
+ {
+ //
+ // Just inform the application that the mode was not device
+ // or host.
+ //
+ USBOTGSetMode(eUSBModeNone);
+
+ break;
+ }
+ }
+ }
+
+ //
+ // If there was a VBUS error then the power should be shut off and the
+ // system is reset to waiting for detection again.
+ //
+ if(ui32Status & USB_INTCTRL_VBUS_ERR)
+ {
+ //
+ // Just inform the application that the mode was not device
+ // or host.
+ //
+ USBOTGSetMode(eUSBModeNone);
+
+ //
+ // Return to idle mode.
+ //
+ g_eOTGModeState = eUSBOTGModeWait;
+ }
+
+ //
+ // If there is a disconnect interrupt and the controller was on the B side
+ // cable as a device then go back to the IDLE state.
+ //
+ if((ui32Status & USB_INTCTRL_DISCONNECT) &&
+ (g_eOTGModeState == eUSBOTGModeBDevice))
+ {
+ //
+ // No longer a device so switch to unconfigured mode.
+ //
+ USBOTGSetMode(eUSBModeNone);
+
+ //
+ // Return to idle mode.
+ //
+ g_eOTGModeState = eUSBOTGModeWait;
+
+ return;
+ }
+
+ //
+ // Handle receiving a reset.
+ //
+ if((ui32Status & USB_INTCTRL_RESET)&&
+ (g_eOTGModeState != eUSBOTGModeBDevice))
+ {
+ //
+ // Getting a reset interrupt when not already a b side device indicates
+ // that a host is resetting the device and the controller should
+ // move to device mode.
+ //
+ g_eOTGModeState = eUSBOTGModeBDevice;
+
+ //
+ // Save the new mode.
+ //
+ USBOTGSetMode(eUSBModeDevice);
+ }
+
+ //
+ // If there is a connect interrupt while the library is waiting for
+ // one then move to full host mode state.
+ //
+ if(ui32Status & USB_INTCTRL_CONNECT)
+ {
+ //
+ // Move to A side host state.
+ //
+ g_eOTGModeState = eUSBOTGModeAHost;
+
+ //
+ // Inform the application that controller is in host mode.
+ //
+ USBOTGSetMode(eUSBModeHost);
+ }
+
+ //
+ // Call the correct device or host interrupt handler based on the current
+ // mode of operation.
+ //
+ switch(g_eOTGModeState)
+ {
+ case eUSBOTGModeAHost:
+ {
+ //
+ // Call the host interrupt handler if there is anything still to
+ // process.
+ //
+ USBHostIntHandlerInternal(0, ui32Status);
+
+ break;
+ }
+
+ //
+ // Operating in pure device mode.
+ //
+ case eUSBOTGModeBDevice:
+ {
+ //
+ // Call the device interrupt handler.
+ //
+ USBDeviceIntHandlerInternal(0, ui32Status);
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB host stack code to indicated that it
+// has completed handing the device disconnection.
+//
+// \param ui32Index specifies the USB controller that has completed disconnect.
+//
+// This internal library function is used when the hsot controller has
+// completed any deferred handling when it has detected a device has been
+// disconnected. The functions main purpose is to return the OTG controller to
+// a state that allows for resuming normal OTG cable detection and negotiation.
+//
+// \note This function should not be called outside the library.
+//
+//*****************************************************************************
+void
+OTGDeviceDisconnect(uint32_t ui32Index)
+{
+ //
+ // This function is only valid when called in host mode.
+ //
+ if(g_eOTGModeState == eUSBOTGModeAHost)
+ {
+ //
+ // No longer a host so switch to unconfigured mode.
+ //
+ USBOTGSetMode(eUSBModeNone);
+
+ g_eOTGModeState = eUSBOTGModeWait;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is the main routine for the OTG Controller Driver.
+//!
+//! \param ui32MsTicks is the number of milliseconds that have passed since the
+//! last time this function was called.
+//!
+//! This function is the main routine for the USB controller when using the
+//! library in OTG mode. This routine must be called periodically by the main
+//! application outside of a callback context. The \e ui32MsTicks value is
+//! used for basic timing needed by the USB library when operating in OTG mode.
+//! This allows for a simple cooperative system to access the the OTG
+//! controller driver interface without the need for an RTOS. All time
+//! critical operations are handled in interrupt context but all longer
+//! operations are run from the this function to allow them to block and wait
+//! for completion without holding off other interrupts.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBOTGMain(uint32_t ui32MsTicks)
+{
+ tEventInfo sEvent;
+
+ if(ui32MsTicks > g_ui32WaitTicks)
+ {
+ g_ui32WaitTicks = 0;
+ }
+ else
+ {
+ g_ui32WaitTicks -= ui32MsTicks;
+ }
+
+ switch(g_eOTGModeState)
+ {
+ case eUSBOTGModeIdle:
+ {
+ g_eOTGModeState = eUSBOTGModeWaitID;
+
+ //
+ // Initiate a session request and check the ID pin.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+ break;
+ }
+ case eUSBOTGModeWait:
+ case eUSBOTGModeWaitID:
+ {
+ //
+ // If reached the timeout and polling is enabled then look again.
+ //
+ if((g_ui32WaitTicks == 0) && (g_ui32PollRate != 0))
+ {
+ //
+ // Remove the session request.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+
+ //
+ // Return to idle mode.
+ //
+ USBOTGSetMode(eUSBModeNone);
+
+ //
+ // Check if the controller is automatically applying power or
+ // not.
+ //
+ if(USBHCDPowerAutomatic(0) == 0)
+ {
+ //
+ // Call the registered event driver to allow it to disable
+ // power.
+ //
+ sEvent.ui32Event = USB_EVENT_POWER_DISABLE;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWRDIS);
+ }
+
+ //
+ // Go back to the idle state.
+ //
+ g_eOTGModeState = eUSBOTGModeIdle;
+ }
+ break;
+ }
+ case eUSBOTGModeAHost:
+ {
+ //
+ // Call the host main routine when acting as a host.
+ //
+ USBHCDMain();
+ break;
+ }
+ case eUSBOTGModeBWaitCon:
+ case eUSBOTGModeBDevice:
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function sets one of the \b USBLIB_FEATURE_ requests.
+//!
+//! \param ui32Index is the index of the USB controller to access.
+//! \param ui32Feature is one of the \b USBLIB_FEATURE_ defines.
+//! \param pvFeature is a pointer to the data for the \b USBLIB_FEATURE
+//! request.
+//!
+//! This function sends the requested feature request to the USB library.
+//! Not all features are supported by all devices so see the documentation
+//! for the \b USBLIB_FEATURE_ to determine if the feature is supported.
+//!
+//! \return Returns \b true if the feature was set and \b false if the feature
+//! is not supported or could not be changed to the requested value.
+//
+//*****************************************************************************
+bool
+USBOTGFeatureSet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
+{
+ bool bRetCode;
+
+ bRetCode = true;
+
+ //
+ // Pass this on to the host and device and indicate false if
+ // either fails.
+ //
+ if(USBDCDFeatureSet(ui32Index, ui32Feature, pvFeature) == false)
+ {
+ bRetCode = false;
+ }
+
+ if(USBHCDFeatureSet(ui32Index, ui32Feature, pvFeature) == false)
+ {
+ bRetCode = false;
+ }
+
+ return(bRetCode);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbmsc.h b/usblib/usbmsc.h
new file mode 100644
index 0000000..115695b
--- /dev/null
+++ b/usblib/usbmsc.h
@@ -0,0 +1,444 @@
+//*****************************************************************************
+//
+// usbmsc.h - Generic types and defines use by the mass storage class.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBMSC_H__
+#define __USBMSC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The request for the maximum number of logical units on a mass storage
+// device.
+//
+//*****************************************************************************
+#define USBREQ_GET_MAX_LUN 0xfe
+
+//*****************************************************************************
+//
+// The request for the bulk only reset of a mass storage device.
+//
+//*****************************************************************************
+#define USBREQ_BULK_ONLY_RESET 0xff
+
+//*****************************************************************************
+//
+// The signatures defined by USB MSC class specification.
+//
+//*****************************************************************************
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+
+//*****************************************************************************
+//
+// Flag for the bmCBWFlags member of tMSCCBW
+//
+//*****************************************************************************
+#define CBWFLAGS_DIR_M 0x80
+#define CBWFLAGS_DIR_IN 0x80
+#define CBWFLAGS_DIR_OUT 0x00
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requries a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+// The following packed structure is used to access the Command Block Wrapper
+// (CBW) data structure that is used when communicating with USB Mass Storage
+// Class devices.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Signature that helps identify this data packet as a CBW. The signature
+ // field shall contain the value 0x43425355 (little endian), indicating a
+ // CBW.
+ //
+ uint32_t dCBWSignature;
+
+ //
+ // The Command Block Tag sent by the host controller. The device shall
+ // echo the contents of this field back to the host in the dCSWTag field
+ // of the associated CSW. The dCSWTag positively associates a CSW with the
+ // corresponding CBW.
+ //
+ uint32_t dCBWTag;
+
+ //
+ // The number of bytes of data that the host expects to transfer on the
+ // Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during
+ // the execution of this command. If this field is zero, the device and
+ // the host will not transfer data between the CBW and the associated CSW,
+ // and the device will ignore the value of the Direction bit in
+ // bmCBWFlags.
+ //
+ uint32_t dCBWDataTransferLength;
+
+ //
+ // The device will ignore these bits if the dCBWDataTransferLength value
+ // is set to 0.
+ //
+ // The bits of this field are defined as follows:
+ // Bit 7 Direction
+ // 0 = Data-Out from host to the device,
+ // 1 = Data-In from the device to the host.
+ // Bit 6 Obsolete - The host shall set this bit to zero.
+ // Bits 5..0 Reserved - the host shall set these bits to zero.
+ //
+ uint8_t bmCBWFlags;
+
+ //
+ // The device Logical Unit Number (LUN) to which the command block is being
+ // sent. For devices that support multiple LUNs, the host shall place into
+ // this field the LUN to which this command block is addressed. Otherwise,
+ // the host shall set this field to zero.
+ //
+ uint8_t bCBWLUN;
+
+ //
+ // The valid length of the CBWCB in bytes. This defines the valid length
+ // of the command block. The only legal values are 1 through 16. All
+ // other values are reserved.
+ //
+ uint8_t bCBWCBLength;
+
+ //
+ // This array holds the command block to be executed by the device. The
+ // MSC device will interpret the first bCBWCBLength bytes in this field as
+ // a command block as defined by the command set identified by
+ // bInterfaceSubClass. If the command set supported by the device uses
+ // command blocks of fewer than 16 bytes in length, the significant bytes
+ // shall be transferred first, beginning with the byte at offset 15. The
+ // device will ignore the content of the CBWCB field past the byte at
+ // offset (15 + bCBWCBLength - 1).
+ //
+ uint8_t CBWCB[16];
+}
+PACKED tMSCCBW;
+
+//*****************************************************************************
+//
+// Flags for the bCSWStatus member of tMSCCSW
+//
+//*****************************************************************************
+#define CSWSTATUS_CMD_SUCCESS 0
+#define CSWSTATUS_CMD_FAILED 1
+#define CSWSTATUS_PHASE_ERROR 2
+
+//*****************************************************************************
+//
+// This structure encapsulates the Command Status Word (CSW) structure that is
+// sent in response to all CBW commands.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Signature that identifies this data packet as a CSW. The signature
+ // field must contain the value 53425355h (little endian) to indicate CSW.
+ //
+ uint32_t dCSWSignature;
+
+ //
+ // The device will set this field to the value received in the dCBWTag of
+ // the associated CBW.
+ //
+ uint32_t dCSWTag;
+
+ //
+ // For OUT transactions the device will fill the dCSWDataResidue field with
+ // the difference between the amount of data expected as stated in the
+ // dCBWDataTransferLength, and the actual amount of data processed by the
+ // device. For IN transactions the device will fill the dCSWDataResidue
+ // field with the difference between the amount of data expected as stated
+ // in the dCBWDataTransferLength and the actual amount of relevant data
+ // sent by the device. The dCSWDataResidue will not exceed the value sent
+ // in the dCBWDataTransferLength.
+ //
+ uint32_t dCSWDataResidue;
+
+ //
+ // The bCSWStatus field indicates the success or failure of the command.
+ // The device shall set this byte to zero if the command completed
+ // successfully. A non-zero value shall indicate a failure during command
+ // execution.
+ //
+ uint8_t bCSWStatus;
+}
+PACKED tMSCCSW;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// SCSI Command return codes.
+//
+//*****************************************************************************
+#define SCSI_CMD_STATUS_PASS 0x00
+#define SCSI_CMD_STATUS_FAIL 0x01
+
+//*****************************************************************************
+//
+// SCSI commands.
+//
+//*****************************************************************************
+#define SCSI_TEST_UNIT_READY 0x00
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_INQUIRY_CMD 0x12
+#define SCSI_MODE_SENSE_6 0x1a
+#define SCSI_START_STOP_UNIT 0x1b
+#define SCSI_MEDIUM_REMOVAL 0x1e
+#define SCSI_READ_CAPACITIES 0x23
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ_10 0x28
+#define SCSI_WRITE_10 0x2a
+
+//*****************************************************************************
+//
+// SCSI Test Unit Ready definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// SCSI Inquiry command definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Size of the SCSI inquiry response data.
+//
+//*****************************************************************************
+#define SCSI_INQUIRY_DATA_SZ 36
+
+//*****************************************************************************
+//
+// Offset 0 of the Inquiry Data.
+//
+//*****************************************************************************
+#define SCSI_INQ_PQ_M 0xe0 // Peripheral Qualifier Mask.
+#define SCSI_INQ_PQ_CNCT 0x00 // Device connected.
+#define SCSI_INQ_PQ_DISC 0x20 // Device disconnected.
+#define SCSI_INQ_PDT_M 0x1f // Peripheral Device Type Mask.
+#define SCSI_INQ_PDT_SBC 0x00 // Direct Access device.
+
+//*****************************************************************************
+//
+// Offset 1 of the Inquiry Data.
+//
+//*****************************************************************************
+#define SCSI_INQ_RMB 0x80 // Device is removable.
+
+//*****************************************************************************
+//
+// Macro to check if removeable.
+//
+//*****************************************************************************
+#define SCSIIsRemovable(pData) \
+ (((uint8_t *)pData)[1] & SCSI_INQ_RMB)
+
+//*****************************************************************************
+//
+// SCSI Read Capacity definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Size of the SCSI Read Capacity response data.
+//
+//*****************************************************************************
+#define SCSI_READ_CAPACITY_SZ 0x08
+
+//*****************************************************************************
+//
+// SCSI Mode Sense definitions, these are passed in via the ui32Flags parameter
+// of the SCSIModeSense() function call.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Disable block descriptors.
+//
+//*****************************************************************************
+#define SCSI_MS_DBD 0x00000800
+
+//*****************************************************************************
+//
+// Page Code values, used in combination with Page Control values.
+//
+//*****************************************************************************
+#define SCSI_MS_PC_VENDOR 0x00000000
+#define SCSI_MS_PC_DISCO 0x00020000
+#define SCSI_MS_PC_CONTROL 0x000a0000
+#define SCSI_MS_PC_LUN 0x00180000
+#define SCSI_MS_PC_PORT 0x00190000
+#define SCSI_MS_PC_POWER 0x001a0000
+#define SCSI_MS_PC_INFORM 0x001c0000
+#define SCSI_MS_PC_ALL 0x003f0000
+
+//*****************************************************************************
+//
+// Page Control values.
+//
+//*****************************************************************************
+#define SCSI_MS_PC_CURRENT 0x00000000
+#define SCSI_MS_PC_CHANGEABLE 0x00400000
+#define SCSI_MS_PC_DEFAULT 0x00800000
+#define SCSI_MS_PC_SAVED 0x00c00000
+
+//*****************************************************************************
+//
+// Request Sense Definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Size of the data returned by the Request Sense command.
+//
+//*****************************************************************************
+#define SCSI_REQUEST_SENSE_SZ 18
+
+#define SCSI_RS_SKEY 2 // Sense Key offset.
+#define SCSI_RS_SKEY_AD_SKEY 12 // Additional Sense Key offset.
+
+//*****************************************************************************
+//
+// Offset 0 in the Request Sense response.
+//
+//*****************************************************************************
+#define SCSI_RS_VALID 0x80 // Response is valid.
+#define SCSI_RS_CUR_ERRORS 0x70 // Current errors returned.
+#define SCSI_RS_DEFER_ERRORS 0x71 // Deferred errors returned.
+
+//*****************************************************************************
+//
+// Offset 2 in the Request Sense response.
+//
+//*****************************************************************************
+#define SCSI_RS_KEY_M 0x0f // Sense Key.
+#define SCSI_RS_KEY_NO_SENSE 0x00 // No Sense Data.
+#define SCSI_RS_KEY_RECOVRD_ERR 0x01 // Recovered Error.
+#define SCSI_RS_KEY_NOT_READY 0x02 // Not Ready.
+#define SCSI_RS_KEY_MEDIUM_ERR 0x03 // Error in the media.
+#define SCSI_RS_KEY_HW_ERR 0x04 // Hardware Error, non recoverable.
+#define SCSI_RS_KEY_ILGL_RQST 0x05 // Illegal request.
+#define SCSI_RS_KEY_UNIT_ATTN 0x06 // Unit changed or reset.
+#define SCSI_RS_KEY_DATA_PROT 0x07 // Write Protect error.
+#define SCSI_RS_KEY_BLANK_CHK 0x08 // Write once error, block not clear.
+#define SCSI_RS_KEY_ABORT 0x0b // Last command was aborted.
+#define SCSI_RS_ILI 0x20 // Incorrect length indicator.
+#define SCSI_RS_EOM 0x40 // End of medium condition.
+#define SCSI_RS_FILEMARK 0x80 // Command has read a filemark/setmark.
+#define SCSI_RS_MED_NOT_PRSNT 0x003a // Medium not present.
+#define SCSI_RS_MED_NOTRDY2RDY 0x0028 // Not ready to ready transition.
+#define SCSI_RS_PV_INVALID 0x0226 // Parameter Value Invalid.
+
+//*****************************************************************************
+//
+// Additional information for SCSI_RS_KEY_NOT_READY
+//
+//*****************************************************************************
+#define SCSI_RS_KEY_NOTPRSNT 0x3A // Media Not Present.
+
+//*****************************************************************************
+//
+// Prevent/Allow Medium Removal Definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Offset 4 in the Prevent/Allow Medium Removal command.
+//
+//*****************************************************************************
+#define SCSI_PE_MEDRMV_M 0x03
+#define SCSI_PE_MEDRMV_ALLOW 0x00
+#define SCSI_PE_MEDRMV_PREVENT 0x01
+
+//*****************************************************************************
+//
+// Start/Stop Unit Definitions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Offset 1 in the Start/Stop Unit command.
+//
+//*****************************************************************************
+#define SCSI_SS_UNIT_IMMED 0x01
+#define SCSI_SS_UNIT_LUN_M 0xe0
+
+//*****************************************************************************
+//
+// Offset 4 in the Start/Stop Unit command.
+//
+//*****************************************************************************
+#define SCSI_SS_UNIT_START 0x01
+#define SCSI_SS_UNIT_LOEJ 0x02
+#define SCSI_SS_UNIT_PWR_M 0xf0
+#define SCSI_SS_UNIT_PWR_ACTIVE 0x10
+#define SCSI_SS_UNIT_PWR_IDLE 0x20
+#define SCSI_SS_UNIT_PWR_STDBY 0x30
+#define SCSI_SS_UNIT_PWR_DSLEEP 0x50
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBMSC_H__
diff --git a/usblib/usbringbuf.c b/usblib/usbringbuf.c
new file mode 100644
index 0000000..733ef64
--- /dev/null
+++ b/usblib/usbringbuf.c
@@ -0,0 +1,715 @@
+//*****************************************************************************
+//
+// usbringbuf.c - USB library ring buffer management utilities.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "usblib/usblib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_buffer_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//*****************************************************************************
+//
+// Change the value of a variable atomically.
+//
+// \param pui32Val points to the index whose value is to be modified.
+// \param ui32Delta is the number of bytes to increment the index by.
+// \param ui32Size is the size of the buffer the index refers to.
+//
+// This function is used to increment a read or write buffer index that may be
+// written in various different contexts. It ensures that the
+// read/modify/write sequence is not interrupted and, hence, guards against
+// corruption of the variable. The new value is adjusted for buffer wrap.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateIndexAtomic(volatile uint32_t *pui32Val, uint32_t ui32Delta,
+ uint32_t ui32Size)
+{
+ bool bIntsOff;
+
+ //
+ // Turn interrupts off temporarily.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the variable value.
+ //
+ *pui32Val += ui32Delta;
+
+ //
+ // Correct for wrap. We use a loop here since we don't want to use a
+ // modulus operation with interrupts off but we don't want to fail in
+ // case ui32Delta is greater than ui32Size (which is extremely unlikely
+ // but...)
+ //
+ while(*pui32Val >= ui32Size)
+ {
+ *pui32Val -= ui32Size;
+ }
+
+ //
+ // Restore the interrupt state
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether a ring buffer is full or not.
+//!
+//! \param psUSBRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is full or \b false otherwise.
+//
+//*****************************************************************************
+bool
+USBRingBufFull(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psUSBRingBuf->ui32WriteIndex;
+ ui32Read = psUSBRingBuf->ui32ReadIndex;
+
+ //
+ // Return the full status of the buffer.
+ //
+ return((((ui32Write + 1) % psUSBRingBuf->ui32Size) == ui32Read) ? true :
+ false);
+}
+
+//*****************************************************************************
+//
+//! Determines whether a ring buffer is empty or not.
+//!
+//! \param psUSBRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is empty or \b false otherwise.
+//
+//*****************************************************************************
+bool
+USBRingBufEmpty(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psUSBRingBuf->ui32WriteIndex;
+ ui32Read = psUSBRingBuf->ui32ReadIndex;
+
+ //
+ // Return the empty status of the buffer.
+ //
+ return((ui32Write == ui32Read) ? true : false);
+}
+
+//*****************************************************************************
+//
+//! Empties the ring buffer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to empty.
+//!
+//! Discards all data from the ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufFlush(tUSBRingBufObject *psUSBRingBuf)
+{
+ bool bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Set the Read/Write pointers to be the same. Do this with interrupts
+ // disabled to prevent the possibility of corruption of the read index.
+ //
+ bIntsOff = IntMasterDisable();
+ psUSBRingBuf->ui32ReadIndex = psUSBRingBuf->ui32WriteIndex;
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes stored in ring buffer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes stored in the ring buffer.
+//!
+//! \return Returns the number of bytes stored in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+USBRingBufUsed(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psUSBRingBuf->ui32WriteIndex;
+ ui32Read = psUSBRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of bytes contained in the ring buffer.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psUSBRingBuf->ui32Size - (ui32Read - ui32Write)));
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes available in a ring buffer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes available in the ring buffer.
+//!
+//! \return Returns the number of bytes available in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+USBRingBufFree(tUSBRingBufObject *psUSBRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return((psUSBRingBuf->ui32Size - 1) - USBRingBufUsed(psUSBRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous bytes of data stored in ring buffer ahead of
+//! the current read pointer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous bytes of data available in
+//! the ring buffer ahead of the current read pointer. This represents the
+//! largest block of data which does not straddle the buffer wrap.
+//!
+//! \return Returns the number of contiguous bytes available.
+//
+//*****************************************************************************
+uint32_t
+USBRingBufContigUsed(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psUSBRingBuf->ui32WriteIndex;
+ ui32Read = psUSBRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psUSBRingBuf->ui32Size - ui32Read));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous free bytes available in a ring buffer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous free bytes ahead of the
+//! current write pointer in the ring buffer.
+//!
+//! \return Returns the number of contiguous bytes available in the ring
+//! buffer.
+//
+//*****************************************************************************
+uint32_t
+USBRingBufContigFree(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psUSBRingBuf->ui32WriteIndex;
+ ui32Read = psUSBRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ if(ui32Read > ui32Write)
+ {
+ //
+ // The read pointer is above the write pointer so the amount of free
+ // space is the difference between the two indices minus 1 to account
+ // for the buffer full condition (write index one behind read index).
+ //
+ return((ui32Read - ui32Write) - 1);
+ }
+ else
+ {
+ //
+ // If the write pointer is above the read pointer, the amount of free
+ // space is the size of the buffer minus the write index. We need to
+ // add a special-case adjustment if the read index is 0 since we need
+ // to leave 1 byte empty to ensure we can tell the difference between
+ // the buffer being full and empty.
+ //
+ return(psUSBRingBuf->ui32Size - ui32Write - ((ui32Read == 0) ? 1 : 0));
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the size in bytes of a ring buffer.
+//!
+//! \param psUSBRingBuf is the ring buffer object to check.
+//!
+//! This function returns the size of the ring buffer.
+//!
+//! \return Returns the size in bytes of the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+USBRingBufSize(tUSBRingBufObject *psUSBRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return(psUSBRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Reads a single byte of data from a ring buffer.
+//!
+//! \param psUSBRingBuf points to the ring buffer to be written to.
+//!
+//! This function reads a single byte of data from a ring buffer.
+//!
+//! \return The byte read from the ring buffer.
+//
+//*****************************************************************************
+uint8_t
+USBRingBufReadOne(tUSBRingBufObject *psUSBRingBuf)
+{
+ uint8_t ui8Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(USBRingBufUsed(psUSBRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ ui8Temp = psUSBRingBuf->pui8Buf[psUSBRingBuf->ui32ReadIndex];
+
+ //
+ // Increment the read index.
+ //
+ UpdateIndexAtomic(&psUSBRingBuf->ui32ReadIndex, 1, psUSBRingBuf->ui32Size);
+
+ //
+ // Return the character read.
+ //
+ return(ui8Temp);
+}
+
+//*****************************************************************************
+//
+//! Reads data from a ring buffer.
+//!
+//! \param psUSBRingBuf points to the ring buffer to be read from.
+//! \param pui8Data points to where the data should be stored.
+//! \param ui32Length is the number of bytes to be read.
+//!
+//! This function reads a sequence of bytes from a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufRead(tUSBRingBufObject *psUSBRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that data is available in the buffer.
+ //
+ ASSERT(ui32Length <= USBRingBufUsed(psUSBRingBuf));
+
+ //
+ // Read the data from the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ pui8Data[ui32Temp] = USBRingBufReadOne(psUSBRingBuf);
+ }
+}
+
+//*****************************************************************************
+//
+//! Removes bytes from the ring buffer by advancing the read index.
+//!
+//! \param psUSBRingBuf points to the ring buffer from which bytes are to be
+//! removed.
+//! \param ui32NumBytes is the number of bytes to be removed from the buffer.
+//!
+//! This function advances the ring buffer read index by a given number of
+//! bytes, removing that number of bytes of data from the buffer. If
+//! \e ui32NumBytes is larger than the number of bytes currently in the buffer,
+//! the buffer is emptied.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufAdvanceRead(tUSBRingBufObject *psUSBRingBuf, uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Make sure that we are not being asked to remove more data than is
+ // there to be removed.
+ //
+ ui32Count = USBRingBufUsed(psUSBRingBuf);
+ ui32Count = (ui32Count < ui32NumBytes) ? ui32Count : ui32NumBytes;
+
+ //
+ // Advance the buffer read index by the required number of bytes.
+ //
+ UpdateIndexAtomic(&psUSBRingBuf->ui32ReadIndex, ui32Count,
+ psUSBRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Adds bytes to the ring buffer by advancing the write index.
+//!
+//! \param psUSBRingBuf points to the ring buffer to which bytes have been
+//! added.
+//! \param ui32NumBytes is the number of bytes added to the buffer.
+//!
+//! This function should be used by clients who wish to add data to the buffer
+//! directly rather than via calls to USBRingBufWrite() or
+//! USBRingBufWriteOne(). It advances the write index by a given number of
+//! bytes.
+//!
+//! \note It is considered an error if the \e ui32NumBytes parameter is larger
+//! than the amount of free space in the buffer and a debug build of this
+//! function will fail (ASSERT) if this condition is detected. In a release
+//! build, the buffer read pointer will be advanced if too much data is written
+//! but this will, of course, result in some of the oldest data in the buffer
+//! being discarded and also, depending upon how data is being read from
+//! the buffer, may result in a race condition which could corrupt the read
+//! pointer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufAdvanceWrite(tUSBRingBufObject *psUSBRingBuf, uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Make sure we were not asked to add a silly number of bytes.
+ //
+ ASSERT(ui32NumBytes <= psUSBRingBuf->ui32Size);
+
+ //
+ // Determine how much free space we currently think the buffer has.
+ //
+ ui32Count = USBRingBufFree(psUSBRingBuf);
+
+ //
+ // Check that the client has not added more data to the buffer than there
+ // is space for. In this case, corruption may have occurred since the
+ // buffer may have been read under interrupt context while the writer was
+ // busy trashing the area around the read pointer.
+ //
+ ASSERT(ui32Count >= ui32NumBytes);
+
+ //
+ // Update the write pointer.
+ //
+ psUSBRingBuf->ui32WriteIndex += ui32NumBytes;
+
+ //
+ // Check and correct for wrap.
+ //
+ if(psUSBRingBuf->ui32WriteIndex >= psUSBRingBuf->ui32Size)
+ {
+ psUSBRingBuf->ui32WriteIndex -= psUSBRingBuf->ui32Size;
+ }
+
+ //
+ // Did the client add more bytes than the buffer had free space for? This
+ // should be considered a bug since, unless this function is called in
+ // the same context as the code which is reading from the buffer, writing
+ // over the earliest data can cause corrupted data to be read. The
+ // ASSERT above catches this in debug builds but, in release builds, we
+ // go ahead and try to fix up the read pointer appropriately.
+ //
+ if(ui32Count < ui32NumBytes)
+ {
+ //
+ // Yes - we need to advance the read pointer to ahead of the write
+ // pointer to discard some of the oldest data.
+ //
+ psUSBRingBuf->ui32ReadIndex = psUSBRingBuf->ui32WriteIndex + 1;
+
+ //
+ // Correct for buffer wrap if necessary.
+ //
+ if(psUSBRingBuf->ui32ReadIndex >= psUSBRingBuf->ui32Size)
+ {
+ psUSBRingBuf->ui32ReadIndex -= psUSBRingBuf->ui32Size;
+ }
+ }
+
+}
+
+//*****************************************************************************
+//
+//! Writes a single byte of data to a ring buffer.
+//!
+//! \param psUSBRingBuf points to the ring buffer to be written to.
+//! \param ui8Data is the byte to be written.
+//!
+//! This function writes a single byte of data into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufWriteOne(tUSBRingBufObject *psUSBRingBuf, uint8_t ui8Data)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(USBRingBufFree(psUSBRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ psUSBRingBuf->pui8Buf[psUSBRingBuf->ui32WriteIndex] = ui8Data;
+
+ //
+ // Increment the write index.
+ //
+ UpdateIndexAtomic(&psUSBRingBuf->ui32WriteIndex, 1,
+ psUSBRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Writes data to a ring buffer.
+//!
+//! \param psUSBRingBuf points to the ring buffer to be written to.
+//! \param pui8Data points to the data to be written.
+//! \param ui32Length is the number of bytes to be written.
+//!
+//! This function write a sequence of bytes into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufWrite(tUSBRingBufObject *psUSBRingBuf, const uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(ui32Length <= USBRingBufFree(psUSBRingBuf));
+
+ //
+ // Write the data into the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ USBRingBufWriteOne(psUSBRingBuf, pui8Data[ui32Temp]);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes a ring buffer object.
+//!
+//! \param psUSBRingBuf points to the ring buffer to be initialized.
+//! \param pui8Buf points to the data buffer to be used for the ring buffer.
+//! \param ui32Size is the size of the buffer in bytes.
+//!
+//! This function initializes a ring buffer object, preparing it to store data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBRingBufInit(tUSBRingBufObject *psUSBRingBuf, uint8_t *pui8Buf,
+ uint32_t ui32Size)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psUSBRingBuf != NULL);
+ ASSERT(pui8Buf != NULL);
+ ASSERT(ui32Size != 0);
+
+ //
+ // Initialize the ring buffer object.
+ //
+ psUSBRingBuf->ui32Size = ui32Size;
+ psUSBRingBuf->pui8Buf = pui8Buf;
+ psUSBRingBuf->ui32WriteIndex = psUSBRingBuf->ui32ReadIndex = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbtick.c b/usblib/usbtick.c
new file mode 100644
index 0000000..c2af1c1
--- /dev/null
+++ b/usblib/usbtick.c
@@ -0,0 +1,219 @@
+//*****************************************************************************
+//
+// usbtick.c - Functions related to USB stack tick timer handling.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup general_usblib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These are the internal timer tick handlers used by the USB stack. Handlers
+// in g_pfnTickHandlers are called in the context of the USB SOF interrupt
+// every USB_SOF_TICK_DIVIDE milliseconds.
+//
+//*****************************************************************************
+tUSBTickHandler g_pfnTickHandlers[MAX_USB_TICK_HANDLERS];
+void *g_pvTickInstance[MAX_USB_TICK_HANDLERS];
+
+//*****************************************************************************
+//
+// Flag to indicate whether or not we have been initialized.
+//
+//*****************************************************************************
+bool g_bUSBTimerInitialized = false;
+
+//*****************************************************************************
+//
+// This is the current tick value in ms for the system. This is used for all
+// instances of USB controllers and for all timer tick handlers.
+//
+//*****************************************************************************
+uint32_t g_ui32CurrentUSBTick = 0;
+
+//*****************************************************************************
+//
+// This is the total number of SOF interrupts received since the system
+// booted. The value is incremented by the low level device- or host-interrupt
+// handler functions.
+//
+//*****************************************************************************
+uint32_t g_ui32USBSOFCount = 0;
+
+//*****************************************************************************
+//
+// This internal function initializes the variables used in processing timer
+// ticks.
+//
+// This function should only be called from within the USB library. It is set
+// up to ensure that it can be called multiple times if necessary without
+// the previous configuration being erased (to cater for OTG mode switching).
+//
+// \return None.
+//
+//*****************************************************************************
+void
+InternalUSBTickInit(void)
+{
+ uint32_t ui32Loop;
+
+ if(!g_bUSBTimerInitialized)
+ {
+ for(ui32Loop = 0; ui32Loop < MAX_USB_TICK_HANDLERS; ui32Loop++)
+ {
+ g_pfnTickHandlers[ui32Loop] = (tUSBTickHandler)0;
+ g_pvTickInstance[ui32Loop] = 0;
+ }
+
+ g_bUSBTimerInitialized = true;
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function resets the USB tick handler.
+//
+// This function should only be called from within the USB library. It will
+// clear out the tick handler state and should be called to allow the tick
+// handlers to be initialized once USBDCDInit() function is called.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+InternalUSBTickReset(void)
+{
+ //
+ // Reset the initialized flag so that the next time InternalUSBTickInit()
+ // is called.
+ //
+ g_bUSBTimerInitialized = 0;
+}
+
+//*****************************************************************************
+//
+// This internal function handles registering OTG, Host, or Device SOF timer
+// handler functions.
+//
+// \param pfHandler specifies the handler to call for the given type of
+// handler.
+// \param pvInstance is the instance pointer that will be returned to the
+// function provided in the \e pfHandler function.
+//
+// This function should only be called inside the USB library and only as a
+// result to a call to reinitialize the stack in a new mode. Currently the
+// following 3 types of timer tick handlers can be registered:
+// TICK_HANDLER_OTG, TICK_HANDLER_HOST, or TICK_HANDLER_DEVICE. Handlers
+// registered via this function are called in the context of the SOF interrupt.
+//
+// \return A value of zero means that the tick handler was registered and any
+// other value indicates an error.
+//
+//*****************************************************************************
+int32_t
+InternalUSBRegisterTickHandler(tUSBTickHandler pfHandler, void *pvInstance)
+{
+ int32_t i32Idx;
+
+ for(i32Idx = 0; i32Idx < MAX_USB_TICK_HANDLERS; i32Idx++)
+ {
+ if(g_pfnTickHandlers[i32Idx] == 0)
+ {
+ //
+ // Save the handler.
+ //
+ g_pfnTickHandlers[i32Idx] = pfHandler;
+
+ //
+ // Save the instance data.
+ //
+ g_pvTickInstance[i32Idx] = pvInstance;
+
+ break;
+ }
+ }
+
+ if(i32Idx == MAX_USB_TICK_HANDLERS)
+ {
+ return(-1);
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//!
+//! Calls internal handlers in response to a tick based on the start of frame
+//! interrupt.
+//!
+//! \param ui32TicksmS specifies how many milliseconds have passed since the
+//! last call to this function.
+//!
+//! This function is called every 5mS in the context of the Start of Frame
+//! (SOF) interrupt. It is used to call any registered internal tick
+//! functions.
+//!
+//! This function should only be called from within the USB library.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+InternalUSBStartOfFrameTick(uint32_t ui32TicksmS)
+{
+ int32_t i32Idx;
+
+ //
+ // Advance time.
+ //
+ g_ui32CurrentUSBTick += ui32TicksmS;
+
+ //
+ // Call any registered SOF tick handlers.
+ //
+ for(i32Idx = 0; i32Idx < MAX_USB_TICK_HANDLERS; i32Idx++)
+ {
+ if(g_pfnTickHandlers[i32Idx])
+ {
+ g_pfnTickHandlers[i32Idx](g_pvTickInstance[i32Idx], ui32TicksmS);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/usbulpi.c b/usblib/usbulpi.c
new file mode 100644
index 0000000..dbbf68a
--- /dev/null
+++ b/usblib/usbulpi.c
@@ -0,0 +1,176 @@
+//*****************************************************************************
+//
+// usbulpi.c - ULPI access functions.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usbulpi.h"
+
+//*****************************************************************************
+//
+// Hardware ULPI registers.
+//
+//*****************************************************************************
+#define ULPI_FCTL 0x04
+#define ULPI_FCTL_SET 0x05
+#define ULPI_FCTL_CLEAR 0x06
+#define ULPI_ICTL 0x07
+#define ULPI_ICTL_SET 0x08
+#define ULPI_ICTL_CLEAR 0x09
+#define ULPI_OTGCTL 0x0A
+#define ULPI_OTGCTL_SET 0x0B
+#define ULPI_OTGCTL_CLEAR 0x0C
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the ULPI_FCTL register.
+//
+//*****************************************************************************
+#define ULPI_FCTL_XCVR_M 0x03
+#define ULPI_FCTL_XCVR_HS 0x00
+#define ULPI_FCTL_XCVR_FS 0x01
+#define ULPI_FCTL_XCVR_LS 0x02
+#define ULPI_FCTL_XCVR_FSLS 0x03
+#define ULPI_FCTL_TERMSEL 0x04
+#define ULPI_FCTL_OPMODE_M 0x18
+#define ULPI_FCTL_OPMODE_NORM 0x00
+#define ULPI_FCTL_OPMODE_NODRV 0x08
+#define ULPI_FCTL_OPMODE_NONRZI 0x10
+#define ULPI_FCTL_OPMODE_DISAUTO \
+ 0x18
+#define ULPI_FCTL_OPMODE_RESET 0x20
+#define ULPI_FCTL_OPMODE_SUSPEND \
+ 0x40
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the ULPI_ICTL register.
+//
+//*****************************************************************************
+#define ULPI_ICTL_SER6PIN 0x01
+#define ULPI_ICTL_SER3PIN 0x02
+#define ULPI_ICTL_AUTORESUME 0x10
+#define ULPI_ICTL_INDINV 0x20
+#define ULPI_ICTL_INDPASSTHRU 0x40
+#define ULPI_ICTL_PROTDIS 0x80
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the ULPI_OTGCTL register.
+//
+//*****************************************************************************
+#define ULPI_OTGCTL_ID_EN 0x01
+#define ULPI_OTGCTL_DPPD_EN 0x02
+#define ULPI_OTGCTL_DMPD_EN 0x04
+#define ULPI_OTGCTL_DISCHRG_VBUS \
+ 0x08
+#define ULPI_OTGCTL_CHRG_VBUS 0x10
+#define ULPI_OTGCTL_VBUSINT_EN 0x20
+#define ULPI_OTGCTL_VBUSEXT_EN 0x40
+#define ULPI_OTGCTL_VBUSEXT_IND 0x80
+
+//*****************************************************************************
+//
+//! Sets the configuration of an external USB Phy.
+//!
+//! \param ui32Base specifies the USB module base address.
+//! \param ui32Config specifies the configuration options for the external Phy.
+//!
+//! This function sets the configuration options for an externally connected
+//! USB Phy that is connected using the ULPI interface. The \e ui32Config
+//! parameter holds all of the configuration options defined by the
+//! \b UPLI_CFG_ values. The values are grouped as follows:
+//!
+//! Connection speed, using one of the following:
+//! - \b UPLI_CFG_HS enables high speed operation.
+//! - \b UPLI_CFG_FS enables full speed operation.
+//! - \b UPLI_CFG_HS enables low speed operation.
+//!
+//! Any of the following can be included:
+//! - \b UPLI_CFG_AUTORESUME enable automatic transmission of resume signaling
+//! from the Phy.
+//! - \b UPLI_CFG_INVVBUSIND inverts the external VBUS indicator if it is
+//! selected.
+//! - \b UPLI_CFG_PASSTHRUIND passes the external VBUS indicator through
+//! without using the Phy's VBUS comparator.
+//! - \b ULPI_CFG_EXTVBUSDRV enables an external VBUS drive source.
+//! - \b ULPI_CFG_EXTVBUSIND enables an external signal for VBUS valid.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ULPIConfigSet(uint32_t ui32Base, uint32_t ui32Config)
+{
+ uint8_t ui8Val;
+
+ ui8Val = USBULPIRegRead(ui32Base, ULPI_FCTL);
+ ui8Val &= ~(ULPI_FCTL_XCVR_M);
+ ui8Val = ui8Val | (uint8_t)ui32Config;
+
+ USBULPIRegWrite(ui32Base, ULPI_FCTL, ui8Val);
+
+ ui8Val = USBULPIRegRead(ui32Base, ULPI_ICTL);
+ ui8Val &= ~(ULPI_ICTL_AUTORESUME | ULPI_ICTL_INDINV |
+ ULPI_ICTL_INDPASSTHRU);
+ ui8Val = ui8Val | (uint8_t)((ui32Config >> 8) & 0xff);
+
+ USBULPIRegWrite(ui32Base, ULPI_ICTL, ui8Val);
+
+ ui8Val = USBULPIRegRead(ui32Base, ULPI_OTGCTL);
+ ui8Val &= ~(ULPI_OTGCTL_VBUSINT_EN | ULPI_OTGCTL_VBUSEXT_EN |
+ ULPI_OTGCTL_VBUSEXT_IND);
+ ui8Val = ui8Val | (uint8_t)((ui32Config >> 16) & 0xff);
+
+ USBULPIRegWrite(ui32Base, ULPI_OTGCTL, ui8Val);
+}
+
+//*****************************************************************************
+//
+//! Enables or disables power to the external USB Phy.
+//!
+//! \param ui32Base specifies the USB module base address.
+//! \param bEnable specifies if the Phy is fully powered or in suspend mode.
+//!
+//! This function sets the current power configuration for the external ULPI
+//! connected Phy. When \e bEnable is \b true the Phy is fully powered and
+//! when \b false the USB Phy is in suspend mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ULPIPowerTransceiver(uint32_t ui32Base, bool bEnable)
+{
+ if(bEnable)
+ {
+ USBULPIRegWrite(ui32Base, ULPI_FCTL_CLEAR,
+ ULPI_FCTL_OPMODE_SUSPEND);
+ }
+ else
+ {
+ USBULPIRegWrite(ui32Base, ULPI_FCTL_SET,
+ ULPI_FCTL_OPMODE_SUSPEND);
+ }
+}
diff --git a/usblib/usbulpi.h b/usblib/usbulpi.h
new file mode 100644
index 0000000..9943d24
--- /dev/null
+++ b/usblib/usbulpi.h
@@ -0,0 +1,40 @@
+//*****************************************************************************
+//
+// usbulpi.h - Header file for ULPI access functions.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __ULPI_H__
+#define __ULPI_H__
+
+#define ULPI_CFG_HS 0x00000000
+#define ULPI_CFG_FS 0x00000001
+#define ULPI_CFG_LS 0x00000002
+#define ULPI_CFG_AUTORESUME 0x00001000
+#define ULPI_CFG_INVVBUSIND 0x00002000
+#define ULPI_CFG_PASSTHRUIND 0x00004000
+#define ULPI_CFG_EXTVBUSDRV 0x00400000
+#define ULPI_CFG_EXTVBUSIND 0x00800000
+
+extern void ULPIConfigSet(uint32_t ui32Base, uint32_t ui32Config);
+extern void ULPIPowerTransceiver(uint32_t ui32Base, bool bEnable);
+
+#endif
diff --git a/utils/cmdline.c b/utils/cmdline.c
new file mode 100644
index 0000000..c9f5971
--- /dev/null
+++ b/utils/cmdline.c
@@ -0,0 +1,193 @@
+//*****************************************************************************
+//
+// cmdline.c - Functions to help with processing command lines.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "utils/cmdline.h"
+
+//*****************************************************************************
+//
+// Defines the maximum number of arguments that can be parsed.
+//
+//*****************************************************************************
+#ifndef CMDLINE_MAX_ARGS
+#define CMDLINE_MAX_ARGS 8
+#endif
+
+//*****************************************************************************
+//
+// An array to hold the pointers to the command line arguments.
+//
+//*****************************************************************************
+static char *g_ppcArgv[CMDLINE_MAX_ARGS + 1];
+
+//*****************************************************************************
+//
+//! Process a command line string into arguments and execute the command.
+//!
+//! \param pcCmdLine points to a string that contains a command line that was
+//! obtained by an application by some means.
+//!
+//! This function will take the supplied command line string and break it up
+//! into individual arguments. The first argument is treated as a command and
+//! is searched for in the command table. If the command is found, then the
+//! command function is called and all of the command line arguments are passed
+//! in the normal argc, argv form.
+//!
+//! The command table is contained in an array named <tt>g_psCmdTable</tt>
+//! containing <tt>tCmdLineEntry</tt> structures which must be provided by the
+//! application. The array must be terminated with an entry whose \b pcCmd
+//! field contains a NULL pointer.
+//!
+//! \return Returns \b CMDLINE_BAD_CMD if the command is not found,
+//! \b CMDLINE_TOO_MANY_ARGS if there are more arguments than can be parsed.
+//! Otherwise it returns the code that was returned by the command function.
+//
+//*****************************************************************************
+int
+CmdLineProcess(char *pcCmdLine)
+{
+ char *pcChar;
+ uint_fast8_t ui8Argc;
+ bool bFindArg = true;
+ tCmdLineEntry *psCmdEntry;
+
+ //
+ // Initialize the argument counter, and point to the beginning of the
+ // command line string.
+ //
+ ui8Argc = 0;
+ pcChar = pcCmdLine;
+
+ //
+ // Advance through the command line until a zero character is found.
+ //
+ while(*pcChar)
+ {
+ //
+ // If there is a space, then replace it with a zero, and set the flag
+ // to search for the next argument.
+ //
+ if(*pcChar == ' ')
+ {
+ *pcChar = 0;
+ bFindArg = true;
+ }
+
+ //
+ // Otherwise it is not a space, so it must be a character that is part
+ // of an argument.
+ //
+ else
+ {
+ //
+ // If bFindArg is set, then that means we are looking for the start
+ // of the next argument.
+ //
+ if(bFindArg)
+ {
+ //
+ // As long as the maximum number of arguments has not been
+ // reached, then save the pointer to the start of this new arg
+ // in the argv array, and increment the count of args, argc.
+ //
+ if(ui8Argc < CMDLINE_MAX_ARGS)
+ {
+ g_ppcArgv[ui8Argc] = pcChar;
+ ui8Argc++;
+ bFindArg = false;
+ }
+
+ //
+ // The maximum number of arguments has been reached so return
+ // the error.
+ //
+ else
+ {
+ return(CMDLINE_TOO_MANY_ARGS);
+ }
+ }
+ }
+
+ //
+ // Advance to the next character in the command line.
+ //
+ pcChar++;
+ }
+
+ //
+ // If one or more arguments was found, then process the command.
+ //
+ if(ui8Argc)
+ {
+ //
+ // Start at the beginning of the command table, to look for a matching
+ // command.
+ //
+ psCmdEntry = &g_psCmdTable[0];
+
+ //
+ // Search through the command table until a null command string is
+ // found, which marks the end of the table.
+ //
+ while(psCmdEntry->pcCmd)
+ {
+ //
+ // If this command entry command string matches argv[0], then call
+ // the function for this command, passing the command line
+ // arguments.
+ //
+ if(!strcmp(g_ppcArgv[0], psCmdEntry->pcCmd))
+ {
+ return(psCmdEntry->pfnCmd(ui8Argc, g_ppcArgv));
+ }
+
+ //
+ // Not found, so advance to the next entry.
+ //
+ psCmdEntry++;
+ }
+ }
+
+ //
+ // Fall through to here means that no matching command was found, so return
+ // an error.
+ //
+ return(CMDLINE_BAD_CMD);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cmdline.h b/utils/cmdline.h
new file mode 100644
index 0000000..42ab9ea
--- /dev/null
+++ b/utils/cmdline.h
@@ -0,0 +1,137 @@
+//*****************************************************************************
+//
+// cmdline.h - Prototypes for command line processing functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __CMDLINE_H__
+#define __CMDLINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if the command is not found.
+//
+//*****************************************************************************
+#define CMDLINE_BAD_CMD (-1)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too many arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_MANY_ARGS (-2)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too few arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_FEW_ARGS (-3)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if an argument is invalid.
+//
+//*****************************************************************************
+#define CMDLINE_INVALID_ARG (-4)
+
+//*****************************************************************************
+//
+// Command line function callback type.
+//
+//*****************************************************************************
+typedef int (*pfnCmdLine)(int argc, char *argv[]);
+
+//*****************************************************************************
+//
+//! Structure for an entry in the command list table.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to a string containing the name of the command.
+ //
+ const char *pcCmd;
+
+ //
+ //! A function pointer to the implementation of the command.
+ //
+ pfnCmdLine pfnCmd;
+
+ //
+ //! A pointer to a string of brief help text for the command.
+ //
+ const char *pcHelp;
+}
+tCmdLineEntry;
+
+//*****************************************************************************
+//
+//! This is the command table that must be provided by the application. The
+//! last element of the array must be a structure whose pcCmd field contains
+//! a NULL pointer.
+//
+//*****************************************************************************
+extern tCmdLineEntry g_psCmdTable[];
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern int CmdLineProcess(char *pcCmdLine);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CMDLINE_H__
diff --git a/utils/cpu_usage.c b/utils/cpu_usage.c
new file mode 100644
index 0000000..1adf020
--- /dev/null
+++ b/utils/cpu_usage.c
@@ -0,0 +1,206 @@
+//*****************************************************************************
+//
+// cpu_usage.c - Routines to determine the CPU utilization.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+#include <stdint.h>
+#include <stdbool.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/timer.h"
+#include "utils/cpu_usage.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cpu_usage_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The peripheral identifier for the timer modules that could be used for
+// tracking CPU utilization.
+//
+//*****************************************************************************
+static uint32_t g_pui32CPUUsageTimerPeriph[6] =
+{
+ SYSCTL_PERIPH_TIMER0, SYSCTL_PERIPH_TIMER1, SYSCTL_PERIPH_TIMER2,
+ SYSCTL_PERIPH_TIMER3, SYSCTL_PERIPH_TIMER4, SYSCTL_PERIPH_TIMER5
+};
+
+//*****************************************************************************
+//
+// The base address of the timer modules that could be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static uint32_t g_pui32CPUUsageTimerBase[6] =
+{
+ TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE, TIMER4_BASE,
+ TIMER5_BASE
+};
+
+//*****************************************************************************
+//
+// The index of the timer module that will be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsageTimer;
+
+//*****************************************************************************
+//
+// The number of processor clock ticks per timing period.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsageTicks;
+
+//*****************************************************************************
+//
+// The value of timer two on the previous timing period. This is used to
+// determine the number of clock ticks counted by the timer during the timing
+// period.
+//
+//*****************************************************************************
+static uint32_t g_ui32CPUUsagePrevious;
+
+//*****************************************************************************
+//
+//! Updates the CPU usage for the new timing period.
+//!
+//! This function, when called at the end of a timing period, will update the
+//! CPU usage.
+//!
+//! \return Returns the CPU usage percentage as a 16.16 fixed-point value.
+//
+//*****************************************************************************
+uint32_t
+CPUUsageTick(void)
+{
+ uint32_t ui32Value, ui32Usage;
+
+ //
+ // Get the current value of the timer.
+ //
+ ui32Value =
+ MAP_TimerValueGet(g_pui32CPUUsageTimerBase[g_ui32CPUUsageTimer],
+ TIMER_A);
+
+ //
+ // Based on the number of clock ticks accumulated by the timer during the
+ // previous timing period, compute the CPU usage as a 16.16 fixed-point
+ // value.
+ //
+ ui32Usage = ((((g_ui32CPUUsagePrevious - ui32Value) * 6400) /
+ g_ui32CPUUsageTicks) * 1024);
+
+ //
+ // Save the previous value of the timer.
+ //
+ g_ui32CPUUsagePrevious = ui32Value;
+
+ //
+ // Return the new CPU usage value.
+ //
+ return(ui32Usage);
+}
+
+//*****************************************************************************
+//
+//! Initializes the CPU usage measurement module.
+//!
+//! \param ui32ClockRate is the rate of the clock supplied to the timer module.
+//! \param ui32Rate is the number of times per second that CPUUsageTick() is
+//! called.
+//! \param ui32Timer is the index of the timer module to use.
+//!
+//! This function prepares the CPU usage measurement module for measuring the
+//! CPU usage of the application.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CPUUsageInit(uint32_t ui32ClockRate, uint32_t ui32Rate, uint32_t ui32Timer)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32ClockRate > ui32Rate);
+ ASSERT(ui32Timer < 6);
+
+ //
+ // Save the timer index.
+ //
+ g_ui32CPUUsageTimer = ui32Timer;
+
+ //
+ // Determine the number of system clocks per measurement period.
+ //
+ g_ui32CPUUsageTicks = ui32ClockRate / ui32Rate;
+
+ //
+ // Set the previous value of the timer to the initial timer value.
+ //
+ g_ui32CPUUsagePrevious = 0xffffffff;
+
+ //
+ // Enable peripheral clock gating.
+ //
+ MAP_SysCtlPeripheralClockGating(true);
+
+ //
+ // Enable the third timer while the processor is in run mode, but disable
+ // it in sleep mode. It will therefore count system clocks when the
+ // processor is running but not when it is sleeping.
+ //
+ MAP_SysCtlPeripheralEnable(g_pui32CPUUsageTimerPeriph[ui32Timer]);
+ MAP_SysCtlPeripheralSleepDisable(g_pui32CPUUsageTimerPeriph[ui32Timer]);
+
+ //
+ // Configure the third timer for 32-bit periodic operation.
+ //
+ MAP_TimerConfigure(g_pui32CPUUsageTimerBase[ui32Timer],
+ TIMER_CFG_PERIODIC);
+
+ //
+ // Set the load value for the third timer to the maximum value.
+ //
+ MAP_TimerLoadSet(g_pui32CPUUsageTimerBase[ui32Timer], TIMER_A, 0xffffffff);
+
+ //
+ // Enable the third timer. It will now count the number of system clocks
+ // during which the processor is executing code.
+ //
+ MAP_TimerEnable(g_pui32CPUUsageTimerBase[ui32Timer], TIMER_A);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cpu_usage.h b/utils/cpu_usage.h
new file mode 100644
index 0000000..181ea2c
--- /dev/null
+++ b/utils/cpu_usage.h
@@ -0,0 +1,57 @@
+//*****************************************************************************
+//
+// cpu_usage.h - Prototypes for the CPU utilization routines.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __CPU_USAGE_H__
+#define __CPU_USAGE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the CPU utilization routines.
+//
+//*****************************************************************************
+extern uint32_t CPUUsageTick(void);
+extern void CPUUsageInit(uint32_t ui32ClockRate, uint32_t ui32Rate,
+ uint32_t ui32Timer);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CPU_USAGE_H__
diff --git a/utils/flash_pb.c b/utils/flash_pb.c
new file mode 100644
index 0000000..ac85830
--- /dev/null
+++ b/utils/flash_pb.c
@@ -0,0 +1,493 @@
+//*****************************************************************************
+//
+// flash_pb.c - Flash parameter block functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_flash.h"
+#include "inc/hw_types.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/debug.h"
+#include "driverlib/flash.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "utils/flash_pb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup flash_pb_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The address of the beginning of the flash used for storing parameter blocks;
+// this must be the start of an erase block in the flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBStart;
+
+//*****************************************************************************
+//
+// The address of the end of the flash used for storing parameter blocks; this
+// must be the start of an erase block in the flash, or the first location
+// after the end of the flash array if the last erase block is used for storing
+// parameters.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBEnd;
+
+//*****************************************************************************
+//
+// The size of the parameter block when stored in flash; this must be a power
+// of two less than or equal to the flash erase sector size such that a single
+// flash sector contains an integral number of parameter blocks.
+//
+//*****************************************************************************
+static uint32_t g_ui32FlashPBSize;
+
+//*****************************************************************************
+//
+// The address of the most recent parameter block in flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBCurrent;
+
+//*****************************************************************************
+//
+// The erase sector size of the current flash.
+//
+//*****************************************************************************
+#define FLASH_SECTOR_SIZE MAP_SysCtlFlashSectorSizeGet()
+
+//*****************************************************************************
+//
+//! Determines if the parameter block at the given address is valid.
+//!
+//! \param pui8Offset is the address of the parameter block to check.
+//!
+//! This function will compute the checksum of a parameter block in flash to
+//! determine if it is valid.
+//!
+//! \return Returns one if the parameter block is valid and zero if it is not.
+//
+//*****************************************************************************
+static uint32_t
+FlashPBIsValid(uint8_t *pui8Offset)
+{
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Offset != (void *)0);
+
+ //
+ // Loop through the bytes in the block, computing the checksum.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum += pui8Offset[ui32Idx];
+ }
+
+ //
+ // The checksum should be zero, so return a failure if it is not.
+ //
+ if((ui32Sum & 255) != 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the sum is equal to the size * 255, then the block is all ones and
+ // should not be considered valid.
+ //
+ if((g_ui32FlashPBSize * 255) == ui32Sum)
+ {
+ return(0);
+ }
+
+ //
+ // This is a valid parameter block.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the address of the most recent parameter block.
+//!
+//! This function returns the address of the most recent parameter block that
+//! is stored in flash.
+//!
+//! \return Returns the address of the most recent parameter block, or NULL if
+//! there are no valid parameter blocks in flash.
+//
+//*****************************************************************************
+uint8_t *
+FlashPBGet(void)
+{
+ //
+ // See if there is a valid parameter block.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Return the address of the most recent parameter block.
+ //
+ return(g_pui8FlashPBCurrent);
+ }
+
+ //
+ // There are no valid parameter blocks in flash, so return NULL.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Writes a new parameter block to flash.
+//!
+//! \param pui8Buffer is the address of the parameter block to be written to
+//! flash.
+//!
+//! This function will write a parameter block to flash. Saving the new
+//! parameter blocks involves three steps:
+//!
+//! - Setting the sequence number such that it is one greater than the sequence
+//! number of the latest parameter block in flash.
+//! - Computing the checksum of the parameter block.
+//! - Writing the parameter block into the storage immediately following the
+//! latest parameter block in flash; if that storage is at the start of an
+//! erase block, that block is erased first.
+//!
+//! By this process, there is always a valid parameter block in flash. If
+//! power is lost while writing a new parameter block, the checksum will not
+//! match and the partially written parameter block will be ignored. This is
+//! what makes this fault-tolerant.
+//!
+//! Another benefit of this scheme is that it provides wear leveling on the
+//! flash. Since multiple parameter blocks fit into each erase block of flash,
+//! and multiple erase blocks are used for parameter block storage, it takes
+//! quite a few parameter block saves before flash is re-written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBSave(uint8_t *pui8Buffer)
+{
+ uint8_t *pui8New;
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Buffer != (void *)0);
+
+ //
+ // See if there is a valid parameter block in flash.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Set the sequence number to one greater than the most recent
+ // parameter block.
+ //
+ pui8Buffer[0] = g_pui8FlashPBCurrent[0] + 1;
+
+ //
+ // Try to write the new parameter block immediately after the most
+ // recent parameter block.
+ //
+ pui8New = g_pui8FlashPBCurrent + g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+ }
+ else
+ {
+ //
+ // There is not a valid parameter block in flash, so set the sequence
+ // number of this parameter block to zero.
+ //
+ pui8Buffer[0] = 0;
+
+ //
+ // Try to write the new parameter block at the beginning of the flash
+ // space for parameter blocks.
+ //
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // Compute the checksum of the parameter block to be written.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum -= pui8Buffer[ui32Idx];
+ }
+
+ //
+ // Store the checksum into the parameter block.
+ //
+ pui8Buffer[1] += ui32Sum;
+
+ //
+ // Look for a location to store this parameter block. This infinite loop
+ // will be explicitly broken out of when a valid location is found.
+ //
+ while(1)
+ {
+ //
+ // See if this location is at the start of an erase block.
+ //
+ if(((uint32_t)pui8New & (FLASH_SECTOR_SIZE - 1)) == 0)
+ {
+ //
+ // Erase this block of the flash. This does not assume that the
+ // erase succeeded in case this block of the flash has become bad
+ // through too much use. Given the extremely low frequency that
+ // the parameter blocks are written, this will likely never fail.
+ // But, that assumption is not made in order to be safe.
+ //
+ MAP_FlashErase((uint32_t)pui8New);
+ }
+
+ //
+ // Loop through this portion of flash to see if is all ones (in other
+ // words, it is an erased portion of flash).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != 0xff)
+ {
+ break;
+ }
+ }
+
+ //
+ // If all bytes in this portion of flash are ones, then break out of
+ // the loop since this is a good location for storing the parameter
+ // block.
+ //
+ if(ui32Idx == g_ui32FlashPBSize)
+ {
+ break;
+ }
+
+ //
+ // Increment to the next parameter block location.
+ //
+ pui8New += g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // If every possible location has been checked and none are valid, then
+ // it will not be possible to write this parameter block. Simply
+ // return without writing it.
+ //
+ if((g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBCurrent)) ||
+ (!g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBStart)))
+ {
+ return;
+ }
+ }
+
+ //
+ // Write this parameter block to flash.
+ //
+ MAP_FlashProgram((uint32_t *)pui8Buffer, (uint32_t)pui8New,
+ g_ui32FlashPBSize);
+
+ //
+ // Compare the parameter block data to the data that should now be in
+ // flash. Return if any of the data does not compare, leaving the previous
+ // parameter block in flash as the most recent (since the current parameter
+ // block failed to properly program).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != pui8Buffer[ui32Idx])
+ {
+ return;
+ }
+ }
+
+ //
+ // The new parameter block becomes the most recent parameter block.
+ //
+ g_pui8FlashPBCurrent = pui8New;
+}
+
+//*****************************************************************************
+//
+//! Initializes the flash parameter block.
+//!
+//! \param ui32Start is the address of the flash memory to be used for storing
+//! flash parameter blocks; this must be the start of an erase block in the
+//! flash.
+//! \param ui32End is the address of the end of flash memory to be used for
+//! storing flash parameter blocks; this must be the start of an erase block in
+//! the flash (the first block that is NOT part of the flash memory to be
+//! used), or the address of the first word after the flash array if the last
+//! block of flash is to be used.
+//! \param ui32Size is the size of the parameter block when stored in flash;
+//! this must be a power of two less than or equal to the flash erase block
+//! size (typically 1024).
+//!
+//! This function initializes a fault-tolerant, persistent storage mechanism
+//! for a parameter block for an application. The last several erase blocks
+//! of flash (as specified by \e ui32Start and \e ui32End are used for the
+//! storage; more than one erase block is required in order to be
+//! fault-tolerant.
+//!
+//! A parameter block is an array of bytes that contain the persistent
+//! parameters for the application. The only special requirement for the
+//! parameter block is that the first byte is a sequence number (explained
+//! in FlashPBSave()) and the second byte is a checksum used to validate the
+//! correctness of the data (the checksum byte is the byte such that the sum of
+//! all bytes in the parameter block is zero).
+//!
+//! The portion of flash for parameter block storage is split into N
+//! equal-sized regions, where each region is the size of a parameter block
+//! (\e ui32Size). Each region is scanned to find the most recent valid
+//! parameter block. The region that has a valid checksum and has the highest
+//! sequence number (with special consideration given to wrapping back to zero)
+//! is considered to be the current parameter block.
+//!
+//! In order to make this efficient and effective, three conditions must be
+//! met. The first is \e ui32Start and \e ui32End must be specified such that
+//! at least two erase blocks of flash are dedicated to parameter block
+//! storage. If not, fault tolerance can not be guaranteed since an erase of a
+//! single block will leave a window where there are no valid parameter blocks
+//! in flash. The second condition is that the size (\e ui32Size) of the
+//! parameter block must be an integral divisor of the size of an erase block
+//! of flash. If not, a parameter block will end up spanning between two erase
+//! blocks of flash, making it more difficult to manage. The final condition
+//! is that the size of the flash dedicated to parameter blocks (\e ui32End -
+//! \e ui32Start) divided by the parameter block size (\e ui32Size) must be
+//! less than or equal to 128. If not, it will not be possible in all cases to
+//! determine which parameter block is the most recent (specifically when
+//! dealing with the sequence number wrapping back to zero).
+//!
+//! When the microcontroller is initially programmed, the flash blocks used for
+//! parameter block storage are left in an erased state.
+//!
+//! This function must be called before any other flash parameter block
+//! functions are called.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBInit(uint32_t ui32Start, uint32_t ui32End, uint32_t ui32Size)
+{
+ uint8_t *pui8Offset, *pui8Current;
+ uint8_t ui8One, ui8Two;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Start % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((ui32End % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((FLASH_SECTOR_SIZE % ui32Size) == 0);
+
+ //
+ // Save the characteristics of the flash memory to be used for storing
+ // parameter blocks.
+ //
+ g_pui8FlashPBStart = (uint8_t *)ui32Start;
+ g_pui8FlashPBEnd = (uint8_t *)ui32End;
+ g_ui32FlashPBSize = ui32Size;
+
+ //
+ // Loop through the portion of flash memory used for storing parameter
+ // blocks.
+ //
+ for(pui8Offset = g_pui8FlashPBStart, pui8Current = 0;
+ pui8Offset < g_pui8FlashPBEnd; pui8Offset += g_ui32FlashPBSize)
+ {
+ //
+ // See if this is a valid parameter block (in other words, the checksum
+ // is correct).
+ //
+ if(FlashPBIsValid(pui8Offset))
+ {
+ //
+ // See if a valid parameter block has been previously found.
+ //
+ if(pui8Current != 0)
+ {
+ //
+ // Get the sequence numbers for the current and new parameter
+ // blocks.
+ //
+ ui8One = pui8Current[0];
+ ui8Two = pui8Offset[0];
+
+ //
+ // See if the sequence number for the new parameter block is
+ // greater than the current block. The comparison isn't
+ // straightforward since the one byte sequence number will wrap
+ // after 256 parameter blocks.
+ //
+ if(((ui8One > ui8Two) && ((ui8One - ui8Two) < 128)) ||
+ ((ui8Two > ui8One) && ((ui8Two - ui8One) > 128)))
+ {
+ //
+ // The new parameter block is older than the current
+ // parameter block, so skip the new parameter block and
+ // keep searching.
+ //
+ continue;
+ }
+ }
+
+ //
+ // The new parameter block is more recent than the current one, so
+ // make it the new current parameter block.
+ //
+ pui8Current = pui8Offset;
+ }
+ }
+
+ //
+ // Save the address of the most recent parameter block found. If no valid
+ // parameter blocks were found, this will be a NULL pointer.
+ //
+ g_pui8FlashPBCurrent = pui8Current;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/flash_pb.h b/utils/flash_pb.h
new file mode 100644
index 0000000..f68329d
--- /dev/null
+++ b/utils/flash_pb.h
@@ -0,0 +1,58 @@
+//*****************************************************************************
+//
+// flash_pb.h - Prototypes for the flash parameter block functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __FLASH_PB_H__
+#define __FLASH_PB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototype for the flash parameter block functions.
+//
+//*****************************************************************************
+extern uint8_t *FlashPBGet(void);
+extern void FlashPBSave(uint8_t *pui8Buffer);
+extern void FlashPBInit(uint32_t ui32Start, uint32_t ui32End,
+ uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FLASH_PB_H__
diff --git a/utils/fswrapper.c b/utils/fswrapper.c
new file mode 100644
index 0000000..74e80af
--- /dev/null
+++ b/utils/fswrapper.c
@@ -0,0 +1,860 @@
+//*****************************************************************************
+//
+// fswrapper.c - File System Processing for lwIP Web Server Apps.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "httpserver_raw/fs.h"
+#include "httpserver_raw/fsdata.h"
+#include "fatfs/src/ff.h"
+#include "fatfs/src/diskio.h"
+#include "utils/fswrapper.h"
+#include "utils/lwiplib.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup fswrapper_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Static file system images for use with this module may be created using
+// the makefsfile.exe utility. Both position-independent (built using the -b
+// command line option to makefsfile) and position dependent file system images
+// may be used.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The index of the file system containing this file.
+ //
+ uint32_t ui32MountIndex;
+
+ //
+ // The FatFs file structure allocated if the target file is in the FAT
+ // file system.
+ //
+ FIL *psFATFile;
+}
+fs_wrapper_data;
+
+//*****************************************************************************
+//
+// A marker used to indicate that a passed filename cannot be mapped to any of
+// the configured mount points.
+//
+//*****************************************************************************
+#define BAD_MOUNT_INDEX 0xFFFFFFFF
+
+//*****************************************************************************
+//
+// This macro is used to extract pointers from the file descriptors. We
+// support files systems linked into the image as well as external, position
+// independent file system images and this macro allows us to use the same code
+// to extract pointers from file descriptors in each case.
+//
+//*****************************************************************************
+#define FS_POINTER(ptTree, ptValue, bPosInd) \
+ ((char *)((bPosInd) ? ((int8_t *)(ptTree) + (uint32_t)(ptValue)) : \
+ (int8_t *)(ptValue)))
+
+//*****************************************************************************
+//
+// The pointer to the mount point table and the number of entries in the
+// table.
+//
+//*****************************************************************************
+static fs_mount_data *g_psMountPoints = NULL;
+static uint32_t g_ui32NumMountPoints = 0;
+static uint32_t g_ui32DefaultMountIndex = BAD_MOUNT_INDEX;
+static bool g_bFatFsEnabled = false;
+
+//*****************************************************************************
+//
+// Given a filename, this function determine which of the configured mount
+// points it resides under. It returns the index of the mount point in the
+// g_psMountPoints array and also a pointer to the first character of the
+// filename with the mount point name (directory) stripped from it.
+//
+//*****************************************************************************
+static uint32_t
+fs_find_mount_index(const char *pcName, char **ppcFSFilename)
+{
+ uint32_t ui32Loop;
+ int iLenDirName;
+ int iLenMountName;
+ char *pcSlash;
+
+ //
+ // First extract the top level directory name which we need to match
+ // with the mount point name. For this to exist, the pcName string
+ // must start with a '/' character and must contain at least one more
+ // '/'.
+ //
+ if(pcName[0] == '/')
+ {
+ //
+ // The string starts with a '/'. Does it contain a second one?
+ //
+ pcSlash = strchr(pcName + 1, '/');
+
+ //
+ // Did we find another forward slash character?
+ //
+ if(pcSlash)
+ {
+ //
+ // Yes - the mount point name is between the start of the
+ // string and the slash we just found. How long is this string?
+ //
+ iLenDirName = (int)(pcSlash - (pcName + 1));
+ }
+ else
+ {
+ //
+ // The mount point name is the whole string.
+ //
+ iLenDirName = ustrlen(pcName + 1);
+ pcSlash = (char *)pcName + 1 + iLenDirName;
+ }
+
+ //
+ // Now figure out which, if any, of the mount points this matches.
+ //
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // Skip the default mount point if found.
+ //
+ if(!g_psMountPoints[ui32Loop].pcNamePrefix)
+ {
+ continue;
+ }
+
+ //
+ // How long is the name of this mount point?
+ //
+ iLenMountName = ustrlen(g_psMountPoints[ui32Loop].pcNamePrefix);
+
+ //
+ // Does the mount point name match the directory name extracted
+ // from the passed pcName?
+ //
+ if(iLenMountName == iLenDirName)
+ {
+ //
+ // The lengths match but are the strings the same?
+ //
+ if(!ustrncmp(g_psMountPoints[ui32Loop].pcNamePrefix,
+ pcName + 1, iLenDirName))
+ {
+ //
+ // Yes - we have a match. Set the stripped filename to
+ // the second '/' and return the mount point index.
+ //
+ *ppcFSFilename = pcSlash;
+ return(ui32Loop);
+ }
+ }
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find a specific mount point for
+ // this file so just return the filename passed and the default mount
+ // point.
+ //
+ *ppcFSFilename = (char *)pcName;
+
+ return(g_ui32DefaultMountIndex);
+}
+
+//*****************************************************************************
+//
+//! Initializes the file system wrapper.
+//!
+//! \param psMountPoints points to an array of fs_mount_data structures. Each
+//! element in the array maps a top level directory name to a particular
+//! file system image or to the FAT file system and a logical drive number.
+//! \param ui32NumMountPoints provides the number of populated elements in the
+//! \e psMountPoints array.
+//!
+//! This function should be called to initialize the file system wrapper and
+//! provide it with the information required to access the files in multiple
+//! file system images via a single filename space.
+//!
+//! Each entry in \e psMountPoints describes a top level directory in the
+//! unified namespace and indicates to fswrapper where the files for that
+//! directory can be found. Each entry can describe either a file system
+//! image in system memory or a logical disk handled via the FatFs file system
+//! driver.
+//!
+//! For example, consider the following 3 entry mount point table:
+//!
+//! \verbatim
+//! {
+//! { "internal", &g_pui8FSImage, 0, NULL, NULL },
+//! { "sdcard", NULL, 0, SDCardEnable, SDCardDisable },
+//! { NULL, &g_pui8FSDefault, 0, NULL, NULL}
+//! }
+//! \endverbatim
+//!
+//! Requests to open file ``/internal/index.html'' will be handled by
+//! attempting to open ``/index.html'' in the internal file system pointed to
+//! by \e g_pui8FSImage. Similarly, opening ``/sdcard/images/logo.gif'' will
+//! result in a call to the FAT f_open function requesting
+//! ``0:/images/logo.gif''. If a request to open ``index.htm'' is received,
+//! this is handled by attempting to open ``index.htm'' in the default internal
+//! file system image, \e g_pui8FSDefault.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Check for non-zero parameters in debug builds.
+ //
+ ASSERT(psMountPoints);
+ ASSERT(ui32NumMountPoints);
+
+ //
+ // Remember the mount point information we have been given.
+ //
+ if(psMountPoints && ui32NumMountPoints)
+ {
+ //
+ // Remember the information passed.
+ //
+ g_psMountPoints = psMountPoints;
+ g_ui32NumMountPoints = ui32NumMountPoints;
+
+ //
+ // Check to determine if any of the mount points refer to FAT file
+ // system drivers. We also hijack this loop to determine what the
+ // default mount point (if any) is.
+ //
+ g_bFatFsEnabled = false;
+ for(ui32Loop = 0; ui32Loop < g_ui32NumMountPoints; ui32Loop++)
+ {
+ //
+ // If the pui8FSImage field of a mount point structure is NULL,
+ // this implies that we are using the FAT file system for that
+ // node.
+ //
+ if(!g_psMountPoints[ui32Loop].pui8FSImage)
+ {
+ g_bFatFsEnabled = true;
+ }
+
+ //
+ // Does this entry describe the default mount point?
+ //
+ if(g_psMountPoints[ui32Loop].pcNamePrefix == NULL)
+ {
+ g_ui32DefaultMountIndex = ui32Loop;
+ }
+ }
+
+ return(true);
+ }
+ else
+ {
+ //
+ // Return an error due to being passed a bad parameter.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Provides a periodic tick for the file system.
+//!
+//! \param ui32TickMS is the number of milliseconds which have elapsed since
+//! the last time this function was called.
+//!
+//! Applications making use of the file system wrapper with underlying FatFs
+//! drives must call this function at least once every 10 milliseconds to
+//! provide a time reference for use by the file system. It is typically
+//! called in the context of the application's SysTick interrupt handler or
+//! from the handler of some other timer interrupt.
+//!
+//! If only binary file system images are in use, this function need not be
+//! called.
+//!
+//! \return None
+//
+//
+//*****************************************************************************
+void
+fs_tick(uint32_t ui32TickMS)
+{
+ static uint32_t ui32TickCounter = 0;
+
+ //
+ // Check if the file system has been enabled yet.
+ //
+ if(!g_bFatFsEnabled)
+ {
+ return;
+ }
+
+ //
+ // Increment the tick counter.
+ //
+ ui32TickCounter += ui32TickMS;
+
+ //
+ // Check to see if the FAT FS tick needs to run.
+ //
+ if(ui32TickCounter >= 10)
+ {
+ ui32TickCounter = 0;
+ disk_timerproc();
+ }
+}
+
+//*****************************************************************************
+//
+//! Opens a file.
+//!
+//! \param pcName points to a NULL terminated string containing the path and
+//! file name to open.
+//!
+//! This function opens a file and returns a handle allowing it to be read.
+//!
+//! \return Returns a valid file handle on success or NULL on failure.
+//
+//*****************************************************************************
+struct fs_file *
+fs_open(const char *pcName)
+{
+ const struct fsdata_file *psTree;
+ const struct fsdata_file *psEnd = NULL;
+ struct fs_file *psFile = NULL;
+ fs_wrapper_data *psWrapper;
+ FRESULT fresult = FR_OK;
+ bool bPosInd = false;
+ char *pcFSFilename;
+ char *pcFilename;
+ uint32_t ui32Length;
+
+ //
+ // Allocate memory for the file system structure.
+ //
+ psFile = mem_malloc(sizeof(struct fs_file));
+ if(NULL == psFile)
+ {
+ return(NULL);
+ }
+
+ //
+ // Allocate memory for our internal control structure.
+ //
+ psFile->pextension = mem_malloc(sizeof(fs_wrapper_data));
+ psWrapper = (fs_wrapper_data *)psFile->pextension;
+
+ if(NULL == psWrapper)
+ {
+ return(NULL);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ psWrapper->ui32MountIndex = fs_find_mount_index(pcName, &pcFSFilename);
+ if(psWrapper->ui32MountIndex == BAD_MOUNT_INDEX)
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ mem_free(psWrapper);
+ mem_free(psFile);
+ return(NULL);
+ }
+
+ //
+ // Enable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Are we opening a file on an internal file system image?
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage)
+ {
+ //
+ // Initialize the file system tree pointer to the root of the linked
+ // list for this mount point's file system image.
+ //
+ psTree = ((const struct fsdata_file *)
+ g_psMountPoints[psWrapper->ui32MountIndex].pui8FSImage);
+
+ //
+ // Which type of file system are we dealing with?
+ //
+ if(psTree->next == FILE_SYSTEM_MARKER)
+ {
+ //
+ // If we found the marker, this is a position independent file
+ // system image. Remember this and fix up the pointer to the
+ // first descriptor by skipping over the 4 byte marker and the
+ // 4 byte image size entry. We also keep track of where the file
+ // system image ends since this allows us to do a bit more error
+ // checking later.
+ //
+ bPosInd = true;
+ ui32Length = *(uint32_t *)((uint8_t *)psTree + 4);
+ psTree = (struct fsdata_file *)((int8_t *)psTree + 8);
+ psEnd = (struct fsdata_file *)((int8_t *)psTree + ui32Length);
+ }
+
+ //
+ // Begin processing the linked list, looking for the requested file
+ // name.
+ //
+ while(NULL != psTree)
+ {
+ //
+ // Compare the requested file "name" to the file name in the
+ // current node.
+ //
+ if(ustrncmp(pcFSFilename,
+ FS_POINTER(psTree, psTree->name, bPosInd),
+ psTree->len) == 0)
+ {
+ //
+ // Fill in the data pointer and length values from the
+ // linked list node.
+ //
+ psFile->data = FS_POINTER(psTree, psTree->data, bPosInd);
+ psFile->len = psTree->len;
+
+ //
+ // For now, we setup the read index to the end of the file,
+ // indicating that all data has been read. This indicates that
+ // all the data is currently available in a contiguous block
+ // of memory (which is always the case with an internal file
+ // system image).
+ //
+ psFile->index = psTree->len;
+
+ //
+ // We are not using a FAT file system file and don't need to
+ // remap the filename so set these pointers to NULL.
+ //
+ psWrapper->psFATFile = NULL;
+
+ //
+ // Exit the loop and return the file system pointer.
+ //
+ break;
+ }
+
+ //
+ // If we get here, we did not find the file at this node of the
+ // linked list. Get the next element in the list. We can't just
+ // assign psTree from psTree->next since this will give us the
+ // wrong pointer for a position independent image (where the values
+ // in the structure are offsets from the start of the file
+ // descriptor, not absolute pointers) but we do know that a 0 in
+ // the "next" field does indicate that this is the last file so we
+ // can use that info to force the loop to exit at the end.
+ //
+ if(psTree->next == 0)
+ {
+ psTree = NULL;
+ }
+ else
+ {
+ psTree = (struct fsdata_file *)FS_POINTER(psTree, psTree->next,
+ bPosInd);
+
+ //
+ // If this is a position independent file system image, we can
+ // also check that the new node is within the image. If it
+ // isn't, the image is corrupted to stop the search.
+ //
+ if(bPosInd && (psTree >= psEnd))
+ {
+ psTree = NULL;
+ }
+ }
+ }
+
+ //
+ // If we didn't find the file, ptTee will be NULL. Make sure we
+ // return a NULL pointer if this happens.
+ //
+ if(NULL == psTree)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ else
+ {
+ //
+ // This file is on the FAT file system.
+ //
+
+ //
+ // Allocate memory for the Fat File system handle.
+ //
+ psWrapper->psFATFile = mem_malloc(sizeof(FIL));
+ if(NULL == psWrapper->psFATFile)
+ {
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ //
+ // Reformat the filename to start with the FAT logical drive
+ // number.
+ //
+ ui32Length = ustrlen(pcFSFilename) + 16;
+ pcFilename = mem_malloc(ui32Length);
+ if(!pcFilename)
+ {
+ //
+ // Can't allocate temporary storage for the reformatted
+ // filename!
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psFile->pextension);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ else
+ {
+ usnprintf(pcFilename, ui32Length, "%d:%s",
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ ui32DriveNum, pcFSFilename);
+ //
+ // Attempt to open the file on the Fat File System.
+ //
+ fresult = f_open(psWrapper->psFATFile, pcFilename, FA_READ);
+
+ //
+ // Free the filename storage
+ //
+ mem_free(pcFilename);
+
+ //
+ // Did we open the file correctly?
+ //
+ if(FR_OK == fresult)
+ {
+ //
+ // Yes - fill in the file structure to indicate that a
+ // FAT file is in use.
+ //
+ psFile->data = NULL;
+ psFile->len = 0;
+ psFile->index = 0;
+ }
+ else
+ {
+ //
+ // If we get here, we failed to find the file on the FAT
+ // file system so free up the FAT handle/object.
+ //
+ mem_free(psWrapper->psFATFile);
+ mem_free(psWrapper);
+ mem_free(psFile);
+ psFile = NULL;
+ }
+ }
+ }
+ }
+
+ //
+ // Disable access to the physical medium if we have been provided with
+ // a callback for this.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ return(psFile);
+}
+
+//*****************************************************************************
+//
+//! Closes a file.
+//!
+//! \param phFile is the handle of the file that is to be closed. This will
+//! have been returned by an earlier call to fs_open().
+//!
+//! This function closes the file identified by \e phFile and frees all
+//! resources associated with the file handle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+fs_close(struct fs_file *phFile)
+{
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // If a Fat file was opened, free its object.
+ //
+ if(psWrapper->psFATFile)
+ {
+ //
+ // Close the file.
+ //
+ f_close(psWrapper->psFATFile);
+
+ //
+ // Free the file object.
+ //
+ mem_free(psWrapper->psFATFile);
+ }
+
+ //
+ // Free our file wrapper control structure.
+ //
+ mem_free(phFile->pextension);
+
+ //
+ // Free the main file system object.
+ //
+ mem_free(phFile);
+}
+
+//*****************************************************************************
+//
+//! Reads data from an open file.
+//!
+//! \param phFile is the handle of the file which is to be read. This will
+//! have been returned by a previous call to fs_open().
+//! \param pcBuffer points to the first byte of the buffer into which the
+//! data read from the file will be copied. This buffer must be large enough
+//! to hold \e iCount bytes.
+//! \param iCount is the maximum number of bytes of data that are to be read
+//! from the file.
+//!
+//! This function reads the next block of data from the given file into a
+//! buffer and returns the number of bytes read or -1 if the end of the file
+//! has been reached.
+//!
+//! \return Returns the number of bytes read from the file or -1 if the end of
+//! the file has been reached and no more data is available.
+//
+//*****************************************************************************
+int
+fs_read(struct fs_file *phFile, char *pcBuffer, int iCount)
+{
+ int iAvailable, iRetcode;
+ fs_wrapper_data *psWrapper;
+
+ psWrapper = (fs_wrapper_data *)phFile->pextension;
+
+ //
+ // Call the application's enable function for this physical medium (if
+ // an enable function has been provided).
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnEnable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnEnable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Check to see if a Fat File was opened and process it.
+ //
+ if(psWrapper->psFATFile)
+ {
+ uint32_t ui32BytesRead;
+ FRESULT fresult;
+
+ //
+ // Read the data.
+ //
+ fresult = f_read(psWrapper->psFATFile, pcBuffer, iCount,
+ (UINT*)&ui32BytesRead);
+ if((fresult != FR_OK) || (ui32BytesRead == 0))
+ {
+ iRetcode = -1;
+ }
+ else
+ {
+ iRetcode = (int)ui32BytesRead;
+ }
+ }
+ else
+ {
+ //
+ // We are reading a file from a file system image. Check to see if
+ // more data is available.
+ //
+ if(phFile->len == phFile->index)
+ {
+ //
+ // There is no remaining data. Return a -1 for EOF indication.
+ //
+ return(-1);
+ }
+
+ //
+ // Determine how much data we can copy. The minimum of the 'iCount'
+ // parameter or the available data in the file system buffer.
+ //
+ iAvailable = phFile->len - phFile->index;
+ if(iAvailable > iCount)
+ {
+ iAvailable = iCount;
+ }
+
+ //
+ // Copy the data.
+ //
+ memcpy(pcBuffer, phFile->data + phFile->index, iAvailable);
+ phFile->index += iAvailable;
+
+ //
+ // Return the count of data that we copied.
+ //
+ iRetcode = iAvailable;
+ }
+
+ //
+ // Call the application's disable function now that we have finished
+ // accessing the file.
+ //
+ if(g_psMountPoints[psWrapper->ui32MountIndex].pfnDisable)
+ {
+ g_psMountPoints[psWrapper->ui32MountIndex].
+ pfnDisable(psWrapper->ui32MountIndex);
+ }
+
+ //
+ // Return the number of bytes read.
+ //
+ return(iRetcode);
+}
+
+//*****************************************************************************
+//
+//! Maps a path string containing mount point names to a path suitable for
+//! use in calls to the FatFs APIs.
+//!
+//! \param pcPath points to a string containing a path in the namespace
+//! defined by the mount information passed to fs_init().
+//! \param pcMapped points to a buffer into which the mapped path string will
+//! be written.
+//! \param iLen is the size, in bytes, of the buffer pointed to by pcMapped.
+//!
+//! This function may be used by applications which want to make use of FatFs
+//! functions which are not directly mapped by the fswrapper layer. A path
+//! in the namespace defined by the mount points passed to function fs_init()
+//! is translated to an equivalent path in the FatFs namespace and this may
+//! then be used in a direct call to functions such as f_opendir() or
+//! f_getfree().
+//!
+//! \return Returns \b true on success or \b false if fs_init() has not
+//! been called, if the path provided maps to an internal file system image
+//! rather than a FatFs logical drive or if the buffer pointed to by
+//! \e pcMapped is too small to fit the output string.
+//
+//*****************************************************************************
+bool
+fs_map_path(const char *pcPath, char *pcMapped, int iLen)
+{
+ char *pcFSFilename;
+ uint32_t ui32MountIndex;
+ int iCount;
+
+ //
+ // If no mount points have been defined, return an error.
+ //
+ if(!g_psMountPoints)
+ {
+ return(false);
+ }
+
+ //
+ // Find which mount point we need to use to satisfy this file open request.
+ //
+ ui32MountIndex = fs_find_mount_index(pcPath, &pcFSFilename);
+
+ //
+ // If we got a bad mount index or the index returned represents a mount
+ // point that is not in the FAT file system, return an error.
+ //
+ if((ui32MountIndex == BAD_MOUNT_INDEX) ||
+ (g_psMountPoints[ui32MountIndex].pui8FSImage))
+ {
+ //
+ // We can't map the mount index so return an error.
+ //
+ return(false);
+ }
+
+ //
+ // Now we can generate the FatFs namespace path string.
+ //
+ iCount = usnprintf(pcMapped, iLen, "%d:%s",
+ g_psMountPoints[ui32MountIndex].ui32DriveNum,
+ pcFSFilename);
+
+ //
+ // Tell the user how we got on. The count returned by usnprintf is the
+ // number of characters that should have been written, excluding the
+ // terminating NULL so we use this to check for overflow of the output
+ // buffer.
+ //
+ return((iLen >= (iCount + 1)) ? true : false);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/fswrapper.h b/utils/fswrapper.h
new file mode 100644
index 0000000..889cdd4
--- /dev/null
+++ b/utils/fswrapper.h
@@ -0,0 +1,142 @@
+//*****************************************************************************
+//
+// fswrapper.h - Public type definitons and function prototypes for the simple
+// file system wrapper module.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __FSWRAPPER_H__
+#define __FSWRAPPER_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup fswrapper_api
+//! @{
+//
+//*****************************************************************************
+
+typedef struct
+{
+ //
+ //! This string provides a pseudo-directory name that will be used to
+ //! identify this mount point in future calls to fs_open. If this string
+ //! is NULL, this indicates that this is the default file system which will
+ //! be used when any simple filename, not including a leading directory
+ //! name is passed or when the leading directory name is not found in the
+ //! list of mount points passed to fs_init.
+ //
+ const char *pcNamePrefix;
+
+ //
+ //! A pointer to the start of the file system image that is to be used to
+ //! satisfy requests for files whose name begins "/name" where
+ //! "name" is the string provided in the pcNamePrefix field. This pointer
+ //! may point to either a position-dependent or position-independent file
+ //! system image generated by the makefsfile executable or makefsdata
+ //! Perl script. If NULL, it is assumed that the FAT file system is to be
+ //! used and that the drive number provided in ui32DriveNum should be
+ //! substituted for "name" in the supplied filename before attempting to
+ //! open the FAT file.
+ //
+ uint8_t *pui8FSImage;
+
+ //
+ //! If this mount point describes a logical drive in the FAT file system,
+ //! this field indicates the drive number that is to be accessed. This
+ //! number will be substituted for the string provided in the pcNamePrefix
+ //! field in the filename passed to fs_open before that filename is passed
+ //! down to the FAT file system. For example, if pcNamePrefix is "sdcard"
+ //! and ui32DriveNum is 0, a call to fs_open passing
+ //! "/sdcard/images/logo.gif" will be passed to the FATfs f_open call as
+ //! "/0/images/logo.gif". This field is ignored if pui8FSImage is not NULL
+ //! (indicating that this mount point refers to a file system image rather
+ //! than the FAT file system).
+ //!
+ uint32_t ui32DriveNum;
+
+ //
+ //! This function pointer is called whenever a file is to be opened, read
+ //! or (for read/write file systems) written on this file system. If any
+ //! special setup is required to allow access to the physical medium (for
+ //! example, setting the SSI mode or clock frequency), the application may
+ //! use this callback to perform that initialization. If this field is
+ //! NULL, no callback will be made.
+ //
+ void (*pfnEnable)(uint32_t ui32FSIndex);
+
+ //
+ //! This callback is made after access to the physical medium has been
+ //! completed. An application may assume that no further access to the
+ //! medium will be made until a call to pfnEnable is made. If this field
+ //! is NULL, no callback will be made.
+ //
+ void (*pfnDisable)(uint32_t ui32FSIndex);
+}
+fs_mount_data;
+
+//*****************************************************************************
+//
+// This marker, "FIMG", is placed at the beginning of a position-independent
+// file system image to differentiate it from a position-dependent image.
+//
+//*****************************************************************************
+#define FILE_SYSTEM_MARKER ((const struct fsdata_file *)0x474D4946)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes
+//
+//*****************************************************************************
+extern bool fs_init(fs_mount_data *psMountPoints, uint32_t ui32NumMountPoints);
+extern void fs_tick(uint32_t ui32TickMS);
+extern struct fs_file *fs_open(const char *name);
+extern void fs_close(struct fs_file *file);
+extern int fs_read(struct fs_file *file, char *buffer, int count);
+extern bool fs_map_path(const char *pcPath, char *pcMapped, int iLen);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FSWRAPPER_H__
diff --git a/utils/isqrt.c b/utils/isqrt.c
new file mode 100644
index 0000000..aa908f6
--- /dev/null
+++ b/utils/isqrt.c
@@ -0,0 +1,118 @@
+//*****************************************************************************
+//
+// isqrt.c - Integer square root.
+//
+// Copyright (c) 2005-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/isqrt.h"
+
+//*****************************************************************************
+//
+//! \addtogroup isqrt_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Compute the integer square root of an integer.
+//!
+//! \param ui32Value is the value whose square root is desired.
+//!
+//! This function will compute the integer square root of the given input
+//! value. Since the value returned is also an integer, it is actually better
+//! defined as the largest integer whose square is less than or equal to the
+//! input value.
+//!
+//! \return Returns the square root of the input value.
+//
+//*****************************************************************************
+uint32_t
+isqrt(uint32_t ui32Value)
+{
+ uint32_t ui32Rem, ui32Root, ui32Idx;
+
+ //
+ // Initialize the remainder and root to zero.
+ //
+ ui32Rem = 0;
+ ui32Root = 0;
+
+ //
+ // Loop over the sixteen bits in the root.
+ //
+ for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
+ {
+ //
+ // Shift the root up by a bit to make room for the new bit that is
+ // about to be computed.
+ //
+ ui32Root <<= 1;
+
+ //
+ // Get two more bits from the input into the remainder.
+ //
+ ui32Rem = ((ui32Rem << 2) + (ui32Value >> 30));
+ ui32Value <<= 2;
+
+ //
+ // Make the test root be 2n + 1.
+ //
+ ui32Root++;
+
+ //
+ // See if the root is greater than the remainder.
+ //
+ if(ui32Root <= ui32Rem)
+ {
+ //
+ // Subtract the test root from the remainder.
+ //
+ ui32Rem -= ui32Root;
+
+ //
+ // Increment the root, setting the second LSB.
+ //
+ ui32Root++;
+ }
+ else
+ {
+ //
+ // The root is greater than the remainder, so the new bit of the
+ // root is actually zero.
+ //
+ ui32Root--;
+ }
+ }
+
+ //
+ // Return the computed root.
+ //
+ return(ui32Root >> 1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/isqrt.h b/utils/isqrt.h
new file mode 100644
index 0000000..2d0de39
--- /dev/null
+++ b/utils/isqrt.h
@@ -0,0 +1,55 @@
+//*****************************************************************************
+//
+// isqrt.h - Prototype for the integer square root function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __ISQRT_H__
+#define __ISQRT_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The prototype for the integer square root function.
+//
+//*****************************************************************************
+extern uint32_t isqrt(uint32_t ui32Value);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/locator.c b/utils/locator.c
new file mode 100644
index 0000000..fb240b2
--- /dev/null
+++ b/utils/locator.c
@@ -0,0 +1,342 @@
+//*****************************************************************************
+//
+// locator.c - A device locator server using UDP in lwIP.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/locator.h"
+#include "utils/lwiplib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup locator_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These defines are used to describe the device locator protocol.
+//
+//*****************************************************************************
+#define TAG_CMD 0xff
+#define TAG_STATUS 0xfe
+#define CMD_DISCOVER_TARGET 0x02
+
+//*****************************************************************************
+//
+// An array that contains the device locator response data. The format of the
+// data is as follows:
+//
+// Byte Description
+// -------- ------------------------
+// 0 TAG_STATUS
+// 1 packet length
+// 2 CMD_DISCOVER_TARGET
+// 3 board type
+// 4 board ID
+// 5..8 client IP address
+// 9..14 MAC address
+// 15..18 firmware version
+// 19..82 application title
+// 83 checksum
+//
+//*****************************************************************************
+static uint8_t g_pui8LocatorData[84];
+
+//*****************************************************************************
+//
+// This function is called by the lwIP TCP/IP stack when it receives a UDP
+// packet from the discovery port. It produces the response packet, which is
+// sent back to the querying client.
+//
+//*****************************************************************************
+static void
+LocatorReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ uint8_t *pui8Data;
+ uint32_t ui32Idx;
+
+ //
+ // Validate the contents of the datagram.
+ //
+ pui8Data = p->payload;
+ if((p->len != 4) || (pui8Data[0] != TAG_CMD) || (pui8Data[1] != 4) ||
+ (pui8Data[2] != CMD_DISCOVER_TARGET) ||
+ (pui8Data[3] != ((0 - TAG_CMD - 4 - CMD_DISCOVER_TARGET) & 0xff)))
+ {
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // The incoming pbuf is no longer needed, so free it.
+ //
+ pbuf_free(p);
+
+ //
+ // Allocate a new pbuf for sending the response.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, sizeof(g_pui8LocatorData), PBUF_RAM);
+ if(p == NULL)
+ {
+ return;
+ }
+
+ //
+ // Calculate and fill in the checksum on the response packet.
+ //
+ for(ui32Idx = 0, g_pui8LocatorData[sizeof(g_pui8LocatorData) - 1] = 0;
+ ui32Idx < (sizeof(g_pui8LocatorData) - 1); ui32Idx++)
+ {
+ g_pui8LocatorData[sizeof(g_pui8LocatorData) - 1] -=
+ g_pui8LocatorData[ui32Idx];
+ }
+
+ //
+ // Copy the response packet data into the pbuf.
+ //
+ pui8Data = p->payload;
+ for(ui32Idx = 0; ui32Idx < sizeof(g_pui8LocatorData); ui32Idx++)
+ {
+ pui8Data[ui32Idx] = g_pui8LocatorData[ui32Idx];
+ }
+
+ //
+ // Send the response.
+ //
+ udp_sendto(pcb, p, addr, port);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+//! Initializes the locator service.
+//!
+//! This function prepares the locator service to handle device discovery
+//! requests. A UDP server is created and the locator response data is
+//! initialized to all empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorInit(void)
+{
+ uint32_t ui32Idx;
+ void *pcb;
+
+ //
+ // Clear out the response data.
+ //
+ for(ui32Idx = 0; ui32Idx < 84; ui32Idx++)
+ {
+ g_pui8LocatorData[ui32Idx] = 0;
+ }
+
+ //
+ // Fill in the header for the response data.
+ //
+ g_pui8LocatorData[0] = TAG_STATUS;
+ g_pui8LocatorData[1] = sizeof(g_pui8LocatorData);
+ g_pui8LocatorData[2] = CMD_DISCOVER_TARGET;
+
+ //
+ // Fill in the MAC address for the response data.
+ //
+ g_pui8LocatorData[9] = 0;
+ g_pui8LocatorData[10] = 0;
+ g_pui8LocatorData[11] = 0;
+ g_pui8LocatorData[12] = 0;
+ g_pui8LocatorData[13] = 0;
+ g_pui8LocatorData[14] = 0;
+
+ //
+ // Create a new UDP port for listening to device locator requests.
+ //
+ pcb = udp_new();
+ udp_recv(pcb, LocatorReceive, NULL);
+ udp_bind(pcb, IP_ADDR_ANY, 23);
+}
+
+//*****************************************************************************
+//
+//! Sets the board type in the locator response packet.
+//!
+//! \param ui32Type is the type of the board.
+//!
+//! This function sets the board type field in the locator response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorBoardTypeSet(uint32_t ui32Type)
+{
+ //
+ // Save the board type in the response data.
+ //
+ g_pui8LocatorData[3] = ui32Type & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the board ID in the locator response packet.
+//!
+//! \param ui32ID is the ID of the board.
+//!
+//! This function sets the board ID field in the locator response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorBoardIDSet(uint32_t ui32ID)
+{
+ //
+ // Save the board ID in the response data.
+ //
+ g_pui8LocatorData[4] = ui32ID & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the client IP address in the locator response packet.
+//!
+//! \param ui32IP is the IP address of the currently connected client.
+//!
+//! This function sets the IP address of the currently connected client in the
+//! locator response packet. The IP should be set to 0.0.0.0 if there is no
+//! client connected. It should never be set for devices that do not have a
+//! strict one-to-one mapping of client to server (for example, a web server).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorClientIPSet(uint32_t ui32IP)
+{
+ //
+ // Save the client IP address in the response data.
+ //
+ g_pui8LocatorData[5] = ui32IP & 0xff;
+ g_pui8LocatorData[6] = (ui32IP >> 8) & 0xff;
+ g_pui8LocatorData[7] = (ui32IP >> 16) & 0xff;
+ g_pui8LocatorData[8] = (ui32IP >> 24) & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the MAC address in the locator response packet.
+//!
+//! \param pui8MACArray is the MAC address of the network interface.
+//!
+//! This function sets the MAC address of the network interface in the locator
+//! response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorMACAddrSet(uint8_t *pui8MACArray)
+{
+ //
+ // Save the MAC address.
+ //
+ g_pui8LocatorData[9] = pui8MACArray[0];
+ g_pui8LocatorData[10] = pui8MACArray[1];
+ g_pui8LocatorData[11] = pui8MACArray[2];
+ g_pui8LocatorData[12] = pui8MACArray[3];
+ g_pui8LocatorData[13] = pui8MACArray[4];
+ g_pui8LocatorData[14] = pui8MACArray[5];
+}
+
+//*****************************************************************************
+//
+//! Sets the firmware version in the locator response packet.
+//!
+//! \param ui32Version is the version number of the device firmware.
+//!
+//! This function sets the version number of the device firmware in the locator
+//! response packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorVersionSet(uint32_t ui32Version)
+{
+ //
+ // Save the firmware version number in the response data.
+ //
+ g_pui8LocatorData[15] = ui32Version & 0xff;
+ g_pui8LocatorData[16] = (ui32Version >> 8) & 0xff;
+ g_pui8LocatorData[17] = (ui32Version >> 16) & 0xff;
+ g_pui8LocatorData[18] = (ui32Version >> 24) & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Sets the application title in the locator response packet.
+//!
+//! \param pcAppTitle is a pointer to the application title string.
+//!
+//! This function sets the application title in the locator response packet.
+//! The string is truncated at 64 characters if it is longer (without a
+//! terminating 0), and is zero-filled to 64 characters if it is shorter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LocatorAppTitleSet(const char *pcAppTitle)
+{
+ uint32_t ui32Count;
+
+ //
+ // Copy the application title string into the response data.
+ //
+ for(ui32Count = 0; (ui32Count < 64) && *pcAppTitle; ui32Count++)
+ {
+ g_pui8LocatorData[ui32Count + 19] = *pcAppTitle++;
+ }
+
+ //
+ // Zero-fill the remainder of the space in the response data (if any).
+ //
+ for(; ui32Count < 64; ui32Count++)
+ {
+ g_pui8LocatorData[ui32Count + 19] = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/locator.h b/utils/locator.h
new file mode 100644
index 0000000..0ef7979
--- /dev/null
+++ b/utils/locator.h
@@ -0,0 +1,61 @@
+//*****************************************************************************
+//
+// locator.h - Prototypes for the device locator server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __LOCATOR_H__
+#define __LOCATOR_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern void LocatorInit(void);
+extern void LocatorBoardTypeSet(uint32_t ui32Type);
+extern void LocatorBoardIDSet(uint32_t ui32ID);
+extern void LocatorClientIPSet(uint32_t ui32IP);
+extern void LocatorMACAddrSet(uint8_t *pui8MACArray);
+extern void LocatorVersionSet(uint32_t ui32Version);
+extern void LocatorAppTitleSet(const char *pcAppTitle);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOCATOR_H__
diff --git a/utils/lwiplib.c b/utils/lwiplib.c
new file mode 100644
index 0000000..89539bd
--- /dev/null
+++ b/utils/lwiplib.c
@@ -0,0 +1,1399 @@
+//*****************************************************************************
+//
+// lwiplib.c - lwIP TCP/IP Library Abstraction Layer.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Ensure that the lwIP compile time options are included first.
+//
+//*****************************************************************************
+#include <stdint.h>
+#include <stdbool.h>
+#include "utils/lwiplib.h"
+
+//*****************************************************************************
+//
+// Ensure that ICMP checksum offloading is enabled; otherwise the TM4C129
+// driver will not operate correctly.
+//
+//*****************************************************************************
+#ifndef LWIP_OFFLOAD_ICMP_CHKSUM
+#define LWIP_OFFLOAD_ICMP_CHKSUM 1
+#endif
+
+//*****************************************************************************
+//
+// Include lwIP high-level API code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/api/api_lib.c"
+#include "third_party/lwip-1.4.1/src/api/api_msg.c"
+#include "third_party/lwip-1.4.1/src/api/err.c"
+#include "third_party/lwip-1.4.1/src/api/netbuf.c"
+#include "third_party/lwip-1.4.1/src/api/netdb.c"
+#include "third_party/lwip-1.4.1/src/api/netifapi.c"
+#include "third_party/lwip-1.4.1/src/api/sockets.c"
+#include "third_party/lwip-1.4.1/src/api/tcpip.c"
+
+//*****************************************************************************
+//
+// Include the core lwIP TCP/IP stack code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/def.c"
+#include "third_party/lwip-1.4.1/src/core/dhcp.c"
+#include "third_party/lwip-1.4.1/src/core/dns.c"
+#include "third_party/lwip-1.4.1/src/core/init.c"
+#include "third_party/lwip-1.4.1/src/core/mem.c"
+#include "third_party/lwip-1.4.1/src/core/memp.c"
+#include "third_party/lwip-1.4.1/src/core/netif.c"
+#include "third_party/lwip-1.4.1/src/core/pbuf.c"
+#include "third_party/lwip-1.4.1/src/core/raw.c"
+#include "third_party/lwip-1.4.1/src/core/stats.c"
+#include "third_party/lwip-1.4.1/src/core/sys.c"
+#include "third_party/lwip-1.4.1/src/core/tcp.c"
+#include "third_party/lwip-1.4.1/src/core/tcp_in.c"
+#include "third_party/lwip-1.4.1/src/core/tcp_out.c"
+#include "third_party/lwip-1.4.1/src/core/timers.c"
+#include "third_party/lwip-1.4.1/src/core/udp.c"
+
+//*****************************************************************************
+//
+// Include the IPV4 code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/ipv4/autoip.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/icmp.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/igmp.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/inet.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/inet_chksum.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip_addr.c"
+#include "third_party/lwip-1.4.1/src/core/ipv4/ip_frag.c"
+
+//*****************************************************************************
+//
+// Include the IPV6 code.
+// Note: Code is experimental and not ready for use.
+// References are included for completeness.
+//
+//*****************************************************************************
+#if 0
+#include "third_party/lwip-1.4.1/src/core/ipv6/icmp6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/inet6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/ip6.c"
+#include "third_party/lwip-1.4.1/src/core/ipv6/ip6_addr.c"
+#endif
+
+//*****************************************************************************
+//
+// Include the lwIP SNMP code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/core/snmp/asn1_dec.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/asn1_enc.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/mib2.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/mib_structs.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/msg_in.c"
+#include "third_party/lwip-1.4.1/src/core/snmp/msg_out.c"
+
+//*****************************************************************************
+//
+// Include the network interface code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/netif/etharp.c"
+
+//*****************************************************************************
+//
+// Include the network interface PPP code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/src/netif/ppp/auth.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/chap.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/chpms.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/fsm.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ipcp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/lcp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/magic.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/md5.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/pap.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ppp.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/ppp_oe.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/randm.c"
+#include "third_party/lwip-1.4.1/src/netif/ppp/vj.c"
+
+//*****************************************************************************
+//
+// Include Tiva-specific lwIP interface/porting layer code.
+//
+//*****************************************************************************
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/perf.c"
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/sys_arch.c"
+#include "third_party/lwip-1.4.1/ports/tiva-tm4c129/netif/tiva-tm4c129.c"
+
+//*****************************************************************************
+//
+//! \addtogroup lwiplib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The lwIP Library abstration layer provides for a host callback function to
+// be called periodically in the lwIP context. This is the timer interval, in
+// ms, for this periodic callback. If the timer interval is defined to 0 (the
+// default value), then no periodic host callback is performed.
+//
+//*****************************************************************************
+#ifndef HOST_TMR_INTERVAL
+#define HOST_TMR_INTERVAL 0
+#else
+extern void lwIPHostTimerHandler(void);
+#endif
+
+//*****************************************************************************
+//
+// The link detect polling interval.
+//
+//*****************************************************************************
+#define LINK_TMR_INTERVAL 10
+
+//*****************************************************************************
+//
+// Set the PHY configuration to the default (internal) option if necessary.
+//
+//*****************************************************************************
+#ifndef EMAC_PHY_CONFIG
+#define EMAC_PHY_CONFIG (EMAC_PHY_TYPE_INTERNAL | \
+ EMAC_PHY_INT_MDIX_EN | \
+ EMAC_PHY_AN_100B_T_FULL_DUPLEX)
+#endif
+
+//*****************************************************************************
+//
+// Driverlib headers needed for this library module.
+//
+//*****************************************************************************
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "driverlib/debug.h"
+#include "driverlib/emac.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#if !NO_SYS
+#if RTOS_FREERTOS
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+#endif
+#if ((RTOS_FREERTOS) < 1)
+ #error No RTOS is defined. Please define an RTOS.
+#endif
+#if ((RTOS_FREERTOS) > 1)
+ #error More than one RTOS defined. Please define only one RTOS at a time.
+#endif
+#endif
+
+//*****************************************************************************
+//
+// The lwIP network interface structure for the Tiva Ethernet MAC.
+//
+//*****************************************************************************
+static struct netif g_sNetIF;
+
+//*****************************************************************************
+//
+// The application's interrupt handler for hardware timer events from the MAC.
+//
+//*****************************************************************************
+tHardwareTimerHandler g_pfnTimerHandler;
+
+//*****************************************************************************
+//
+// The local time for the lwIP Library Abstraction layer, used to support the
+// Host and lwIP periodic callback functions.
+//
+//*****************************************************************************
+#if NO_SYS
+uint32_t g_ui32LocalTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the TCP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS
+static uint32_t g_ui32TCPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the HOST timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && HOST_TMR_INTERVAL
+static uint32_t g_ui32HostTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the ARP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_ARP
+static uint32_t g_ui32ARPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the AutoIP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_AUTOIP
+static uint32_t g_ui32AutoIPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DHCP Coarse timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DHCP
+static uint32_t g_ui32DHCPCoarseTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DHCP Fine timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DHCP
+static uint32_t g_ui32DHCPFineTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the IP Reassembly timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && IP_REASSEMBLY
+static uint32_t g_ui32IPReassemblyTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the IGMP timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_IGMP
+static uint32_t g_ui32IGMPTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the DNS timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && LWIP_DNS
+static uint32_t g_ui32DNSTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The local time when the link detect timer was last serviced.
+//
+//*****************************************************************************
+#if NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+static uint32_t g_ui32LinkTimer = 0;
+#endif
+
+//*****************************************************************************
+//
+// The default IP address acquisition mode.
+//
+//*****************************************************************************
+static uint32_t g_ui32IPMode = IPADDR_USE_STATIC;
+
+//*****************************************************************************
+//
+// The most recently detected link state.
+//
+//*****************************************************************************
+#if LWIP_AUTOIP || LWIP_DHCP
+static bool g_bLinkActive = false;
+#endif
+
+//*****************************************************************************
+//
+// The IP address to be used. This is used during the initialization of the
+// stack and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32IPAddr;
+
+//*****************************************************************************
+//
+// The netmask to be used. This is used during the initialization of the stack
+// and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32NetMask;
+
+//*****************************************************************************
+//
+// The gateway address to be used. This is used during the initialization of
+// the stack and when the interface configuration is changed.
+//
+//*****************************************************************************
+static uint32_t g_ui32GWAddr;
+
+//*****************************************************************************
+//
+// The stack size for the interrupt task.
+//
+//*****************************************************************************
+#if !NO_SYS
+#define STACKSIZE_LWIPINTTASK 128
+#endif
+
+//*****************************************************************************
+//
+// The handle for the "queue" (semaphore) used to signal the interrupt task
+// from the interrupt handler.
+//
+//*****************************************************************************
+#if !NO_SYS
+static xQueueHandle g_pInterrupt;
+#endif
+
+//*****************************************************************************
+//
+// This task handles reading packets from the Ethernet controller and supplying
+// them to the TCP/IP thread.
+//
+//*****************************************************************************
+#if !NO_SYS
+static void
+lwIPInterruptTask(void *pvArg)
+{
+ //
+ // Loop forever.
+ //
+ while(1)
+ {
+ //
+ // Wait until the semaphore has been signaled.
+ //
+ while(xQueueReceive(g_pInterrupt, &pvArg, portMAX_DELAY) != pdPASS)
+ {
+ }
+
+ //
+ // Processes any packets waiting to be sent or received.
+ //
+ tivaif_interrupt(&g_sNetIF, (uint32_t)pvArg);
+
+ //
+ // Re-enable the Ethernet interrupts.
+ //
+ MAP_EMACIntEnable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
+ EMAC_INT_TX_STOPPED |
+ EMAC_INT_RX_NO_BUFFER |
+ EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// This function performs a periodic check of the link status and responds
+// appropriately if it has changed.
+//
+//*****************************************************************************
+#if LWIP_AUTOIP || LWIP_DHCP
+static void
+lwIPLinkDetect(void)
+{
+ bool bHaveLink;
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // See if there is an active link.
+ //
+ bHaveLink = MAP_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) & EPHY_BMSR_LINKSTAT;
+
+ //
+ // Return without doing anything else if the link state hasn't changed.
+ //
+ if(bHaveLink == g_bLinkActive)
+ {
+ return;
+ }
+
+ //
+ // Save the new link state.
+ //
+ g_bLinkActive = bHaveLink;
+
+ //
+ // Clear any address information from the network interface.
+ //
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+
+ //
+ // See if there is a link now.
+ //
+ if(bHaveLink)
+ {
+ //
+ // Start DHCP, if enabled.
+ //
+#if LWIP_DHCP
+ if(g_ui32IPMode == IPADDR_USE_DHCP)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // Start AutoIP, if enabled and DHCP is not.
+ //
+#if LWIP_AUTOIP
+ if(g_ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ autoip_start(&g_sNetIF);
+ }
+#endif
+ }
+ else
+ {
+ //
+ // Stop DHCP, if enabled.
+ //
+#if LWIP_DHCP
+ if(g_ui32IPMode == IPADDR_USE_DHCP)
+ {
+ dhcp_stop(&g_sNetIF);
+ }
+#endif
+
+ //
+ // Stop AutoIP, if enabled and DHCP is not.
+ //
+#if LWIP_AUTOIP
+ if(g_ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ autoip_stop(&g_sNetIF);
+ }
+#endif
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// This function services all of the lwIP periodic timers, including TCP and
+// Host timers. This should be called from the lwIP context, which may be
+// the Ethernet interrupt (in the case of a non-RTOS system) or the lwIP
+// thread, in the event that an RTOS is used.
+//
+//*****************************************************************************
+#if NO_SYS
+static void
+lwIPServiceTimers(void)
+{
+ //
+ // Service the host timer.
+ //
+#if HOST_TMR_INTERVAL
+ if((g_ui32LocalTimer - g_ui32HostTimer) >= HOST_TMR_INTERVAL)
+ {
+ g_ui32HostTimer = g_ui32LocalTimer;
+ lwIPHostTimerHandler();
+ }
+#endif
+
+ //
+ // Service the ARP timer.
+ //
+#if LWIP_ARP
+ if((g_ui32LocalTimer - g_ui32ARPTimer) >= ARP_TMR_INTERVAL)
+ {
+ g_ui32ARPTimer = g_ui32LocalTimer;
+ etharp_tmr();
+ }
+#endif
+
+ //
+ // Service the TCP timer.
+ //
+#if LWIP_TCP
+ if((g_ui32LocalTimer - g_ui32TCPTimer) >= TCP_TMR_INTERVAL)
+ {
+ g_ui32TCPTimer = g_ui32LocalTimer;
+ tcp_tmr();
+ }
+#endif
+
+ //
+ // Service the AutoIP timer.
+ //
+#if LWIP_AUTOIP
+ if((g_ui32LocalTimer - g_ui32AutoIPTimer) >= AUTOIP_TMR_INTERVAL)
+ {
+ g_ui32AutoIPTimer = g_ui32LocalTimer;
+ autoip_tmr();
+ }
+#endif
+
+ //
+ // Service the DCHP Coarse Timer.
+ //
+#if LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32DHCPCoarseTimer) >= DHCP_COARSE_TIMER_MSECS)
+ {
+ g_ui32DHCPCoarseTimer = g_ui32LocalTimer;
+ dhcp_coarse_tmr();
+ }
+#endif
+
+ //
+ // Service the DCHP Fine Timer.
+ //
+#if LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32DHCPFineTimer) >= DHCP_FINE_TIMER_MSECS)
+ {
+ g_ui32DHCPFineTimer = g_ui32LocalTimer;
+ dhcp_fine_tmr();
+ }
+#endif
+
+ //
+ // Service the IP Reassembly Timer
+ //
+#if IP_REASSEMBLY
+ if((g_ui32LocalTimer - g_ui32IPReassemblyTimer) >= IP_TMR_INTERVAL)
+ {
+ g_ui32IPReassemblyTimer = g_ui32LocalTimer;
+ ip_reass_tmr();
+ }
+#endif
+
+ //
+ // Service the IGMP Timer
+ //
+#if LWIP_IGMP
+ if((g_ui32LocalTimer - g_ui32IGMPTimer) >= IGMP_TMR_INTERVAL)
+ {
+ g_ui32IGMPTimer = g_ui32LocalTimer;
+ igmp_tmr();
+ }
+#endif
+
+ //
+ // Service the DNS Timer
+ //
+#if LWIP_DNS
+ if((g_ui32LocalTimer - g_ui32DNSTimer) >= DNS_TMR_INTERVAL)
+ {
+ g_ui32DNSTimer = g_ui32LocalTimer;
+ dns_tmr();
+ }
+#endif
+
+ //
+ // Service the link timer.
+ //
+#if LWIP_AUTOIP || LWIP_DHCP
+ if((g_ui32LocalTimer - g_ui32LinkTimer) >= LINK_TMR_INTERVAL)
+ {
+ g_ui32LinkTimer = g_ui32LocalTimer;
+ lwIPLinkDetect();
+ }
+#endif
+}
+#endif
+
+//*****************************************************************************
+//
+// Handles the timeout for the host callback function timer when using a RTOS.
+//
+//*****************************************************************************
+#if !NO_SYS && HOST_TMR_INTERVAL
+static void
+lwIPPrivateHostTimer(void *pvArg)
+{
+ //
+ // Call the application-supplied host timer callback function.
+ //
+ lwIPHostTimerHandler();
+
+ //
+ // Re-schedule the host timer callback function timeout.
+ //
+ sys_timeout(HOST_TMR_INTERVAL, lwIPPrivateHostTimer, NULL);
+}
+#endif
+
+//*****************************************************************************
+//
+// Handles the timeout for the link detect timer when using a RTOS.
+//
+//*****************************************************************************
+#if !NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+static void
+lwIPPrivateLinkTimer(void *pvArg)
+{
+ //
+ // Perform the link detection.
+ //
+ lwIPLinkDetect();
+
+ //
+ // Re-schedule the link detect timer timeout.
+ //
+ sys_timeout(LINK_TMR_INTERVAL, lwIPPrivateLinkTimer, NULL);
+}
+#endif
+
+//*****************************************************************************
+//
+// Completes the initialization of lwIP. This is directly called when not
+// using a RTOS and provided as a callback to the TCP/IP thread when using a
+// RTOS.
+//
+//*****************************************************************************
+static void
+lwIPPrivateInit(void *pvArg)
+{
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // If not using a RTOS, initialize the lwIP stack.
+ //
+#if NO_SYS
+ lwip_init();
+#endif
+
+ //
+ // If using a RTOS, create a queue (to be used as a semaphore) to signal
+ // the Ethernet interrupt task from the Ethernet interrupt handler.
+ //
+#if !NO_SYS
+#if RTOS_FREERTOS
+ g_pInterrupt = xQueueCreate(1, sizeof(void *));
+#endif
+#endif
+
+ //
+ // If using a RTOS, create the Ethernet interrupt task.
+ //
+#if !NO_SYS
+#if RTOS_FREERTOS
+ xTaskCreate(lwIPInterruptTask, (signed portCHAR *)"eth_int",
+ STACKSIZE_LWIPINTTASK, 0, tskIDLE_PRIORITY + 1,
+ 0);
+#endif
+#endif
+
+ //
+ // Setup the network address values.
+ //
+ if(g_ui32IPMode == IPADDR_USE_STATIC)
+ {
+ ip_addr.addr = htonl(g_ui32IPAddr);
+ net_mask.addr = htonl(g_ui32NetMask);
+ gw_addr.addr = htonl(g_ui32GWAddr);
+ }
+ else
+ {
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ }
+
+ //
+ // Create, configure and add the Ethernet controller interface with
+ // default settings. ip_input should be used to send packets directly to
+ // the stack when not using a RTOS and tcpip_input should be used to send
+ // packets to the TCP/IP thread's queue when using a RTOS.
+ //
+#if NO_SYS
+ netif_add(&g_sNetIF, &ip_addr, &net_mask, &gw_addr, NULL, tivaif_init,
+ ip_input);
+#else
+ netif_add(&g_sNetIF, &ip_addr, &net_mask, &gw_addr, NULL, tivaif_init,
+ tcpip_input);
+#endif
+ netif_set_default(&g_sNetIF);
+
+ //
+ // Bring the interface up.
+ //
+ netif_set_up(&g_sNetIF);
+
+ //
+ // Setup a timeout for the host timer callback function if using a RTOS.
+ //
+#if !NO_SYS && HOST_TMR_INTERVAL
+ sys_timeout(HOST_TMR_INTERVAL, lwIPPrivateHostTimer, NULL);
+#endif
+
+ //
+ // Setup a timeout for the link detect callback function if using a RTOS.
+ //
+#if !NO_SYS && (LWIP_AUTOIP || LWIP_DHCP)
+ sys_timeout(LINK_TMR_INTERVAL, lwIPPrivateLinkTimer, NULL);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Initializes the lwIP TCP/IP stack.
+//!
+//! \param ui32SysClkHz is the current system clock rate in Hz.
+//! \param pui8MAC is a pointer to a six byte array containing the MAC
+//! address to be used for the interface.
+//! \param ui32IPAddr is the IP address to be used (static).
+//! \param ui32NetMask is the network mask to be used (static).
+//! \param ui32GWAddr is the Gateway address to be used (static).
+//! \param ui32IPMode is the IP Address Mode. \b IPADDR_USE_STATIC will force
+//! static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP with
+//! fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will force
+//! Link Local only.
+//!
+//! This function performs initialization of the lwIP TCP/IP stack for the
+//! Ethernet MAC, including DHCP and/or AutoIP, as configured.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPInit(uint32_t ui32SysClkHz, const uint8_t *pui8MAC, uint32_t ui32IPAddr,
+ uint32_t ui32NetMask, uint32_t ui32GWAddr, uint32_t ui32IPMode)
+{
+ //
+ // Check the parameters.
+ //
+#if LWIP_DHCP && LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#elif LWIP_DHCP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP));
+#elif LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#else
+ ASSERT(ui32IPMode == IPADDR_USE_STATIC);
+#endif
+
+ //
+ // Enable the ethernet peripheral.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
+
+ //
+ // Enable the internal PHY if it's present and we're being
+ // asked to use it.
+ //
+ if((EMAC_PHY_CONFIG & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL)
+ {
+ //
+ // We've been asked to configure for use with the internal
+ // PHY. Is it present?
+ //
+ if(MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_EPHY0))
+ {
+ //
+ // Yes - enable and reset it.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
+ }
+ else
+ {
+ //
+ // Internal PHY is not present on this part so hang here.
+ //
+ while(1)
+ {
+ }
+ }
+ }
+
+ //
+ // Wait for the MAC to come out of reset.
+ //
+ while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
+ {
+ }
+
+ //
+ // Configure for use with whichever PHY the user requires.
+ //
+ MAP_EMACPHYConfigSet(EMAC0_BASE, EMAC_PHY_CONFIG);
+
+ //
+ // Initialize the MAC and set the DMA mode.
+ //
+ MAP_EMACInit(EMAC0_BASE, ui32SysClkHz,
+ EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED,
+ 4, 4, 0);
+
+ //
+ // Set MAC configuration options.
+ //
+ MAP_EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX |
+ EMAC_CONFIG_CHECKSUM_OFFLOAD |
+ EMAC_CONFIG_7BYTE_PREAMBLE |
+ EMAC_CONFIG_IF_GAP_96BITS |
+ EMAC_CONFIG_USE_MACADDR0 |
+ EMAC_CONFIG_SA_FROM_DESCRIPTOR |
+ EMAC_CONFIG_BO_LIMIT_1024),
+ (EMAC_MODE_RX_STORE_FORWARD |
+ EMAC_MODE_TX_STORE_FORWARD |
+ EMAC_MODE_TX_THRESHOLD_64_BYTES |
+ EMAC_MODE_RX_THRESHOLD_64_BYTES), 0);
+
+ //
+ // Program the hardware with its MAC address (for filtering).
+ //
+ MAP_EMACAddrSet(EMAC0_BASE, 0, (uint8_t *)pui8MAC);
+
+ //
+ // Save the network configuration for later use by the private
+ // initialization.
+ //
+ g_ui32IPMode = ui32IPMode;
+ g_ui32IPAddr = ui32IPAddr;
+ g_ui32NetMask = ui32NetMask;
+ g_ui32GWAddr = ui32GWAddr;
+
+ //
+ // Initialize lwIP. The remainder of initialization is done immediately if
+ // not using a RTOS and it is deferred to the TCP/IP thread's context if
+ // using a RTOS.
+ //
+#if NO_SYS
+ lwIPPrivateInit(0);
+#else
+ tcpip_init(lwIPPrivateInit, 0);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Registers an interrupt callback function to handle the IEEE-1588 timer.
+//!
+//! \param pfnTimerFunc points to a function which is called whenever the
+//! Ethernet MAC reports an interrupt relating to the IEEE-1588 hardware timer.
+//!
+//! This function allows an application to register a handler for all
+//! interrupts generated by the IEEE-1588 hardware timer in the Ethernet MAC.
+//! To allow minimal latency timer handling, the callback function provided
+//! will be called in interrupt context, regardless of whether or not lwIP is
+//! configured to operate with an RTOS. In an RTOS environment, the callback
+//! function is responsible for ensuring that all processing it performs is
+//! compatible with the low level interrupt context it is called in.
+//!
+//! The callback function takes two parameters. The first is the base address
+//! of the MAC reporting the timer interrupt and the second is the timer
+//! interrupt status as reported by EMACTimestampIntStatus(). Note that
+//! EMACTimestampIntStatus() causes the timer interrupt sources to be cleared
+//! so the application should not call EMACTimestampIntStatus() within the
+//! handler.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPTimerCallbackRegister(tHardwareTimerHandler pfnTimerFunc)
+{
+ //
+ // Remember the callback function address passed.
+ //
+ g_pfnTimerHandler = pfnTimerFunc;
+}
+
+//*****************************************************************************
+//
+//! Handles periodic timer events for the lwIP TCP/IP stack.
+//!
+//! \param ui32TimeMS is the incremental time for this periodic interrupt.
+//!
+//! This function will update the local timer by the value in \e ui32TimeMS.
+//! If the system is configured for use without an RTOS, an Ethernet interrupt
+//! will be triggered to allow the lwIP periodic timers to be serviced in the
+//! Ethernet interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if NO_SYS
+void
+lwIPTimer(uint32_t ui32TimeMS)
+{
+ //
+ // Increment the lwIP Ethernet timer.
+ //
+ g_ui32LocalTimer += ui32TimeMS;
+
+ //
+ // Generate an Ethernet interrupt. This will perform the actual work
+ // of checking the lwIP timers and taking the appropriate actions. This is
+ // needed since lwIP is not re-entrant, and this allows all lwIP calls to
+ // be placed inside the Ethernet interrupt handler ensuring that all calls
+ // into lwIP are coming from the same context, preventing any reentrancy
+ // issues. Putting all the lwIP calls in the Ethernet interrupt handler
+ // avoids the use of mutexes to avoid re-entering lwIP.
+ //
+ HWREG(NVIC_SW_TRIG) |= INT_EMAC0 - 16;
+}
+#endif
+
+//*****************************************************************************
+//
+//! Handles Ethernet interrupts for the lwIP TCP/IP stack.
+//!
+//! This function handles Ethernet interrupts for the lwIP TCP/IP stack. At
+//! the lowest level, all receive packets are placed into a packet queue for
+//! processing at a higher level. Also, the transmit packet queue is checked
+//! and packets are drained and transmitted through the Ethernet MAC as needed.
+//! If the system is configured without an RTOS, additional processing is
+//! performed at the interrupt level. The packet queues are processed by the
+//! lwIP TCP/IP code, and lwIP periodic timers are serviced (as needed).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPEthernetIntHandler(void)
+{
+ uint32_t ui32Status;
+ uint32_t ui32TimerStatus;
+#if !NO_SYS
+ portBASE_TYPE xWake;
+#endif
+
+ //
+ // Read and Clear the interrupt.
+ //
+ ui32Status = MAP_EMACIntStatus(EMAC0_BASE, true);
+
+ //
+ // If the interrupt really came from the Ethernet and not our
+ // timer, clear it.
+ //
+ if(ui32Status)
+ {
+ MAP_EMACIntClear(EMAC0_BASE, ui32Status);
+ }
+
+ //
+ // Check to see whether a hardware timer interrupt has been reported.
+ //
+ if(ui32Status & EMAC_INT_TIMESTAMP)
+ {
+ //
+ // Yes - read and clear the timestamp interrupt status.
+ //
+ ui32TimerStatus = EMACTimestampIntStatus(EMAC0_BASE);
+
+ //
+ // If a timer interrupt handler has been registered, call it.
+ //
+ if(g_pfnTimerHandler)
+ {
+ g_pfnTimerHandler(EMAC0_BASE, ui32TimerStatus);
+ }
+ }
+
+ //
+ // The handling of the interrupt is different based on the use of a RTOS.
+ //
+#if NO_SYS
+ //
+ // No RTOS is being used. If a transmit/receive interrupt was active,
+ // run the low-level interrupt handler.
+ //
+ if(ui32Status)
+ {
+ tivaif_interrupt(&g_sNetIF, ui32Status);
+ }
+
+ //
+ // Service the lwIP timers.
+ //
+ lwIPServiceTimers();
+#else
+ //
+ // A RTOS is being used. Signal the Ethernet interrupt task.
+ //
+ xQueueSendFromISR(g_pInterrupt, (void *)&ui32Status, &xWake);
+
+ //
+ // Disable the Ethernet interrupts. Since the interrupts have not been
+ // handled, they are not asserted. Once they are handled by the Ethernet
+ // interrupt task, it will re-enable the interrupts.
+ //
+ MAP_EMACIntDisable(EMAC0_BASE, (EMAC_INT_RECEIVE | EMAC_INT_TRANSMIT |
+ EMAC_INT_TX_STOPPED |
+ EMAC_INT_RX_NO_BUFFER |
+ EMAC_INT_RX_STOPPED | EMAC_INT_PHY));
+
+ //
+ // Potentially task switch as a result of the above queue write.
+ //
+#if RTOS_FREERTOS
+ if(xWake == pdTRUE)
+ {
+ portYIELD_FROM_ISR(true);
+ }
+#endif
+#endif
+}
+
+//*****************************************************************************
+//
+//! Returns the IP address for this interface.
+//!
+//! This function will read and return the currently assigned IP address for
+//! the Stellaris Ethernet interface.
+//!
+//! \return Returns the assigned IP address for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalIPAddrGet(void)
+{
+#if LWIP_AUTOIP || LWIP_DHCP
+ if(g_bLinkActive)
+ {
+ return((uint32_t)g_sNetIF.ip_addr.addr);
+ }
+ else
+ {
+ return(0xffffffff);
+ }
+#else
+ return((uint32_t)g_sNetIF.ip_addr.addr);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Returns the network mask for this interface.
+//!
+//! This function will read and return the currently assigned network mask for
+//! the Stellaris Ethernet interface.
+//!
+//! \return the assigned network mask for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalNetMaskGet(void)
+{
+ return((uint32_t)g_sNetIF.netmask.addr);
+}
+
+//*****************************************************************************
+//
+//! Returns the gateway address for this interface.
+//!
+//! This function will read and return the currently assigned gateway address
+//! for the Stellaris Ethernet interface.
+//!
+//! \return the assigned gateway address for this interface.
+//
+//*****************************************************************************
+uint32_t
+lwIPLocalGWAddrGet(void)
+{
+ return((uint32_t)g_sNetIF.gw.addr);
+}
+
+//*****************************************************************************
+//
+//! Returns the local MAC/HW address for this interface.
+//!
+//! \param pui8MAC is a pointer to an array of bytes used to store the MAC
+//! address.
+//!
+//! This function will read the currently assigned MAC address into the array
+//! passed in \e pui8MAC.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPLocalMACGet(uint8_t *pui8MAC)
+{
+ MAP_EMACAddrGet(EMAC0_BASE, 0, pui8MAC);
+}
+
+//*****************************************************************************
+//
+// Completes the network configuration change. This is directly called when
+// not using a RTOS and provided as a callback to the TCP/IP thread when using
+// a RTOS.
+//
+//*****************************************************************************
+static void
+lwIPPrivateNetworkConfigChange(void *pvArg)
+{
+ uint32_t ui32IPMode;
+ struct ip_addr ip_addr;
+ struct ip_addr net_mask;
+ struct ip_addr gw_addr;
+
+ //
+ // Get the new address mode.
+ //
+ ui32IPMode = (uint32_t)pvArg;
+
+ //
+ // Setup the network address values.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ ip_addr.addr = htonl(g_ui32IPAddr);
+ net_mask.addr = htonl(g_ui32NetMask);
+ gw_addr.addr = htonl(g_ui32GWAddr);
+ }
+#if LWIP_DHCP || LWIP_AUTOIP
+ else
+ {
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+ }
+#endif
+
+ //
+ // Switch on the current IP Address Aquisition mode.
+ //
+ switch(g_ui32IPMode)
+ {
+ //
+ // Static IP
+ //
+ case IPADDR_USE_STATIC:
+ {
+ //
+ // Set the new address parameters. This will change the address
+ // configuration in lwIP, and if necessary, will reset any links
+ // that are active. This is valid for all three modes.
+ //
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+
+ //
+ // If we are going to DHCP mode, then start the DHCP server now.
+ //
+#if LWIP_DHCP
+ if((ui32IPMode == IPADDR_USE_DHCP) && g_bLinkActive)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // If we are going to AutoIP mode, then start the AutoIP process
+ // now.
+ //
+#if LWIP_AUTOIP
+ if((ui32IPMode == IPADDR_USE_AUTOIP) && g_bLinkActive)
+ {
+ autoip_start(&g_sNetIF);
+ }
+#endif
+
+ //
+ // And we're done.
+ //
+ break;
+ }
+
+ //
+ // DHCP (with AutoIP fallback).
+ //
+#if LWIP_DHCP
+ case IPADDR_USE_DHCP:
+ {
+ //
+ // If we are going to static IP addressing, then disable DHCP and
+ // force the new static IP address.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ dhcp_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ }
+
+ //
+ // If we are going to AUTO IP addressing, then disable DHCP, set
+ // the default addresses, and start AutoIP.
+ //
+#if LWIP_AUTOIP
+ else if(ui32IPMode == IPADDR_USE_AUTOIP)
+ {
+ dhcp_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ if(g_bLinkActive)
+ {
+ autoip_start(&g_sNetIF);
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ //
+ // AUTOIP
+ //
+#if LWIP_AUTOIP
+ case IPADDR_USE_AUTOIP:
+ {
+ //
+ // If we are going to static IP addressing, then disable AutoIP and
+ // force the new static IP address.
+ //
+ if(ui32IPMode == IPADDR_USE_STATIC)
+ {
+ autoip_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ }
+
+ //
+ // If we are going to DHCP addressing, then disable AutoIP, set the
+ // default addresses, and start dhcp.
+ //
+#if LWIP_DHCP
+ else if(ui32IPMode == IPADDR_USE_DHCP)
+ {
+ autoip_stop(&g_sNetIF);
+ netif_set_addr(&g_sNetIF, &ip_addr, &net_mask, &gw_addr);
+ if(g_bLinkActive)
+ {
+ dhcp_start(&g_sNetIF);
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ }
+
+ //
+ // Bring the interface up.
+ //
+ netif_set_up(&g_sNetIF);
+
+ //
+ // Save the new mode.
+ //
+ g_ui32IPMode = ui32IPMode;
+}
+
+//*****************************************************************************
+//
+//! Change the configuration of the lwIP network interface.
+//!
+//! \param ui32IPAddr is the new IP address to be used (static).
+//! \param ui32NetMask is the new network mask to be used (static).
+//! \param ui32GWAddr is the new Gateway address to be used (static).
+//! \param ui32IPMode is the IP Address Mode. \b IPADDR_USE_STATIC 0 will
+//! force static IP addressing to be used, \b IPADDR_USE_DHCP will force DHCP
+//! with fallback to Link Local (Auto IP), while \b IPADDR_USE_AUTOIP will
+//! force Link Local only.
+//!
+//! This function will evaluate the new configuration data. If necessary, the
+//! interface will be brought down, reconfigured, and then brought back up
+//! with the new configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+lwIPNetworkConfigChange(uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode)
+{
+ //
+ // Check the parameters.
+ //
+#if LWIP_DHCP && LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#elif LWIP_DHCP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_DHCP));
+#elif LWIP_AUTOIP
+ ASSERT((ui32IPMode == IPADDR_USE_STATIC) ||
+ (ui32IPMode == IPADDR_USE_AUTOIP));
+#else
+ ASSERT(ui32IPMode == IPADDR_USE_STATIC);
+#endif
+
+ //
+ // Save the network configuration for later use by the private network
+ // configuration change.
+ //
+ g_ui32IPAddr = ui32IPAddr;
+ g_ui32NetMask = ui32NetMask;
+ g_ui32GWAddr = ui32GWAddr;
+
+ //
+ // Complete the network configuration change. The remainder is done
+ // immediately if not using a RTOS and it is deferred to the TCP/IP
+ // thread's context if using a RTOS.
+ //
+#if NO_SYS
+ lwIPPrivateNetworkConfigChange((void *)ui32IPMode);
+#else
+ tcpip_callback(lwIPPrivateNetworkConfigChange, (void *)ui32IPMode);
+#endif
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/lwiplib.h b/utils/lwiplib.h
new file mode 100644
index 0000000..3a3f622
--- /dev/null
+++ b/utils/lwiplib.h
@@ -0,0 +1,121 @@
+//*****************************************************************************
+//
+// lwiplib.h - Prototypes for the lwIP library wrapper API.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __LWIPLIB_H__
+#define __LWIPLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// lwIP Options
+//
+//*****************************************************************************
+#include "lwip/opt.h"
+
+//*****************************************************************************
+//
+// Ensure that AUTOIP COOP option is configured correctly.
+//
+//*****************************************************************************
+#undef LWIP_DHCP_AUTOIP_COOP
+#define LWIP_DHCP_AUTOIP_COOP ((LWIP_DHCP) && (LWIP_AUTOIP))
+
+//*****************************************************************************
+//
+// lwIP API Header Files
+//
+//*****************************************************************************
+#include <stdint.h>
+#include "lwip/api.h"
+#include "lwip/netifapi.h"
+#include "lwip/tcp.h"
+#include "lwip/udp.h"
+#include "lwip/tcpip.h"
+#include "lwip/sockets.h"
+#include "lwip/mem.h"
+#include "lwip/stats.h"
+#include "lwip/def.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/timers.h"
+
+//*****************************************************************************
+//
+// IP Address Acquisition Modes
+//
+//*****************************************************************************
+#define IPADDR_USE_STATIC 0
+#define IPADDR_USE_DHCP 1
+#define IPADDR_USE_AUTOIP 2
+
+//*****************************************************************************
+//
+// Hardware timer interrupt callback function type (available only when running
+// on TM4C parts). This function is called in interrupt context whenever the
+// Ethernet MAC reports an interrupt from the IEEE-1588 timestamping
+// timer. The first parameter is the base address of the MAC and the second
+// is the interrupt status as reported via EthMACTimestampIntStatus.
+//
+//*****************************************************************************
+typedef void (* tHardwareTimerHandler)(uint32_t ui32Base,
+ uint32_t ui32IntStatus);
+
+//*****************************************************************************
+//
+// lwIP Abstraction Layer API
+//
+//*****************************************************************************
+extern void lwIPInit(uint32_t ui32SysClkHz, const uint8_t *pui8Mac,
+ uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode);
+extern void lwIPTimerCallbackRegister(tHardwareTimerHandler pfnTimerFunc);
+extern void lwIPTimer(uint32_t ui32TimeMS);
+extern void lwIPEthernetIntHandler(void);
+extern uint32_t lwIPLocalIPAddrGet(void);
+extern uint32_t lwIPLocalNetMaskGet(void);
+extern uint32_t lwIPLocalGWAddrGet(void);
+extern void lwIPLocalMACGet(uint8_t *pui8Mac);
+extern void lwIPNetworkConfigChange(uint32_t ui32IPAddr, uint32_t ui32NetMask,
+ uint32_t ui32GWAddr, uint32_t ui32IPMode);
+extern uint32_t lwIPAcceptUDPPort(uint16_t ui16Port);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LWIPLIB_H__
diff --git a/utils/ptpdlib.c b/utils/ptpdlib.c
new file mode 100644
index 0000000..ec340d2
--- /dev/null
+++ b/utils/ptpdlib.c
@@ -0,0 +1,56 @@
+//*****************************************************************************
+//
+// ptpdlib.c - ptpd Library Abstraction Layer.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Include the necessary system header files.
+//
+//*****************************************************************************
+#include <limits.h>
+
+//*****************************************************************************
+//
+// Include the library source code header files next.
+//
+//*****************************************************************************
+#include "utils/ptpdlib.h"
+
+//*****************************************************************************
+//
+// Include ptpd library code.
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/arith.c"
+#include "ptpd-1.1.0/src/bmc.c"
+#include "ptpd-1.1.0/src/protocol.c"
+
+//*****************************************************************************
+//
+// Include ptpd porting layer code.
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_timer.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_servo.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_msg.c"
+#include "ptpd-1.1.0/src/dep-tiva/ptpd_net.c"
diff --git a/utils/ptpdlib.h b/utils/ptpdlib.h
new file mode 100644
index 0000000..5692877
--- /dev/null
+++ b/utils/ptpdlib.h
@@ -0,0 +1,55 @@
+//*****************************************************************************
+//
+// ptpdlib.h - Prototypes for the ptpd library wrapper API.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __PTPDLIB_H__
+#define __PTPDLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// ptpd API Header Files
+//
+//*****************************************************************************
+#include "ptpd-1.1.0/src/ptpd.h"
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PTPDLIB_H__
diff --git a/utils/random.c b/utils/random.c
new file mode 100644
index 0000000..0588c44
--- /dev/null
+++ b/utils/random.c
@@ -0,0 +1,169 @@
+//*****************************************************************************
+//
+// random.c - Random number generator utilizing MD4 hash function of
+// environmental noise captured as the seed and a linear congruence
+// generator for the random numbers.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "ustdlib.h"
+#include "random.h"
+
+//*****************************************************************************
+//
+//! \addtogroup random_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The pool of entropy that has been collected.
+//
+//*****************************************************************************
+static uint32_t g_pui32RandomEntropy[16];
+
+//*****************************************************************************
+//
+// The index of the next byte to be added to the entropy pool.
+//
+//*****************************************************************************
+static uint32_t g_ui32RandomIndex = 0;
+
+//*****************************************************************************
+//
+//! Add entropy to the pool.
+//!
+//! \param ui32Entropy is an 8-bit value that is added to the entropy pool
+//!
+//! This function allows the user application code to add entropy (random data)
+//! to the pool at any time.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+RandomAddEntropy(uint32_t ui32Entropy)
+{
+ //
+ // Add this byte to the entropy pool.
+ //
+ ((uint8_t *)g_pui32RandomEntropy)[g_ui32RandomIndex] = ui32Entropy & 0xff;
+
+ //
+ // Increment to the next byte of the entropy pool.
+ //
+ g_ui32RandomIndex = (g_ui32RandomIndex + 1) & 63;
+}
+
+//*****************************************************************************
+//
+//! Set the random number generator seed.
+//!
+//! Seed the random number generator by running a MD4 hash on the entropy pool.
+//! Note that the entropy pool may change from beneath us, but for the purposes
+//! of generating random numbers that is not a concern. Also, the MD4 hash was
+//! broken long ago, but since it is being used to generate random numbers
+//! instead of providing security this is not a concern.
+//!
+//! \return New seed value.
+//
+//*****************************************************************************
+uint32_t
+RandomSeed(void)
+{
+ uint32_t ui32A, ui32B, ui32C, ui32D, ui32Temp, ui32Idx;
+
+ //
+ // Initialize the digest.
+ //
+ ui32A = 0x67452301;
+ ui32B = 0xefcdab89;
+ ui32C = 0x98badcfe;
+ ui32D = 0x10325476;
+
+ //
+ // Perform the first round of operations.
+ //
+#define F(a, b, c, d, k, s) \
+ { \
+ ui32Temp = a + (d ^ (b & (c ^ d))) + g_pui32RandomEntropy[k]; \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 16; ui32Idx += 4)
+ {
+ F(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ F(ui32D, ui32A, ui32B, ui32C, ui32Idx + 1, 7);
+ F(ui32C, ui32D, ui32A, ui32B, ui32Idx + 2, 11);
+ F(ui32B, ui32C, ui32D, ui32A, ui32Idx + 3, 19);
+ }
+
+ //
+ // Perform the second round of operations.
+ //
+#define G(a, b, c, d, k, s) \
+ { \
+ ui32Temp = (a + ((b & c) | (b & d) | (c & d)) + \
+ g_pui32RandomEntropy[k] + 0x5a827999); \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 4; ui32Idx++)
+ {
+ G(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ G(ui32D, ui32A, ui32B, ui32C, ui32Idx + 4, 5);
+ G(ui32C, ui32D, ui32A, ui32B, ui32Idx + 8, 9);
+ G(ui32B, ui32C, ui32D, ui32A, ui32Idx + 12, 13);
+ }
+
+ //
+ // Perform the third round of operations.
+ //
+#define H(a, b, c, d, k, s) \
+ { \
+ ui32Temp = a + (b ^ c ^ d) + g_pui32RandomEntropy[k] + 0x6ed9eba1; \
+ a = (ui32Temp << s) | (ui32Temp >> (32 - s)); \
+ }
+ for(ui32Idx = 0; ui32Idx < 4; ui32Idx += 2)
+ {
+ H(ui32A, ui32B, ui32C, ui32D, ui32Idx + 0, 3);
+ H(ui32D, ui32A, ui32B, ui32C, ui32Idx + 8, 9);
+ H(ui32C, ui32D, ui32A, ui32B, ui32Idx + 4, 11);
+ H(ui32B, ui32C, ui32D, ui32A, ui32Idx + 12, 15);
+
+ if(ui32Idx == 2)
+ {
+ ui32Idx -= 3;
+ }
+ }
+
+ //
+ // Use the first word of the resulting digest as the random number seed.
+ //
+ return(ui32A + 0x67452301);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/random.h b/utils/random.h
new file mode 100644
index 0000000..a2c719e
--- /dev/null
+++ b/utils/random.h
@@ -0,0 +1,56 @@
+//*****************************************************************************
+//
+// random.h - Header for random number generation functions.
+//
+// Copyright (c) 2011-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __RANDOM_H__
+#define __RANDOM_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the random number generator functions.
+//
+//*****************************************************************************
+extern void RandomAddEntropy(uint32_t ui32Entropy);
+extern uint32_t RandomSeed(void);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RANDOM_H__
diff --git a/utils/ringbuf.c b/utils/ringbuf.c
new file mode 100644
index 0000000..f489239
--- /dev/null
+++ b/utils/ringbuf.c
@@ -0,0 +1,712 @@
+//*****************************************************************************
+//
+// ringbuf.c - Ring buffer management utilities.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "utils/ringbuf.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ringbuf_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//*****************************************************************************
+//
+// Change the value of a variable atomically.
+//
+// \param pui32Val points to the index whose value is to be modified.
+// \param ui32Delta is the number of bytes to increment the index by.
+// \param ui32Size is the size of the buffer the index refers to.
+//
+// This function is used to increment a read or write buffer index that may be
+// written in various different contexts. It ensures that the
+// read/modify/write sequence is not interrupted and, hence, guards against
+// corruption of the variable. The new value is adjusted for buffer wrap.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateIndexAtomic(volatile uint32_t *pui32Val, uint32_t ui32Delta,
+ uint32_t ui32Size)
+{
+ bool bIntsOff;
+
+ //
+ // Turn interrupts off temporarily.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the variable value.
+ //
+ *pui32Val += ui32Delta;
+
+ //
+ // Correct for wrap. We use a loop here since we don't want to use a
+ // modulus operation with interrupts off but we don't want to fail in
+ // case ui32Delta is greater than ui32Size (which is extremely unlikely
+ // but...)
+ //
+ while(*pui32Val >= ui32Size)
+ {
+ *pui32Val -= ui32Size;
+ }
+
+ //
+ // Restore the interrupt state
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is full or not.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is full or \b false otherwise.
+//
+//*****************************************************************************
+bool
+RingBufFull(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the full status of the buffer.
+ //
+ return((((ui32Write + 1) % psRingBuf->ui32Size) == ui32Read) ? true :
+ false);
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is empty or \b false otherwise.
+//
+//*****************************************************************************
+bool
+RingBufEmpty(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the empty status of the buffer.
+ //
+ return((ui32Write == ui32Read) ? true : false);
+}
+
+//*****************************************************************************
+//
+//! Empties the ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to empty.
+//!
+//! Discards all data from the ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufFlush(tRingBufObject *psRingBuf)
+{
+ bool bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Set the Read/Write pointers to be the same. Do this with interrupts
+ // disabled to prevent the possibility of corruption of the read index.
+ //
+ bIntsOff = IntMasterDisable();
+ psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex;
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes stored in ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes stored in the ring buffer.
+//!
+//! \return Returns the number of bytes stored in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufUsed(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of bytes contained in the ring buffer.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psRingBuf->ui32Size - (ui32Read - ui32Write)));
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes available in a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes available in the ring buffer.
+//!
+//! \return Returns the number of bytes available in the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufFree(tRingBufObject *psRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return((psRingBuf->ui32Size - 1) - RingBufUsed(psRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous bytes of data stored in ring buffer ahead of
+//! the current read pointer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous bytes of data available in
+//! the ring buffer ahead of the current read pointer. This represents the
+//! largest block of data which does not straddle the buffer wrap.
+//!
+//! \return Returns the number of contiguous bytes available.
+//
+//*****************************************************************************
+uint32_t
+RingBufContigUsed(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (psRingBuf->ui32Size - ui32Read));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous free bytes available in a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous free bytes ahead of the
+//! current write pointer in the ring buffer.
+//!
+//! \return Returns the number of contiguous bytes available in the ring
+//! buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufContigFree(tRingBufObject *psRingBuf)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ui32Write = psRingBuf->ui32WriteIndex;
+ ui32Read = psRingBuf->ui32ReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ if(ui32Read > ui32Write)
+ {
+ //
+ // The read pointer is above the write pointer so the amount of free
+ // space is the difference between the two indices minus 1 to account
+ // for the buffer full condition (write index one behind read index).
+ //
+ return((ui32Read - ui32Write) - 1);
+ }
+ else
+ {
+ //
+ // If the write pointer is above the read pointer, the amount of free
+ // space is the size of the buffer minus the write index. We need to
+ // add a special-case adjustment if the read index is 0 since we need
+ // to leave 1 byte empty to ensure we can tell the difference between
+ // the buffer being full and empty.
+ //
+ return(psRingBuf->ui32Size - ui32Write - ((ui32Read == 0) ? 1 : 0));
+ }
+}
+
+//*****************************************************************************
+//
+//! Return size in bytes of a ring buffer.
+//!
+//! \param psRingBuf is the ring buffer object to check.
+//!
+//! This function returns the size of the ring buffer.
+//!
+//! \return Returns the size in bytes of the ring buffer.
+//
+//*****************************************************************************
+uint32_t
+RingBufSize(tRingBufObject *psRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return(psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Reads a single byte of data from a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//!
+//! This function reads a single byte of data from a ring buffer.
+//!
+//! \return The byte read from the ring buffer.
+//
+//*****************************************************************************
+uint8_t
+RingBufReadOne(tRingBufObject *psRingBuf)
+{
+ uint8_t ui8Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufUsed(psRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ ui8Temp = psRingBuf->pui8Buf[psRingBuf->ui32ReadIndex];
+
+ //
+ // Increment the read index.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, 1, psRingBuf->ui32Size);
+
+ //
+ // Return the character read.
+ //
+ return(ui8Temp);
+}
+
+//*****************************************************************************
+//
+//! Reads data from a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be read from.
+//! \param pui8Data points to where the data should be stored.
+//! \param ui32Length is the number of bytes to be read.
+//!
+//! This function reads a sequence of bytes from a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufRead(tRingBufObject *psRingBuf, uint8_t *pui8Data, uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that data is available in the buffer.
+ //
+ ASSERT(ui32Length <= RingBufUsed(psRingBuf));
+
+ //
+ // Read the data from the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ pui8Data[ui32Temp] = RingBufReadOne(psRingBuf);
+ }
+}
+
+//*****************************************************************************
+//
+//! Remove bytes from the ring buffer by advancing the read index.
+//!
+//! \param psRingBuf points to the ring buffer from which bytes are to be
+//! removed.
+//! \param ui32NumBytes is the number of bytes to be removed from the buffer.
+//!
+//! This function advances the ring buffer read index by a given number of
+//! bytes, removing that number of bytes of data from the buffer. If
+//! \e ui32NumBytes is larger than the number of bytes currently in the buffer,
+//! the buffer is emptied.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceRead(tRingBufObject *psRingBuf, uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Make sure that we are not being asked to remove more data than is
+ // there to be removed.
+ //
+ ui32Count = RingBufUsed(psRingBuf);
+ ui32Count = (ui32Count < ui32NumBytes) ? ui32Count : ui32NumBytes;
+
+ //
+ // Advance the buffer read index by the required number of bytes.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32ReadIndex, ui32Count,
+ psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Add bytes to the ring buffer by advancing the write index.
+//!
+//! \param psRingBuf points to the ring buffer to which bytes have been added.
+//! \param ui32NumBytes is the number of bytes added to the buffer.
+//!
+//! This function should be used by clients who wish to add data to the buffer
+//! directly rather than via calls to RingBufWrite() or RingBufWriteOne(). It
+//! advances the write index by a given number of bytes. If the
+//! \e ui32NumBytes parameter is larger than the amount of free space in the
+//! buffer, the read pointer will be advanced to cater for the addition. Note
+//! that this will result in some of the oldest data in the buffer being
+//! discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceWrite(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes)
+{
+ uint32_t ui32Count;
+ bool bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Make sure we were not asked to add a silly number of bytes.
+ //
+ ASSERT(ui32NumBytes <= psRingBuf->ui32Size);
+
+ //
+ // Determine how much free space we currently think the buffer has.
+ //
+ ui32Count = RingBufFree(psRingBuf);
+
+ //
+ // Advance the buffer write index by the required number of bytes and
+ // check that we have not run past the read index. Note that we must do
+ // this within a critical section (interrupts disabled) to prevent
+ // race conditions that could corrupt one or other of the indices.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the write pointer.
+ //
+ psRingBuf->ui32WriteIndex += ui32NumBytes;
+
+ //
+ // Check and correct for wrap.
+ //
+ if(psRingBuf->ui32WriteIndex >= psRingBuf->ui32Size)
+ {
+ psRingBuf->ui32WriteIndex -= psRingBuf->ui32Size;
+ }
+
+ //
+ // Did the client add more bytes than the buffer had free space for?
+ //
+ if(ui32Count < ui32NumBytes)
+ {
+ //
+ // Yes - we need to advance the read pointer to ahead of the write
+ // pointer to discard some of the oldest data.
+ //
+ psRingBuf->ui32ReadIndex = psRingBuf->ui32WriteIndex + 1;
+
+ //
+ // Correct for buffer wrap if necessary.
+ //
+ if(psRingBuf->ui32ReadIndex >= psRingBuf->ui32Size)
+ {
+ psRingBuf->ui32ReadIndex -= psRingBuf->ui32Size;
+ }
+ }
+
+ //
+ // Restore interrupts if we turned them off earlier.
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Writes a single byte of data to a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//! \param ui8Data is the byte to be written.
+//!
+//! This function writes a single byte of data into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWriteOne(tRingBufObject *psRingBuf, uint8_t ui8Data)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufFree(psRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ psRingBuf->pui8Buf[psRingBuf->ui32WriteIndex] = ui8Data;
+
+ //
+ // Increment the write index.
+ //
+ UpdateIndexAtomic(&psRingBuf->ui32WriteIndex, 1, psRingBuf->ui32Size);
+}
+
+//*****************************************************************************
+//
+//! Writes data to a ring buffer.
+//!
+//! \param psRingBuf points to the ring buffer to be written to.
+//! \param pui8Data points to the data to be written.
+//! \param ui32Length is the number of bytes to be written.
+//!
+//! This function write a sequence of bytes into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWrite(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Data != NULL);
+ ASSERT(ui32Length != 0);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(ui32Length <= RingBufFree(psRingBuf));
+
+ //
+ // Write the data into the ring buffer.
+ //
+ for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
+ {
+ RingBufWriteOne(psRingBuf, pui8Data[ui32Temp]);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initialize a ring buffer object.
+//!
+//! \param psRingBuf points to the ring buffer to be initialized.
+//! \param pui8Buf points to the data buffer to be used for the ring buffer.
+//! \param ui32Size is the size of the buffer in bytes.
+//!
+//! This function initializes a ring buffer object, preparing it to store data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufInit(tRingBufObject *psRingBuf, uint8_t *pui8Buf,
+ uint32_t ui32Size)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psRingBuf != NULL);
+ ASSERT(pui8Buf != NULL);
+ ASSERT(ui32Size != 0);
+
+ //
+ // Initialize the ring buffer object.
+ //
+ psRingBuf->ui32Size = ui32Size;
+ psRingBuf->pui8Buf = pui8Buf;
+ psRingBuf->ui32WriteIndex = psRingBuf->ui32ReadIndex = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ringbuf.h b/utils/ringbuf.h
new file mode 100644
index 0000000..9b1ff56
--- /dev/null
+++ b/utils/ringbuf.h
@@ -0,0 +1,105 @@
+//*****************************************************************************
+//
+// ringbuf.h - Defines and Macros for the ring buffer utilities.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __RINGBUF_H__
+#define __RINGBUF_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure used for encapsulating all the items associated with a
+// ring buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The ring buffer size.
+ //
+ uint32_t ui32Size;
+
+ //
+ // The ring buffer write index.
+ //
+ volatile uint32_t ui32WriteIndex;
+
+ //
+ // The ring buffer read index.
+ //
+ volatile uint32_t ui32ReadIndex;
+
+ //
+ // The ring buffer.
+ //
+ uint8_t *pui8Buf;
+
+}
+tRingBufObject;
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern bool RingBufFull(tRingBufObject *psRingBuf);
+extern bool RingBufEmpty(tRingBufObject *psRingBuf);
+extern void RingBufFlush(tRingBufObject *psRingBuf);
+extern uint32_t RingBufUsed(tRingBufObject *psRingBuf);
+extern uint32_t RingBufFree(tRingBufObject *psRingBuf);
+extern uint32_t RingBufContigUsed(tRingBufObject *psRingBuf);
+extern uint32_t RingBufContigFree(tRingBufObject *psRingBuf);
+extern uint32_t RingBufSize(tRingBufObject *psRingBuf);
+extern uint8_t RingBufReadOne(tRingBufObject *psRingBuf);
+extern void RingBufRead(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length);
+extern void RingBufWriteOne(tRingBufObject *psRingBuf, uint8_t ui8Data);
+extern void RingBufWrite(tRingBufObject *psRingBuf, uint8_t *pui8Data,
+ uint32_t ui32Length);
+extern void RingBufAdvanceWrite(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes);
+extern void RingBufAdvanceRead(tRingBufObject *psRingBuf,
+ uint32_t ui32NumBytes);
+extern void RingBufInit(tRingBufObject *psRingBuf, uint8_t *pui8Buf,
+ uint32_t ui32Size);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RINGBUF_H__
diff --git a/utils/scheduler.c b/utils/scheduler.c
new file mode 100644
index 0000000..bb66c4e
--- /dev/null
+++ b/utils/scheduler.c
@@ -0,0 +1,310 @@
+//*****************************************************************************
+//
+// scheduler.c - A simple task scheduler
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "driverlib/systick.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/debug.h"
+#include "utils/scheduler.h"
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+static volatile uint32_t g_ui32SchedulerTickCount;
+
+//*****************************************************************************
+//
+//! Handles the SysTick interrupt on behalf of the scheduler module.
+//!
+//! Applications using the scheduler module must ensure that this function is
+//! hooked to the SysTick interrupt vector.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerSysTickIntHandler(void)
+{
+ g_ui32SchedulerTickCount++;
+}
+
+//*****************************************************************************
+//
+//! Initializes the task scheduler.
+//!
+//! \param ui32TicksPerSecond sets the basic frequency of the SysTick interrupt
+//! used by the scheduler to determine when to run the various task functions.
+//!
+//! This function must be called during application startup to configure the
+//! SysTick timer. This is used by the scheduler module to determine when each
+//! of the functions provided in the g_psSchedulerTable array is called.
+//!
+//! The caller is responsible for ensuring that SchedulerSysTickIntHandler()
+//! has previously been installed in the SYSTICK vector in the vector table
+//! and must also ensure that interrupts are enabled at the CPU level.
+//!
+//! Note that this call does not start the scheduler calling the configured
+//! functions. All function calls are made in the context of later calls to
+//! SchedulerRun(). This call merely configures the SysTick interrupt that is
+//! used by the scheduler to determine what the current system time is.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerInit(uint32_t ui32TicksPerSecond)
+{
+ ASSERT(ui32TicksPerSecond);
+
+ //
+ // Configure SysTick for a periodic interrupt.
+ //
+ SysTickPeriodSet(SysCtlClockGet() / ui32TicksPerSecond);
+ SysTickEnable();
+ SysTickIntEnable();
+}
+
+//*****************************************************************************
+//
+//! Instructs the scheduler to update its task table and make calls to
+//! functions needing called.
+//!
+//! This function must be called periodically by the client to allow the
+//! scheduler to make calls to any configured task functions if it is their
+//! time to be called. The call must be made at least as frequently as the
+//! most frequent task configured in the g_psSchedulerTable array.
+//!
+//! Although the scheduler makes use of the SysTick interrupt, all calls to
+//! functions configured in \e g_psSchedulerTable are made in the context of
+//! SchedulerRun().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerRun(void)
+{
+ uint32_t ui32Loop;
+ tSchedulerTask *pi16Task;
+
+ //
+ // Loop through each task in the task table.
+ //
+ for(ui32Loop = 0; ui32Loop < g_ui32SchedulerNumTasks; ui32Loop++)
+ {
+ //
+ // Get a pointer to the task information.
+ //
+ pi16Task = &g_psSchedulerTable[ui32Loop];
+
+ //
+ // Is this task active and, if so, is it time to call it's function?
+ //
+ if(pi16Task->bActive &&
+ (SchedulerElapsedTicksGet(pi16Task->ui32LastCall) >=
+ pi16Task->ui32FrequencyTicks))
+ {
+ //
+ // Remember the timestamp at which we make the function call.
+ //
+ pi16Task->ui32LastCall = g_ui32SchedulerTickCount;
+
+ //
+ // Call the task function, passing the provided parameter.
+ //
+ pi16Task->pfnFunction(pi16Task->pvParam);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables a task and allows the scheduler to call it periodically.
+//!
+//! \param ui32Index is the index of the task which is to be enabled in the
+//! global \e g_psSchedulerTable array.
+//! \param bRunNow is \b true if the task is to be run on the next call to
+//! SchedulerRun() or \b false if one whole period is to elapse before the task
+//! is run.
+//!
+//! This function marks one of the configured tasks as enabled and causes
+//! SchedulerRun() to call that task periodically. The caller may choose to
+//! have the enabled task run for the first time on the next call to
+//! SchedulerRun() or to wait one full task period before making the first
+//! call.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerTaskEnable(uint32_t ui32Index, bool bRunNow)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ui32Index < g_ui32SchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as active.
+ //
+ g_psSchedulerTable[ui32Index].bActive = true;
+
+ //
+ // Set the last call time to ensure that the function is called either
+ // next time the scheduler is run or after the desired number of ticks
+ // depending upon the value of the bRunNow parameter.
+ //
+ if(bRunNow)
+ {
+ //
+ // Cause the task to run on the next call to SchedulerRun().
+ //
+ g_psSchedulerTable[ui32Index].ui32LastCall =
+ (g_ui32SchedulerTickCount -
+ g_psSchedulerTable[ui32Index].ui32FrequencyTicks);
+ }
+ else
+ {
+ //
+ // Cause the task to run after one full time period.
+ //
+ g_psSchedulerTable[ui32Index].ui32LastCall =
+ g_ui32SchedulerTickCount;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Disables a task and prevents the scheduler from calling it.
+//!
+//! \param ui32Index is the index of the task which is to be disabled in the
+//! global \e g_psSchedulerTable array.
+//!
+//! This function marks one of the configured tasks as inactive and prevents
+//! SchedulerRun() from calling it. The task may be reenabled by calling
+//! SchedulerTaskEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SchedulerTaskDisable(uint32_t ui32Index)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ui32Index < g_ui32SchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as inactive.
+ //
+ g_psSchedulerTable[ui32Index].bActive = false;
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the current system time in ticks since power on.
+//!
+//! This function may be called by a client to retrieve the current system
+//! time. The value returned is a count of ticks elapsed since the system
+//! last booted.
+//!
+//! \return Tick count since last boot.
+//
+//*****************************************************************************
+uint32_t
+SchedulerTickCountGet(void)
+{
+ return(g_ui32SchedulerTickCount);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of ticks elapsed since the provided tick count.
+//!
+//! \param ui32TickCount is the tick count from which to determine the elapsed
+//! time.
+//!
+//! This function may be called by a client to determine how much time has
+//! passed since a particular tick count provided in the \e ui32TickCount
+//! parameter. This function takes into account wrapping of the global tick
+//! counter and assumes that the provided tick count always represents a time
+//! in the past. The returned value will, of course, be wrong if the tick
+//! counter has wrapped more than once since the passed \e ui32TickCount. As a
+//! result, please do not use this function if you are dealing with timeouts
+//! of 497 days or longer (assuming you use a 10mS tick period).
+//!
+//! \return The number of ticks elapsed since the provided tick count.
+//
+//*****************************************************************************
+uint32_t
+SchedulerElapsedTicksGet(uint32_t ui32TickCount)
+{
+ //
+ // Determine the calculation based upon whether the global tick count has
+ // wrapped since the passed ui32TickCount.
+ //
+ return(SchedulerElapsedTicksCalc(ui32TickCount, g_ui32SchedulerTickCount));
+}
+
+//*****************************************************************************
+//
+//! Returns the number of ticks elapsed between two times.
+//!
+//! \param ui32TickStart is the system tick count for the start of the period.
+//! \param ui32TickEnd is the system tick count for the end of the period.
+//!
+//! This function may be called by a client to determine the number of ticks
+//! which have elapsed between provided starting and ending tick counts. The
+//! function takes into account wrapping cases where the end tick count is
+//! lower than the starting count assuming that the ending tick count always
+//! represents a later time than the starting count.
+//!
+//! \return The number of ticks elapsed between the provided start and end
+//! counts.
+//
+//*****************************************************************************
+uint32_t
+SchedulerElapsedTicksCalc(uint32_t ui32TickStart, uint32_t ui32TickEnd)
+{
+ return((ui32TickEnd > ui32TickStart) ? (ui32TickEnd - ui32TickStart) :
+ ((0xFFFFFFFF - ui32TickStart) + ui32TickEnd + 1));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/scheduler.h b/utils/scheduler.h
new file mode 100644
index 0000000..79ae1e2
--- /dev/null
+++ b/utils/scheduler.h
@@ -0,0 +1,140 @@
+//*****************************************************************************
+//
+// scheduler.h - Public header for the simple timed function scheduler module.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+#ifndef __SCHEDULER_H__
+#define __SCHEDULER_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype of a function that the scheduler can call periodically.
+//
+//*****************************************************************************
+typedef void (*tSchedulerFunction)(void *pvParam);
+
+//*****************************************************************************
+//
+//! The structure defining a function which the scheduler will call
+//! periodically.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to the function which is to be called periodically by the
+ //! scheduler.
+ //
+ void (*pfnFunction)(void *);
+
+ //
+ //! The parameter which is to be passed to this function when it is called.
+ //
+ void *pvParam;
+
+ //
+ //! The frequency the function is to be called expressed in terms of system
+ //! ticks. If this value is 0, the function will be called on every call
+ //! to SchedulerRun.
+ //
+ uint32_t ui32FrequencyTicks;
+
+ //
+ //! Tick count when this function was last called. This field is updated
+ //! by the scheduler.
+ //
+ uint32_t ui32LastCall;
+
+ //
+ //! A flag indicating whether or not this task is active. If true, the
+ //! function will be called periodically. If false, the function is
+ //! disabled and will not be called.
+ //
+ bool bActive;
+}
+tSchedulerTask;
+
+//*****************************************************************************
+//
+//! This global table must be populated by the client and contains information
+//! on each function that the scheduler is to call.
+//
+//*****************************************************************************
+extern tSchedulerTask g_psSchedulerTable[];
+
+//*****************************************************************************
+//
+//! This global variable must be exported by the client. It must contain the
+//! number of entries in the g_psSchedulerTable array.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SchedulerNumTasks;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes
+//
+//*****************************************************************************
+extern void SchedulerSysTickIntHandler(void);
+extern void SchedulerInit(uint32_t ui32TicksPerSecond);
+extern void SchedulerRun(void);
+extern void SchedulerTaskEnable(uint32_t ui32Index, bool bRunNow);
+extern void SchedulerTaskDisable(uint32_t ui32Index);
+extern uint32_t SchedulerTickCountGet(void);
+extern uint32_t SchedulerElapsedTicksGet(uint32_t ui32TickCount);
+extern uint32_t SchedulerElapsedTicksCalc(uint32_t ui32TickStart,
+ uint32_t ui32TickEnd);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ SCHEDULER_H_
diff --git a/utils/sine.c b/utils/sine.c
new file mode 100644
index 0000000..52cd222
--- /dev/null
+++ b/utils/sine.c
@@ -0,0 +1,126 @@
+//*****************************************************************************
+//
+// sine.c - Fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "utils/sine.h"
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A table of the value of the sine function for the first ninety degrees with
+// 129 entries (that is, [0] = 0 degrees, [128] = 90 degrees). Each entry is
+// in 0.16 fixed point notation.
+//
+//*****************************************************************************
+static const uint16_t g_pui16FixedSineTable[] =
+{
+ 0x0000, 0x0324, 0x0648, 0x096C, 0x0C8F, 0x0FB2, 0x12D5, 0x15F6, 0x1917,
+ 0x1C37, 0x1F56, 0x2273, 0x2590, 0x28AA, 0x2BC4, 0x2EDB, 0x31F1, 0x3505,
+ 0x3817, 0x3B26, 0x3E33, 0x413E, 0x4447, 0x474D, 0x4A50, 0x4D50, 0x504D,
+ 0x5347, 0x563E, 0x5931, 0x5C22, 0x5F0E, 0x61F7, 0x64DC, 0x67BD, 0x6A9B,
+ 0x6D74, 0x7049, 0x7319, 0x75E5, 0x78AD, 0x7B70, 0x7E2E, 0x80E7, 0x839C,
+ 0x864B, 0x88F5, 0x8B9A, 0x8E39, 0x90D3, 0x9368, 0x95F6, 0x987F, 0x9B02,
+ 0x9D7F, 0x9FF6, 0xA267, 0xA4D2, 0xA736, 0xA994, 0xABEB, 0xAE3B, 0xB085,
+ 0xB2C8, 0xB504, 0xB73A, 0xB968, 0xBB8F, 0xBDAE, 0xBFC7, 0xC1D8, 0xC3E2,
+ 0xC5E4, 0xC7DE, 0xC9D1, 0xCBBB, 0xCD9F, 0xCF7A, 0xD14D, 0xD318, 0xD4DB,
+ 0xD695, 0xD848, 0xD9F2, 0xDB94, 0xDD2D, 0xDEBE, 0xE046, 0xE1C5, 0xE33C,
+ 0xE4AA, 0xE60F, 0xE76B, 0xE8BF, 0xEA09, 0xEB4B, 0xEC83, 0xEDB2, 0xEED8,
+ 0xEFF5, 0xF109, 0xF213, 0xF314, 0xF40B, 0xF4FA, 0xF5DE, 0xF6BA, 0xF78B,
+ 0xF853, 0xF912, 0xF9C7, 0xFA73, 0xFB14, 0xFBAC, 0xFC3B, 0xFCBF, 0xFD3A,
+ 0xFDAB, 0xFE13, 0xFE70, 0xFEC4, 0xFF0E, 0xFF4E, 0xFF84, 0xFFB1, 0xFFD3,
+ 0xFFEC, 0xFFFB, 0xFFFF
+};
+
+//*****************************************************************************
+//
+//! Computes an approximation of the sine of the input angle.
+//!
+//! \param ui32Angle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the sine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the sine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+int32_t
+sine(uint32_t ui32Angle)
+{
+ uint32_t ui32Idx;
+
+ //
+ // Add 0.5 to the angle. Since only the upper 9 bits are used to compute
+ // the sine value, adding one to the tenth bit is 0.5 from the point of
+ // view of the sine table.
+ //
+ ui32Angle += 0x00400000;
+
+ //
+ // Get the index into the sine table from bits 30:23.
+ //
+ ui32Idx = (ui32Angle >> 23) & 255;
+
+ //
+ // If bit 30 is set, the angle is between 90 and 180 or 270 and 360. In
+ // these cases, the sine value is decreasing from one instead of increasing
+ // from zero. The indexing into the table needs to be reversed.
+ //
+ if(ui32Angle & 0x40000000)
+ {
+ ui32Idx = 256 - ui32Idx;
+ }
+
+ //
+ // Get the value of the sine.
+ //
+ ui32Idx = g_pui16FixedSineTable[ui32Idx];
+
+ //
+ // If bit 31 is set, the angle is between 180 and 360. In this case, the
+ // sine value is negative; otherwise it is positive.
+ //
+ if(ui32Angle & 0x80000000)
+ {
+ return(0 - ui32Idx);
+ }
+ else
+ {
+ return(ui32Idx);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/sine.h b/utils/sine.h
new file mode 100644
index 0000000..c3f8c51
--- /dev/null
+++ b/utils/sine.h
@@ -0,0 +1,85 @@
+//*****************************************************************************
+//
+// sine.h - Prototypes for the fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SINE_H__
+#define __SINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Computes an approximation of the cosine of the input angle.
+//!
+//! \param ui32Angle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the cosine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the cosine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+#define cosine(ui32Angle) sine((ui32Angle) + 0x40000000)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype for the fixed point sine function.
+//
+//*****************************************************************************
+extern int32_t sine(uint32_t ui32Angle);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SINE_H__
diff --git a/utils/smbus.c b/utils/smbus.c
new file mode 100644
index 0000000..8ed9c3a
--- /dev/null
+++ b/utils/smbus.c
@@ -0,0 +1,5173 @@
+//*****************************************************************************
+//
+// smbus.c - SMBus protocol layer API.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_i2c.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/i2c.h"
+#include "driverlib/sw_crc.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/udma.h"
+#include "utils/smbus.h"
+
+//*****************************************************************************
+//
+//! \addtogroup smbus_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states for the master and slave interrupt handler state machines.
+//
+//*****************************************************************************
+#define SMBUS_STATE_IDLE 0
+#define SMBUS_STATE_SLAVE_POST_COMMAND 1
+#define SMBUS_STATE_WRITE_BLOCK_SIZE 2
+#define SMBUS_STATE_WRITE_NEXT 3
+#define SMBUS_STATE_WRITE_FINAL 4
+#define SMBUS_STATE_WRITE_DONE 5
+#define SMBUS_STATE_READ_ONE 6
+#define SMBUS_STATE_READ_FIRST 7
+#define SMBUS_STATE_READ_BLOCK_SIZE 8
+#define SMBUS_STATE_READ_NEXT 9
+#define SMBUS_STATE_READ_FINAL 10
+#define SMBUS_STATE_READ_WAIT 11
+#define SMBUS_STATE_READ_PEC 12
+#define SMBUS_STATE_READ_DONE 13
+#define SMBUS_STATE_READ_ERROR_STOP 14
+
+//*****************************************************************************
+//
+// Status flags for various instance-specific tasks.
+//
+//*****************************************************************************
+#define FLAG_PEC 0
+#define FLAG_PROCESS_CALL 1
+#define FLAG_BLOCK_TRANSFER 2
+#define FLAG_TRANSFER_IN_PROGRESS 3
+#define FLAG_RAW_I2C 4
+#define FLAG_ADDRESS_RESOLVED 5
+#define FLAG_ADDRESS_VALID 6
+#define FLAG_ARP 7
+//*****************************************************************************
+//
+//! Enables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sets the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function clears the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 0;
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes in the receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the number of bytes in the active receive buffer.
+//! It can be used to determine how many bytes have been received in the slave
+//! receive or master block read configurations.
+//!
+//! \return Number of bytes in the buffer.
+//
+//*****************************************************************************
+uint8_t
+SMBusRxPacketSizeGet(tSMBus *psSMBus)
+{
+ //
+ // Return the number of bytes received.
+ //
+ return(psSMBus->ui8RxIndex);
+}
+
+//*****************************************************************************
+//
+//! Returns the state of an SMBus transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the status of an SMBus transaction. It can be used
+//! to determine whether a transfer is ongoing or complete.
+//!
+//! \return Returns \b SMBUS_TRANSFER_IN_PROGRESS if transfer is ongoing, or
+//! \b SMBUS_TRANSFER_COMPLETE if transfer has completed.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Check to see if there is an ongoing transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS))
+ {
+ //
+ // If the flag is set, return in progress status.
+ //
+ return(SMBUS_TRANSFER_IN_PROGRESS);
+ }
+
+ //
+ // If the transfer complete flag is cleared, transfer is done.
+ //
+ else
+ {
+ //
+ // If the flag isn't set, return complete status.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Encodes a UDID structure and address into SMBus-transferable byte order.
+//!
+//! \param pUDID specifies the structure to encode.
+//! \param ui8Address specifies the address to send with the UDID (byte 17).
+//! \param pui8Data specifies the location of the destination data buffer.
+//!
+//! This function takes a tSMBusUDID structure and re-orders the bytes so that
+//! it can be transferred on the bus. The destination data buffer must contain
+//! at least 17 bytes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID, uint8_t ui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Place data from the UDID structure and address into the data buffer
+ // using the correct MSB->LSB + address order.
+ //
+ pui8Data[0] = pUDID->ui8DeviceCapabilities;
+ pui8Data[1] = pUDID->ui8Version;
+ pui8Data[2] = (uint8_t)((pUDID->ui16VendorID & 0xff00) >> 8);
+ pui8Data[3] = (uint8_t)(pUDID->ui16VendorID & 0x00ff);
+ pui8Data[4] = (uint8_t)((pUDID->ui16DeviceID & 0xff00) >> 8);
+ pui8Data[5] = (uint8_t)(pUDID->ui16DeviceID & 0x00ff);
+ pui8Data[6] = (uint8_t)((pUDID->ui16Interface & 0xff00) >> 8);
+ pui8Data[7] = (uint8_t)(pUDID->ui16Interface & 0x00ff);
+ pui8Data[8] = (uint8_t)((pUDID->ui16SubSystemVendorID & 0xff00) >> 8);
+ pui8Data[9] = (uint8_t)(pUDID->ui16SubSystemVendorID & 0x00ff);
+ pui8Data[10] = (uint8_t)((pUDID->ui16SubSystemDeviceID & 0xff00) >> 8);
+ pui8Data[11] = (uint8_t)(pUDID->ui16SubSystemDeviceID & 0x00ff);
+ pui8Data[12] = (uint8_t)((pUDID->ui32VendorSpecificID & 0xff000000) >>
+ 24);
+ pui8Data[13] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x00ff0000) >>
+ 16);
+ pui8Data[14] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x0000ff00) >>
+ 8);
+ pui8Data[15] = (uint8_t)(pUDID->ui32VendorSpecificID & 0x000000ff);
+ pui8Data[16] = ui8Address;
+}
+
+//*****************************************************************************
+//
+//! Decodes an SMBus packet into a UDID structure and address.
+//!
+//! \param pUDID specifies the structure that is updated with new data.
+//! \param pui8Address specifies the location of the variable that holds the
+//! the address sent with the UDID (byte 17).
+//! \param pui8Data specifies the location of the source data.
+//!
+//! This function takes a data buffer and decodes it into a tSMBusUDID
+//! structure and an address variable. It is assumed that there are 17 bytes
+//! in the data buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID, uint8_t *pui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Populate the UDID structure with data from the input data buffer.
+ //
+ pUDID->ui8DeviceCapabilities = pui8Data[0];
+ pUDID->ui8Version = pui8Data[1];
+ pUDID->ui16VendorID = (uint16_t)((pui8Data[2] << 8) | pui8Data[3]);
+ pUDID->ui16DeviceID = (uint16_t)((pui8Data[4] << 8) | pui8Data[5]);
+ pUDID->ui16Interface = (uint16_t)((pui8Data[6] << 8) | pui8Data[7]);
+ pUDID->ui16SubSystemVendorID = (uint16_t)((pui8Data[8] << 8) |
+ pui8Data[9]);
+ pUDID->ui16SubSystemDeviceID = (uint16_t)((pui8Data[10] << 8) |
+ pui8Data[11]);
+ pUDID->ui32VendorSpecificID = (uint32_t)((pui8Data[12] << 24) |
+ (pui8Data[13] << 16) |
+ (pui8Data[14] << 8) |
+ pui8Data[15]);
+
+ //
+ // Populate the address.
+ //
+ *pui8Address = pui8Data[16];
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Quick Command transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param bData is the value of the single data bit sent to the slave.
+//!
+//! Quick Command is an SMBus protocol that sends a single data bit using the
+//! I2C R/S bit. This function issues a single I2C transfer with the slave
+//! address and data bit.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterQuickCommand(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ bool bData)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, bData);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_QUICK_COMMAND);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Host Notify transfer to the SMBus Host.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8OwnSlaveAddress specifies the peripheral's own slave address.
+//! \param pui8Data is a pointer to the two byte data payload.
+//!
+//! The Host Notify protocol is used by SMBus slaves to alert the bus Host
+//! about an event. Most slave devices that operate in this environment only
+//! become a bus master when this packet type is used. Host Notify always
+//! sends two data bytes to the host along with the peripheral's own slave
+//! address so that the Host knows which peripheral requested the Host's
+//! attention.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterHostNotify(tSMBus *psSMBus, uint8_t ui8OwnSlaveAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = SMBUS_ADR_HOST;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8OwnSlaveAddress);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Send Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Data is the data byte to send to the slave.
+//!
+//! The Send Byte protocol is a basic SMBus protocol that sends a single data
+//! byte to the slave. Unlike most of the other SMBus protocols, Send Byte
+//! does not send a ``command'' byte before the data payload and is intended
+//! for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteSend(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Data;
+ psSMBus->pui8TxBuffer = &ui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the data byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8Data);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the data to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8TxBuffer[0],
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Receive Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the location to store the received data
+//! byte.
+//!
+//! The Receive Byte protocol is a basic SMBus protocol that receives a single
+//! data byte from the slave. Unlike most of the other SMBus protocols,
+//! Receive Byte does not send a ``command'' byte before the data payload and
+//! is intended for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteReceive(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxSize = 1;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Write Byte or Write Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data payload.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports both the Write Byte and Write Word protocols. The
+//! amount of data to send is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ else
+ {
+ //
+ // If only one byte to send, move to the final state.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Read Byte or Read Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to receive from the slave.
+//!
+//! This function supports both the Read Byte and Read Word protocols. The
+//! amount of data to receive is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ if(psSMBus->ui8RxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ONE;
+ }
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Write transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports the Block Write protocol. The amount of data sent
+//! to the slave is user defined, but limited to 32 bytes per the SMBus spec.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8Size > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Read transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Read protocol. The amount of data read
+//! is defined by the slave device, but should never exceed 32 bytes per the
+//! SMBus spec. The receive size is the first data byte returned by the slave,
+//! so this function assumes a size of 3 until the actual number is sent by
+//! the slave. In the application interrupt handler, SMBusRxPacketSizeGet()
+//! can be used to obtain the amount of data sent by the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag..
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Initially set the RX size to 3 to make the state machine work.
+ // The slave will respond with the actual size of the transfer in the
+ // first byte and that data will replace this initial value.
+ //
+ psSMBus->ui8RxSize = 3;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Process Call protocol. The amount of data sent
+//! to and received from the slave is fixed to 2 bytes per direction (2 sent,
+//! 2 received).
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 2;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Write/Block Read Process Call protocol.
+//! The amount of data sent to the slave is user defined but limited to 32 data
+//! bytes. The amount of data read is defined by the slave device, but should
+//! never exceed 32 bytes per the SMBus spec. The receive size is the first
+//! data byte returned by the slave, so the actual size is populated in
+//! SMBusMasterISRProcess(). In the application interrupt handler,
+//! SMBusRxPacketSizeGet() can be used to obtain the amount of data sent by
+//! the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8TxSize is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t ui8TxSize, uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8TxSize > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 3;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call and block transfer flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function sends a user-defined number of bytes to an I2C slave without
+//! using an SMBus protocol. The data size is only limited to the size of the
+//! ui8Size variable, which is an unsigned character (8 bits, value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the first byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+ else if(ui8Size == 2)
+ {
+ //
+ // If there are only 2 bytes to send just jump to the final write
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function receives a user-defined number of bytes from an I2C slave
+//! without using an SMBus protocol. The data size is only limited to the size
+//! of the ui8Size variable, which is an unsigned character (8 bits, value of
+//! 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Choose what to do based on the receive size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+ else if(ui8Size == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ if(ui8Size == 1)
+ {
+ //
+ // Start the single receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+ else
+ {
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write-read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//! \param ui8RxSize is the number of bytes to receive from the slave.
+//!
+//! This function initiates a write-read transfer to an I2C slave without using
+//! an SMBus protocol. The user-defined number of bytes is written to the
+//! slave first, followed by the reception of the user-defined number of bytes.
+//! The transmit and receive data sizes are only limited to the size of the
+//! ui8TxSize and ui8RxSize variables, which are unsigned characters (8 bits,
+//! value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWriteRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8TxData, uint8_t ui8TxSize,
+ uint8_t *pui8RxData, uint8_t ui8RxSize)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8RxSize;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Set the process call flag. Even though this is technically not an SMBus
+ // process call, this flag is used in the interrupt state machine for
+ // the bus turn around.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8TxSize == 1)
+ {
+ //
+ // Move to the read first state for the turn around.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else if(ui8TxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``general'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). Since SMBus requires that data bytes be
+//! transmitted in a certain order, the raw data in the pui8Data needs to be
+//! treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDGen(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_GET_UDID, pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``directed'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). A directed packet differs from a general packet
+//! in that it targets a specific slave device. Since SMBus requires that data
+//! bytes be transmitted in a certain order, the raw data in the pui8Data needs
+//! to be treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDDir(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1 | 1), pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``general'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! all non-PSA (Persistent Slave Address), ARP-capable devices to return to
+//! their initial state. This packet also tells the devices to clear their
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceGen(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_RESET_DEVICE));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``directed'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! a specific non-PSA (Persistent Slave Address), ARP-capable device to return
+//! to its initial state. This packet also tells the device to clear its
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceDir(tSMBus *psSMBus, uint8_t ui8TargetAddress)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1)));
+}
+
+//*****************************************************************************
+//
+//! Sends an ARP Assign Address packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. This buffer
+//! should be correctly formatted using SMBusARPUDIDPacketEncode() and
+//! should contain the UDID data and the address for the slave.
+//!
+//! This function sends an Assign Address packet, used during Address
+//! Resolution Protocol (ARP). Because SMBus requires data bytes be sent out
+//! MSB first, the UDID and target address should be formatted correctly by the
+//! application or using SMBusARPUDIDPacketEncode() and placed into a data
+//! buffer pointed to by pui8Data.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPAssignAddress(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Block Write protocol to send the packet.
+ //
+ return(SMBusMasterBlockWrite(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_ASSIGN_ADDRESS, pui8Data, 17));
+}
+
+//*****************************************************************************
+//
+//! Sends a Notify ARP Master packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. The data payload
+//! should be 0x0000 for this packet.
+//!
+//! This function sends a Notify ARP Master packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by a slave to indicate
+//! to the ARP Master that it needs attention.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPNotifyMaster(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Host Notify protocol to send the packet.
+ //
+ return(SMBusMasterHostNotify(psSMBus, (SMBUS_ADR_DEFAULT_DEVICE << 1),
+ pui8Data));
+}
+
+//*****************************************************************************
+//
+//! Sends a Prepare to ARP packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a Prepare to ARP packet, used during Address Resolution
+//! Protocol (ARP). This packet is used by an ARP Master to alert devices on
+//! the bus that ARP is about to begin. All ARP-capable devices must
+//! acknowledge all bytes in this packet and clear their Address Resolved (AR)
+//! flag.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPPrepareToARP(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_PREPARE_TO_ARP));
+}
+
+//*****************************************************************************
+//
+//! Master ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus master interrupts.
+//!
+//! \return Returns \b SMBUS_TIMEOUT if a bus timeout is detected,
+//! \b SMBUS_ARB_LOST if I2C bus arbitration lost is detected,
+//! \b SMBUS_ADDR_ACK_ERROR if the address phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_ACK_ERROR if the data phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_SIZE_ERROR if a receive buffer overrun is detected or
+//! if a transmit operation tries to write more data than is allowed,
+//! \b SMBUS_MASTER_ERROR if an unknown error occurs, \b SMBUS_PEC_ERROR if the
+//! received PEC byte does not match the locally calculated value, or
+//! \b SMBUS_OK if processing finished successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32IntStatus;
+ uint32_t ui32ErrorStatus;
+ uint8_t ui8TempData;
+
+ //
+ // Determine which interrupt made us get here.
+ //
+ ui32IntStatus = MAP_I2CMasterIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check for the timeout interrupt. Since the peripheral will
+ // automatically issue a stop, just clear the interrupt and return.
+ //
+ if(ui32IntStatus & I2C_MASTER_INT_TIMEOUT)
+ {
+ //
+ // Clear all pending interrupts and wait for the bus to become
+ // free so we can issue a STOP.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_TIMEOUT |
+ I2C_MASTER_INT_DATA);
+
+ //
+ // Clear the transfer in progress flag. New transactions will
+ // be aborted until the bus is free.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_TIMEOUT);
+ }
+ else
+ {
+ //
+ // Clear the data interrupt.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA);
+ }
+
+ //
+ // Read the master interrupt status bits.
+ //
+ ui32ErrorStatus = HWREG(psSMBus->ui32I2CBase + I2C_O_MCS);
+
+ //
+ // Check for arbitration lost.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ARBLST)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ARB_LOST);
+ }
+
+ //
+ // Check for an error.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ERROR)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Check to see if the bus is free. There are two interrupts when a
+ // NACK happens, and the bus should only be free during the second
+ // interrupt. During the first interrupt (when the bus is busy),
+ // generate the necessary STOP condition.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Issue a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
+ }
+ else
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // Check for ACK errors.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ADRACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ADDR_ACK_ERROR);
+ }
+ else if(ui32ErrorStatus & I2C_MCS_DATACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_DATA_ACK_ERROR);
+ }
+ else
+ {
+ //
+ // Return to caller. Should never get here.
+ //
+ return(SMBUS_MASTER_ERROR);
+ }
+ }
+
+ //
+ // If no error conditions, determine what to do based on the state.
+ //
+ switch(psSMBus->ui8MasterState)
+ {
+ //
+ // The idle state. This state should only be reached after the last
+ // byte of a master transmit.
+ //
+ case SMBUS_STATE_IDLE:
+ {
+ //
+ // If the peripheral is not busy clear the transfer in progress
+ // flag. This means that the peripheral has given up the bus,
+ // most likely due to the end of a transmit operation.
+ //
+ if(!MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // When using a block write, the transfer size must be sent before the
+ // data payload.
+ //
+ case SMBUS_STATE_WRITE_BLOCK_SIZE:
+ {
+ //
+ // Write the block write size to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8TxSize);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // The next data byte is from the data payload.
+ //
+ if((psSMBus->ui8TxSize == 1) &&
+ !(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC)))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ //
+ // The state for the middle of a burst write.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++]);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Determine the next state based on the values of the PEC and
+ // process call flags.
+ //
+
+ //
+ // If PEC is active and process call is not active.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call, there is no PEC byte on the transmit.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Check to see if the TX index is equal to size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // If the TX index is the same as the size, we're done.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ }
+
+ //
+ // If PEC is not used, regardless of whether this is a process
+ // call.
+ //
+ else
+ {
+ //
+ // Check to see if the TX index is equal to the size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the final write of a burst sequence.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Determine what data to write to the data register based
+ // on the values of the PEC and process call flags.
+ //
+ //
+ // If PEC is active, write the PEC byte to the data register.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call is active, send data, not CRC.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Write the final byte from TX buffer to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+ else
+ {
+ //
+ // Write the calculated CRC (PEC) byte to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->ui8CalculatedCRC);
+ }
+ }
+ else
+ {
+ //
+ // Write the final byte from TX buffer to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+
+ //
+ // If a process call is active, send out the repeated start to
+ // begin the RX portion.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Move to the read first "turnaround" state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // Since we end the transaction after the last byte is sent,
+ // the next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for a single byte read.
+ //
+ case SMBUS_STATE_READ_ONE:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the start of a burst read.
+ //
+ case SMBUS_STATE_READ_FIRST:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Handle the case where PEC is used.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the target address and R/S bit to the running CRC
+ // calculation.
+ //
+ ui8TempData =
+ ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Update the calculated CRC value in the configuration
+ // structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC, &ui8TempData, 1);
+
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 1)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 1 byte remains, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 2)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 2 bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the size of a block read.
+ //
+ case SMBUS_STATE_READ_BLOCK_SIZE:
+ {
+ //
+ // Update the RX size with the data byte.
+ //
+ psSMBus->ui8RxSize = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If more than 32 bytes are going to be sent, error.
+ //
+ if((psSMBus->ui8RxSize > 32) || (psSMBus->ui8RxSize == 0))
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // If PEC is enabled, add the size byte to the calculation and
+ // add one to the size variable to account for the extra PEC byte.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8RxSize, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ switch(psSMBus->ui8RxSize)
+ {
+ //
+ // 1 byte remaining.
+ //
+ case 1:
+ {
+ //
+ // If only one byte remains and PEC, go to the second
+ // to last byte state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // If only one byte remains and no PEC, end the burst
+ // transfer.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // 2 bytes remaining.
+ //
+ case 2:
+ {
+ //
+ // If two bytes and PEC remain, move to read next
+ // state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // If two bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // For every other situation (in other words, remaining bytes
+ // is greater than 2).
+ //
+ default:
+ {
+ //
+ // If more than 2 bytes to read, move to the next byte
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Determine how to step the I2C state machine.
+ //
+ if((psSMBus->ui8RxSize == 1) &&
+ !HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If exactly 1 byte remains, read the byte and send a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+ }
+ else
+ {
+ //
+ // Otherwise, continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the middle of a burst read.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there is 1 byte remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 1)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there are two bytes remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the end of a burst read.
+ //
+ case SMBUS_STATE_READ_FINAL:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+ }
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for the final read of a single or burst read.
+ //
+ case SMBUS_STATE_READ_WAIT:
+ {
+ //
+ // Read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If PEC is enabled, check the value that just came in to see
+ // if it matches.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex > psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Store the received CRC byte.
+ //
+ psSMBus->ui8ReceivedCRC = ui8TempData;
+
+ //
+ // If the CRC doesn't match, send a NACK and indicate the
+ // failure to the application.
+ //
+ if(psSMBus->ui8ReceivedCRC != psSMBus->ui8CalculatedCRC)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Read the received byte.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] = ui8TempData;
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for a transaction that needed to end due to a
+ // size error.
+ //
+ case SMBUS_STATE_READ_ERROR_STOP:
+ {
+ //
+ // Dummy read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ }
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate master interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus master. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusMasterInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the master interrupts.
+ //
+ MAP_I2CMasterIntEnableEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA |
+ I2C_MASTER_INT_TIMEOUT);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C master peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C master peripheral.
+//! \param ui32SMBusClock specifies the system clock speed of the MCU.
+//!
+//! This function initializes an I2C peripheral for SMBus master use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured for 100kHz use, which is
+//! required by the SMBus specification.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
+ uint32_t ui32SMBusClock)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable and initialize the I2C master module Using the system clock.
+ // The I2C transfer rate will always be 100kHz since fast mode is not
+ // supported by SMBus.
+ //
+ MAP_I2CMasterInitExpClk(psSMBus->ui32I2CBase, ui32SMBusClock, false);
+
+ //
+ // Configure bus timeout to 25ms. 12-bit value for 25ms is 0x9C4 (2500
+ // clocks), so round upper 8 bits to 0x9C. Each clock is 10us since
+ // 100kHz I2C is required for SMBus.
+ //
+ MAP_I2CMasterTimeoutSet(psSMBus->ui32I2CBase, 0x9C);
+}
+
+//*****************************************************************************
+//
+//! Slave ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus slave interrupts.
+//!
+//! If manual acknowledge is enabled using SMBusSlaveManualACKEnable(), this
+//! function processes the data byte, but does not send the ACK/NACK value. In
+//! this case, the user application is responsible for sending the acknowledge
+//! bit based on the return code of this function.
+//!
+//! When receiving a Quick Command from the master, the slave has some set-up
+//! requirements. When the master sends the R/S (data) bit as '0', nothing
+//! additional needs to be done in the slave and SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_QCMD_0. However, when the master sends the R/S (data) bit
+//! as '1', the slave must write the data register with data containing a '1'
+//! in bit 7. This means that when receiving a Quick Command, the slave must
+//! set up the TX buffer to either have 1 data byte with bit 7 set to '1' or
+//! set up the TX buffer to be zero length. In the case where 1 data byte is
+//! put in the TX buffer, SMBusSlaveIntProcess() returns \b SMBUS_OK the first
+//! time its called and \b SMBUS_SLAVE_QCMD_0 the second. In the case where
+//! the TX buffer has no data, SMBusSlaveIntProcess() will return
+//! \b SMBUS_SLAVE_ERROR the first time its called, and \b SMBUS_SLAVE_QCMD_1
+//! the second time.
+//!
+//! \return Returns \b SMBUS_SLAVE_FIRST_BYTE if the first byte (typically the
+//! SMBus command) has been received; \b SMBUS_SLAVE_NOT_READY if the slave's
+//! transmit buffer is not yet initialized when the master requests data from
+//! the slave; \b SMBUS_DATA_SIZE_ERROR if during a master block write, the
+//! size sent by the master is greater than the amount of available space in
+//! the receive buffer; \b SMBUS_SLAVE_ERROR if a buffer overrun is detected
+//! during a slave receive operation or if data is sent and was not expected;
+//! \b SMBUS_SLAVE_QCMD_0 if a Quick Command was received with data '0';
+//! \b SMBUS_SLAVE_QCMD_1 if a Quick Command was received with data '1';
+//! \b SMBUS_TRANSFER_COMPLETE if a STOP is detected on the bus, marking the
+//! end of a transfer; \b SMBUS_PEC_ERROR if the received PEC byte does not
+//! match the locally calculated value; or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32InterruptStatus;
+ uint32_t ui32SlaveStatus = 0;
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Determine which interrupt was asserted.
+ //
+ ui32InterruptStatus = I2CSlaveIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check the status register.
+ //
+ ui32SlaveStatus = I2CSlaveStatus(psSMBus->ui32I2CBase);
+
+ //
+ // Check for the START interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_START)
+ {
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_START);
+
+
+ //
+ // This interrupt is not supported outside of using the FIFO.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Check for the STOP interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_STOP)
+ {
+ //
+ // Make sure the transfer in progress flag is cleared. In the case
+ // of Quick Command, it should never be set, so this is safe.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_STOP);
+
+ //
+ // Check to see if a Quick Command was sent.
+ //
+ if(ui32SlaveStatus & 0x10)
+ {
+ //
+ // Make sure the TX/RX index is 0. If not, we should not be here.
+ // Other data should not have been sent or received during a Quick
+ // Command.
+ //
+ if((psSMBus->ui8RxIndex != 0) || (psSMBus->ui8TxIndex != 0))
+ {
+ //
+ // Return an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Tell caller a Quick Command has occurred and the data value.
+ //
+ if(ui32SlaveStatus & 0x20)
+ {
+ return(SMBUS_SLAVE_QCMD_1);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_QCMD_0);
+ }
+ }
+
+ //
+ // Move to the idle state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+
+ //
+ // Return end of transfer.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+
+ //
+ // Check for the DATA interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_DATA)
+ {
+ //
+ // Clear the I2C interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_DATA);
+
+ //
+ // Make sure that at least one of the relevant status bits is set.
+ //
+ if(!(ui32SlaveStatus & 0x07))
+ {
+ //
+ // No status bits were set - this is bad. Should never get here.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Every time this interrupt occurs, a transfer is in progress. Make
+ // sure the flag is set appropriately.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Handle the request type.
+ //
+ switch((ui32SlaveStatus & 0x07))
+ {
+ //
+ // The first byte after the slave's own address has been received.
+ // This is almost always the command byte in SMBus. The only
+ // exception is when the Send Byte protocol is used by the master.
+ //
+ case I2C_SLAVE_ACT_RREQ_FBR:
+ {
+ //
+ // Check which slave address was called out. Set the active
+ // address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) & 0x7f;
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // If raw I2C, data goes into buffer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C))
+ {
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // Read the first byte into the ui8CurrentCommand member.
+ //
+ else
+ {
+ psSMBus->ui8CurrentCommand =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // If PEC is enabled, add the address to the CRC calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the address to the CRC calculation. In this case
+ // R/S will always be 0. Also, this is the start of the
+ // CRC calculation, so the initial value is 0.
+ //
+ ui8CRCTemp = psSMBus->ui8OwnSlaveAddress << 1;
+
+ //
+ // Calculate new CRC.
+ //
+ psSMBus->ui8CalculatedCRC = Crc8CCITT(0, &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte (ui8CurrentCommand) to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_SLAVE_POST_COMMAND;
+
+ //
+ // Actions for this case are complete.
+ //
+ return(SMBUS_SLAVE_FIRST_BYTE);
+ }
+
+ //
+ // A data byte other than the first data byte has been received.
+ //
+ case I2C_SLAVE_ACT_RREQ:
+ {
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // Receive first post-command byte.
+ //
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Check if this is a block transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // Make sure there is enough space in the buffer.
+ // If not, NACK. If there is, overwrite the
+ // current size with the size sent by the master.
+ //
+ if(ui8DataTemp > psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Indicate a size error.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ else
+ {
+ //
+ // Update the size.
+ //
+ psSMBus->ui8RxSize = ui8DataTemp;
+
+ //
+ // Check to see if PEC is enabled.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // Read the next byte into the buffer.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_PROCESS_CALL))
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ else
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Read the PEC byte and compare it.
+ //
+ case SMBUS_STATE_READ_PEC:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Compare PEC.
+ //
+ if(psSMBus->ui8CalculatedCRC != ui8DataTemp)
+ {
+ //
+ // Indicate PEC error.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ break;
+ }
+
+ //
+ // No more data to receive. If we get here, read data
+ // into a dummy variable and NACK.
+ //
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // The master has requested that the slave transmit data back to
+ // master.
+ //
+ case I2C_SLAVE_ACT_TREQ:
+ {
+ //
+ // Initialize temporary variable that stores transmit byte to
+ // 0xff. If data is not set by another condition, the 0xff
+ // carries through. This happens if ui8TxIndex is equal to or
+ // greater than ui8TxSize.
+ //
+ ui8DataTemp = 0xff;
+
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // The state machine is currently idle, or if the last
+ // state was SMBUS_STATE_SLAVE_POST_COMMAND or
+ // SMBUS_READ_DONE, this is the first byte transmitted. In
+ // the case of slave post command, this means that the
+ // command was received followed by a repeated start (with
+ // R/S = 1). In the case of read next, this means that a
+ // raw I2C master transmit changed direction with a
+ // repeated start and is now a master receive. In the case
+ // of read done, this means that a previous master transmit
+ // was finished (non-command followed by a repeated start).
+ //
+ case SMBUS_STATE_IDLE:
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ case SMBUS_STATE_READ_NEXT:
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Check which slave address was called out. Set the
+ // active address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) &
+ I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ (HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) &
+ 0x7f);
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data
+ // register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp =
+ (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to
+ // the done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The first byte has already been sent, handle the rest.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Set the transmit data to the next item in the
+ // buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Check if it's time to move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ if((psSMBus->ui8TxSize - psSMBus->ui8TxIndex) == 1)
+ {
+ //
+ // If only 1 byte remains, move to the final
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // Write the final byte, whether PEC or data.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Send the CRC byte.
+ //
+ ui8DataTemp = psSMBus->ui8CalculatedCRC;
+ }
+ else
+ {
+ //
+ // Send the last data byte.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Move to the write done state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // All data has been sent, send 0xff.
+ //
+ case SMBUS_STATE_WRITE_DONE:
+ {
+ //
+ // Send 0xff because there is no more data to send.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, 0xff);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+ }
+
+ //
+ // Return OK status.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Return OK. Should never get here.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Sends data outside of the interrupt processing function.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends data outside the interrupt processing function, and
+//! should only be used when SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_NOT_READY. At this point, the application should set up the
+//! transfer and call this function (it assumes that the transmit buffer has
+//! already been populated when called). When called, this function updates
+//! the slave state machine as if SMBusSlaveIntProcess() were called.
+//!
+//! \return Returns \b SMBUS_SLAVE_NOT_READY if the slave's transmit buffer is
+//! not yet initialized (ui8TxSize is 0), or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveDataSend(tSMBus *psSMBus)
+{
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp = psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec. Should not get here.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp = (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to the
+ // done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave transmit buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave transmit buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the trasmit buffer.
+ //
+ psSMBus->pui8TxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8TxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the receive buffer.
+ //
+ psSMBus->pui8RxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8RxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Get the current command byte.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Returns the current value of the ui8CurrentCommand variable in the SMBus
+//! configuration structure. This can be used to help the user application
+//! set up the SMBus slave transmit and receive buffers.
+//!
+//! \return None.
+//
+//*****************************************************************************
+uint8_t
+SMBusSlaveCommandGet(tSMBus *psSMBus)
+{
+ //
+ // Return the current command.
+ //
+ return(psSMBus->ui8CurrentCommand);
+}
+
+//*****************************************************************************
+//
+//! Sets the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the process call flag in the configuration structure so that the SMBus
+//! slave can respond correctly to a Process Call request. This flag must be
+//! set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the process call flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the block transfer flag in the configuration structure so that the
+//! SMBus slave can respond correctly to a Block Write or Block Read request.
+//! This flag must be set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the block transfer flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the raw I2C flag in the configuration structure so that the
+//! SMBus slave can respond correctly to raw I2C (non-SMBus protocol) requests.
+//! This flag must be set prior to the transfer, and is a global setting.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the raw I2C flag in the configuration structure. This flag is a
+//! global setting similar to the PEC flag and cannot be cleared using
+//! SMBusSlaveTransferInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AR flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AR flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address resolved flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AR (Address Resolved) flag.
+//!
+//! \return Returns \b true if set, \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagARGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address resolved flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED));
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AV flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AV flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address valid flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AV (Address Valid) flag.
+//!
+//! \return Returns \b true if set, or \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagAVGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address valid flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID));
+}
+
+//*****************************************************************************
+//
+//! Sets up the SMBus slave for a new transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function is used to re-initialize the configuration structure for a
+//! new transfer. Once a transfer is complete and the data has been processed,
+//! unused flags, states, the data buffers and buffer indexes should be reset
+//! to a known state before a new transfer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTransferInit(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer, process call and transfer in progress flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Set the configuration structure to a known, zeroed state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the ACK bit when using manual acknowledgement.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bACK specifies whether to ACK (\b true) or NACK (\b false).
+//!
+//! This function sets the value of the ACK bit. In order for the ACK bit to
+//! take effect, manual acknowledgement must be enabled on the slave using
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK)
+{
+ //
+ // Send ACK or NACK based on the value of bACK.
+ //
+ if(bACK)
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, true);
+ }
+ else
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables manual acknowledge capability in the slave. If the
+//! application requires that the slave NACK on a bad command or a bad PEC
+//! calculation, manual acknowledgement allows this to happen.
+//!
+//! In the case of responding to a bad command with a NACK, the application
+//! should use SMBusSlaveACKSend() to ACK/NACK the command. The slave ISR
+//! should check for the SMBUS_SLAVE_FIRST_BYTE return code from
+//! SMBusSlaveISRProcess() and ACK/NACK accordingly. All other cases should be
+//! handled in the application based on the return code of
+//! SMBusSlaveISRProcess().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, true);
+}
+
+//*****************************************************************************
+//
+//! Disables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables manual acknowledge capability in the slave. When
+//! manual acknowledgement is disabled, the slave automatically ACKs every
+//! byte sent by the master.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKDisable(tSMBus *psSMBus)
+{
+ //
+ // Disable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, false);
+}
+
+//*****************************************************************************
+//
+//! Returns the manual acknowledgement status of the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the state of the I2C ACKOEN bit in the I2CSACKCTL
+//! register. This feature is disabled out of reset and must be enabled
+//! using SMBusSlaveManualACKEnable().
+//!
+//! \return Returns \b true if manual acknowledge is enabled, or \b false if
+//! manual acknowledge is disabled.
+//
+//*****************************************************************************
+bool
+SMBusSlaveManualACKStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Return the value of the bit.
+ //
+ return(HWREG(psSMBus->ui32I2CBase + I2C_O_SACKCTL) & 0x1);
+}
+
+//*****************************************************************************
+//
+//! Determine whether primary or secondary slave address has been requested by
+//! the master.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Tells the caller whether the I2C slave address requested by the master or
+//! SMBus Host is the primary or secondary I2C slave address of the peripheral.
+//! The primary is defined as the address programmed into I2CSOAR, and the
+//! secondary as the address programmed into I2CSOAR2.
+//!
+//! \return Returns \b SMBUS_SLAVE_ADDR_PRIMARY if the primary address is
+//! called out or \b SMBUS_SLAVE_ADDR_SECONDARY if the secondary address is
+//! called out.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntAddressGet(tSMBus *psSMBus)
+{
+ //
+ // Determine whether the primary or secondary address was called out.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ return(SMBUS_SLAVE_ADDR_SECONDARY);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_ADDR_PRIMARY);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate slave interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus slave. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusSlaveInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the slave interrupts.
+ //
+ I2CSlaveIntEnableEx(psSMBus->ui32I2CBase,
+ I2C_SLAVE_INT_DATA | I2C_SLAVE_INT_STOP);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the slave address for an SMBus slave peripheral.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8AddressNum specifies which address (primary or secondary)
+//! \param ui8SlaveAddress is the address of the slave.
+//!
+//! This function sets the slave address. Both the primary and secondary
+//! addresses can be set using this function. To set the primary address
+//! (stored in I2CSOAR), ui8AddressNum should be '0'. To set the secondary
+//! address (stored in I2CSOAR2), ui8AddressNum should be '1'.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
+ uint8_t ui8SlaveAddress)
+{
+ //
+ // Write the slave address.
+ //
+ I2CSlaveAddressSet(psSMBus->ui32I2CBase, ui8AddressNum, ui8SlaveAddress);
+}
+
+//*****************************************************************************
+//
+//! Sets a slave's UDID structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pUDID is a pointer to the UDID configuration for the slave. This
+//! is only needed if the slave is on a bus that uses ARP.
+//!
+//! This function sets the UDID for a slave instance.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID)
+{
+ psSMBus->pUDID = pUDID;
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C slave peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C slave peripheral.
+//!
+//! This function initializes an I2C peripheral for SMBus slave use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured based on the input arguments.
+//!
+//! The default configuration of the SMBus slave uses automatic
+//! acknowledgement. If manual acknowledgement is required, call
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable the I2C slave module. The slave is always enabled because the
+ // SMBus spec requires that all devices respond whne their slave address
+ // is put on the bus.
+ //
+ I2CSlaveEnable(psSMBus->ui32I2CBase);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/smbus.h b/utils/smbus.h
new file mode 100644
index 0000000..c483025
--- /dev/null
+++ b/utils/smbus.h
@@ -0,0 +1,463 @@
+//*****************************************************************************
+//
+// smbus.h - Prototypes for the SMBus driver.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SMBUS_H__
+#define __SMBUS_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup smbus_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure holds the SMBus Unique Device ID (UDID). For detailed
+//! information, please refer to the SMBus Specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Device capabilities field. This 8-bit field reports generic SMBus
+ //! capabilities such as address type for ARP.
+ //
+ uint8_t ui8DeviceCapabilities;
+
+ //
+ //! Version Revision field. This 8-bit field reports UDID revision
+ //! information as well as some vendor-specific things such as silicon
+ //! revision.
+ //
+ uint8_t ui8Version;
+
+ //
+ //! Vendor ID. This 16-bit field contains the manufacturer's ID as
+ //! assigned by the SBS Implementers' Forum of the PCI SIG.
+ //
+ uint16_t ui16VendorID;
+
+ //
+ //! Device ID. This 16-bit field contains the device ID assigned by the
+ //! device manufacturer.
+ //
+ uint16_t ui16DeviceID;
+
+ //
+ //! Interface. This 16-bit field identifies the protocol layer interfaces
+ //! supported over the SMBus connection.
+ //
+ uint16_t ui16Interface;
+
+ //
+ //! Subsystem Vendor ID. This 16-bit field holds additional information
+ //! that may be derived from the vendor ID or other information.
+ //
+ uint16_t ui16SubSystemVendorID;
+
+ //
+ //! Subsystem Device ID. This 16-bit field holds additional information
+ //! that may be derived from the device ID or other information.
+ //
+ uint16_t ui16SubSystemDeviceID;
+
+ //
+ //! Vendor-specific ID. This 32-bit field contains a unique number that
+ //! can be assigned per device by the manufacturer.
+ //
+ uint32_t ui32VendorSpecificID;
+}
+tSMBusUDID;
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of an SMBus module.
+//! Master and slave instances require unique configuration structures.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The SMBus Unique Device ID (UDID) for this SMBus instance. If
+ //! operating as a host, master-only, or on a bus that does not use Address
+ //! Resolution Protocol (ARP), this is not required. This member can be
+ //! set via a direct structure access or using the SMBusSlaveInit
+ //! function. For detailed information about the UDID, refer to the SMBus
+ //! spec.
+ //
+ tSMBusUDID *pUDID;
+
+ //
+ //! The base address of the I2C master peripheral. This member can be set
+ //! via a direct structure access or using the SMBusMasterInit or
+ //! SMBusSlaveInit functions.
+ //
+ uint32_t ui32I2CBase;
+
+ //
+ //! The address of the data buffer used for transmit operations. For
+ //! master operations, this member is set by the SMBusMasterxxxx functions
+ //! that pass a buffer pointer (for example, SMBusMasterBlockWrite). For
+ //! slave operations, this member can be set via direct structure access or
+ //! using the SMBusSlaveTxBufferSet function.
+ //
+ uint8_t *pui8TxBuffer;
+
+ //
+ //! The address of the data buffer used for receive operations. For master
+ //! operations, this member is set by the SMBusMasterxxxx functions that
+ //! pass a buffer pointer (for example, SMBusMasterBlockRead). For slave
+ //! operations, this member can be set via direct structure access or using
+ //! the SMBusSlaveRxBufferSet function.
+ //
+ uint8_t *pui8RxBuffer;
+
+ //
+ //! The amount of data to transmit from pui8TxBuffer. For master
+ //! operations this member is set by the SMBusMasterxxxx functions either
+ //! via an input argument (example SMBusMasterByteWordWrite) or explicitly
+ //! (example SMBusMasterSendByte). In master mode, this member should not
+ //! be accessed or modified by the application. For slave operations, this
+ //! member can be set via direct structure access of using the
+ //! SMBusSlaveTxBufferSet function.
+ //
+ uint8_t ui8TxSize;
+
+ //
+ //! The current index in the transmit buffer. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint8_t ui8TxIndex;
+
+ //
+ //! The amount of data to receive into pui8RxBuffer. For master
+ //! operations, this member is set by the SMBusMasterxxxx functions either
+ //! via an input argument (example SMBusMasterByteWordRead), explicitly
+ //! (example SMBusMasterReceiveByte), or by the slave (example
+ //! SMBusMasterBlockRead). In master mode, this member should not be
+ //! accessed or modified by the application. For slave operations, this
+ //! member can be set via direct structure access of using the
+ //! SMBusSlaveRxBufferSet function.
+ //
+ uint8_t ui8RxSize;
+
+ //
+ //! The current index in the receive buffer. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint8_t ui8RxIndex;
+
+ //
+ //! The active slave address of the I2C peripheral on the device.
+ //! When using dual address in slave mode, the active address is store
+ //! here. In master mode, this member is not used. This member is updated
+ //! as requests come in from the master.
+ //
+ uint8_t ui8OwnSlaveAddress;
+
+ //
+ //! The address of the targeted slave device. In master mode, this member
+ //! is set by the ui8TargetSlaveAddress argument in the SMBusMasterxxxx
+ //! transfer functions. In slave mode, it is not used. This member should
+ //! not be modified by the application.
+ //
+ uint8_t ui8TargetSlaveAddress;
+
+ //
+ //! The last used command. In master mode, this member is set by the
+ //! ui8Command argument in the SMBusMasterxxxx transfer functions. In
+ //! slave mode, the first received byte will always be considered the
+ //! command. This member should not be modified by the application.
+ //
+ uint8_t ui8CurrentCommand;
+
+ //
+ //! The running CRC calculation used for transfers that require Packet
+ //! Error Checking (PEC). This member is updated by the SMBus software and
+ //! should not be modified by the application.
+ //
+ uint8_t ui8CalculatedCRC;
+
+ //
+ //! The received CRC calculation used for transfers that require Packet
+ //! Error Checking (PEC). This member is updated by the SMBus software and
+ //! should not be modified by the application.
+ //
+ uint8_t ui8ReceivedCRC;
+
+ //
+ //! The current state of the SMBusMasterISRProcess state machine. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8MasterState;
+
+ //
+ //! The current state of the SMBusSlaveISRProcess state machine. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8SlaveState;
+
+ //
+ //! Flags used for various items in the SMBus state machines for different
+ //! transaction types and status.
+ //!
+ //! FLAG_PEC can be modified via the SMBusPECEnable or SMBusPECDisable
+ //! functions or via direct structure access.
+ //!
+ //! FLAG_BLOCK_TRANSFER can be set via the SMBusSlaveBlockTransferEnable
+ //! function and is cleared automatically by the SMBusSlaveTransferInit
+ //! function or manually using the SMBusSlaveBlockTransferDisable function.
+ //!
+ //! FLAG_RAW_I2C can be modified via the SMBusSlaveI2CEnable or
+ //! SMBusSlaveI2CDisable functions or via direct structure access.
+ //!
+ //! FLAG_TRANSFER_IN_PROGRESS should not be modified by the application,
+ //! but can be read via the SMBusStatusGet function.
+ //!
+ //! FLAG_PROCESS_CALL can be set via the SMBusSlaveProcessCallEnable
+ //! function and is cleared automatically by the SMBusSlaveTransferInit
+ //! function or manually using the SMBusSlaveProcessCallDisable function.
+ //!
+ //! FLAG_ADDRESS_RESOLVED is only used by an SMBus Slave that supports ARP.
+ //! This flag can be modified via the SMBusSlaveARPFlagARSet function and
+ //! read via SMBusSlaveARPFlagARGet. It can also be modified by direct
+ //! structure access.
+ //!
+ //! FLAG_ADDRESS_VALID is only used by an SMBus Slave that supports ARP.
+ //! This flag can be modified via the SMBusSlaveARPFlagAVSet function and
+ //! read via SMBusSlaveARPFlagAVGet. It can also be modified by direct
+ //! structure access.
+ //!
+ //! FLAG_ARP is used to indicate that ARP is currently active. This flag
+ //! is not used by the SMBus stack and can (optionally) be used by the
+ //! application to keep track of the ARP session.
+ //
+ uint16_t ui16Flags;
+}
+tSMBus;
+
+//*****************************************************************************
+//
+// ! Return codes.
+//
+//*****************************************************************************
+typedef enum
+{
+ SMBUS_OK = 0, // General "OK" return code
+ SMBUS_TIMEOUT, // Master detected bus timeout from slave
+ SMBUS_PERIPHERAL_BUSY, // The I2C peripheral is currently in use
+ SMBUS_BUS_BUSY, // The I2C bus is currently in use
+ SMBUS_ARB_LOST, // Bus arbitration was lost (master mode)
+ SMBUS_ADDR_ACK_ERROR, // In master mode, the address was NAK'd
+ SMBUS_DATA_ACK_ERROR, // Data transfer was NAK'd by receiver
+ SMBUS_PEC_ERROR, // PEC mismatch occurred
+ SMBUS_DATA_SIZE_ERROR, // Data size error has occurred
+ SMBUS_MASTER_ERROR, // Error occurred in the master ISR
+ SMBUS_SLAVE_ERROR, // Error occurred in the slave ISR
+ SMBUS_SLAVE_QCMD_0, // Slave transaction is Quick Command with
+ // data value 0.
+ SMBUS_SLAVE_QCMD_1, // Slave transaction is Quick Command with
+ // data value 1.
+ SMBUS_SLAVE_FIRST_BYTE, // The first byte has been received
+ SMBUS_SLAVE_ADDR_PRIMARY, // Primary address was detected
+ SMBUS_SLAVE_ADDR_SECONDARY, // Secondary address was detected
+ SMBUS_TRANSFER_IN_PROGRESS, // A transfer is currently in progress
+ SMBUS_TRANSFER_COMPLETE, // The last active transfer is complete
+ SMBUS_SLAVE_NOT_READY, // A slave transmit has been requested, but is
+ // not ready (TX buffer not set).
+ SMBUS_FIFO_ERROR, // A master receive operation did not receive
+ // enough data from the slave.
+}
+tSMBusStatus;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// ARP Commands
+//
+//*****************************************************************************
+#define SMBUS_CMD_PREPARE_TO_ARP 0x01
+#define SMBUS_CMD_ARP_RESET_DEVICE 0x02
+#define SMBUS_CMD_ARP_GET_UDID 0x03
+#define SMBUS_CMD_ARP_ASSIGN_ADDRESS 0x04
+
+//*****************************************************************************
+//
+// Fixed addresses defined by the SMBus specification.
+//
+//*****************************************************************************
+#define SMBUS_ADR_HOST 0x08
+#define SMBUS_ADR_SMART_BATTERY_CHARGER 0x09
+#define SMBUS_ADR_SMART_BATTERY_SELECTOR 0x0A
+#define SMBUS_ADR_SMART_BATTERY 0x0B
+#define SMBUS_ADR_DEFAULT_DEVICE 0x61
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern void SMBusPECEnable(tSMBus *psSMBus);
+extern void SMBusPECDisable(tSMBus *psSMBus);
+extern void SMBusARPEnable(tSMBus *psSMBus);
+extern void SMBusARPDisable(tSMBus *psSMBus);
+extern tSMBusStatus SMBusStatusGet(tSMBus *psSMBus);
+extern void SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID,
+ uint8_t ui8Address,
+ uint8_t *pui8Data);
+extern void SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID,
+ uint8_t *pui8Address,
+ uint8_t *pui8Data);
+extern uint8_t SMBusRxPacketSizeGet(tSMBus *psSMBus);
+extern void SMBusUDIDDataGet(tSMBus *psSMBus, tSMBusUDID *pUDID);
+extern tSMBusStatus SMBusMasterQuickCommand(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ bool bData);
+extern tSMBusStatus SMBusMasterByteSend(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Data);
+extern tSMBusStatus SMBusMasterByteReceive(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterByteWordWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterBlockWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterByteWordRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterBlockRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterProcessCall(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8TxData,
+ uint8_t *pui8RxData);
+extern tSMBusStatus SMBusMasterBlockProcessCall(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t ui8Command,
+ uint8_t *pui8TxData,
+ uint8_t ui8TxSize,
+ uint8_t *pui8RxData);
+extern tSMBusStatus SMBusMasterHostNotify(tSMBus *psSMBus,
+ uint8_t ui8OwnSlaveAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterI2CWrite(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterI2CRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern tSMBusStatus SMBusMasterI2CWriteRead(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8TxData,
+ uint8_t ui8TxSize,
+ uint8_t *pui8RxData,
+ uint8_t ui8RxSize);
+extern tSMBusStatus SMBusMasterARPGetUDIDGen(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPGetUDIDDir(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPResetDeviceGen(tSMBus *psSMBus);
+extern tSMBusStatus SMBusMasterARPResetDeviceDir(tSMBus *psSMBus,
+ uint8_t ui8TargetAddress);
+extern tSMBusStatus SMBusMasterARPAssignAddress(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPNotifyMaster(tSMBus *psSMBus,
+ uint8_t *pui8Data);
+extern tSMBusStatus SMBusMasterARPPrepareToARP(tSMBus *psSMBus);
+extern tSMBusStatus SMBusMasterIntProcess(tSMBus *psSMBus);
+extern void SMBusMasterIntEnable(tSMBus *psSMBus);
+extern void SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
+ uint32_t ui32SMBusClock);
+extern void SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern void SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size);
+extern uint8_t SMBusSlaveCommandGet(tSMBus *psSMBus);
+extern void SMBusSlaveProcessCallEnable(tSMBus *psSMBus);
+extern void SMBusSlaveProcessCallDisable(tSMBus *psSMBus);
+extern void SMBusSlaveBlockTransferEnable(tSMBus *psSMBus);
+extern void SMBusSlaveBlockTransferDisable(tSMBus *psSMBus);
+extern void SMBusSlaveI2CEnable(tSMBus *psSMBus);
+extern void SMBusSlaveI2CDisable(tSMBus *psSMBus);
+extern void SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue);
+extern bool SMBusSlaveARPFlagARGet(tSMBus *psSMBus);
+extern void SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue);
+extern bool SMBusSlaveARPFlagAVGet(tSMBus *psSMBus);
+extern void SMBusSlaveTransferInit(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveIntProcess(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveDataSend(tSMBus *psSMBus);
+extern void SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK);
+extern void SMBusSlaveManualACKEnable(tSMBus *psSMBus);
+extern void SMBusSlaveManualACKDisable(tSMBus *psSMBus);
+extern bool SMBusSlaveManualACKStatusGet(tSMBus *psSMBus);
+extern tSMBusStatus SMBusSlaveIntAddressGet(tSMBus *psSMBus);
+extern void SMBusSlaveIntEnable(tSMBus *psSMBus);
+extern void SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID);
+extern void SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
+ uint8_t ui8SlaveAddress);
+extern void SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SMBUS_H__
diff --git a/utils/softi2c.c b/utils/softi2c.c
new file mode 100644
index 0000000..ab3e5a6
--- /dev/null
+++ b/utils/softi2c.c
@@ -0,0 +1,1321 @@
+//*****************************************************************************
+//
+// softi2c.c - Driver for the SoftI2C.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softi2c.h"
+
+//*****************************************************************************
+//
+// The states in the SoftI2C state machine. The code depends upon the fact
+// that the value of STATE_X1 is exactly one greater than STATE_X0 (for any
+// value of X and for any following digit)...however there is no dependence on
+// the values of STATE_Xn and STATE_Yn.
+//
+//*****************************************************************************
+#define SOFTI2C_STATE_IDLE 0
+#define SOFTI2C_STATE_START0 1
+#define SOFTI2C_STATE_START1 2
+#define SOFTI2C_STATE_START2 3
+#define SOFTI2C_STATE_START3 4
+#define SOFTI2C_STATE_START4 5
+#define SOFTI2C_STATE_START5 6
+#define SOFTI2C_STATE_START6 7
+#define SOFTI2C_STATE_START7 8
+#define SOFTI2C_STATE_ADDR0 9
+#define SOFTI2C_STATE_ADDR1 10
+#define SOFTI2C_STATE_ADDR2 11
+#define SOFTI2C_STATE_ADDR3 12
+#define SOFTI2C_STATE_SEND0 13
+#define SOFTI2C_STATE_SEND1 14
+#define SOFTI2C_STATE_SEND2 15
+#define SOFTI2C_STATE_SEND3 16
+#define SOFTI2C_STATE_RECV0 17
+#define SOFTI2C_STATE_RECV1 18
+#define SOFTI2C_STATE_RECV2 19
+#define SOFTI2C_STATE_RECV3 20
+#define SOFTI2C_STATE_STOP0 21
+#define SOFTI2C_STATE_STOP1 22
+#define SOFTI2C_STATE_STOP2 23
+#define SOFTI2C_STATE_STOP3 24
+#define SOFTI2C_STATE_STOP4 25
+
+//*****************************************************************************
+//
+// The flags in the SoftI2C ui8Flags structure member. The first four flags,
+// RUN, START, STOP, and ACK, must match with the definitions of the
+// SOFTI2C_CMD_* commands in softi2c.h.
+//
+//*****************************************************************************
+#define SOFTI2C_FLAG_RUN 0
+#define SOFTI2C_FLAG_START 1
+#define SOFTI2C_FLAG_STOP 2
+#define SOFTI2C_FLAG_ACK 3
+#define SOFTI2C_FLAG_ADDR_ACK 5
+#define SOFTI2C_FLAG_DATA_ACK 6
+#define SOFTI2C_FLAG_RECEIVE 7
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftI2C
+//! module. The transmission and reception of data over the SoftI2C link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at four times the desired SoftI2C clock rate.
+//! For example, to run the SoftI2C clock at 10 KHz, this function must be
+//! called at a 40 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CTimerTick(tSoftI2C *psI2C)
+{
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psI2C->ui8State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTI2C_STATE_IDLE:
+ {
+ //
+ // See if the START flag is set, indicating that a start condition
+ // should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_START) == 1)
+ {
+ //
+ // Based on the current state of the SCL and SDA pins, pick the
+ // appropriate place within the state machine to begin the
+ // start/repeated-start signalling.
+ //
+ if(HWREG(psI2C->ui32SCLGPIO) != 0)
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START4;
+ }
+ else if(HWREG(psI2C->ui32SDAGPIO) == 0)
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START0;
+ }
+ else
+ {
+ psI2C->ui8State = SOFTI2C_STATE_START2;
+ }
+ }
+
+ //
+ // Otherwise, see if the RUN flag is set, indicating that a data
+ // byte should be transferred.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Start the transfer from the first bit.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // See if a byte should be sent or received.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // A byte should be sent.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // A byte should be received. Clear out the receive data
+ // buffer in preparation for receiving the new byte.
+ //
+ psI2C->ui8Data = 0;
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Generate a stop condition.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // See if the SoftI2C state machine has left the idle state.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ //
+ // The address and data ACK error flags should be cleared; they
+ // will be set if appropriate while the current command is
+ // being executed.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) = 0;
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) = 0;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The beginning of the start condition sequence when SDA and SCL are
+ // low. SDA must be driven high prior to driving SCL high so that a
+ // repeated-start is generated, instead of a stop then start.
+ //
+ case SOFTI2C_STATE_START0:
+ {
+ //
+ // Set SDA high.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_START1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Each of these states exists only to provide some timing delay in
+ // order to conform with the signalling requirements of I2C. This
+ // depends upon STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START1:
+ case SOFTI2C_STATE_START3:
+ case SOFTI2C_STATE_START5:
+ case SOFTI2C_STATE_STOP1:
+ case SOFTI2C_STATE_STOP3:
+ {
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SCL must be driven high. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START2:
+ case SOFTI2C_STATE_ADDR1:
+ case SOFTI2C_STATE_SEND1:
+ case SOFTI2C_STATE_RECV1:
+ case SOFTI2C_STATE_STOP2:
+ {
+ //
+ // Set SCL high.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SDA must be driven low. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START4:
+ case SOFTI2C_STATE_STOP0:
+ {
+ //
+ // Set SDA low.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low.
+ //
+ case SOFTI2C_STATE_START6:
+ {
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_START7;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the start condition has been generated.
+ //
+ case SOFTI2C_STATE_START7:
+ {
+ //
+ // Start with the first bit of the address.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // Advance to the address output state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the slave address must be sent.
+ //
+ case SOFTI2C_STATE_ADDR0:
+ {
+ //
+ // See if this is one of the first seven bits of the address phase.
+ //
+ if(psI2C->ui8CurrentBit < 7)
+ {
+ //
+ // Write the next bit of the slave address to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ ((psI2C->ui8SlaveAddr &
+ (1 << (6 - psI2C->ui8CurrentBit))) ? 255 : 0);
+ }
+
+ //
+ // Otherwise, see if this is the eight bit of the address phase
+ // (which is the read/not write bit).
+ //
+ else if(psI2C->ui8CurrentBit == 7)
+ {
+ //
+ // Write the read/not write bit to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ (HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) ?
+ 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, wait until SCL has gone high (it has been
+ // released by the SoftI2C master, but may be held low by the slave).
+ // This depends upon STATE_Xn and STATE_X(n+1) being consecutively
+ // numbered.
+ //
+ case SOFTI2C_STATE_ADDR2:
+ case SOFTI2C_STATE_SEND2:
+ case SOFTI2C_STATE_RECV2:
+ {
+ //
+ // See if SCL has gone high.
+ //
+ if(HWREG(psI2C->ui32SCLGPIO) != 0)
+ {
+ //
+ // Advance to the next state now that SCL has gone high.
+ //
+ psI2C->ui8State++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // address transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_ADDR3:
+ {
+ //
+ // See if this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(psI2C->ui32SDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the address byte has not
+ // been ACKed by any slave.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The start phase (start or repeated-start, plus the address
+ // byte) have completed, so clear the START flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_START) = 0;
+
+ //
+ // See if the RUN flag is set, indicating that a data byte
+ // should be transferred as well.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Reset the current bit to zero for the start of the data
+ // phase.
+ //
+ psI2C->ui8CurrentBit = 0;
+
+ //
+ // See if the data byte is being sent or received.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags),
+ SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // The data byte is being sent, so advance to the data
+ // send state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // The data byte is being received, so clear the data
+ // buffer and advance to the data receive state.
+ //
+ psI2C->ui8Data = 0;
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a
+ // stop condition should be generated.
+ //
+ else if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the address should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the address tranfer state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_ADDR0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be sent.
+ //
+ case SOFTI2C_STATE_SEND0:
+ {
+ //
+ // See if this is one of the first eight bits of the data phase.
+ //
+ if(psI2C->ui8CurrentBit < 8)
+ {
+ //
+ // Write the next bit of the data byte to SDA.
+ //
+ HWREG(psI2C->ui32SDAGPIO) =
+ ((psI2C->ui8Data &
+ (1 << (7 - psI2C->ui8CurrentBit))) ? 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the data phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // data transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_SEND3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(psI2C->ui32SDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the data byte has not been
+ // ACKed by the slave.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the data transmit state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_SEND0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be received.
+ //
+ case SOFTI2C_STATE_RECV0:
+ {
+ //
+ // See if this is the first bit of the data phase.
+ //
+ if(psI2C->ui8CurrentBit == 0)
+ {
+ //
+ // Change the SDA GPIO into an input so that the data provided
+ // by the slave can be read.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Otherwise, see if this is the ninth bit of the data phase (in
+ // other words, the ACK bit).
+ //
+ else if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // Change the SDA GPIO into an output so that the ACK bit can
+ // be driven to the slave.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // See if this byte should be ACKed or NAKed.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ACK) == 1)
+ {
+ //
+ // Drive SDA low to ACK the data byte.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 0;
+ }
+ else
+ {
+ //
+ // Allow SDA to get pulled high to NAK the data byte.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+ }
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_RECV1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. For the first eight bits of
+ // the data transfer, the data bits are read from the slave.
+ //
+ case SOFTI2C_STATE_RECV3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(psI2C->ui8CurrentBit == 8)
+ {
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Read the next bit of data from the SDA line.
+ //
+ psI2C->ui8Data |= (HWREG(psI2C->ui32SDAGPIO) ?
+ (1 << (7 - psI2C->ui8CurrentBit)) : 0);
+
+ //
+ // Increment the bit count.
+ //
+ psI2C->ui8CurrentBit++;
+
+ //
+ // Advance to the data receive state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_RECV0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SDA must be driven high to create the stop condition.
+ //
+ case SOFTI2C_STATE_STOP4:
+ {
+ //
+ // Set SDA high to create the stop condition.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // The stop condition has been generated, so clear the STOP flag.
+ //
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_STOP) = 0;
+
+ //
+ // Since the requested operations have completed, set the SoftI2C
+ // ``interrupt''.
+ //
+ psI2C->ui8IntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the I2C peripheral.
+ //
+ while(((psI2C->ui8IntStatus & psI2C->ui8IntMask) != 0) &&
+ (psI2C->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psI2C->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function initializes operation of the SoftI2C module. After
+//! successful initialization of the SoftI2C module, the software I2C bus is in
+//! the idle state.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CInit(tSoftI2C *psI2C)
+{
+ //
+ // Configure the SCL pin.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SCLGPIO & 0xfffff000,
+ (psI2C->ui32SCLGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(psI2C->ui32SCLGPIO & 0xfffff000,
+ (psI2C->ui32SCLGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SCL pin high.
+ //
+ HWREG(psI2C->ui32SCLGPIO) = 255;
+
+ //
+ // Configure the SDA pin.
+ //
+ MAP_GPIODirModeSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(psI2C->ui32SDAGPIO & 0xfffff000,
+ (psI2C->ui32SDAGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SDA pin high.
+ //
+ HWREG(psI2C->ui32SDAGPIO) = 255;
+
+ //
+ // The ``interrupt'' is not asserted at the start.
+ //
+ psI2C->ui8IntStatus = 0;
+
+ //
+ // There are no flags at the start.
+ //
+ psI2C->ui8Flags = 0;
+
+ //
+ // Start the SoftI2C state machine in the idle state.
+ //
+ psI2C->ui8State = SOFTI2C_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftI2C module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CCallbackSet(tSoftI2C *psI2C, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psI2C->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SCL signal.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SCL signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSCLGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the SCL signal.
+ //
+ psI2C->ui32SCLGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SDA signal.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SDA signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSDAGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the SDA signal.
+ //
+ psI2C->ui32SDAGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! Enables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntEnable(tSoftI2C *psI2C)
+{
+ //
+ // Enable the master interrupt.
+ //
+ psI2C->ui8IntMask = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! Disables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntDisable(tSoftI2C *psI2C)
+{
+ //
+ // Disable the master interrupt.
+ //
+ psI2C->ui8IntMask = 0;
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftI2C ``interrupt'' status.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is requested and
+//! \b true if the masked ``interrupt'' status is requested.
+//!
+//! This returns the ``interrupt'' status for the SoftI2C module. Either the
+//! raw ``interrupt'' status or the status of ``interrupts'' that are allowed
+//! to reflect to the processor can be returned.
+//!
+//! \return The current interrupt status, returned as \b true if active
+//! or \b false if not active.
+//
+//*****************************************************************************
+bool
+SoftI2CIntStatus(tSoftI2C *psI2C, bool bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return((psI2C->ui8IntStatus & psI2C->ui8IntMask) ? true : false);
+ }
+ else
+ {
+ return(psI2C->ui8IntStatus ? true : false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears the SoftI2C ``interrupt''.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! The SoftI2C ``interrupt'' source is cleared, so that it no longer asserts.
+//! This function must be called in the ``interrupt'' handler to keep it from
+//! being called again immediately on exit.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntClear(tSoftI2C *psI2C)
+{
+ //
+ // Clear the SoftI2C interrupt source.
+ //
+ psI2C->ui8IntStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the address that the SoftI2C module places on the bus.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui8SlaveAddr 7-bit slave address
+//! \param bReceive flag indicating the type of communication with the slave.
+//!
+//! This function sets the address that the SoftI2C module places on the bus
+//! when initiating a transaction. When the \e bReceive parameter is set to
+//! \b true, the address indicates that the SoftI2C moudle is initiating a read
+//! from the slave; otherwise the address indicates that the SoftI2C module is
+//! initiating a write to the slave.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSlaveAddrSet(tSoftI2C *psI2C, uint8_t ui8SlaveAddr,
+ bool bReceive)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(!(ui8SlaveAddr & 0x80));
+
+ //
+ // Set the address of the slave with which the master will communicate.
+ //
+ psI2C->ui8SlaveAddr = ui8SlaveAddr;
+
+ //
+ // Set a flag to indicate if this is a transmit or receive.
+ //
+ if(bReceive)
+ {
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) = 1;
+ }
+ else
+ {
+ HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_RECEIVE) = 0;
+ }
+}
+
+//*****************************************************************************
+//
+//! Indicates whether or not the SoftI2C module is busy.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function returns an indication of whether or not the SoftI2C module is
+//! busy transmitting or receiving data.
+//!
+//! \return Returns \b true if the SoftI2C module is busy; otherwise, returns
+//! \b false.
+//
+//*****************************************************************************
+bool
+SoftI2CBusy(tSoftI2C *psI2C)
+{
+ //
+ // Return the busy status.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ return(true);
+ }
+ else
+ {
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Controls the state of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui32Cmd command to be issued to the SoftI2C module.
+//!
+//! This function is used to control the state of the SoftI2C module send and
+//! receive operations. The \e ui8Cmd parameter can be one of the following
+//! values:
+//!
+//! - \b SOFTI2C_CMD_SINGLE_SEND
+//! - \b SOFTI2C_CMD_SINGLE_RECEIVE
+//! - \b SOFTI2C_CMD_BURST_SEND_START
+//! - \b SOFTI2C_CMD_BURST_SEND_CONT
+//! - \b SOFTI2C_CMD_BURST_SEND_FINISH
+//! - \b SOFTI2C_CMD_BURST_SEND_ERROR_STOP
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_START
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_CONT
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_FINISH
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CControl(tSoftI2C *psI2C, uint32_t ui32Cmd)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Cmd == SOFTI2C_CMD_SINGLE_SEND) ||
+ (ui32Cmd == SOFTI2C_CMD_SINGLE_RECEIVE) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_START) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_CONT) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_FINISH) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_SEND_ERROR_STOP) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_START) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_CONT) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_FINISH) ||
+ (ui32Cmd == SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP));
+
+ //
+ // Send the command.
+ //
+ psI2C->ui8Flags = (psI2C->ui8Flags & 0xf0) | ui32Cmd;
+}
+
+//*****************************************************************************
+//
+//! Gets the error status of the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function is used to obtain the error status of the SoftI2C module send
+//! and receive operations.
+//!
+//! \return Returns the error status, as one of \b SOFTI2C_ERR_NONE,
+//! \b SOFTI2C_ERR_ADDR_ACK, or \b SOFTI2C_ERR_DATA_ACK.
+//
+//*****************************************************************************
+uint32_t
+SoftI2CErr(tSoftI2C *psI2C)
+{
+ //
+ // If the SoftI2C is busy, there is no error to report.
+ //
+ if(psI2C->ui8State != SOFTI2C_STATE_IDLE)
+ {
+ return(SOFTI2C_ERR_NONE);
+ }
+
+ //
+ // Return any errors that may have occurred.
+ //
+ return((HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_ADDR_ACK) ?
+ SOFTI2C_ERR_ADDR_ACK : 0) |
+ (HWREGBITB(&(psI2C->ui8Flags), SOFTI2C_FLAG_DATA_ACK) ?
+ SOFTI2C_ERR_DATA_ACK : 0));
+}
+
+//*****************************************************************************
+//
+//! Transmits a byte from the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//! \param ui8Data data to be transmitted from the SoftI2C module.
+//!
+//! This function places the supplied data into SoftI2C module in preparation
+//! for being transmitted via an appropriate call to SoftI2CControl().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CDataPut(tSoftI2C *psI2C, uint8_t ui8Data)
+{
+ //
+ // Write the byte.
+ //
+ psI2C->ui8Data = ui8Data;
+}
+
+//*****************************************************************************
+//
+//! Receives a byte that has been sent to the SoftI2C module.
+//!
+//! \param psI2C specifies the SoftI2C data structure.
+//!
+//! This function reads a byte of data from the SoftI2C module that was
+//! received as a result of an appropriate call to SoftI2CControl().
+//!
+//! \return Returns the byte received by the SoftI2C module, cast as an
+//! uint32_t.
+//
+//*****************************************************************************
+uint32_t
+SoftI2CDataGet(tSoftI2C *psI2C)
+{
+ //
+ // Read a byte.
+ //
+ return(psI2C->ui8Data);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softi2c.h b/utils/softi2c.h
new file mode 100644
index 0000000..0ac876a
--- /dev/null
+++ b/utils/softi2c.h
@@ -0,0 +1,195 @@
+//*****************************************************************************
+//
+// softi2c.h - Defines and macros for the SoftI2C.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTI2C_H__
+#define __SOFTI2C_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftI2C module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware I2C implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftI2CCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the SCL signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSCLGPIOSet
+ //! function.
+ //
+ uint32_t ui32SCLGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the SDA signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSDAGPIOSet
+ //! function.
+ ///
+ uint32_t ui32SDAGPIO;
+
+ //
+ //! The flags that control the operation of the SoftI2C module. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The slave address that is currently being accessed. This member should
+ //! not be accessed or modified by the application.
+ //
+ uint8_t ui8SlaveAddr;
+
+ //
+ //! The data that is currently being transmitted or received. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8Data;
+
+ //
+ //! The current state of the SoftI2C state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint8_t ui8State;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8CurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8IntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8IntStatus;
+}
+tSoftI2C;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// SoftI2C commands.
+//
+//*****************************************************************************
+#define SOFTI2C_CMD_SINGLE_SEND 0x00000007
+#define SOFTI2C_CMD_SINGLE_RECEIVE \
+ 0x00000007
+#define SOFTI2C_CMD_BURST_SEND_START \
+ 0x00000003
+#define SOFTI2C_CMD_BURST_SEND_CONT \
+ 0x00000001
+#define SOFTI2C_CMD_BURST_SEND_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_SEND_ERROR_STOP \
+ 0x00000004
+#define SOFTI2C_CMD_BURST_RECEIVE_START \
+ 0x0000000b
+#define SOFTI2C_CMD_BURST_RECEIVE_CONT \
+ 0x00000009
+#define SOFTI2C_CMD_BURST_RECEIVE_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP \
+ 0x00000004
+
+//*****************************************************************************
+//
+// SoftI2C error status.
+//
+//*****************************************************************************
+#define SOFTI2C_ERR_NONE 0x00000000
+#define SOFTI2C_ERR_ADDR_ACK 0x00000004
+#define SOFTI2C_ERR_DATA_ACK 0x00000008
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern bool SoftI2CBusy(tSoftI2C *psI2C);
+extern void SoftI2CCallbackSet(tSoftI2C *psI2C, void (*pfnCallback)(void));
+extern void SoftI2CControl(tSoftI2C *psI2C, uint32_t ui32Cmd);
+extern uint32_t SoftI2CDataGet(tSoftI2C *psI2C);
+extern void SoftI2CDataPut(tSoftI2C *psI2C, uint8_t ui8Data);
+extern uint32_t SoftI2CErr(tSoftI2C *psI2C);
+extern void SoftI2CInit(tSoftI2C *psI2C);
+extern void SoftI2CIntClear(tSoftI2C *psI2C);
+extern void SoftI2CIntDisable(tSoftI2C *psI2C);
+extern void SoftI2CIntEnable(tSoftI2C *psI2C);
+extern bool SoftI2CIntStatus(tSoftI2C *psI2C, bool bMasked);
+extern void SoftI2CSCLGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftI2CSDAGPIOSet(tSoftI2C *psI2C, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftI2CSlaveAddrSet(tSoftI2C *psI2C, uint8_t ui8SlaveAddr,
+ bool bReceive);
+extern void SoftI2CTimerTick(tSoftI2C *psI2C);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTI2C_H__
diff --git a/utils/softssi.c b/utils/softssi.c
new file mode 100644
index 0000000..d2a155c
--- /dev/null
+++ b/utils/softssi.c
@@ -0,0 +1,1297 @@
+//*****************************************************************************
+//
+// softssi.c - Driver for the SoftSSI.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softssi.h"
+
+//*****************************************************************************
+//
+// The states in the SoftSSI state machine.
+//
+//*****************************************************************************
+#define SOFTSSI_STATE_IDLE 0
+#define SOFTSSI_STATE_START 1
+#define SOFTSSI_STATE_IN 2
+#define SOFTSSI_STATE_OUT 3
+#define SOFTSSI_STATE_STOP1 4
+#define SOFTSSI_STATE_STOP2 5
+
+//*****************************************************************************
+//
+// The flags in the SoftSSI ui8Flags structure member.
+//
+//*****************************************************************************
+#define SOFTSSI_FLAG_ENABLE 0x80
+#define SOFTSSI_FLAG_SPH 0x02
+#define SOFTSSI_FLAG_SPO 0x01
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui8Protocol specifes the data transfer protocol.
+//! \param ui8Bits specifies the number of bits transferred per frame.
+//!
+//! This function configures the data format of a SoftSSI module. The
+//! \e ui8Protocol parameter can be one of the following values:
+//! \b SOFTSSI_FRF_MOTO_MODE_0, \b SOFTSSI_FRF_MOTO_MODE_1,
+//! \b SOFTSSI_FRF_MOTO_MODE_2, or \b SOFTSSI_FRF_MOTO_MODE_3. These frame
+//! formats imply the following polarity and phase configurations:
+//!
+//! <pre>
+//! Polarity Phase Mode
+//! 0 0 SOFTSSI_FRF_MOTO_MODE_0
+//! 0 1 SOFTSSI_FRF_MOTO_MODE_1
+//! 1 0 SOFTSSI_FRF_MOTO_MODE_2
+//! 1 1 SOFTSSI_FRF_MOTO_MODE_3
+//! </pre>
+//!
+//! The \e ui8Bits parameter defines the width of the data transfers, and can
+//! be a value between 4 and 16, inclusive.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIConfigSet(tSoftSSI *psSSI, uint8_t ui8Protocol,
+ uint8_t ui8Bits)
+{
+ //
+ // See if a GPIO pin has been set for Fss.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ //
+ // Configure the Fss pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32FssGPIO & 0xfffff000,
+ (psSSI->ui32FssGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Fss pin high.
+ //
+ HWREG(psSSI->ui32FssGPIO) = 255;
+ }
+
+ //
+ // Configure the Clk pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32ClkGPIO & 0xfffff000,
+ (psSSI->ui32ClkGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Clk pin high or low based on the configured clock polarity.
+ //
+ if((ui8Protocol & SOFTSSI_FLAG_SPO) == 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) = 0;
+ }
+ else
+ {
+ HWREG(psSSI->ui32ClkGPIO) = 255;
+ }
+
+ //
+ // Configure the Tx pin and set it low.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psSSI->ui32TxGPIO & 0xfffff000,
+ (psSSI->ui32TxGPIO & 0x00000fff) >> 2);
+ HWREG(psSSI->ui32TxGPIO) = 0;
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(psSSI->ui32RxGPIO != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(psSSI->ui32RxGPIO & 0xfffff000,
+ (psSSI->ui32RxGPIO & 0x00000fff) >> 2);
+ }
+
+ //
+ // Make sure that the transmit and receive FIFOs are empty.
+ //
+ psSSI->ui16TxBufferRead = 0;
+ psSSI->ui16TxBufferWrite = 0;
+ psSSI->ui16RxBufferRead = 0;
+ psSSI->ui16RxBufferWrite = 0;
+
+ //
+ // Save the frame protocol.
+ //
+ psSSI->ui8Flags = ui8Protocol;
+
+ //
+ // Save the number of data bits.
+ //
+ psSSI->ui8Bits = ui8Bits;
+
+ //
+ // Since the FIFOs are empty, the transmit FIFO "interrupt" is asserted.
+ //
+ psSSI->ui8IntStatus = SOFTSSI_TXFF;
+
+ //
+ // Reset the idle counter.
+ //
+ psSSI->ui8IdleCount = 0;
+
+ //
+ // Disable the SoftSSI module.
+ //
+ psSSI->ui8Flags &= ~(SOFTSSI_FLAG_ENABLE);
+
+ //
+ // Start the SoftSSI state machine in the idle state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the transmit FIFO ``interrupt''.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the transmit
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSITxInt(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the number of words left in the transmit FIFO.
+ //
+ if(psSSI->ui16TxBufferRead > psSSI->ui16TxBufferWrite)
+ {
+ ui16Temp = (psSSI->ui16TxBufferLen + psSSI->ui16TxBufferWrite -
+ psSSI->ui16TxBufferRead);
+ }
+ else
+ {
+ ui16Temp = psSSI->ui16TxBufferWrite - psSSI->ui16TxBufferRead;
+ }
+
+ //
+ // If the transmit FIFO is now half full or less, generate a transmit FIFO
+ // "interrupt". Otherwise, clear the transmit FIFO "interrupt".
+ //
+ if(ui16Temp <= (psSSI->ui16TxBufferLen / 2))
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_TXFF;
+ }
+ else
+ {
+ psSSI->ui8IntStatus &= ~(SOFTSSI_TXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the receive FIFO ``interrupt''.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the receive
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSIRxInt(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the number of words in the receive FIFO.
+ //
+ if(psSSI->ui16RxBufferRead > psSSI->ui16RxBufferWrite)
+ {
+ ui16Temp = (psSSI->ui16RxBufferLen + psSSI->ui16RxBufferWrite -
+ psSSI->ui16RxBufferRead);
+ }
+ else
+ {
+ ui16Temp = psSSI->ui16RxBufferWrite - psSSI->ui16RxBufferRead;
+ }
+
+ //
+ // If the receive FIFO is now half full or more, generate a receive FIFO
+ // "interrupt". Otherwise, clear the receive FIFO "interrupt".
+ //
+ if(ui16Temp >= (psSSI->ui16RxBufferLen / 2))
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_RXFF;
+ }
+ else
+ {
+ psSSI->ui8IntStatus &= ~(SOFTSSI_RXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftSSI
+//! module. The transmission and reception of data over the SoftSSI link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at twice the desired SoftSSI clock rate. For
+//! example, to run the SoftSSI clock at 10 KHz, this function must be called
+//! at a 20 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITimerTick(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psSSI->ui8State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTSSI_STATE_IDLE:
+ {
+ //
+ // See if the SoftSSI module is enabled and there is data in the
+ // transmit FIFO.
+ //
+ if(((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ (psSSI->ui16TxBufferRead != psSSI->ui16TxBufferWrite))
+ {
+ //
+ // Assert the Fss signal if it is configured.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ HWREG(psSSI->ui32FssGPIO) = 0;
+ }
+
+ //
+ // Move to the start state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_START;
+ }
+
+ //
+ // Otherwise, see if there is data in the receive FIFO.
+ //
+ else if((psSSI->ui16RxBufferRead != psSSI->ui16RxBufferWrite) &&
+ (psSSI->ui8IdleCount != 64))
+ {
+ //
+ // Increment the idle counter.
+ //
+ psSSI->ui8IdleCount++;
+
+ //
+ // See if the idle counter has become large enough to trigger
+ // a timeout "interrupt".
+ //
+ if(psSSI->ui8IdleCount == 64)
+ {
+ //
+ // Trigger the receive timeout "interrupt".
+ //
+ psSSI->ui8IntStatus |= SOFTSSI_RXTO;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The start machine is in the transfer start state.
+ //
+ case SOFTSSI_STATE_START:
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ psSSI->ui16TxData =
+ (psSSI->pui16TxBuffer[psSSI->ui16TxBufferRead] <<
+ (16 - psSSI->ui8Bits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ psSSI->ui16RxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ psSSI->ui8CurrentBit = 0;
+
+ //
+ // Write the first bit of the transmit word to the Tx pin.
+ //
+ HWREG(psSSI->ui32TxGPIO) =
+ (psSSI->ui16TxData & 0x8000) ? 255 : 0;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ psSSI->ui16TxData <<= 1;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) != 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the data input state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data input state.
+ //
+ case SOFTSSI_STATE_IN:
+ {
+ //
+ // Read the next bit from the Rx signal if it is configured.
+ //
+ if(psSSI->ui32RxGPIO != 0)
+ {
+ psSSI->ui16RxData = ((psSSI->ui16RxData << 1) |
+ (HWREG(psSSI->ui32RxGPIO) ? 1 : 0));
+ }
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+
+ //
+ // Increment the number of bits transferred.
+ //
+ psSSI->ui8CurrentBit++;
+
+ //
+ // See if the entire word has been transferred.
+ //
+ if(psSSI->ui8CurrentBit != psSSI->ui8Bits)
+ {
+ //
+ // There are more bits to transfer, so move to the data output
+ // state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // Increment the transmit read pointer, removing the word that
+ // was just transferred from the transmit FIFO.
+ //
+ psSSI->ui16TxBufferRead++;
+ if(psSSI->ui16TxBufferRead == psSSI->ui16TxBufferLen)
+ {
+ psSSI->ui16TxBufferRead = 0;
+ }
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSITxInt(psSSI);
+
+ //
+ // Determine the new value for the receive FIFO write pointer.
+ //
+ ui16Temp = psSSI->ui16RxBufferWrite + 1;
+ if(ui16Temp >= psSSI->ui16RxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive FIFO for the word that
+ // was just received.
+ //
+ if(ui16Temp == psSSI->ui16RxBufferRead)
+ {
+ //
+ // The receive FIFO is full, so generate a receive FIFO
+ // overrun "interrupt".
+ //
+ psSSI->ui8IntStatus |= SOFTSSI_RXOR;
+ }
+ else
+ {
+ //
+ // Store the new word into the receive FIFO.
+ //
+ psSSI->pui16RxBuffer[psSSI->ui16RxBufferWrite] =
+ psSSI->ui16RxData;
+
+ //
+ // Save the new receive FIFO write pointer.
+ //
+ psSSI->ui16RxBufferWrite = ui16Temp;
+
+ //
+ // See if a receive FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSIRxInt(psSSI);
+ }
+
+ //
+ // See if the next word should be transmitted immediately.
+ // This will occur when there is data in the transmit FIFO, the
+ // SoftSSI module is enabled, and the SoftSSI module is in SPI
+ // mode 1 or 3.
+ //
+ if(((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ ((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) != 0) &&
+ (psSSI->ui16TxBufferRead != psSSI->ui16TxBufferWrite))
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ psSSI->ui16TxData =
+ (psSSI->pui16TxBuffer[psSSI->ui16TxBufferRead] <<
+ (16 - psSSI->ui8Bits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ psSSI->ui16RxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ psSSI->ui8CurrentBit = 0;
+
+ //
+ // Move to the data output state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // The next word should not be transmitted immediately, so
+ // move to the first step of the stop state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_STOP1;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data output state.
+ //
+ case SOFTSSI_STATE_OUT:
+ {
+ //
+ // Write the next bit of the transmit word to the Tx pin.
+ //
+ HWREG(psSSI->ui32TxGPIO) = (psSSI->ui16TxData & 0x8000) ? 255 : 0;
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ psSSI->ui16TxData <<= 1;
+
+ //
+ // Move to the data input state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the first step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP1:
+ {
+ //
+ // Set the Tx pin low.
+ //
+ HWREG(psSSI->ui32TxGPIO) = 0;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((psSSI->ui8Flags & SOFTSSI_FLAG_SPH) == 0)
+ {
+ HWREG(psSSI->ui32ClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the second step of the stop state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_STOP2;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the second step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP2:
+ {
+ //
+ // Deassert the Fss signal if it is configured.
+ //
+ if(psSSI->ui32FssGPIO != 0)
+ {
+ HWREG(psSSI->ui32FssGPIO) = 255;
+ }
+
+ //
+ // Move to the idle state.
+ //
+ psSSI->ui8State = SOFTSSI_STATE_IDLE;
+
+ //
+ // Reset the idle counter.
+ //
+ psSSI->ui8IdleCount = 0;
+
+ //
+ // See if the end of transfer "interrupt" should be generated.
+ //
+ if(psSSI->ui16TxBufferRead == psSSI->ui16TxBufferWrite)
+ {
+ psSSI->ui8IntStatus |= SOFTSSI_TXEOT;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the SSI peripheral.
+ //
+ while(((psSSI->ui8IntStatus & psSSI->ui8IntMask) != 0) &&
+ (psSSI->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psSSI->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function enables operation of the SoftSSI module. The SoftSSI module
+//! must be configured before it is enabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIEnable(tSoftSSI *psSSI)
+{
+ //
+ // Enable the SoftSSI module.
+ //
+ psSSI->ui8Flags |= SOFTSSI_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function disables operation of the SoftSSI module. If a data transfer
+//! is in progress, it is finished before the module is fully disabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDisable(tSoftSSI *psSSI)
+{
+ //
+ // Disable the SoftSSI module.
+ //
+ psSSI->ui8Flags &= ~(SOFTSSI_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! enabled.
+//!
+//! Enables the indicated SoftSSI ``interrupt'' sources. Only the sources that
+//! are enabled can be reflected to the callback function; disabled sources do
+//! not result in a callback. The \e ui32IntFlags parameter can be any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or
+//! \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntEnable(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Enable the specified "interrupts".
+ //
+ psSSI->ui8IntMask |= ui32IntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftSSI ``interrupt'' sources. The \e ui32IntFlags
+//! parameter can be any of the \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF,
+//! \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntDisable(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Disable the specified "interrupts".
+ //
+ psSSI->ui8IntMask &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current ``interrupt'' status.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required or
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This function returns the ``interrupt'' status for the SoftSSI module.
+//! Either the raw ``interrupt'' status or the status of ``interrupts'' that
+//! are allowed to reflect to the callback can be returned.
+//!
+//! \return The current ``interrupt'' status, enumerated as a bit field of
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, and
+//! \b SOFTSSI_RXOR.
+//
+//*****************************************************************************
+uint32_t
+SoftSSIIntStatus(tSoftSSI *psSSI, bool bMasked)
+{
+ //
+ // Return either the "interrupt" status or the raw "interrupt" status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(psSSI->ui8IntStatus & psSSI->ui8IntMask);
+ }
+ else
+ {
+ return(psSSI->ui8IntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftSSI ``interrupt'' sources.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! cleared.
+//!
+//! The specified SoftSSI ``interrupt'' sources are cleared so that they no
+//! longer assert. This function must be called in the ``interrupt'' handler
+//! to keep the ``interrupt'' from being recognized again immediately upon
+//! exit. The \e ui32IntFlags parameter is the logical OR of any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_RXTO, and \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntClear(tSoftSSI *psSSI, uint32_t ui32IntFlags)
+{
+ //
+ // Clear the requested "interrupt" sources.
+ //
+ psSSI->ui8IntStatus &= ~(ui32IntFlags) | SOFTSSI_TXFF | SOFTSSI_RXFF;
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any data in the receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is any data available to be read from the
+//! receive FIFO.
+//!
+//! \return Returns \b true if there is data in the receive FIFO or \b false
+//! if there is no data in the receive FIFO.
+//
+//*****************************************************************************
+bool
+SoftSSIDataAvail(tSoftSSI *psSSI)
+{
+ //
+ // Return the availability of data.
+ //
+ return((psSSI->ui16RxBufferRead == psSSI->ui16RxBufferWrite) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is space available in the transmit FIFO.
+//!
+//! \return Returns \b true if there is space available in the transmit FIFO or
+//! \b false if there is no space available in the transmit FIFO.
+//
+//*****************************************************************************
+bool
+SoftSSISpaceAvail(tSoftSSI *psSSI)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((psSSI->ui16TxBufferRead == ui16Temp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Data is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module.
+//!
+//! \note The upper 32 - N bits of the \e ui32Data are discarded, where N is
+//! the data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ui32Data are discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataPut(tSoftSSI *psSSI, uint32_t ui32Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Wait until there is space.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+ while(ui16Temp == *(volatile uint16_t *)(&(psSSI->ui16TxBufferRead)))
+ {
+ }
+
+ //
+ // Write the data to the SoftSSI.
+ //
+ psSSI->pui16TxBuffer[psSSI->ui16TxBufferWrite] = ui32Data;
+ psSSI->ui16TxBufferWrite = ui16Temp;
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSITxInt(psSSI);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Data is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module. If there is no space in the FIFO, then this
+//! function returns a zero.
+//!
+//! \note The upper 32 - N bits of the \e ui32Data are discarded, where N is
+//! the data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ui32Data are discarded.
+//!
+//! \return Returns the number of elements written to the SSI transmit FIFO.
+//
+//*****************************************************************************
+int32_t
+SoftSSIDataPutNonBlocking(tSoftSSI *psSSI, uint32_t ui32Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psSSI->ui16TxBufferWrite + 1;
+ if(ui16Temp == psSSI->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Check for space to write.
+ //
+ if(ui16Temp != psSSI->ui16TxBufferRead)
+ {
+ psSSI->pui16TxBuffer[psSSI->ui16TxBufferWrite] = ui32Data;
+ psSSI->ui16TxBufferWrite = ui16Temp;
+ SoftSSITxInt(psSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui32Data is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e pui32Data parameter.
+//!
+//! \note Only the lower N bits of the value written to \e pui32Data contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pui32Data contain valid data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataGet(tSoftSSI *psSSI, uint32_t *pui32Data)
+{
+ //
+ // Wait until there is data to be read.
+ //
+ while(psSSI->ui16RxBufferRead ==
+ *(volatile uint16_t *)(&(psSSI->ui16RxBufferWrite)))
+ {
+ }
+
+ //
+ // Read data from SoftSSI.
+ //
+ *pui32Data = psSSI->pui16RxBuffer[psSSI->ui16RxBufferRead];
+ psSSI->ui16RxBufferRead++;
+ if(psSSI->ui16RxBufferRead == psSSI->ui16RxBufferLen)
+ {
+ psSSI->ui16RxBufferRead = 0;
+ }
+
+ //
+ // See if a receive FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSIRxInt(psSSI);
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui32Data is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e ui32Data parameter. If there is no data in the FIFO, then this function
+//! returns a zero.
+//!
+//! \note Only the lower N bits of the value written to \e pui32Data contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pui32Data contain valid data.
+//!
+//! \return Returns the number of elements read from the SoftSSI receive FIFO.
+//
+//*****************************************************************************
+int32_t
+SoftSSIDataGetNonBlocking(tSoftSSI *psSSI, uint32_t *pui32Data)
+{
+ //
+ // Check for data to read.
+ //
+ if(psSSI->ui16RxBufferRead != psSSI->ui16RxBufferWrite)
+ {
+ *pui32Data = psSSI->pui16RxBuffer[psSSI->ui16RxBufferRead];
+ psSSI->ui16RxBufferRead++;
+ if(psSSI->ui16RxBufferRead == psSSI->ui16RxBufferLen)
+ {
+ psSSI->ui16RxBufferRead = 0;
+ }
+ SoftSSIRxInt(psSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the SoftSSI transmitter is busy or not.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter. If \b false is returned, then the transmit FIFO is empty
+//! and all bits of the last transmitted word have left the shift register.
+//!
+//! \return Returns \b true if the SoftSSI is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+bool
+SoftSSIBusy(tSoftSSI *psSSI)
+{
+ //
+ // Determine if the SSI is busy.
+ //
+ return(((psSSI->ui8State == SOFTSSI_STATE_IDLE) &&
+ (((psSSI->ui8Flags & SOFTSSI_FLAG_ENABLE) == 0) ||
+ (psSSI->ui16TxBufferRead == psSSI->ui16TxBufferWrite))) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftSSI module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSICallbackSet(tSoftSSI *psSSI, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psSSI->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Fss signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Fss signal.
+//! If there is not a GPIO pin allocated for Fss, the SoftSSI module does not
+//! assert/deassert the Fss signal, leaving it to the application either to do
+//! manually or to not do at all if the slave device has Fss tied to ground.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIFssGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Fss signal.
+ //
+ if(ui32Base == 0)
+ {
+ psSSI->ui32FssGPIO = 0;
+ }
+ else
+ {
+ psSSI->ui32FssGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Clk signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Clk signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIClkGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Clk signal.
+ //
+ psSSI->ui32ClkGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Tx signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ psSSI->ui32TxGPIO = ui32Base + (ui8Pin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Rx signal.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Rx signal. If
+//! there is not a GPIO pin allocated for Rx, the SoftSSI module does not read
+//! data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psSSI->ui32RxGPIO = 0;
+ }
+ else
+ {
+ psSSI->ui32RxGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit FIFO buffer for a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui16TxBuffer is the address of the transmit FIFO buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the transmit FIFO
+//! buffer.
+//!
+//! This function sets the address and size of the transmit FIFO buffer and
+//! also resets the read and write pointers, marking the transmit FIFO as
+//! empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxBufferSet(tSoftSSI *psSSI, uint16_t *pui16TxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the transmit FIFO buffer address and length.
+ //
+ psSSI->pui16TxBuffer = pui16TxBuffer;
+ psSSI->ui16TxBufferLen = ui16Len;
+
+ //
+ // Reset the transmit FIFO read and write pointers.
+ //
+ psSSI->ui16TxBufferRead = 0;
+ psSSI->ui16TxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the receive FIFO buffer for a SoftSSI module.
+//!
+//! \param psSSI specifies the SoftSSI data structure.
+//! \param pui16RxBuffer is the address of the receive FIFO buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the receive FIFO
+//! buffer.
+//!
+//! This function sets the address and size of the receive FIFO buffer and also
+//! resets the read and write pointers, marking the receive FIFO as empty.
+//! When the buffer pointer and length are configured as zero, all data
+//! received from the slave device is discarded. This capability is useful
+//! when there is no GPIO pin allocated for the Rx signal.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxBufferSet(tSoftSSI *psSSI, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the receive FIFO buffer address and length.
+ //
+ psSSI->pui16RxBuffer = pui16RxBuffer;
+ psSSI->ui16RxBufferLen = ui16Len;
+
+ //
+ // Reset the receive FIFO read and write pointers.
+ //
+ psSSI->ui16RxBufferRead = 0;
+ psSSI->ui16RxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softssi.h b/utils/softssi.h
new file mode 100644
index 0000000..72ee068
--- /dev/null
+++ b/utils/softssi.h
@@ -0,0 +1,280 @@
+//*****************************************************************************
+//
+// softssi.h - Defines and macros for the SoftSSI.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTSSI_H__
+#define __SOFTSSI_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftSSI module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware SSI implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftSSICallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Fss signal. If this
+ //! member is zero, the Fss signal is not generated. This member can be
+ //! set via a direct structure access or using the SoftSSIFssGPIOSet
+ //! function.
+ ///
+ uint32_t ui32FssGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Clk signal. This member
+ //! can be set via a direct structure access or using the SoftSSIClkGPIOSet
+ //! function.
+ //
+ uint32_t ui32ClkGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftSSITxGPIOSet
+ //! function.
+ //
+ uint32_t ui32TxGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Rx signal. If this
+ //! member is zero, the Rx signal is not read. This member can be set via
+ //! a direct structure access or using the SoftSSIRxGPIOSet function.
+ //
+ uint32_t ui32RxGPIO;
+
+ //
+ //! The address of the data buffer used for the transmit FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSITxBufferSet function.
+ //
+ uint16_t *pui16TxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSIRxBufferSet function.
+ //
+ uint16_t *pui16RxBuffer;
+
+ //
+ //! The length of the transmit FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSITxBufferSet function.
+ //
+ uint16_t ui16TxBufferLen;
+
+ //
+ //! The index into the transmit FIFO of the next word to be transmitted.
+ //! This member should be initialized to zero, but should not be accessed
+ //! or modified by the application.
+ //
+ uint16_t ui16TxBufferRead;
+
+ //
+ //! The index into the transmit FIFO of the next location to store data
+ //! into the FIFO. This member should be initialized to zero, but should
+ //! not be accessed or modified by the application.
+ //
+ uint16_t ui16TxBufferWrite;
+
+ //
+ //! The length of the receive FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSIRxBufferSet function.
+ //
+ uint16_t ui16RxBufferLen;
+
+ //
+ //! The index into the receive FIFO of the next word to be read from the
+ //! FIFO. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferRead;
+
+ //
+ //! The index into the receive FIFO of the location to store the next word
+ //! received. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferWrite;
+
+ //
+ //! The word that is currently being transmitted. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint16_t ui16TxData;
+
+ //
+ //! The word that is currently being received. This member should not be
+ //! accessed or modified by the application.
+ //
+ uint16_t ui16RxData;
+
+ //
+ //! The flags that control the operation of the SoftSSI module. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The number of data bits in each SoftSSI frame, which also specifies the
+ //! width of each data item in the transmit and receive FIFOs. This member
+ //! can be set via a direct structure access or using the SoftSSIConfigSet
+ //! function.
+ //
+ uint8_t ui8Bits;
+
+ //
+ //! The current state of the SoftSSI state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ uint8_t ui8State;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8CurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint8_t ui8IntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8IntStatus;
+
+ //
+ //! The number of tick counts that the SoftSSI module has been idle with
+ //! data stored in the receive FIFO, which is used to generate the receive
+ //! timeout interrupt. This member should not be accessed or modified by
+ //! the application.
+ //
+ uint8_t ui8IdleCount;
+}
+tSoftSSI;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIIntEnable, SoftSSIIntDisable, and
+// SoftSSIIntClear as the ui32IntFlags parameter, and returned by
+// SoftSSIIntStatus.
+//
+//*****************************************************************************
+#define SOFTSSI_TXEOT 0x00000010 // TX end of transmit
+#define SOFTSSI_TXFF 0x00000008 // TX FIFO half full or less
+#define SOFTSSI_RXFF 0x00000004 // RX FIFO half full or more
+#define SOFTSSI_RXTO 0x00000002 // RX timeout
+#define SOFTSSI_RXOR 0x00000001 // RX overrun
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIConfigSet.
+//
+//*****************************************************************************
+#define SOFTSSI_FRF_MOTO_MODE_0 0x00000000 // Moto fmt, polarity 0, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_1 0x00000002 // Moto fmt, polarity 0, phase 1
+#define SOFTSSI_FRF_MOTO_MODE_2 0x00000001 // Moto fmt, polarity 1, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_3 0x00000003 // Moto fmt, polarity 1, phase 1
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern bool SoftSSIBusy(tSoftSSI *psSSI);
+extern void SoftSSICallbackSet(tSoftSSI *psSSI, void (*pfnCallback)(void));
+extern void SoftSSIClkGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftSSIConfigSet(tSoftSSI *psSSI, uint8_t ui8Protocol,
+ uint8_t ui8Bits);
+extern bool SoftSSIDataAvail(tSoftSSI *psSSI);
+extern void SoftSSIDataGet(tSoftSSI *psSSI, uint32_t *pui32Data);
+extern int32_t SoftSSIDataGetNonBlocking(tSoftSSI *psSSI, uint32_t *pui32Data);
+extern void SoftSSIDataPut(tSoftSSI *psSSI, uint32_t ui32Data);
+extern int32_t SoftSSIDataPutNonBlocking(tSoftSSI *psSSI, uint32_t ui32Data);
+extern void SoftSSIDisable(tSoftSSI *psSSI);
+extern void SoftSSIEnable(tSoftSSI *psSSI);
+extern void SoftSSIFssGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftSSIIntClear(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern void SoftSSIIntDisable(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern void SoftSSIIntEnable(tSoftSSI *psSSI, uint32_t ui32IntFlags);
+extern uint32_t SoftSSIIntStatus(tSoftSSI *psSSI, bool bMasked);
+extern void SoftSSIRxBufferSet(tSoftSSI *psSSI, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len);
+extern void SoftSSIRxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern bool SoftSSISpaceAvail(tSoftSSI *psSSI);
+extern void SoftSSITimerTick(tSoftSSI *psSSI);
+extern void SoftSSITxBufferSet(tSoftSSI *psSSI, uint16_t *pui16TxBuffer,
+ uint16_t ui16Len);
+extern void SoftSSITxGPIOSet(tSoftSSI *psSSI, uint32_t ui32Base,
+ uint8_t ui8Pin);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTSSI_H__
diff --git a/utils/softuart.c b/utils/softuart.c
new file mode 100644
index 0000000..d4aa3b3
--- /dev/null
+++ b/utils/softuart.c
@@ -0,0 +1,2591 @@
+//*****************************************************************************
+//
+// softuart.c - Driver for the SoftUART.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/uart.h"
+#include "utils/softuart.h"
+
+//*****************************************************************************
+//
+// The states in the SoftUART transmit state machine. The code depends upon
+// the fact that the value of TXSTATE_DATA_n is n + 1, and that TXSTATE_DATA_0
+// is 1.
+//
+//*****************************************************************************
+#define SOFTUART_TXSTATE_IDLE 0
+#define SOFTUART_TXSTATE_DATA_0 1
+#define SOFTUART_TXSTATE_DATA_1 2
+#define SOFTUART_TXSTATE_DATA_2 3
+#define SOFTUART_TXSTATE_DATA_3 4
+#define SOFTUART_TXSTATE_DATA_4 5
+#define SOFTUART_TXSTATE_DATA_5 6
+#define SOFTUART_TXSTATE_DATA_6 7
+#define SOFTUART_TXSTATE_DATA_7 8
+#define SOFTUART_TXSTATE_START 9
+#define SOFTUART_TXSTATE_PARITY 10
+#define SOFTUART_TXSTATE_STOP_0 11
+#define SOFTUART_TXSTATE_STOP_1 12
+#define SOFTUART_TXSTATE_BREAK 13
+
+//*****************************************************************************
+//
+// The states of the SoftUART receive state machine. The code depends upon the
+// the fact that the value of RXSTATE_DATA_n is n, and that RXSTATE_DATA_0 is
+// 0.
+//
+//*****************************************************************************
+#define SOFTUART_RXSTATE_DATA_0 0
+#define SOFTUART_RXSTATE_DATA_1 1
+#define SOFTUART_RXSTATE_DATA_2 2
+#define SOFTUART_RXSTATE_DATA_3 3
+#define SOFTUART_RXSTATE_DATA_4 4
+#define SOFTUART_RXSTATE_DATA_5 5
+#define SOFTUART_RXSTATE_DATA_6 6
+#define SOFTUART_RXSTATE_DATA_7 7
+#define SOFTUART_RXSTATE_IDLE 8
+#define SOFTUART_RXSTATE_PARITY 9
+#define SOFTUART_RXSTATE_STOP_0 10
+#define SOFTUART_RXSTATE_STOP_1 11
+#define SOFTUART_RXSTATE_BREAK 12
+#define SOFTUART_RXSTATE_DELAY 13
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ui8Flags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_FLAG_ENABLE 0x01
+#define SOFTUART_FLAG_TXBREAK 0x02
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ui8RxFlags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_RXFLAG_OE 0x08
+#define SOFTUART_RXFLAG_BE 0x04
+#define SOFTUART_RXFLAG_PE 0x02
+#define SOFTUART_RXFLAG_FE 0x01
+
+//*****************************************************************************
+//
+// Additional internal configuration stored in the SoftUART ui16Config
+// structure member.
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_BASE_M 0x00ff
+#define SOFTUART_CONFIG_EXT_M 0xff00
+#define SOFTUART_CONFIG_TXLVL_M 0x0700
+#define SOFTUART_CONFIG_TXLVL_1 0x0000
+#define SOFTUART_CONFIG_TXLVL_2 0x0100
+#define SOFTUART_CONFIG_TXLVL_4 0x0200
+#define SOFTUART_CONFIG_TXLVL_6 0x0300
+#define SOFTUART_CONFIG_TXLVL_7 0x0400
+#define SOFTUART_CONFIG_RXLVL_M 0x3800
+#define SOFTUART_CONFIG_RXLVL_1 0x0000
+#define SOFTUART_CONFIG_RXLVL_2 0x0800
+#define SOFTUART_CONFIG_RXLVL_4 0x1000
+#define SOFTUART_CONFIG_RXLVL_6 0x1800
+#define SOFTUART_CONFIG_RXLVL_7 0x2000
+
+//*****************************************************************************
+//
+// The odd parity of each possible data byte. The odd parity of N can be found
+// by looking at bit N % 32 of word N / 32.
+//
+//*****************************************************************************
+static uint32_t g_pui32ParityOdd[] =
+{
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669,
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996
+};
+
+//*****************************************************************************
+//
+//! Initializes the SoftUART module.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function initializes the data structure for the SoftUART module,
+//! putting it into the default configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTInit(tSoftUART *psUART)
+{
+ //
+ // Clear the SoftUART data structure.
+ //
+ memset(psUART, 0, sizeof(tSoftUART));
+
+ //
+ // Set the default transmit and receive buffer interrupt level.
+ //
+ psUART->ui16Config = SOFTUART_CONFIG_TXLVL_4 | SOFTUART_CONFIG_RXLVL_4;
+}
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Config is the data format for the port (number of data bits,
+//! number of stop bits, and parity).
+//!
+//! This function configures the SoftUART for operation in the specified data
+//! format, as specified in the \e ui32Config parameter.
+//!
+//! The \e ui32Config parameter is the logical OR of three values: the number
+//! of data bits, the number of stop bits, and the parity.
+//! \b SOFTUART_CONFIG_WLEN_8, \b SOFTUART_CONFIG_WLEN_7,
+//! \b SOFTUART_CONFIG_WLEN_6, and \b SOFTUART_CONFIG_WLEN_5 select from eight
+//! to five data bits per byte (respectively). \b SOFTUART_CONFIG_STOP_ONE and
+//! \b SOFTUART_CONFIG_STOP_TWO select one or two stop bits (respectively).
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, and
+//! \b SOFTUART_CONFIG_PAR_ZERO select the parity mode (no parity bit, even
+//! parity bit, odd parity bit, parity bit always one, and parity bit always
+//! zero, respectively).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigSet(tSoftUART *psUART, uint32_t ui32Config)
+{
+ //
+ // See if a GPIO pin has been set for Tx.
+ //
+ if(psUART->ui32TxGPIO != 0)
+ {
+ //
+ // Configure the Tx pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(psUART->ui32TxGPIO & 0xfffff000,
+ (psUART->ui32TxGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Tx pin high.
+ //
+ HWREG(psUART->ui32TxGPIO) = 255;
+ }
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(psUART->ui32RxGPIOPort != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Set the Rx pin to generate an interrupt on the next falling edge.
+ //
+ MAP_GPIOIntTypeSet(psUART->ui32RxGPIOPort, psUART->ui8RxPin,
+ GPIO_FALLING_EDGE);
+
+ //
+ // Enable the Rx pin interrupt.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ }
+
+ //
+ // Make sure that the transmit and receive buffers are empty.
+ //
+ psUART->ui16TxBufferRead = 0;
+ psUART->ui16TxBufferWrite = 0;
+ psUART->ui16RxBufferRead = 0;
+ psUART->ui16RxBufferWrite = 0;
+
+ //
+ // Save the data format.
+ //
+ psUART->ui16Config = ((psUART->ui16Config & SOFTUART_CONFIG_EXT_M) |
+ (ui32Config & SOFTUART_CONFIG_BASE_M));
+
+ //
+ // Enable the SoftUART module.
+ //
+ psUART->ui8Flags |= SOFTUART_FLAG_ENABLE;
+
+ //
+ // The next value to be written to the Tx pin is one since the SoftUART is
+ // idle.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // Start the SoftUART state machines in the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ psUART->ui8RxState = SOFTUART_RXSTATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART transmitter.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! transmitter. The transmission of data from the SoftUART is performed by
+//! the state machine in this function.
+//!
+//! This function must be called at the desired SoftUART baud rate. For
+//! example, to run the SoftUART at 115,200 baud, this function must be called
+//! at a 115,200 Hz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxTimerTick(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Write the next value to the Tx data line. This value was computed on
+ // the previous timer tick, which helps to reduce the jitter on the Tx
+ // edges (which is important since a UART connection does not contain a
+ // clock signal).
+ //
+ HWREG(psUART->ui32TxGPIO) = psUART->ui8TxNext;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psUART->ui8TxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_TXSTATE_IDLE:
+ {
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do nothing and stay
+ // in the idle state.
+ //
+ break;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(psUART->ui16TxBufferRead != psUART->ui16TxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the start bit state.
+ //
+ case SOFTUART_TXSTATE_START:
+ {
+ //
+ // Get the next byte to be transmitted.
+ //
+ psUART->ui8TxData = psUART->pui8TxBuffer[psUART->ui16TxBufferRead];
+
+ //
+ // The next value to be written to the data line is the LSB of the
+ // next data byte.
+ //
+ psUART->ui8TxNext = (psUART->ui8TxData & 1) ? 255 : 0;
+
+ //
+ // Move to the data bit 0 state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // This depends upon TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_0:
+ case SOFTUART_TXSTATE_DATA_1:
+ case SOFTUART_TXSTATE_DATA_2:
+ case SOFTUART_TXSTATE_DATA_3:
+ {
+ //
+ // The next value to be written to the data line is the next bit of
+ // the data byte.
+ //
+ psUART->ui8TxNext =
+ (psUART->ui8TxData & (1 << psUART->ui8TxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8TxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last data bit of the data byte. This depends upon
+ // TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_4:
+ case SOFTUART_TXSTATE_DATA_5:
+ case SOFTUART_TXSTATE_DATA_6:
+ case SOFTUART_TXSTATE_DATA_7:
+ {
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((psUART->ui16Config & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (psUART->ui8TxState - SOFTUART_TXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // The next value to be written to the data line is
+ // one.
+ //
+ psUART->ui8TxNext = 255;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // The next value to be written to the data line is
+ // zero.
+ //
+ psUART->ui8TxNext = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ psUART->ui8TxNext =
+ ((g_pui32ParityOdd[psUART->ui8TxData >> 5] &
+ (1 << (psUART->ui8TxData & 31))) ? 255 : 0);
+
+ //
+ // If the parity is set to even, then invert the
+ // parity just computed (making it even parity).
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ psUART->ui8TxNext ^= 255;
+ }
+ }
+
+ //
+ // Advance to the parity state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_PARITY;
+ }
+
+ //
+ // Parity is not enabled.
+ //
+ else
+ {
+ //
+ // The next value to write to the data line is the stop
+ // bit.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+ }
+ }
+ }
+
+ //
+ // Otherwise, there are more data bits to transfer.
+ //
+ else
+ {
+ //
+ // The next value to be written to the data line is the next
+ // bit of the data byte.
+ //
+ psUART->ui8TxNext =
+ (psUART->ui8TxData & (1 << psUART->ui8TxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8TxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_TXSTATE_PARITY:
+ {
+ //
+ // The next value to write to the data line is the stop bit.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_TXSTATE_STOP_0:
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_TXSTATE_STOP_1:
+ {
+ //
+ // The data byte has been completely transferred, so advance the
+ // read pointer.
+ //
+ psUART->ui16TxBufferRead++;
+ if(psUART->ui16TxBufferRead == psUART->ui16TxBufferLen)
+ {
+ psUART->ui16TxBufferRead = 0;
+ }
+
+ //
+ // Determine the number of characters in the transmit buffer.
+ //
+ if(psUART->ui16TxBufferRead > psUART->ui16TxBufferWrite)
+ {
+ ui32Temp = (psUART->ui16TxBufferLen -
+ (psUART->ui16TxBufferRead -
+ psUART->ui16TxBufferWrite));
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16TxBufferWrite -
+ psUART->ui16TxBufferRead);
+ }
+
+ //
+ // If the transmit buffer fullness just crossed the programmed
+ // level, generate a transmit "interrupt".
+ //
+ if(ui32Temp == psUART->ui16TxBufferLevel)
+ {
+ psUART->ui16IntStatus |= SOFTUART_INT_TX;
+ }
+
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do advance to the
+ // idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(psUART->ui16TxBufferRead != psUART->ui16TxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ psUART->ui8TxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // Otherwise, there is nothing to do.
+ //
+ else
+ {
+ //
+ // Assert the end of transmission "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_EOT;
+
+ //
+ // Advance to the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_TXSTATE_BREAK:
+ {
+ //
+ // See if the break should be deasserted.
+ //
+ if(!(psUART->ui8Flags & SOFTUART_FLAG_ENABLE) ||
+ !(psUART->ui8Flags & SOFTUART_FLAG_TXBREAK))
+ {
+ //
+ // The data line should be driven high to indicate it is idle.
+ //
+ psUART->ui8TxNext = 255;
+
+ //
+ // Advance to the idle state.
+ //
+ psUART->ui8TxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((psUART->ui16IntStatus & psUART->ui16IntMask) != 0) &&
+ (psUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psUART->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion of the receive ``interrupt''.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to assert the receive ``interrupt''
+//! as a result of writing data into the receive buffer (when characters are
+//! received from the Rx pin).
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxWriteInt(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferWrite > psUART->ui16RxBufferRead)
+ {
+ ui32Temp = psUART->ui16RxBufferWrite - psUART->ui16RxBufferRead;
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16RxBufferLen + psUART->ui16RxBufferWrite -
+ psUART->ui16RxBufferRead);
+ }
+
+ //
+ // If the receive buffer fullness just crossed the programmed level,
+ // generate a receive "interrupt".
+ //
+ if(ui32Temp == psUART->ui16RxBufferLevel)
+ {
+ psUART->ui16IntStatus |= SOFTUART_INT_RX;
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART receiver.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bEdgeInt should be \b true if this function is being called because
+//! of a GPIO edge interrupt and \b false if it is being called because of a
+//! timer interrupt.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! receiver. The reception of data to the SoftUART is performed by the state
+//! machine in this function.
+//!
+//! This function must be called by the GPIO interrupt handler, and then
+//! periodically at the desired SoftUART baud rate. For example, to run the
+//! SoftUART at 115,200 baud, this function must be called at a 115,200 Hz
+//! rate.
+//!
+//! \return Returns \b SOFTUART_RXTIMER_NOP if the receive timer should
+//! continue to operate or \b SOFTUART_RXTIMER_END if it should be stopped.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTRxTick(tSoftUART *psUART, bool bEdgeInt)
+{
+ uint32_t ui32PinState, ui32Temp, ui32Ret;
+
+ //
+ // Read the current state of the Rx data line.
+ //
+ ui32PinState = MAP_GPIOPinRead(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // The default return code inidicates that the receive timer does not need
+ // to be stopped.
+ //
+ ui32Ret = SOFTUART_RXTIMER_NOP;
+
+ //
+ // See if this is an edge interrupt while delaying for the receive timeout
+ // interrupt.
+ //
+ if(bEdgeInt && (psUART->ui8RxState == SOFTUART_RXSTATE_DELAY))
+ {
+ //
+ // The receive timeout has been cancelled since the next character has
+ // started, so go to the idle state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(psUART->ui8RxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_RXSTATE_IDLE:
+ {
+ //
+ // The falling edge of the start bit was just sampled, so disable
+ // the GPIO edge interrupt since the remainder of the character
+ // will be read using a timer tick.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntDisable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Clear the receive data buffer.
+ //
+ psUART->ui8RxData = 0;
+
+ //
+ // Clear all reception errors other than overrun (which is cleared
+ // only when the first character after the overrun is written into
+ // the receive buffer), and set the break error (which is cleared
+ // if any non-zero bits are read during this character).
+ //
+ psUART->ui8RxFlags = ((psUART->ui8RxFlags & SOFTUART_RXFLAG_OE) |
+ SOFTUART_RXFLAG_BE);
+
+ //
+ // Advance to the first data bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read. This
+ // depends upon RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_0:
+ case SOFTUART_RXSTATE_DATA_1:
+ case SOFTUART_RXSTATE_DATA_2:
+ case SOFTUART_RXSTATE_DATA_3:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ psUART->ui8RxData |= 1 << psUART->ui8RxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8RxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last bit of the data byte. This depends upon
+ // RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_4:
+ case SOFTUART_RXSTATE_DATA_5:
+ case SOFTUART_RXSTATE_DATA_6:
+ case SOFTUART_RXSTATE_DATA_7:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ psUART->ui8RxData |= 1 << psUART->ui8RxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((psUART->ui16Config & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (psUART->ui8RxState - SOFTUART_RXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // Advance to the parity state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_PARITY;
+ }
+
+ //
+ // Otherwise, see if there are one or two stop bits.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_0;
+ }
+
+ //
+ // Otherwise, advance to the one stop bit state.
+ //
+ else
+ {
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+ }
+ }
+
+ //
+ // Otherwise, there are more bits to receive.
+ //
+ else
+ {
+ //
+ // Advance to the next state.
+ //
+ psUART->ui8RxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_RXSTATE_PARITY:
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // Set the expected parity to one.
+ //
+ ui32Temp = psUART->ui8RxPin;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // Set the expected parity to zero.
+ //
+ ui32Temp = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ ui32Temp = ((g_pui32ParityOdd[psUART->ui8RxData >> 5] &
+ (1 << (psUART->ui8RxData & 31))) ?
+ psUART->ui8RxPin : 0);
+
+ //
+ // If the parity is set to even, then invert the parity just
+ // computed (making it even parity).
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ ui32Temp ^= psUART->ui8RxPin;
+ }
+ }
+
+ //
+ // See if the pin state matches the expected parity.
+ //
+ if(ui32PinState != ui32Temp)
+ {
+ //
+ // The parity does not match, so set the parity error flag.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_PE;
+ }
+
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((psUART->ui16Config & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_RXSTATE_STOP_0:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ui32PinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the one stop bit state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_RXSTATE_STOP_1:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ui32PinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the break error is still asserted (meaning that every bit
+ // received was zero).
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Since every bit was zero, advance to the break state.
+ //
+ psUART->ui8RxState = SOFTUART_RXSTATE_BREAK;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ui32Temp = psUART->ui16RxBufferWrite + 1;
+ if(ui32Temp == psUART->ui16RxBufferLen)
+ {
+ ui32Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ui32Temp == psUART->ui16RxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ psUART->ui8RxStatus |= SOFTUART_RXERROR_OVERRUN;
+ psUART->ui16IntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ psUART->pui16RxBuffer[psUART->ui16RxBufferWrite] =
+ psUART->ui8RxData | (psUART->ui8RxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ psUART->ui16RxBufferWrite = ui32Temp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ psUART->ui8RxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(psUART);
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // See if this character had a framing error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_FE)
+ {
+ //
+ // Assert the framing error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_FE;
+ }
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ psUART->ui8RxData = 0;
+ psUART->ui8RxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_RXSTATE_BREAK:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ui32PinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ psUART->ui8RxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ui32Temp = psUART->ui16RxBufferWrite + 1;
+ if(ui32Temp == psUART->ui16RxBufferLen)
+ {
+ ui32Temp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ui32Temp == psUART->ui16RxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ psUART->ui8RxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ psUART->ui8RxStatus |= SOFTUART_RXERROR_OVERRUN;
+ psUART->ui16IntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ psUART->pui16RxBuffer[psUART->ui16RxBufferWrite] =
+ psUART->ui8RxData | (psUART->ui8RxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ psUART->ui16RxBufferWrite = ui32Temp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ psUART->ui8RxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(psUART);
+ }
+
+ //
+ // See if this was a break error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Assert the break error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_BE;
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(psUART->ui8RxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // Assert the framing error "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_FE;
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ GPIOIntClear(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+ GPIOIntEnable(psUART->ui32RxGPIOPort, psUART->ui8RxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ psUART->ui8RxData = 0;
+ psUART->ui8RxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the receive timeout delay state.
+ //
+ case SOFTUART_RXSTATE_DELAY:
+ {
+ //
+ // See if the receive timeout has expired.
+ //
+ if(psUART->ui8RxData++ == 32)
+ {
+ //
+ // Assert the receive timeout "interrupt".
+ //
+ psUART->ui16IntStatus |= SOFTUART_INT_RT;
+
+ //
+ // Tell the caller that the receive timer can be disabled.
+ //
+ ui32Ret = SOFTUART_RXTIMER_END;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((psUART->ui16IntStatus & psUART->ui16IntMask) != 0) &&
+ (psUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ psUART->pfnIntCallback();
+ }
+
+ //
+ // Return to the caller.
+ //
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! Sets the type of parity.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Parity specifies the type of parity to use.
+//!
+//! Sets the type of parity to use for transmitting and expect when receiving.
+//! The \e ui32Parity parameter must be one of \b SOFTUART_CONFIG_PAR_NONE,
+//! \b SOFTUART_CONFIG_PAR_EVEN, \b SOFTUART_CONFIG_PAR_ODD,
+//! \b SOFTUART_CONFIG_PAR_ONE, or \b SOFTUART_CONFIG_PAR_ZERO. The last two
+//! allow direct control of the parity bit; it is always either one or zero
+//! based on the mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTParityModeSet(tSoftUART *psUART, uint32_t ui32Parity)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Parity == SOFTUART_CONFIG_PAR_NONE) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_EVEN) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ODD) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ONE) ||
+ (ui32Parity == SOFTUART_CONFIG_PAR_ZERO));
+
+ //
+ // Set the parity mode.
+ //
+ psUART->ui16Config =
+ (psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK) | ui32Parity;
+}
+
+//*****************************************************************************
+//
+//! Gets the type of parity currently being used.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function gets the type of parity used for transmitting data and
+//! expected when receiving data.
+//!
+//! \return Returns the current parity settings, specified as one of
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, or
+//! \b SOFTUART_CONFIG_PAR_ZERO.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTParityModeGet(tSoftUART *psUART)
+{
+ //
+ // Return the current parity setting.
+ //
+ return(psUART->ui16Config & SOFTUART_CONFIG_PAR_MASK);
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit ``interrupt'' buffer level.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function computes the transmit buffer level at which the transmit
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTTxLevelSet(tSoftUART *psUART)
+{
+ //
+ // Determine the transmit buffer "interrupt" fullness setting.
+ //
+ switch(psUART->ui16Config & SOFTUART_CONFIG_TXLVL_M)
+ {
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_1:
+ {
+ //
+ // Set the transmit buffer level to 1/8 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_2:
+ {
+ //
+ // Set the transmit buffer level to 1/4 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_4:
+ {
+ //
+ // Set the transmit buffer level to 1/2 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = psUART->ui16TxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_6:
+ {
+ //
+ // Set the transmit buffer level to 3/4 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = (psUART->ui16TxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_7:
+ {
+ //
+ // Set the transmit buffer level to 7/8 of the buffer length.
+ //
+ psUART->ui16TxBufferLevel = (psUART->ui16TxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the receive ``interrupt'' buffer level.
+//!
+//! \param psUART specifies the soft UART data structure.
+//!
+//! This function computes the receive buffer level at which the receive
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxLevelSet(tSoftUART *psUART)
+{
+ //
+ // Determine the receive buffer "interrupt" fullness setting.
+ //
+ switch(psUART->ui16Config & SOFTUART_CONFIG_RXLVL_M)
+ {
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_1:
+ {
+ //
+ // Set the receive buffer level to 1/8 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_2:
+ {
+ //
+ // Set the receive buffer level to 1/4 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_4:
+ {
+ //
+ // Set the receive buffer level to 1/2 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = psUART->ui16RxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_6:
+ {
+ //
+ // Set the receive buffer level to 3/4 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = (psUART->ui16RxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_7:
+ {
+ //
+ // Set the receive buffer level to 7/8 of the buffer length.
+ //
+ psUART->ui16RxBufferLevel = (psUART->ui16RxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32TxLevel is the transmit buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, \b UART_FIFO_TX4_8,
+//! \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param ui32RxLevel is the receive buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, \b UART_FIFO_RX4_8,
+//! \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function sets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelSet(tSoftUART *psUART, uint32_t ui32TxLevel,
+ uint32_t ui32RxLevel)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32TxLevel == SOFTUART_FIFO_TX1_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX2_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX4_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX6_8) ||
+ (ui32TxLevel == SOFTUART_FIFO_TX7_8));
+ ASSERT((ui32RxLevel == SOFTUART_FIFO_RX1_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX2_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX4_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX6_8) ||
+ (ui32RxLevel == SOFTUART_FIFO_RX7_8));
+
+ //
+ // Save the buffer "interrupt" levels.
+ //
+ psUART->ui16Config = ((psUART->ui16Config & SOFTUART_CONFIG_BASE_M) |
+ ((ui32TxLevel | ui32RxLevel) << 8));
+
+ //
+ // Compute the new buffer "interrupt" levels.
+ //
+ SoftUARTTxLevelSet(psUART);
+ SoftUARTRxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+//! Gets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui32TxLevel is a pointer to storage for the transmit buffer level,
+//! returned as one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8,
+//! \b UART_FIFO_TX4_8, \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param pui32RxLevel is a pointer to storage for the receive buffer level,
+//! returned as one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8,
+//! \b UART_FIFO_RX4_8, \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function gets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelGet(tSoftUART *psUART, uint32_t *pui32TxLevel,
+ uint32_t *pui32RxLevel)
+{
+ //
+ // Extract the transmit and receive buffer levels.
+ //
+ *pui32TxLevel = (psUART->ui16Config & SOFTUART_CONFIG_TXLVL_M) >> 8;
+ *pui32RxLevel = (psUART->ui16Config & SOFTUART_CONFIG_RXLVL_M) >> 8;
+}
+
+//*****************************************************************************
+//
+//! Gets the current configuration of a UART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui32Config is a pointer to storage for the data format.
+//!
+//! Returns the data format of the SoftUART. The data format returned in
+//! \e pui32Config is enumerated the same as the \e ui32Config parameter of
+//! SoftUARTConfigSet().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigGet(tSoftUART *psUART, uint32_t *pui32Config)
+{
+ //
+ // Get the data format.
+ //
+ *pui32Config = psUART->ui16Config & SOFTUART_CONFIG_BASE_M;
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftUART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function enables the SoftUART, allowing data to be transmitted and
+//! received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTEnable(tSoftUART *psUART)
+{
+ //
+ // Enable the SoftUART.
+ //
+ psUART->ui8Flags |= SOFTUART_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftUART.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function disables the SoftUART after waiting for it to become idle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTDisable(tSoftUART *psUART)
+{
+ //
+ // Wait for end of TX.
+ //
+ while(SoftUARTBusy(psUART))
+ {
+ }
+
+ //
+ // Disable the SoftUART.
+ //
+ psUART->ui8Flags &= ~(SOFTUART_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Determines if there are any characters in the receive buffer.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is data
+//! available in the receive buffer.
+//!
+//! \return Returns \b true if there is data in the receive buffer or \b false
+//! if there is no data in the receive buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTCharsAvail(tSoftUART *psUART)
+{
+ //
+ // Return the availability of characters.
+ //
+ return((psUART->ui16RxBufferRead == psUART->ui16RxBufferWrite) ? false :
+ true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit buffer.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is space
+//! available in the transmit buffer.
+//!
+//! \return Returns \b true if there is space available in the transmit buffer
+//! or \b false if there is no space available in the transmit buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTSpaceAvail(tSoftUART *psUART)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((psUART->ui16TxBufferRead == ui16Temp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Handles the deassertion of the receive ``interrupts''.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to deassert the receive
+//! ``interrupt'' as a result of reading data from the receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxReadInt(tSoftUART *psUART)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferWrite > psUART->ui16RxBufferRead)
+ {
+ ui32Temp = psUART->ui16RxBufferWrite - psUART->ui16RxBufferRead;
+ }
+ else
+ {
+ ui32Temp = (psUART->ui16RxBufferLen + psUART->ui16RxBufferWrite -
+ psUART->ui16RxBufferRead);
+ }
+
+ //
+ // See if the number of characters in the receive buffer have dropped below
+ // the receive trigger level.
+ //
+ if(ui32Temp < psUART->ui16RxBufferLevel)
+ {
+ //
+ // Deassert the receive "interrupt".
+ //
+ psUART->ui16IntStatus &= ~(SOFTUART_INT_RX);
+ }
+
+ //
+ // See if the receive buffer is now empty.
+ //
+ if(ui32Temp == 0)
+ {
+ //
+ // Deassert the receive timeout "interrupt".
+ //
+ psUART->ui16IntStatus &= ~(SOFTUART_INT_RT);
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e int32_t. A \b -1 is returned if there are no characters present in the
+//! receive buffer. The SoftUARTCharsAvail() function should be called before
+//! attempting to call this function.
+//
+//*****************************************************************************
+int32_t
+SoftUARTCharGetNonBlocking(tSoftUART *psUART)
+{
+ int32_t i32Temp;
+
+ //
+ // See if there are any characters in the receive buffer.
+ //
+ if(psUART->ui16RxBufferRead != psUART->ui16RxBufferWrite)
+ {
+ //
+ // Read the next character.
+ //
+ i32Temp = psUART->pui16RxBuffer[psUART->ui16RxBufferRead];
+ psUART->ui16RxBufferRead++;
+ if(psUART->ui16RxBufferRead == psUART->ui16RxBufferLen)
+ {
+ psUART->ui16RxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(psUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ psUART->ui8RxStatus =
+ ((psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((i32Temp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(i32Temp);
+ }
+ else
+ {
+ //
+ // There are no characters, so return a failure.
+ //
+ return(-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits for a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port. If there
+//! are no characters available, this function waits until a character is
+//! received before returning.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e int32_t.
+//
+//*****************************************************************************
+int32_t
+SoftUARTCharGet(tSoftUART *psUART)
+{
+ int32_t i32Temp;
+
+ //
+ // Wait until a int8_t is available.
+ //
+ while(psUART->ui16RxBufferRead ==
+ *(volatile uint16_t *)(&(psUART->ui16RxBufferWrite)))
+ {
+ }
+
+ //
+ // Read the next character.
+ //
+ i32Temp = psUART->pui16RxBuffer[psUART->ui16RxBufferRead];
+ psUART->ui16RxBufferRead++;
+ if(psUART->ui16RxBufferRead == psUART->ui16RxBufferLen)
+ {
+ psUART->ui16RxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(psUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ psUART->ui8RxStatus = ((psUART->ui8RxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((i32Temp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(i32Temp);
+}
+
+//*****************************************************************************
+//
+//! Sends a character to the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui8Data is the character to be transmitted.
+//!
+//! Writes the character \e ui8Data to the transmit buffer for the specified
+//! port. This function does not block, so if there is no space available,
+//! then a \b false is returned, and the application must retry the function
+//! later.
+//!
+//! \return Returns \b true if the character was successfully placed in the
+//! transmit buffer or \b false if there was no space available in the
+//! transmit buffer.
+//
+//*****************************************************************************
+bool
+SoftUARTCharPutNonBlocking(tSoftUART *psUART, uint8_t ui8Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+
+ //
+ // See if there is space in the transmit buffer.
+ //
+ if(ui16Temp != psUART->ui16TxBufferRead)
+ {
+ //
+ // Write this character to the transmit buffer.
+ //
+ psUART->pui8TxBuffer[psUART->ui16TxBufferWrite] = ui8Data;
+ psUART->ui16TxBufferWrite = ui16Temp;
+
+ //
+ // Success.
+ //
+ return(true);
+ }
+ else
+ {
+ //
+ // There is no space in the transmit buffer, so return a failure.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits to send a character from the specified port.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui8Data is the character to be transmitted.
+//!
+//! Sends the character \e ui8Data to the transmit buffer for the specified
+//! port. If there is no space available in the transmit buffer, this function
+//! waits until there is space available before returning.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCharPut(tSoftUART *psUART, uint8_t ui8Data)
+{
+ uint16_t ui16Temp;
+
+ //
+ // Wait until space is available.
+ //
+ ui16Temp = psUART->ui16TxBufferWrite + 1;
+ if(ui16Temp == psUART->ui16TxBufferLen)
+ {
+ ui16Temp = 0;
+ }
+ while(ui16Temp == *(volatile uint16_t *)(&(psUART->ui16TxBufferRead)))
+ {
+ }
+
+ //
+ // Send the int8_t.
+ //
+ psUART->pui8TxBuffer[psUART->ui16TxBufferWrite] = ui8Data;
+ psUART->ui16TxBufferWrite = ui16Temp;
+}
+
+//*****************************************************************************
+//
+//! Causes a BREAK to be sent.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bBreakState controls the output level.
+//!
+//! Calling this function with \e bBreakState set to \b true asserts a break
+//! condition on the SoftUART. Calling this function with \e bBreakState set
+//! to \b false removes the break condition. For proper transmission of a
+//! break command, the break must be asserted for at least two complete frames.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTBreakCtl(tSoftUART *psUART, bool bBreakState)
+{
+ //
+ // Set the break condition as requested.
+ //
+ if(bBreakState)
+ {
+ psUART->ui8Flags |= SOFTUART_FLAG_TXBREAK;
+ }
+ else
+ {
+ psUART->ui8Flags &= ~(SOFTUART_FLAG_TXBREAK);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the UART transmitter is busy or not.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter hardware. If \b false is returned, the transmit buffer is
+//! empty and all bits of the last transmitted character, including all stop
+//! bits, have left the hardware shift register.
+//!
+//! \return Returns \b true if the UART is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+bool
+SoftUARTBusy(tSoftUART *psUART)
+{
+ //
+ // Determine if the UART is busy.
+ //
+ return(((psUART->ui8TxState == SOFTUART_TXSTATE_IDLE) &&
+ (((psUART->ui8Flags & SOFTUART_FLAG_ENABLE) == 0) ||
+ (psUART->ui16TxBufferRead == psUART->ui16TxBufferWrite))) ?
+ false : true);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is the bit mask of the ``interrupt'' sources to be
+//! enabled.
+//!
+//! Enables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ui32IntFlags parameter is the logical OR of any of the following:
+//!
+//! - \b SOFTUART_INT_OE - Overrun Error ``interrupt''
+//! - \b SOFTUART_INT_BE - Break Error ``interrupt''
+//! - \b SOFTUART_INT_PE - Parity Error ``interrupt''
+//! - \b SOFTUART_INT_FE - Framing Error ``interrupt''
+//! - \b SOFTUART_INT_RT - Receive Timeout ``interrupt''
+//! - \b SOFTUART_INT_TX - Transmit ``interrupt''
+//! - \b SOFTUART_INT_RX - Receive ``interrupt''
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntEnable(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Enable the specified interrupts.
+ //
+ psUART->ui16IntMask |= ui32IntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is the bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ui32IntFlags parameter has the same definition as the
+//! \e ui32IntFlags parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntDisable(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Disable the specified interrupts.
+ //
+ psUART->ui16IntMask &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftUART ``interrupt'' status.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required and
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This returns the ``interrupt'' status for the SoftUART. Either the raw
+//! ``interrupt'' status or the status of ``interrupts'' that are allowed to
+//! reflect to the SoftUART callback can be returned.
+//!
+//! \return Returns the current ``interrupt'' status, enumerated as a bit field
+//! of values described in SoftUARTIntEnable().
+//
+//*****************************************************************************
+uint32_t
+SoftUARTIntStatus(tSoftUART *psUART, bool bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(psUART->ui16IntStatus & psUART->ui16IntMask);
+ }
+ else
+ {
+ return(psUART->ui16IntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftUART ``interrupt'' sources.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32IntFlags is a bit mask of the ``interrupt'' sources to be
+//! cleared.
+//!
+//! The specified SoftUART ``interrupt'' sources are cleared, so that they no
+//! longer assert. This function must be called in the callback function to
+//! keep the ``interrupt'' from being recognized again immediately upon exit.
+//!
+//! The \e ui32IntFlags parameter has the same definition as the
+//! \e ui32IntFlags parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntClear(tSoftUART *psUART, uint32_t ui32IntFlags)
+{
+ //
+ // Clear the requested interrupt sources.
+ //
+ psUART->ui16IntStatus &= ~(ui32IntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets current receiver errors.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function returns the current state of each of the 4 receiver error
+//! sources. The returned errors are equivalent to the four error bits
+//! returned via the previous call to SoftUARTCharGet() or
+//! SoftUARTCharGetNonBlocking() with the exception that the overrun error is
+//! set immediately when the overrun occurs rather than when a character is
+//! next read.
+//!
+//! \return Returns a logical OR combination of the receiver error flags,
+//! \b SOFTUART_RXERROR_FRAMING, \b SOFTUART_RXERROR_PARITY,
+//! \b SOFTUART_RXERROR_BREAK and \b SOFTUART_RXERROR_OVERRUN.
+//
+//*****************************************************************************
+uint32_t
+SoftUARTRxErrorGet(tSoftUART *psUART)
+{
+ //
+ // Return the current value of the receive status.
+ //
+ return(psUART->ui8RxStatus);
+}
+
+//*****************************************************************************
+//
+//! Clears all reported receiver errors.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//!
+//! This function is used to clear all receiver error conditions reported via
+//! SoftUARTRxErrorGet(). If using the overrun, framing error, parity error or
+//! break interrupts, this function must be called after clearing the interrupt
+//! to ensure that later errors of the same type trigger another interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxErrorClear(tSoftUART *psUART)
+{
+ //
+ // Clear any receive error status.
+ //
+ psUART->ui8RxStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftUART module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCallbackSet(tSoftUART *psUART, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ psUART->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Tx signal.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must assert
+//! the Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxGPIOSet(tSoftUART *psUART, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psUART->ui32TxGPIO = 0;
+ }
+ else
+ {
+ psUART->ui32TxGPIO = ui32Base + (ui8Pin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Rx signal.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param ui32Base is the base address of the GPIO module.
+//! \param ui8Pin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must sample
+//! the Rx signal. If there is not a GPIO pin allocated for Rx, the SoftUART
+//! module will not read data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxGPIOSet(tSoftUART *psUART, uint32_t ui32Base, uint8_t ui8Pin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ui32Base == 0)
+ {
+ psUART->ui32RxGPIOPort = 0;
+ psUART->ui8RxPin = 0;
+ }
+ else
+ {
+ psUART->ui32RxGPIOPort = ui32Base;
+ psUART->ui8RxPin = ui8Pin;
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit buffer for a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui8TxBuffer is the address of the transmit buffer.
+//! \param ui16Len is the size, in 8-bit bytes, of the transmit buffer.
+//!
+//! This function sets the address and size of the transmit buffer. It also
+//! resets the read and write pointers, marking the transmit buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxBufferSet(tSoftUART *psUART, uint8_t *pui8TxBuffer, uint16_t ui16Len)
+{
+ //
+ // Save the transmit buffer address and length.
+ //
+ psUART->pui8TxBuffer = pui8TxBuffer;
+ psUART->ui16TxBufferLen = ui16Len;
+
+ //
+ // Reset the transmit buffer read and write pointers.
+ //
+ psUART->ui16TxBufferRead = 0;
+ psUART->ui16TxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTTxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+//! Sets the receive buffer for a SoftUART module.
+//!
+//! \param psUART specifies the SoftUART data structure.
+//! \param pui16RxBuffer is the address of the receive buffer.
+//! \param ui16Len is the size, in 16-bit half-words, of the receive buffer.
+//!
+//! This function sets the address and size of the receive buffer. It also
+//! resets the read and write pointers, marking the receive buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxBufferSet(tSoftUART *psUART, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len)
+{
+ //
+ // Save the receive buffer address and length.
+ //
+ psUART->pui16RxBuffer = pui16RxBuffer;
+ psUART->ui16RxBufferLen = ui16Len;
+
+ //
+ // Reset the receive read and write pointers.
+ //
+ psUART->ui16RxBufferRead = 0;
+ psUART->ui16RxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTRxLevelSet(psUART);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softuart.h b/utils/softuart.h
new file mode 100644
index 0000000..d9184d7
--- /dev/null
+++ b/utils/softuart.h
@@ -0,0 +1,375 @@
+//*****************************************************************************
+//
+// softuart.h - Defines and macros for the SoftUART.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SOFTUART_H__
+#define __SOFTUART_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftUART
+//! module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware UART implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftUARTCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTTxGPIOSet
+ //! function.
+ //
+ uint32_t ui32TxGPIO;
+
+ //
+ //! The address of the GPIO port to be used for the Rx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTRxGPIOSet
+ //! function.
+ //
+ uint32_t ui32RxGPIOPort;
+
+ //
+ //! The address of the data buffer used for the transmit buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTTxBufferSet function.
+ //
+ uint8_t *pui8TxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTRxBufferSet function.
+ //
+ uint16_t *pui16RxBuffer;
+
+ //
+ //! The length of the transmit buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTTxBufferSet function.
+ //
+ uint16_t ui16TxBufferLen;
+
+ //
+ //! The index into the transmit buffer of the next character to be
+ //! transmitted. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16TxBufferRead;
+
+ //
+ //! The index into the transmit buffer of the next location to store a
+ //! character into the buffer. This member should not be accessed or
+ //! modified by the application.
+ //
+ uint16_t ui16TxBufferWrite;
+
+ //
+ //! The transmit buffer level at which the transmit interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ uint16_t ui16TxBufferLevel;
+
+ //
+ //! The length of the receive buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTRxBufferSet function.
+ //
+ uint16_t ui16RxBufferLen;
+
+ //
+ //! The index into the receive buffer of the next character to be read from
+ //! the buffer. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16RxBufferRead;
+
+ //
+ //! The index into the receive buffer of the lcoation to store the next
+ //! character received. This member should not be accessed or modified by
+ //! the application.
+ //
+ uint16_t ui16RxBufferWrite;
+
+ //
+ //! The receive buffer level at which the receive interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ uint16_t ui16RxBufferLevel;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint16_t ui16IntStatus;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ uint16_t ui16IntMask;
+
+ //
+ //! The configuration of the SoftUART module. This member can be set via
+ //! the SoftUARTConfigSet and SoftUARTFIFOLevelSet functions.
+ //
+ uint16_t ui16Config;
+
+ //
+ //! The flags that control the operation of the SoftUART module. This
+ //! member should not be be accessed or modified by the application.
+ //
+ uint8_t ui8Flags;
+
+ //
+ //! The current state of the SoftUART transmit state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8TxState;
+
+ //
+ //! The value that is written to the Tx pin at the start of the next
+ //! transmit timer tick. This member should not be accessed or modified
+ //! by the application.
+ //
+ uint8_t ui8TxNext;
+
+ //
+ //! The character that is currently be sent via the Tx pin. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8TxData;
+
+ //
+ //! The GPIO pin to be used for the Rx signal. This member can be set via
+ //! a direct structure access or using the SoftUARTRxGPIOSet function.
+ //
+ uint8_t ui8RxPin;
+
+ //
+ //! The current state of the SoftUART receive state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ uint8_t ui8RxState;
+
+ //
+ //! The character that is currently being received via the Rx pin. This
+ //! member should not be accessed or modified by the application.
+ //
+ uint8_t ui8RxData;
+
+ //
+ //! The flags that indicate any errors that have occurred during the
+ //! reception of the current character via the Rx pin. This member should
+ //! not be accessed or modified by the application.
+ //
+ uint8_t ui8RxFlags;
+
+ //
+ //! The receive error status. This member should only be accessed via the
+ //! SoftUARTRxErrorGet and SoftURATRxErrorClear functions.
+ //
+ uint8_t ui8RxStatus;
+}
+tSoftUART;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTIntEnable(), SoftUARTIntDisable(), and
+// SoftUARTIntClear() as the ui32IntFlags parameter, and returned from
+// SoftUARTIntStatus().
+//
+//*****************************************************************************
+#define SOFTUART_INT_EOT 0x800 // End of transmission interrupt
+#define SOFTUART_INT_OE 0x400 // Overrun error interrupt
+#define SOFTUART_INT_BE 0x200 // Break error interrupt
+#define SOFTUART_INT_PE 0x100 // Parity error interrupt
+#define SOFTUART_INT_FE 0x080 // Framing error interrupt
+#define SOFTUART_INT_RT 0x040 // Receive timeout interrupt
+#define SOFTUART_INT_TX 0x020 // Transmit interrupt
+#define SOFTUART_INT_RX 0x010 // Receive interrupt
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTConfigSet() as the ui32Config parameter
+// and returned by SoftUARTConfigGet() in the pui32Config parameter.
+// Additionally, the UART_CONFIG_PAR_* subset can be passed to
+// SoftUARTParityModeSet() as the ui32Parity parameter, and are returned by
+// SoftUARTParityModeGet().
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_WLEN_MASK \
+ 0x00000060 // Mask for extracting word length
+#define SOFTUART_CONFIG_WLEN_8 0x00000060 // 8 bit data
+#define SOFTUART_CONFIG_WLEN_7 0x00000040 // 7 bit data
+#define SOFTUART_CONFIG_WLEN_6 0x00000020 // 6 bit data
+#define SOFTUART_CONFIG_WLEN_5 0x00000000 // 5 bit data
+#define SOFTUART_CONFIG_STOP_MASK \
+ 0x00000008 // Mask for extracting stop bits
+#define SOFTUART_CONFIG_STOP_ONE \
+ 0x00000000 // One stop bit
+#define SOFTUART_CONFIG_STOP_TWO \
+ 0x00000008 // Two stop bits
+#define SOFTUART_CONFIG_PAR_MASK \
+ 0x00000086 // Mask for extracting parity
+#define SOFTUART_CONFIG_PAR_NONE \
+ 0x00000000 // No parity
+#define SOFTUART_CONFIG_PAR_EVEN \
+ 0x00000006 // Even parity
+#define SOFTUART_CONFIG_PAR_ODD 0x00000002 // Odd parity
+#define SOFTUART_CONFIG_PAR_ONE 0x00000082 // Parity bit is one
+#define SOFTUART_CONFIG_PAR_ZERO \
+ 0x00000086 // Parity bit is zero
+#define SOFTUART_CONFIG_WLEN_S 5
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet() as the ui32TxLevel
+// parameter and returned by SoftUARTFIFOLevelGet() in the pui32TxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_TX1_8 0x00000000 // Transmit interrupt at 1/8 Full
+#define SOFTUART_FIFO_TX2_8 0x00000001 // Transmit interrupt at 1/4 Full
+#define SOFTUART_FIFO_TX4_8 0x00000002 // Transmit interrupt at 1/2 Full
+#define SOFTUART_FIFO_TX6_8 0x00000003 // Transmit interrupt at 3/4 Full
+#define SOFTUART_FIFO_TX7_8 0x00000004 // Transmit interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet() as the ui32RxLevel
+// parameter and returned by SoftUARTFIFOLevelGet() in the pui32RxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_RX1_8 0x00000000 // Receive interrupt at 1/8 Full
+#define SOFTUART_FIFO_RX2_8 0x00000008 // Receive interrupt at 1/4 Full
+#define SOFTUART_FIFO_RX4_8 0x00000010 // Receive interrupt at 1/2 Full
+#define SOFTUART_FIFO_RX6_8 0x00000018 // Receive interrupt at 3/4 Full
+#define SOFTUART_FIFO_RX7_8 0x00000020 // Receive interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxErrorGet().
+//
+//*****************************************************************************
+#define SOFTUART_RXERROR_OVERRUN \
+ 0x00000008 // An overrun error occurred
+#define SOFTUART_RXERROR_BREAK 0x00000004 // A break was received
+#define SOFTUART_RXERROR_PARITY 0x00000002 // A parity error occurred
+#define SOFTUART_RXERROR_FRAMING \
+ 0x00000001 // A framing error occurred
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxTick().
+//
+//*****************************************************************************
+#define SOFTUART_RXTIMER_NOP 0 // The timer should continue to run
+#define SOFTUART_RXTIMER_END 1 // The timer should be stopped
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern void SoftUARTInit(tSoftUART *psUART);
+extern void SoftUARTParityModeSet(tSoftUART *psUART, uint32_t ui32Parity);
+extern uint32_t SoftUARTParityModeGet(tSoftUART *psUART);
+extern void SoftUARTFIFOLevelSet(tSoftUART *psUART, uint32_t ui32TxLevel,
+ uint32_t ui32RxLevel);
+extern void SoftUARTFIFOLevelGet(tSoftUART *psUART, uint32_t *pui32TxLevel,
+ uint32_t *pui32RxLevel);
+extern void SoftUARTConfigSet(tSoftUART *psUART, uint32_t ui32Config);
+extern void SoftUARTConfigGet(tSoftUART *psUART, uint32_t *pui32Config);
+extern void SoftUARTEnable(tSoftUART *psUART);
+extern void SoftUARTDisable(tSoftUART *psUART);
+extern void SoftUARTFIFOEnable(tSoftUART *psUART);
+extern void SoftUARTFIFODisable(tSoftUART *psUART);
+extern bool SoftUARTCharsAvail(tSoftUART *psUART);
+extern bool SoftUARTSpaceAvail(tSoftUART *psUART);
+extern int32_t SoftUARTCharGetNonBlocking(tSoftUART *psUART);
+extern int32_t SoftUARTCharGet(tSoftUART *psUART);
+extern bool SoftUARTCharPutNonBlocking(tSoftUART *psUART,
+ uint8_t ui8Data);
+extern void SoftUARTCharPut(tSoftUART *psUART, uint8_t ui8Data);
+extern void SoftUARTBreakCtl(tSoftUART *psUART, bool bBreakState);
+extern bool SoftUARTBusy(tSoftUART *psUART);
+extern void SoftUARTIntEnable(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern void SoftUARTIntDisable(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern uint32_t SoftUARTIntStatus(tSoftUART *psUART, bool bMasked);
+extern void SoftUARTIntClear(tSoftUART *psUART, uint32_t ui32IntFlags);
+extern uint32_t SoftUARTRxErrorGet(tSoftUART *psUART);
+extern void SoftUARTRxErrorClear(tSoftUART *psUART);
+extern uint32_t SoftUARTRxTick(tSoftUART *psUART, bool bEdgeInt);
+extern void SoftUARTTxIntModeSet(tSoftUART *psUART, uint32_t ui32Mode);
+extern uint32_t SoftUARTTxIntModeGet(tSoftUART *psUART);
+extern void SoftUARTTxTimerTick(tSoftUART *psUART);
+extern void SoftUARTCallbackSet(tSoftUART *psUART, void (*pfnCallback)(void));
+extern void SoftUARTTxGPIOSet(tSoftUART *psUART, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftUARTRxGPIOSet(tSoftUART *psUART, uint32_t ui32Base,
+ uint8_t ui8Pin);
+extern void SoftUARTTxBufferSet(tSoftUART *psUART, uint8_t *pui8TxBuffer,
+ uint16_t ui16Len);
+extern void SoftUARTRxBufferSet(tSoftUART *psUART, uint16_t *pui16RxBuffer,
+ uint16_t ui16Len);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTUART_H__
diff --git a/utils/speexlib.c b/utils/speexlib.c
new file mode 100644
index 0000000..3a58ebc
--- /dev/null
+++ b/utils/speexlib.c
@@ -0,0 +1,377 @@
+//*****************************************************************************
+//
+// speexlib.c - interface to the speex coder/encoder library.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "third_party/speex-1.2rc1/include/speex/speex.h"
+#include "third_party/speex-1.2rc1/include/speex/speex_header.h"
+#include "utils/speexlib.h"
+#include "driverlib/debug.h"
+
+//*****************************************************************************
+//
+// The private structure that is used by the speex encoder or decoder for
+// holding all state information for an encoder or decoder.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Holds the state of the decoder.
+ //
+ void *pvState;
+
+ //
+ // Holds bits so they can be read and written to by the Speex routines
+ //
+ SpeexBits sBits;
+
+ //
+ // Holds the header information for the current file.
+ //
+ SpeexHeader sHeader;
+
+ //
+ // The current Segment table for the stream.
+ //
+ uint8_t pui8SegTable[256];
+
+ //
+ // The size of the current Segment table.
+ //
+ uint8_t ui8SegTableSize;
+
+ //
+ // The current active page in a segment.
+ //
+ uint8_t ui8PageCurrent;
+
+ //
+ // Current state flags.
+ //
+ uint32_t ui32Flags;
+}
+tSpeexInstance;
+
+//*****************************************************************************
+//
+// The decoder and encoder instance data.
+//
+//*****************************************************************************
+tSpeexInstance g_sSpeexDecoder, g_sSpeexEncoder;
+
+//*****************************************************************************
+//
+//! Initialize the decoder's state to prepare for decoding new frames.
+//!
+//! This function will initializes the decoder so that it is prepared to start
+//! receiving frames to decode.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexDecodeInit(void)
+{
+ int iTemp;
+
+ //
+ // Clear out the flags for this instance.
+ //
+ g_sSpeexDecoder.ui32Flags = 0;
+
+ //
+ // Create a new decoder state in narrow band mode.
+ //
+ g_sSpeexDecoder.pvState = speex_decoder_init(&speex_nb_mode);
+
+ //
+ // Disable enhanced decoding to reduce processing requirements.
+ //
+ iTemp = 0;
+ speex_decoder_ctl(g_sSpeexDecoder.pvState, SPEEX_SET_ENH, &iTemp);
+
+ //
+ // Initialization of the structure that holds the bits.
+ //
+ speex_bits_init(&g_sSpeexDecoder.sBits);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current frame size from the decoder.
+//!
+//! This function queries the decoder for the current decode frame size in byte
+//! and returns it to the caller.
+//!
+//! \return The current decoder frame size.
+//
+//*****************************************************************************
+int32_t
+SpeexDecodeFrameSizeGet(void)
+{
+ int iFrameSize;
+
+ //
+ // Return 0 if the wrong request is made.
+ //
+ iFrameSize = 0;
+
+ //
+ // Query the decoder for the current frame size.
+ //
+ speex_decoder_ctl(g_sSpeexDecoder.pvState, SPEEX_GET_FRAME_SIZE,
+ &iFrameSize);
+
+ return(iFrameSize);
+}
+
+//*****************************************************************************
+//
+//! This function decodes a single frame of Speex encoded audio.
+//!
+//! \param pui8InBuffer is the buffer that contains the Speex encoded audio.
+//! \param ui32InSize is the number of valid bytes in the \e pui8InBuffer
+//! buffer.
+//! \param pui8OutBuffer is a pointer to the buffer to store decoded audio.
+//! \param ui32OutSize is the size of the buffer pointed to by the
+//! \e pui8OutBuffer pointer.
+//!
+//! This function will take a buffer of Speex encoded audio and decode it into
+//! raw PCM audio. The \e pui16InBuffer parameter should contain a single
+//! frame encoded Speex audio. The \e pui8OutBuffer will contain the decoded
+//! audio after returning from this function.
+//!
+//! \return This function returns the number of decoded bytes in the
+//! \e pui8OutBuffer buffer.
+//
+//*****************************************************************************
+int32_t
+SpeexDecode(uint8_t *pui8InBuffer, uint32_t ui32InSize, uint8_t *pui8OutBuffer,
+ uint32_t ui32OutSize)
+{
+ int32_t i32Bytes;
+
+ //
+ // Read in the bit stream to the Speex library.
+ //
+ speex_bits_read_from(&g_sSpeexDecoder.sBits, (char *)pui8InBuffer,
+ ui32InSize);
+
+ //
+ // Decode one frame of data.
+ //
+ i32Bytes = speex_decode_int(g_sSpeexDecoder.pvState,
+ &g_sSpeexDecoder.sBits,
+ (int16_t *)pui8OutBuffer);
+
+ return(i32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function sets the current quality setting for the Speex encoder.
+//!
+//! \param iQuality is the new Quality setting to use for the Speex encoder.
+//!
+//! This function will use the \e iQuality setting as the new quality setting
+//! for the Speex encoder.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeQualitySet(int iQuality)
+{
+ //
+ // Set the current encoder quality setting.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_QUALITY, &iQuality);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current frame size from the encoder.
+//!
+//! This function queries the encoder for the current encode frame size in byte
+//! and returns it to the caller.
+//!
+//! \return The current encoder frame size.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeFrameSizeGet(void)
+{
+ int iFrameSize;
+
+ //
+ // Return 0 if the wrong request is made.
+ //
+ iFrameSize = 0;
+
+ //
+ // Query the encoder for the current frame size.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_GET_FRAME_SIZE,
+ &iFrameSize);
+
+ return(iFrameSize);
+}
+
+//*****************************************************************************
+//
+//! Initialize the encoder's state to prepare for encoding new frames.
+//!
+//! \param iSampleRate is the sample rate of the incoming audio.
+//! \param iComplexity is the complexity setting for the encoder.
+//! \param iQuality is the quality setting for the encoder.
+//!
+//! This function will initializes the encoder by setting the sample rate,
+//! complexity and quality settings. The \e iComplexity and \e iQuality
+//! settings are explained further in the Speex documentation.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+int32_t
+SpeexEncodeInit(int iSampleRate, int iComplexity, int iQuality)
+{
+ const SpeexMode *psMode;
+
+ //
+ // Clear out the flags for this instance.
+ //
+ g_sSpeexEncoder.ui32Flags = 0;
+
+ //
+ // Read out the current encoder mode.
+ //
+ psMode = speex_lib_get_mode(SPEEX_MODEID_NB);
+
+ //
+ // Create a new decoder state in narrow band mode.
+ //
+ g_sSpeexEncoder.pvState = speex_encoder_init(psMode);
+
+ //
+ // Initialize the bit stream.
+ //
+ speex_bits_init(&g_sSpeexEncoder.sBits);
+
+ //
+ // Set the quality.
+ //
+ SpeexEncodeQualitySet(iQuality);
+
+ //
+ // Set the complexity and sample rate for the encoder.
+ //
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_COMPLEXITY,
+ &iComplexity);
+ speex_encoder_ctl(g_sSpeexEncoder.pvState, SPEEX_SET_SAMPLING_RATE,
+ &iSampleRate);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Encode a single frame of speex encoded audio.
+//!
+//! \param pui16InBuffer is the buffer that contains the raw PCM audio.
+//! \param ui32InSize is the number of valid bytes in the \e pui16InBuffer
+//! buffer.
+//! \param pui8OutBuffer is a pointer to the buffer to store the encoded audio.
+//! \param ui32OutSize is the size of the buffer pointed to by the
+//! \e pui8OutBuffer pointer.
+//!
+//! This function will take a buffer of PCM audio and encode it into a frame
+//! of speex compressed audio. The \e pui16InBuffer parameter should contain
+//! a single frame of PCM audio. The \e pui8OutBuffer will contain the encoded
+//! audio after returning from this function.
+//!
+//! \return This function returns the number of encoded bytes in the
+//! \e pui8OutBuffer parameter.
+//
+//*****************************************************************************
+int32_t
+SpeexEncode(int16_t *pui16InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize)
+{
+ int32_t i32Bytes;
+
+ //
+ // Reset the bit stream before encoding a new frame.
+ //
+ speex_bits_reset(&g_sSpeexEncoder.sBits);
+
+ //
+ // Encode a single frame.
+ //
+ speex_encode_int(g_sSpeexEncoder.pvState, pui16InBuffer,
+ &g_sSpeexEncoder.sBits);
+
+ //
+ // Read the PCM data from the encoded bit stream.
+ //
+ i32Bytes = speex_bits_write(&g_sSpeexEncoder.sBits, (char *)pui8OutBuffer,
+ ui32OutSize);
+
+ //
+ // Return the number of bytes in the PCM data.
+ //
+ return(i32Bytes);
+}
+
+//*****************************************************************************
+//
+// This is called by speex in the event of a fatal error.
+//
+//*****************************************************************************
+void
+_speex_fatal(const int8_t *str, const int8_t *file, int line)
+{
+ ASSERT(0);
+ while(1)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+// Speex wrapper for putc so that it does not use any file writing library
+// functions. The speex library uses some file access for debug printing, this
+// will disable this feature.
+//
+//*****************************************************************************
+void
+_speex_putc(int ch, void *file)
+{
+}
diff --git a/utils/speexlib.h b/utils/speexlib.h
new file mode 100644
index 0000000..5b3f712
--- /dev/null
+++ b/utils/speexlib.h
@@ -0,0 +1,63 @@
+//*****************************************************************************
+//
+// speexlib.h - interface to the speex coder/encoder library.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SPEEXLIB_H__
+#define __SPEEXLIB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern int32_t SpeexEncodeInit(int iSampleRate, int iComplexity, int iQuality);
+extern int32_t SpeexEncode(int16_t *pui16InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize);
+extern int32_t SpeexEncodeQualitySet(int iQuality);
+extern int32_t SpeexEncodeFrameSizeGet(void);
+extern int32_t SpeexDecodeFrameSizeGet(void);
+extern int32_t SpeexDecodeInit(void);
+extern int32_t SpeexDecode(uint8_t *pui8InBuffer, uint32_t ui32InSize,
+ uint8_t *pui8OutBuffer, uint32_t ui32OutSize);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SPEEXLIB_H__
diff --git a/utils/spi_flash.c b/utils/spi_flash.c
new file mode 100644
index 0000000..6e5b24a
--- /dev/null
+++ b/utils/spi_flash.c
@@ -0,0 +1,2484 @@
+//*****************************************************************************
+//
+// spi_flash.c - Driver for a SPI flash that supports the "Intel" SPI flash
+// command set, capable of utilizing Bi-SPI and Quad-SPI.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ssi.h"
+#include "inc/hw_types.h"
+#include "inc/hw_udma.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/ssi.h"
+#include "driverlib/udma.h"
+#include "utils/spi_flash.h"
+
+//*****************************************************************************
+//
+//! \addtogroup spi_flash_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The commands that can be sent to the SPI flash. This is the "generic"
+// command set that is supported by a wide number of SPI flashes.
+//
+//*****************************************************************************
+#define CMD_WRSR 0x01 // Write status register
+#define CMD_PP 0x02 // Page program
+#define CMD_READ 0x03 // Read data
+#define CMD_WRDI 0x04 // Disable writes
+#define CMD_RDSR 0x05 // Read status register
+#define CMD_WREN 0x06 // Enable writes
+#define CMD_FREAD 0x0b // Fast read data
+#define CMD_SE 0x20 // Sector erase (4K)
+#define CMD_DREAD 0x3b // 1 in 2 out read data
+#define CMD_BE32 0x52 // Block erase (32K)
+#define CMD_QREAD 0x6b // 1 in 4 out read data
+#define CMD_RDID 0x9f // Read JEDEC ID
+#define CMD_CE 0xc7 // Chip erase
+#define CMD_BE64 0xd8 // Block erase (64K)
+
+//*****************************************************************************
+//
+// The states for the SPI flash interrupt handler state machine.
+//
+//*****************************************************************************
+#define STATE_IDLE 0
+#define STATE_CMD 1
+#define STATE_ADDR1 2
+#define STATE_ADDR2 3
+#define STATE_ADDR3 4
+#define STATE_READ_DUMMY 5
+#define STATE_READ_DATA_SETUP 6
+#define STATE_READ_DATA 7
+#define STATE_READ_DATA_DMA 8
+#define STATE_READ_DATA_END 9
+#define STATE_WRITE_DATA_SETUP 10
+#define STATE_WRITE_DATA 11
+#define STATE_WRITE_DATA_DMA 12
+#define STATE_WRITE_DATA_END 13
+
+//*****************************************************************************
+//
+//! Handles SSI module interrupts for the SPI flash driver.
+//!
+//! \param pState is a pointer to the SPI flash driver instance data.
+//!
+//! This function handles SSI module interrupts that are generated as a result
+//! of SPI flash driver operations. This must be called by the application in
+//! response to the SSI module interrupt when using the SPIFlashxxxNonBlocking
+//! APIs.
+//!
+//! \return Returns \b SPI_FLASH_IDLE if there is no transfer in progress,
+//! \b SPI_FLASH_WORKING is the requested transfer is still in progress, or
+//! \b SPI_FLASH_DONE if the requested transfer has completed.
+//
+//*****************************************************************************
+uint32_t
+SPIFlashIntHandler(tSPIFlashState *pState)
+{
+ uint32_t ui32Data, ui32Count;
+
+ //
+ // Set the write count to four. This is the maximum number of bytes that
+ // will be written into the SSI transmit FIFO in the interrupt handler.
+ // Writing more might be possible but makes the latency of handling future
+ // SSI interrupt critical to preventing receive FIFO overruns.
+ //
+ ui32Count = 4;
+
+ //
+ // Get the set of asserted and unmasked SSI module interrupts. Only some
+ // of these are directly handled; the others are implicitly handled via the
+ // operation of the state machine.
+ //
+ ui32Data = HWREG(pState->ui32Base + SSI_O_MIS);
+
+ //
+ // See if the uDMA transmit complete interrupt has asserted.
+ //
+ if(ui32Data & SSI_MIS_DMATXMIS)
+ {
+ //
+ // Determine the size of the uDMA transfer based on the number of bytes
+ // left to write.
+ //
+ if(pState->ui32WriteCount > 1024)
+ {
+ //
+ // There are more than 1024 bytes left to transfer, so the uDMA
+ // transfer that just completed was for a full 1024 bytes.
+ //
+ pState->ui32WriteCount -= 1024;
+
+ //
+ // If a page program is being performed, then the data buffer
+ // pointer needs to be incremented as well.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ //
+ // Increment the data buffer pointer.
+ //
+ pState->pui8Buffer += 1024;
+
+ //
+ // See if there is more than one byte left to transfer.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Configure the uDMA to transmit the next portion of the
+ // data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ }
+ }
+ }
+ else
+ {
+ //
+ // There are 1024 or less bytes left to transfer, so the uDMA
+ // transfer that just copmleted was for one less than the remaining
+ // transfer count. If a page program is being performed, then the
+ // data buffer pointer needs to be incremented.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ pState->pui8Buffer += (pState->ui32WriteCount - 1);
+ }
+
+ //
+ // Set the remaining transfer count to 1. The final byte will be
+ // transferred with PIO since the end of frame flag needs to be set
+ // first.
+ //
+ pState->ui32WriteCount = 1;
+ }
+
+ //
+ // Clear the uDMA transmit complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ }
+
+ //
+ // See if the uDMA receive complete interrupt has asserted.
+ //
+ if(ui32Data & SSI_MIS_DMARXMIS)
+ {
+ //
+ // Determine the size of the uDMA transfer based on the number of bytes
+ // left to read.
+ //
+ if(pState->ui32ReadCount >= 1024)
+ {
+ //
+ // There are 1024 or more bytes left to transfer, so the uDMA
+ // transfer that just completed was for a full 1024 bytes.
+ //
+ pState->ui32ReadCount -= 1024;
+ if(pState->ui32WriteCount != 0)
+ {
+ pState->ui32WriteCount -= 1024;
+ }
+
+ //
+ // The data buffer pointer needs to be incremented as well.
+ //
+ pState->pui8Buffer += 1024;
+
+ //
+ // See if there is additional data to transfer.
+ //
+ if(pState->ui32ReadCount != 0)
+ {
+ //
+ // Configure the transmit uDMA if there is more than one byte
+ // left to write.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Configure the uDMA to transmit the next portion of the
+ // data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC, pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ }
+
+ //
+ // Configure the uDMA to receive the next portion of the data
+ // buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32RxChannel, UDMA_MODE_BASIC,
+ (void *)(pState->ui32Base + SSI_O_DR),
+ pState->pui8Buffer,
+ (pState->ui32ReadCount >= 1024) ?
+ 1024 : pState->ui32ReadCount);
+
+ //
+ // Enable the uDMA receive channel.
+ //
+ uDMAChannelEnable(pState->ui32RxChannel);
+
+ //
+ // If this is the final receive uDMA buffer and there is a
+ // transmit uDMA buffer associated, enable the DMA transmit
+ // interrupt.
+ //
+ if((pState->ui32ReadCount <= 1024) &&
+ (pState->ui32WriteCount > 1))
+ {
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+ }
+ }
+ }
+ else
+ {
+ //
+ // There are less than 1024 bytes left to transfer, so the uDMA
+ // transfer that copmleted was for the remaining transfer count.
+ //
+ pState->ui32ReadCount = 0;
+ }
+
+ //
+ // Clear the uDMA receive complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMARXIC;
+ }
+
+ //
+ // Drain the receive FIFO is not using uDMA.
+ //
+ if(!pState->bUseDMA)
+ {
+ //
+ // Loop while there is more data in the receive FIFO and more data to
+ // be read.
+ //
+ while((pState->ui32ReadCount != 0) &&
+ (MAP_SSIDataGetNonBlocking(pState->ui32Base, &ui32Data) != 0))
+ {
+ //
+ // Save this byte into the data buffer.
+ //
+ *(pState->pui8Buffer)++ = ui32Data & 0xff;
+
+ //
+ // Decrement the read count.
+ //
+ pState->ui32ReadCount--;
+ }
+ }
+
+ //
+ // The SPI flash state machine. Loop forever; the state machine will
+ // explicitly return to the caller when there is no further work that can
+ // be done without stalling.
+ //
+ while(1)
+ {
+ //
+ // Determine the current state.
+ //
+ switch(pState->ui16State)
+ {
+ //
+ // The state machine is idle.
+ //
+ case STATE_IDLE:
+ {
+ //
+ // Return indicating that the state machine is idle. This
+ // should never happen since no further interrupts should occur
+ // once the transfer has completed and the state machine goes
+ // into the idle state.
+ //
+ return(SPI_FLASH_IDLE);
+ }
+
+ //
+ // The state machine is in the command state.
+ //
+ case STATE_CMD:
+ {
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Attempt to write the command byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ pState->ui16Cmd) == 0)
+ {
+ //
+ // The command byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The command byte has been written, so move to the first
+ // address byte state.
+ //
+ pState->ui16State = STATE_ADDR1;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the first address byte state.
+ //
+ case STATE_ADDR1:
+ {
+ //
+ // Attempt to write the first address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ (pState->ui32Addr >> 16) &
+ 0xff) == 0)
+ {
+ //
+ // The first address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The first address byte has been written, so move to the
+ // second address byte state.
+ //
+ pState->ui16State = STATE_ADDR2;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the second address byte state.
+ //
+ case STATE_ADDR2:
+ {
+ //
+ // Attempt to write the second address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ (pState->ui32Addr >> 8) & 0xff) ==
+ 0)
+ {
+ //
+ // The second address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The second address byte has been written, so move to the
+ // third address byte state.
+ //
+ pState->ui16State = STATE_ADDR3;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the third address byte state.
+ //
+ case STATE_ADDR3:
+ {
+ //
+ // Attempt to write the third address byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ pState->ui32Addr & 0xff) == 0)
+ {
+ //
+ // The third address byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The third address byte has been written, so determine
+ // the next state based on the command byte.
+ //
+ if(pState->ui16Cmd == CMD_PP)
+ {
+ //
+ // A page program is being performed, so move to the
+ // write data setup state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_SETUP;
+ }
+ else if(pState->ui16Cmd == CMD_READ)
+ {
+ //
+ // A read is being performed, so move to the read data
+ // setup state.
+ //
+ pState->ui16State = STATE_READ_DATA_SETUP;
+ }
+ else
+ {
+ //
+ // The other forms of read (fast read, dual read, and
+ // quad read) all require a dummy byte. Move to the
+ // dummy byte state.
+ //
+ pState->ui16State = STATE_READ_DUMMY;
+ }
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the dummy byte state.
+ //
+ case STATE_READ_DUMMY:
+ {
+ //
+ // Attempt to write the dummy byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base, 0) == 0)
+ {
+ //
+ // THe dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+ else
+ {
+ //
+ // The dummy byte has been written, so move to the read
+ // data setup state.
+ //
+ pState->ui16State = STATE_READ_DATA_SETUP;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the read data setup state.
+ //
+ case STATE_READ_DATA_SETUP:
+ {
+ //
+ // Set the SSI module into the appropriate mode based on the
+ // command byte.
+ //
+ if(pState->ui16Cmd == CMD_DREAD)
+ {
+ //
+ // Bi-SPI read mode is used for the dual read command.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base, SSI_ADV_MODE_BI_READ);
+ }
+ else if(pState->ui16Cmd == CMD_QREAD)
+ {
+ //
+ // Quad-SPI read mode is used for the quad read command.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base,
+ SSI_ADV_MODE_QUAD_READ);
+ }
+ else
+ {
+ //
+ // Advanced read/write mode is used for the read and fast
+ // read commands.
+ //
+ MAP_SSIAdvModeSet(pState->ui32Base,
+ SSI_ADV_MODE_READ_WRITE);
+ }
+
+ //
+ // See if a single byte is being transferred.
+ //
+ if(pState->ui32ReadCount == 1)
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the read data end state to transfer the single
+ // byte. This uses PIO even if uDMA has been requested.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+ }
+
+ //
+ // See if uDMA has been requested for this transfer.
+ //
+ else if(!pState->bUseDMA || (pState->ui32ReadCount < 4))
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the read data state.
+ //
+ pState->ui16State = STATE_READ_DATA;
+ }
+
+ //
+ // This transfer should use uDMA.
+ //
+ else
+ {
+ //
+ // If the transfer is larger than 1024 bytes, enable the
+ // uDMA receive complete interrupt which will be used to
+ // move to the next block of the transfer. Otherwise,
+ // enable the uDMA transmit complete interrupt which will
+ // be used to complete the transaction.
+ //
+ if(pState->ui32ReadCount > 1024)
+ {
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMARXIM;
+ }
+ else
+ {
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+ }
+
+ //
+ // Disable the uDMA channels.
+ //
+ HWREG(UDMA_ENACLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+
+ //
+ // Configure the attributes for the transmit uDMA channel.
+ //
+ HWREG(UDMA_USEBURSTSET) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+ HWREG(UDMA_ALTCLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+ HWREG(UDMA_PRIOCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_PRIOSET) = 1 << pState->ui32RxChannel;
+ HWREG(UDMA_REQMASKCLR) = ((1 << pState->ui32TxChannel) |
+ (1 << pState->ui32RxChannel));
+
+ //
+ // Configure the control parameters of the uDMA channels.
+ //
+ uDMAChannelControlSet(pState->ui32TxChannel,
+ UDMA_SRC_INC_NONE |
+ UDMA_DST_INC_NONE |
+ UDMA_SIZE_8 | UDMA_ARB_2);
+ uDMAChannelControlSet(pState->ui32RxChannel,
+ UDMA_SRC_INC_NONE |
+ UDMA_DST_INC_8 |
+ UDMA_SIZE_8 | UDMA_ARB_4);
+
+ //
+ // Configure the uDMA receive channel to transfer the first
+ // portion of the data buffer.
+ //
+ uDMAChannelTransferSet(pState->ui32RxChannel,
+ UDMA_MODE_BASIC,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ pState->pui8Buffer,
+ (pState->ui32ReadCount >= 1024) ?
+ 1024 : pState->ui32ReadCount);
+
+ //
+ // Enable the uDMA receive channel.
+ //
+ uDMAChannelEnable(pState->ui32RxChannel);
+
+ //
+ // Configure the uDMA channel to transfer the dummy bytes
+ // for the first portion of the data buffer. The last
+ // dummy byte will not be included since it must be treated
+ // special.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+
+ //
+ // Clear any previously pending uDMA completion interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMARXIC;
+
+ //
+ // Enable uDMA transmit and receive in the SSI module.
+ //
+ MAP_SSIDMAEnable(pState->ui32Base,
+ SSI_DMA_TX | SSI_DMA_RX);
+
+ //
+ // Move to the uDMA data read state.
+ //
+ pState->ui16State = STATE_READ_DATA_DMA;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the read data state.
+ //
+ case STATE_READ_DATA:
+ {
+ //
+ // Loop while there is more than one byte left to write.
+ //
+ while(pState->ui32WriteCount != 1)
+ {
+ //
+ // Dummy bytes are written into the FIFO in order to
+ // trigger the read operation. Attempt to write another
+ // dummy byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base, 0) == 0)
+ {
+ //
+ // The dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Decrement the count of dummy bytes to write.
+ //
+ pState->ui32WriteCount--;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Move to the read data end state.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the uDMA read data state.
+ //
+ case STATE_READ_DATA_DMA:
+ {
+ //
+ // See if the write count is greater than one.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Return indicating that the transfer is still in
+ // progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA transmit in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Enable the uDMA receive done and FIFO transmit interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) =
+ SSI_IM_DMARXIM | SSI_IM_TXIM;
+
+ //
+ // Move to the read data end state.
+ //
+ pState->ui16State = STATE_READ_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data read end state.
+ //
+ case STATE_READ_DATA_END:
+ {
+ //
+ // See if the final dummy byte still needs to be written.
+ //
+ if(pState->ui32WriteCount != 0)
+ {
+ //
+ // Attempt to write the final dummy byte into the FIFO and
+ // mark it as the end of the frame.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIAdvDataPutFrameEndNonBlocking(pState->ui32Base,
+ 0) == 0)
+ {
+ //
+ // The dummy byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // The write portion of the transfer has completed.
+ //
+ pState->ui32WriteCount = 0;
+
+ //
+ // Disable the transmit interrupt now that the write
+ // write portion of the transfer has completed.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) &= ~(SSI_IM_TXIM);
+ }
+
+ //
+ // Return indicating that the transfer is still in progress if
+ // there are still data bytes to be read.
+ //
+ if(pState->ui32ReadCount != 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA receive in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_RX);
+
+ //
+ // The transfer is complete, so disable all interrupts.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = 0;
+
+ //
+ // Move to the idle state.
+ //
+ pState->ui16State = STATE_IDLE;
+
+ //
+ // Return indicating that the transfer has completed.
+ //
+ return(SPI_FLASH_DONE);
+ }
+
+ //
+ // The state machine is in the write data setup state.
+ //
+ case STATE_WRITE_DATA_SETUP:
+ {
+ //
+ // See if a single data byte is being transferred.
+ //
+ if(pState->ui32WriteCount == 1)
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // Move to the write data end state to transfer the single
+ // byte. This uses PIO even if uDMA has been requested.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+ }
+
+ //
+ // See if uDMA has been requested for this transfer.
+ //
+ else if(!pState->bUseDMA || (pState->ui32WriteCount < 4))
+ {
+ //
+ // Disable the use of uDMA.
+ //
+ pState->bUseDMA = false;
+
+ //
+ // uDMA is not being used, so move to the write data state.
+ //
+ pState->ui16State = STATE_WRITE_DATA;
+ }
+
+ //
+ // This transfer should use uDMA.
+ //
+ else
+ {
+ //
+ // Enable the uDMA transmit complete interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_DMATXIM;
+
+ //
+ // Disable the transmit uDMA channel.
+ //
+ HWREG(UDMA_ENACLR) = 1 << pState->ui32TxChannel;
+
+ //
+ // Configure the attributes for the transmit uDMA channel.
+ //
+ HWREG(UDMA_USEBURSTSET) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_ALTCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_PRIOCLR) = 1 << pState->ui32TxChannel;
+ HWREG(UDMA_REQMASKCLR) = 1 << pState->ui32TxChannel;
+
+ //
+ // Configure the control parameters of the uDMA channel.
+ //
+ uDMAChannelControlSet(pState->ui32TxChannel,
+ UDMA_SRC_INC_8 |
+ UDMA_DST_INC_NONE |
+ UDMA_SIZE_8 | UDMA_ARB_4);
+
+ //
+ // Configure the uDMA channel to transfer the next portion
+ // of the data buffer. The last byte in the buffer will
+ // not be included since it must be treated special.
+ //
+ uDMAChannelTransferSet(pState->ui32TxChannel,
+ UDMA_MODE_BASIC,
+ pState->pui8Buffer,
+ (void *)(pState->ui32Base +
+ SSI_O_DR),
+ (pState->ui32WriteCount > 1024) ?
+ 1024 : pState->ui32WriteCount - 1);
+
+ //
+ // Enable the uDMA transmit channel.
+ //
+ uDMAChannelEnable(pState->ui32TxChannel);
+ HWREG(pState->ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+
+ //
+ // Enable uDMA in the SSI module.
+ //
+ MAP_SSIDMAEnable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Move to the uDMA data write state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_DMA;
+ }
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the write data state.
+ //
+ case STATE_WRITE_DATA:
+ {
+ //
+ // Loop while there is more than one byte left to write.
+ //
+ while(pState->ui32WriteCount != 1)
+ {
+ //
+ // Attempt to write the next data byte into the FIFO.
+ //
+ if(ui32Count == 0)
+ {
+ return(SPI_FLASH_WORKING);
+ }
+ if(MAP_SSIDataPutNonBlocking(pState->ui32Base,
+ *(pState->pui8Buffer)) == 0)
+ {
+ //
+ // The next data byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Increment the buffer pointer and decrement the byte
+ // count.
+ //
+ pState->pui8Buffer++;
+ pState->ui32WriteCount--;
+
+ //
+ // Decrement the count of bytes that have been written.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Move to the write data end state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the uDMA write data state.
+ //
+ case STATE_WRITE_DATA_DMA:
+ {
+ //
+ // See if the write count is greater than one.
+ //
+ if(pState->ui32WriteCount > 1)
+ {
+ //
+ // Return indicating that the transfer is still in
+ // progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // Disable uDMA in the SSI module.
+ //
+ MAP_SSIDMADisable(pState->ui32Base, SSI_DMA_TX);
+
+ //
+ // Disable the uDMA transmit complete interrupt and enable the
+ // FIFO interrupt.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = SSI_IM_TXIM;
+
+ //
+ // Move to the write data end state.
+ //
+ pState->ui16State = STATE_WRITE_DATA_END;
+
+ //
+ // Done with this state.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the write data end state.
+ //
+ case STATE_WRITE_DATA_END:
+ {
+ //
+ // Attempt to write the final data byte into the FIFO.
+ //
+ if(MAP_SSIAdvDataPutFrameEndNonBlocking(pState->ui32Base,
+ *(pState->pui8Buffer)) ==
+ 0)
+ {
+ //
+ // The final data byte could not be written, so return
+ // indicating that the transfer is still in progress.
+ //
+ return(SPI_FLASH_WORKING);
+ }
+
+ //
+ // The transfer is complete, so disable all interrupts.
+ //
+ HWREG(pState->ui32Base + SSI_O_IM) = 0;
+
+ //
+ // Move to the idle state.
+ //
+ pState->ui16State = STATE_IDLE;
+
+ //
+ // Return indicating that the transfer has completed.
+ //
+ return(SPI_FLASH_DONE);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SPI flash driver.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Clock is the rate of the clock supplied to the SSI module.
+//! \param ui32BitRate is the SPI clock rate.
+//!
+//! This function configures the SSI module for use by the SPI flash driver.
+//! The SSI module will be placed into the correct mode of operation to allow
+//! communication with the SPI flash. This function must be called prior to
+//! calling the remaining SPI flash driver APIs. It can be called at a later
+//! point to reconfigure the SSI module, such as to increase the SPI clock rate
+//! once it has been determined that it is safe to use a higher speed clock.
+//!
+//! It is the responsibility of the caller to enable the SSI module and
+//! configure the pins that it will utilize.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock, uint32_t ui32BitRate)
+{
+ //
+ // Configure the SPI module.
+ //
+ MAP_SSIConfigSetExpClk(ui32Base, ui32Clock, SSI_FRF_MOTO_MODE_0,
+ SSI_MODE_MASTER, ui32BitRate, 8);
+
+ //
+ // Enable the advanced mode of operation, defaulting to read/write mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Enable the frame hold feature.
+ //
+ MAP_SSIAdvFrameHoldEnable(ui32Base);
+
+ //
+ // Enable the SPI module.
+ //
+ MAP_SSIEnable(ui32Base);
+}
+
+//*****************************************************************************
+//
+//! Writes the SPI flash status register.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui8Status is the value to write to the status register.
+//!
+//! This function writes the SPI flash status register. This uses the 0x01 SPI
+//! flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteStatus(uint32_t ui32Base, uint8_t ui8Status)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write status register command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_WRSR);
+
+ //
+ // Send the new status register value, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui8Status);
+}
+
+//*****************************************************************************
+//
+//! Programs the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to be programmed.
+//! \param pui8Data is a pointer to the data to be programmed.
+//! \param ui32Count is the number of bytes to be programmed.
+//!
+//! This function programs data into the SPI flash, using PIO mode. This
+//! function will not return until the entire program command has been written
+//! into the SSI transmit FIFO. This uses the 0x02 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashPageProgram(uint32_t ui32Base, uint32_t ui32Addr,
+ const uint8_t *pui8Data, uint32_t ui32Count)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the page program command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_PP);
+
+ //
+ // Send the address of the first byte to program.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Loop while there is more than one data byte left to be sent.
+ //
+ while(ui32Count-- != 1)
+ {
+ //
+ // Send the next data byte.
+ //
+ MAP_SSIDataPut(ui32Base, *pui8Data++);
+ }
+
+ //
+ // Send the last data byte, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, *pui8Data);
+}
+
+//*****************************************************************************
+//
+//! Programs the SPI flash in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to be programmed.
+//! \param pui8Data is a pointer to the data to be programmed.
+//! \param ui32Count is the number of bytes to be programmed.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//!
+//! This function programs data into the SPI flash, using either interrupts or
+//! uDMA to transfer the data. This function will return immediately and send
+//! the data in the background. In order for this to complete successfully,
+//! several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the programming operation is indicated when
+//! SPIFlashIntHandler() returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashPageProgram(), this uses the 0x02 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashPageProgramNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, const uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel)
+{
+ //
+ // Save the parameters of this program operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_PP;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = (uint8_t *)pui8Data;
+ pState->ui32ReadCount = 0;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit interrupt. This will start the transfer. If
+ // uDMA is being used, the uDMA-related interrupt will be enabled at the
+ // appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash, using PIO mode. This function
+//! will not return until the read has completed. This uses the 0x03 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_READ);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash, using either interrupts or
+//! uDMA to transfer the data. This function will return immediately and read
+//! the data in the background. In order for this to complete successfully,
+//! several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashRead(), this uses the 0x03 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_READ;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Disables SPI flash write operations.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function sets the SPI flash to disallow program and erase operations.
+//! This uses the 0x04 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteDisable(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write disable command, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_WRDI);
+}
+
+//*****************************************************************************
+//
+//! Reads the SPI flash status register.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function reads the SPI flash status register. This uses the 0x05 SPI
+//! flash command.
+//!
+//! \return Returns the value of the SPI flash status register.
+//
+//*****************************************************************************
+uint8_t
+SPIFlashReadStatus(uint32_t ui32Base)
+{
+ uint32_t ui32Data;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write status register command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_RDSR);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the value of the status register.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data);
+
+ //
+ // Return the status register value.
+ //
+ return(ui32Data & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Enables SPI flash write operations.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This function sets the SPI flash to allow program and erase operations.
+//! This must be done prior to each SPI flash program or erase operation; the
+//! SPI flash will automatically disable program and erase operations once a
+//! program or erase operation has completed. This uses the 0x06 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashWriteEnable(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the write enable command, marking this byte as the end of the
+ // frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_WREN);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using the fast read command.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with the fast read command,
+//! using PIO mode. The fast read command allows the SPI flash to be read at
+//! a higher SPI clock rate because of the addition of a dummy cycle during the
+//! command setup. This function will not return until the read has completed.
+//! This uses the 0x0b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashFastRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the fast read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_FREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using the fast read command in the
+//! background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with the fast read command,
+//! using either interrupts or uDMA to transfer the data. The fast read
+//! command allows the SPI flash to be read at a higher SPI clock rate because
+//! of the addition of a dummy cycle during the command setup. This function
+//! will return immediately and read the data in the background. In order for
+//! this to complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashFastRead(), this uses the 0x0b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashFastReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_FREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Erases a 4 KB sector of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a sector of the SPI flash. Each sector is 4 KB with a
+//! 4 KB alignment; the SPI flash will ignore the lower ten bits of the address
+//! provided. The sector erase command is issued by this function;
+//! SPIFlashReadStatus() must be used to query the SPI flash to determine when
+//! the sector erase operation has completed. This uses the 0x20 SPI flash
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashSectorErase(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the sector erase command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_SE);
+
+ //
+ // Send the address of the sector to be erased, marking the last byte of
+ // the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Bi-SPI.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with Bi-SPI, using PIO mode.
+//! This function will not return until the read has completed. This uses the
+//! 0x3b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashDualRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the dual read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_DREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into Bi-SPI read mode. In this mode, dummy writes
+ // are required in order to make the transfer occur; the SSI module will
+ // ignore the data (the SPI flash will never see the dummy data since
+ // Bi-SPI read mode is a uni-directional input mode).
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_BI_READ);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Bi-SPI in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with Bi-SPI, using either
+//! interrupts or uDMA to transfer the data. This function will return
+//! immediately and read the data in the background. In order for this to
+//! complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFLashDualRead(), this uses the 0x3b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashDualReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_DREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Erases a 32 KB block of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a 32 KB block of the SPI flash. Each 32 KB block has
+//! a 32 KB alignment; the SPI flash will ignore the lower 15 bits of the
+//! address provided. The 32 KB block erase command is issued by this
+//! function; SPIFlashReadStatus() must be used to query the SPI flash to
+//! determine when the 32 KB block erase operation has completed. This uses
+//! the 0x52 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashBlockErase32(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the 32 KB block erase command command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_BE32);
+
+ //
+ // Send the address of the 32 KB block to be erased, marking the last byte
+ // of the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Quad-SPI.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//!
+//! This function reads data from the SPI flash with Quad-SPI, using PIO mode.
+//! This function will not return until the read has completed. This uses the
+//! 0x6b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashQuadRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the quad read command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_QREAD);
+
+ //
+ // Send the address of the first byte to read.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
+
+ //
+ // Send a dummy byte.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Set the SSI module into Quad-SPI read mode. In this mode, dummy writes
+ // are required in order to make the transfer occur; the SSI module will
+ // ignore the data (the SPI flash will never see the dummy data since
+ // Quad-SPI read mode is a uni-directional input mode).
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_QUAD_READ);
+
+ //
+ // See if there is a single byte to be read.
+ //
+ if(ui32Count == 1)
+ {
+ //
+ // Perform a single dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+ }
+ else
+ {
+ //
+ // Perform a dummy write to prime the loop.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Loop while there is more than one byte left to be read.
+ //
+ while(--ui32Count != 1)
+ {
+ //
+ // Perform a dummy write to keep the transmit FIFO from going
+ // empty.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into
+ // the data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Perform the final dummy write, marking it as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the next data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+ }
+
+ //
+ // Read the final data byte from the receive FIFO and place it into the
+ // data buffer.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Addr);
+ *pui8Data++ = ui32Addr & 0xff;
+}
+
+//*****************************************************************************
+//
+//! Reads data from the SPI flash using Quad-SPI in the background.
+//!
+//! \param pState is a pointer to the SPI flash state structure.
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to read.
+//! \param pui8Data is a pointer to the data buffer to into which to read the
+//! data.
+//! \param ui32Count is the number of bytes to read.
+//! \param bUseDMA is \b true if uDMA should be used and \b false otherwise.
+//! \param ui32TxChannel is the uDMA channel to be used for writing to the SSI
+//! module.
+//! \param ui32RxChannel is the uDMA channel to be used for reading from the
+//! SSI module.
+//!
+//! This function reads data from the SPI flash with Quad-SPI, using either
+//! interrupts or uDMA to transfer the data. This function will return
+//! immediately and read the data in the background. In order for this to
+//! complete successfully, several conditions must be satisfied:
+//!
+//! - Prior to calling this function:
+//! - The SSI module must be enabled in SysCtl.
+//! - The SSI pins must be configured for use by the SSI module.
+//! - The SSI module interrupt must be enabled in NVIC.
+//! - The uDMA module must be enabled in SysCtl and the control table set (if
+//! using uDMA).
+//! - The uDMA channels must be assigned to the SSI module.
+//!
+//! - After calling this function:
+//! - The interrupt handler for the SSI module must call
+//! SPIFlashIntHandler(), passing the same pState structure pointer that
+//! was supplied to this function.
+//! - No other SPI flash operation can be called until this operation has
+//! completed.
+//!
+//! Completion of the read operation is indicated when SPIFlashIntHandler()
+//! returns \b SPI_FLASH_DONE.
+//!
+//! Like SPIFlashQuadRead(), this uses the 0x6b SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashQuadReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel, uint32_t ui32RxChannel)
+{
+ uint32_t ui32Trash;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
+ {
+ }
+
+ //
+ // Save the parameters of this read operation to the state structure.
+ //
+ pState->ui32Base = ui32Base;
+ pState->ui16Cmd = CMD_QREAD;
+ pState->ui16State = STATE_CMD;
+ pState->ui32Addr = ui32Addr;
+ pState->pui8Buffer = pui8Data;
+ pState->ui32ReadCount = ui32Count;
+ pState->ui32WriteCount = ui32Count;
+ pState->bUseDMA = bUseDMA;
+ pState->ui32TxChannel = ui32TxChannel & 0x1f;
+ pState->ui32RxChannel = ui32RxChannel & 0x1f;
+
+ //
+ // Enable the SSI transmit and receive interrupts. This will start the
+ // transfer. If uDMA is being used, the uDMA-related interrupts will be
+ // enabled at the appropriate time by the interrupt handler.
+ //
+ HWREG(ui32Base + SSI_O_ICR) = SSI_ICR_DMATXIC | SSI_ICR_DMARXIC;
+ HWREG(ui32Base + SSI_O_IM) = SSI_IM_TXIM | SSI_IM_RXIM | SSI_IM_RTIM;
+}
+
+//*****************************************************************************
+//
+//! Reads the manufacturer and device IDs from the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param pui8ManufacturerID is a pointer to the location into which to store
+//! the manufacturer ID.
+//! \param pui16DeviceID is a pointer to the location into which to store the
+//! device ID.
+//!
+//! This function reads the manufacturer and device IDs from the SPI flash.
+//! These values can be used to identify the SPI flash that is attached, as
+//! well as determining if a SPI flash is attached (if the \b SSIRx pin is
+//! pulled up or down, either using the pad's weak pull up/down or using an
+//! external resistor, which will cause the returned IDs to be either all zeros
+//! or all ones if the SPI flash is not attached). This uses the 0x9f SPI
+//! flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashReadID(uint32_t ui32Base, uint8_t *pui8ManufacturerID,
+ uint16_t *pui16DeviceID)
+{
+ uint32_t ui32Data1, ui32Data2;
+
+ //
+ // Drain any residual data from the receive FIFO.
+ //
+ while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data1) != 0)
+ {
+ }
+
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the read ID command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_RDID);
+
+ //
+ // Set the SSI module into read/write mode. In this mode, dummy writes are
+ // required in order to make the transfer occur; the SPI flash will ignore
+ // the data.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
+
+ //
+ // Send three dummy bytes, marking the last as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, 0);
+ MAP_SSIDataPut(ui32Base, 0);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, 0);
+
+ //
+ // Read the first returned data byte, which contains the manufacturer ID.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data1);
+ *pui8ManufacturerID = ui32Data1 & 0xff;
+
+ //
+ // Read the remaining two data bytes, which contain the device ID.
+ //
+ MAP_SSIDataGet(ui32Base, &ui32Data1);
+ MAP_SSIDataGet(ui32Base, &ui32Data2);
+ *pui16DeviceID = ((ui32Data1 & 0xff) << 8) | (ui32Data2 & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Erases the entire SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//!
+//! This command erase the entire SPI flash. The chip erase command is issued
+//! by this function; SPIFlashReadStatus() must be used to query the SPI flash
+//! to determine when the chip erase operation has completed. This uses the
+//! 0xc7 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashChipErase(uint32_t ui32Base)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the chip erase command, marking this byte as the end of the frame.
+ //
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, CMD_CE);
+}
+
+//*****************************************************************************
+//
+//! Erases a 64 KB block of the SPI flash.
+//!
+//! \param ui32Base is the SSI module base address.
+//! \param ui32Addr is the SPI flash address to erase.
+//!
+//! This function erases a 64 KB block of the SPI flash. Each 64 KB block has
+//! a 64 KB alignment; the SPI flash will ignore the lower 16 bits of the
+//! address provided. The 64 KB block erase command is issued by this
+//! function; SPIFlashReadStatus() must be used to query the SPI flash to
+//! determine when the 64 KB block erase operation has completed. This uses
+//! the 0xd8 SPI flash command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SPIFlashBlockErase64(uint32_t ui32Base, uint32_t ui32Addr)
+{
+ //
+ // Set the SSI module into write-only mode.
+ //
+ MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
+
+ //
+ // Send the 64 KB block erase command command.
+ //
+ MAP_SSIDataPut(ui32Base, CMD_BE64);
+
+ //
+ // Send the address of the 64 KB block to be erased, marking the last byte
+ // of the address as the end of the frame.
+ //
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
+ MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
+ MAP_SSIAdvDataPutFrameEnd(ui32Base, ui32Addr & 0xff);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/spi_flash.h b/utils/spi_flash.h
new file mode 100644
index 0000000..59311fb
--- /dev/null
+++ b/utils/spi_flash.h
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// spi_flash.h - Prototypes for the SPI flash driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SPI_FLASH_H__
+#define __SPI_FLASH_H__
+
+//*****************************************************************************
+//
+//! \addtogroup spi_flash_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The state structure used when performing non-blocking SPI flash operations.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The base address of the SSI module that is being used.
+ //
+ uint32_t ui32Base;
+
+ //
+ //! The command that is being send to the SPI flash.
+ //
+ uint16_t ui16Cmd;
+
+ //
+ //! The current state of the SPI flash state machine.
+ //
+ uint16_t ui16State;
+
+ //
+ //! The SPI flash address associated with the command.
+ //
+ uint32_t ui32Addr;
+
+ //
+ //! A pointer to the data buffer that is being read or written.
+ //
+ uint8_t *pui8Buffer;
+
+ //
+ //! The count of bytes left to be read.
+ //
+ uint32_t ui32ReadCount;
+
+ //
+ //! The count of bytes left to be written.
+ //
+ uint32_t ui32WriteCount;
+
+ //
+ //! A flag that is true if uDMA used be used for the transfer.
+ //
+ bool bUseDMA;
+
+ //
+ //! The uDMA channel to use for transmitting when using uDMA for the
+ //! transfer.
+ //
+ uint32_t ui32TxChannel;
+
+ //
+ //! The uDMA channel to use for receiving when using uDMA for the transfer.
+ //
+ uint32_t ui32RxChannel;
+}
+tSPIFlashState;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The possible return values from the SPI flash interrupt handler.
+//
+//*****************************************************************************
+#define SPI_FLASH_IDLE 0
+#define SPI_FLASH_WORKING 1
+#define SPI_FLASH_DONE 3
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern uint32_t SPIFlashIntHandler(tSPIFlashState *pState);
+extern void SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock,
+ uint32_t ui32BitRate);
+extern void SPIFlashWriteStatus(uint32_t ui32Base, uint8_t ui8Status);
+extern void SPIFlashPageProgram(uint32_t ui32Base, uint32_t ui32Addr,
+ const uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashPageProgramNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base,
+ uint32_t ui32Addr,
+ const uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel);
+extern void SPIFlashRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashReadNonBlocking(tSPIFlashState *pState, uint32_t ui32Base,
+ uint32_t ui32Addr, uint8_t *pui8Data,
+ uint32_t ui32Count, bool bUseDMA,
+ uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashWriteDisable(uint32_t ui32Base);
+extern uint8_t SPIFlashReadStatus(uint32_t ui32Base);
+extern void SPIFlashWriteEnable(uint32_t ui32Base);
+extern void SPIFlashFastRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashFastReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashSectorErase(uint32_t ui32Base, uint32_t ui32Addr);
+extern void SPIFlashDualRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashDualReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashBlockErase32(uint32_t ui32Base, uint32_t ui32Addr);
+extern void SPIFlashQuadRead(uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count);
+extern void SPIFlashQuadReadNonBlocking(tSPIFlashState *pState,
+ uint32_t ui32Base, uint32_t ui32Addr,
+ uint8_t *pui8Data, uint32_t ui32Count,
+ bool bUseDMA, uint32_t ui32TxChannel,
+ uint32_t ui32RxChannel);
+extern void SPIFlashReadID(uint32_t ui32Base, uint8_t *pui8ManufacturerID,
+ uint16_t *pui16DeviceID);
+extern void SPIFlashChipErase(uint32_t ui32Base);
+extern void SPIFlashBlockErase64(uint32_t ui32Base, uint32_t ui32Addr);
+
+#endif // __SPI_FLASH_H__
diff --git a/utils/swupdate.c b/utils/swupdate.c
new file mode 100644
index 0000000..edd523b
--- /dev/null
+++ b/utils/swupdate.c
@@ -0,0 +1,355 @@
+//*****************************************************************************
+//
+// swupdate.c - A module wrapping the Ethernet bootloader software update
+// functionality.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/flash.h"
+#include "driverlib/rom.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/systick.h"
+#include "utils/lwiplib.h"
+#include "utils/swupdate.h"
+
+//*****************************************************************************
+//
+//! \addtogroup swupdate_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The UDP port used to send the remote firmware update request signal. This
+// is the well-known port associated with "discard" function and is also used
+// by some Wake-On-LAN implementations.
+//
+//*****************************************************************************
+#define MPACKET_PORT 9
+
+//*****************************************************************************
+//
+// The length of the various parts of the remote firmware update request magic
+// packet and its total length. This contains a 6 byte header followed by 4
+// copies of the target MAC address.
+//
+//*****************************************************************************
+#define MPACKET_HEADER_LEN 6
+#define MPACKET_MAC_REP 4
+#define MPACKET_MAC_LEN 6
+#define MPACKET_LEN (MPACKET_HEADER_LEN + \
+ (MPACKET_MAC_REP * MPACKET_MAC_LEN))
+
+//*****************************************************************************
+//
+// The marker byte used at the start of the magic packet. This is repeated
+// MPACKET_HEADER_LEN times.
+//
+//*****************************************************************************
+#define MPACKET_MARKER 0xAA
+
+//*****************************************************************************
+//
+// The callback function which is used to determine whether or not the
+// application wants to allow a remotely-requested firmware update.
+//
+//*****************************************************************************
+tSoftwareUpdateRequested g_pfnUpdateCallback = NULL;
+
+//*****************************************************************************
+//
+// A pointer to the remote firmware update signal PCB data structure.
+//
+//*****************************************************************************
+static struct udp_pcb *g_psMagicPacketPCB = NULL;
+
+//*****************************************************************************
+//
+// The MAC address for this board.
+//
+//*****************************************************************************
+static uint8_t g_pui8MACAddr[6];
+
+//*****************************************************************************
+//
+// Receives a UDP port 9 packet from lwIP.
+//
+// \param arg is not used in this implementation.
+// \param pcb is the pointer to the UDB control structure.
+// \param p is the pointer to the PBUF structure containing the packet data.
+// \param addr is the source (remote) IP address for this packet.
+// \param port is the source (remote) port for this packet.
+//
+// This function is called when the lwIP TCP/IP stack has an incoming
+// UDP packet to be processed on the remote firmware update signal port.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+SoftwareUpdateUDPReceive(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ int8_t *pi8Data = p->payload;
+ uint32_t ui32Loop, ui32MACLoop;
+
+ //
+ // Check that the packet length is what we expect. If not, ignore the
+ // packet.
+ //
+ if(p->len == MPACKET_LEN)
+ {
+ //
+ // The length matches so now look for the 6 byte header
+ //
+ for(ui32Loop = 0; ui32Loop < MPACKET_HEADER_LEN; ui32Loop++)
+ {
+ //
+ // Does this header byte match the expected marker?
+ //
+ if((*pi8Data & 0x000000FF)!= MPACKET_MARKER)
+ {
+ //
+ // No - free the buffer and return - this is not a packet
+ // we are interested in.
+ //
+ pbuf_free(p);
+ return;
+ }
+ else
+ {
+ //
+ // Byte matched so move on to the next one.
+ //
+ pi8Data++;
+ }
+ }
+ }
+ else
+ {
+ //
+ // No - free the buffer and return - this is not a packet
+ // we are interested in.
+ //
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // If we get here, the packet length and header markers indicate
+ // that this is a remote firmware update request. Now check that it
+ // is for us and that it contains the required number of copies of
+ // the MAC address.
+ //
+
+ //
+ // Loop through each of the expected MAC address copies.
+ //
+ for(ui32Loop = 0; ui32Loop < MPACKET_MAC_REP; ui32Loop++)
+ {
+ //
+ // Loop through each byte of the MAC address in this
+ // copy.
+ //
+ for(ui32MACLoop = 0; ui32MACLoop < MPACKET_MAC_LEN; ui32MACLoop++)
+ {
+ //
+ // Does the payload MAC address byte match what we expect?
+ //
+ if((*pi8Data & 0x000000FF) != g_pui8MACAddr[ui32MACLoop])
+ {
+ //
+ // No match - free the packet and return.
+ //
+ pbuf_free(p);
+ return;
+ }
+ else
+ {
+ //
+ // Byte matched so move on to the next one.
+ //
+ pi8Data++;
+ }
+ }
+ }
+
+ //
+ // Free the pbuf since we are finished with it now.
+ //
+ pbuf_free(p);
+
+ //
+ // If we get this far, we've received a valid remote firmare update
+ // request targetted at this board. Signal this to the application
+ // if we have a valid callback pointer.
+ //
+ if(g_pfnUpdateCallback)
+ {
+ g_pfnUpdateCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the remote Ethernet software update notification feature.
+//!
+//! \param pfnCallback is a pointer to a function which will be called whenever
+//! a remote firmware update request is received. If the application wishes
+//! to allow the update to go ahead, it must call SoftwareUpdateBegin() from
+//! non-interrupt context after the callback is received. Note that the
+//! callback will most likely be made in interrupt context so it is not safe
+//! to call SoftwareUpdateBegin() from within the callback itself.
+//!
+//! This function may be used on Ethernet-enabled parts to support
+//! remotely-signaled firmware updates over Ethernet. The LM Flash Programmer
+//! (LMFlash.exe) application sends a magic packet to UDP port 9 whenever the
+//! user requests an Ethernet-based firmware update. This packet consists of
+//! 6 bytes of 0xAA followed by the target MAC address repeated 4 times.
+//! This function starts listening on UDP port 9 and, if a magic packet
+//! matching the MAC address of this board is received, makes a call to the
+//! provided callback function to indicate that an update has been requested.
+//!
+//! The callback function provided here will typically be called in the context
+//! of the lwIP Ethernet interrupt handler. It is not safe to call
+//! SoftwareUpdateBegin() in this context so the application should use the
+//! callback to signal code running in a non-interrupt context to perform the
+//! update if it is to be allowed.
+//!
+//! UDP port 9 is chosen for this function since this is the well-known port
+//! associated with ``discard'' operation. In other words, any other system
+//! receiving the magic packet will simply ignore it. The actual magic packet
+//! used is modeled on Wake-On-LAN which uses a similar structure (6 bytes of
+//! 0xFF followed by 16 repetitions of the target MAC address). Some
+//! Wake-On-LAN implementations also use UDP port 9 for their signaling.
+//!
+//! \note Applications using this function must initialize the lwIP stack prior
+//! to making this call and must ensure that the lwIPTimer() function is called
+//! periodically. lwIP UDP must be enabled in lwipopts.h to ensure that the
+//! magic packets can be received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftwareUpdateInit(tSoftwareUpdateRequested pfnCallback)
+{
+ uint32_t ui32User0, ui32User1;
+
+ //
+ // Remember the callback function pointer we have been given.
+ //
+ g_pfnUpdateCallback = pfnCallback;
+
+ //
+ // Get the MAC address from the user registers in NV ram.
+ //
+ FlashUserGet(&ui32User0, &ui32User1);
+
+ //
+ // Convert the 24/24 split MAC address from NV ram into a MAC address
+ // array.
+ //
+ g_pui8MACAddr[0] = ui32User0 & 0xff;
+ g_pui8MACAddr[1] = (ui32User0 >> 8) & 0xff;
+ g_pui8MACAddr[2] = (ui32User0 >> 16) & 0xff;
+ g_pui8MACAddr[3] = ui32User1 & 0xff;
+ g_pui8MACAddr[4] = (ui32User1 >> 8) & 0xff;
+ g_pui8MACAddr[5] = (ui32User1 >> 16) & 0xff;
+
+ //
+ // Set up a UDP PCB to allow us to receive the magic packets sent from
+ // LMFlash. These may be sent to port 9 from any port on the source
+ // machine so we do not call udp_connect here (since this causes lwIP to
+ // filter any packet that did not originate from port 9 too).
+ //
+ g_psMagicPacketPCB = udp_new();
+ udp_recv(g_psMagicPacketPCB, SoftwareUpdateUDPReceive, NULL);
+ udp_bind(g_psMagicPacketPCB, IP_ADDR_ANY, MPACKET_PORT);
+}
+
+//*****************************************************************************
+//
+//! Passes control to the bootloader and initiates a remote software update
+//! over Ethernet.
+//!
+//! This function passes control to the bootloader and initiates an update of
+//! the main application firmware image via BOOTP across Ethernet. This
+//! function may only be used on parts supporting Ethernet and in cases where
+//! the Ethernet boot loader is in use alongside the main application image.
+//! It must not be called in interrupt context.
+//!
+//! Applications wishing to make use of this function must be built to
+//! operate with the bootloader. If this function is called on a system
+//! which does not include the bootloader, the results are unpredictable.
+//!
+//! \note It is not safe to call this function from within the callback
+//! provided on the initial call to SoftwareUpdateInit(). The application
+//! must use the callback to signal a pending update (assuming the update is to
+//! be permitted) to some other code running in a non-interrupt context.
+//!
+//! \return Never returns.
+//
+//*****************************************************************************
+void
+SoftwareUpdateBegin(uint32_t ui32SysClock)
+{
+ //
+ // Disable all processor interrupts. Instead of disabling them
+ // one at a time (and possibly missing an interrupt if new sources
+ // are added), a direct write to NVIC is done to disable all
+ // peripheral interrupts.
+ //
+ HWREG(NVIC_DIS0) = 0xffffffff;
+ HWREG(NVIC_DIS1) = 0xffffffff;
+ HWREG(NVIC_DIS2) = 0xffffffff;
+ HWREG(NVIC_DIS3) = 0xffffffff;
+ HWREG(NVIC_DIS4) = 0xffffffff;
+
+ //
+ // Also disable the SysTick interrupt.
+ //
+ SysTickIntDisable();
+ SysTickDisable();
+
+ //
+ // Return control to the boot loader. This is a call to the SVC
+ // handler in the flashed-based boot loader, or to the ROM if configured.
+ //
+#if ((defined ROM_UpdateEthernet) && !(defined USE_FLASH_BOOT_LOADER))
+ ROM_UpdateEMAC(ui32SysClock);
+#else
+ (*((void (*)(void))(*(uint32_t *)0x2c)))();
+#endif
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/swupdate.h b/utils/swupdate.h
new file mode 100644
index 0000000..1cd44db
--- /dev/null
+++ b/utils/swupdate.h
@@ -0,0 +1,66 @@
+//*****************************************************************************
+//
+// swupdate.h - Prototypes for the bootloader software update module.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __SWUPDATE_H__
+#define __SWUPDATE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// This function pointer represents the callback made to the application in
+// cases where a remote host requests a software update be performed. The
+// application should use this to trigger a call to SoftwareUpdateBegin from
+// a non-interrupt context.
+//
+//*****************************************************************************
+typedef void (*tSoftwareUpdateRequested)(void);
+
+//*****************************************************************************
+//
+// Public function prototypes.
+//
+//*****************************************************************************
+extern void SoftwareUpdateInit(tSoftwareUpdateRequested pfnCallback);
+extern void SoftwareUpdateBegin(uint32_t ui32SysClock);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SWUPDATE_H__
diff --git a/utils/tftp.c b/utils/tftp.c
new file mode 100644
index 0000000..674c307
--- /dev/null
+++ b/utils/tftp.c
@@ -0,0 +1,710 @@
+//*****************************************************************************
+//
+// tftp.c - A very simple lwIP TFTP server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "utils/uartstdio.h"
+#include "utils/lwiplib.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup tftp_api
+//! @{
+//
+//*****************************************************************************
+#include "utils/tftp.h"
+
+//*****************************************************************************
+//
+// The TFTP commands.
+//
+//*****************************************************************************
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DATA 3
+#define TFTP_ACK 4
+#define TFTP_ERROR 5
+
+//*****************************************************************************
+//
+// The UDP port for the TFTP server.
+//
+//*****************************************************************************
+#define TFTP_PORT 69
+
+//*****************************************************************************
+//
+// Application connection notification callback.
+//
+//*****************************************************************************
+static tTFTPRequest g_pfnRequest;
+
+//*****************************************************************************
+//
+// Close the TFTP connection and free associated resources.
+//
+//*****************************************************************************
+static void
+TFTPClose(tTFTPConnection *psTFTP)
+{
+ //
+ // Tell the application we are closing the connection.
+ //
+ if(psTFTP->pfnClose)
+ {
+ psTFTP->pfnClose(psTFTP);
+ }
+
+ //
+ // Close the underlying UDP connection.
+ //
+ udp_remove(psTFTP->psPCB);
+
+ //
+ // Free the instance data structure.
+ //
+ mem_free(psTFTP);
+}
+
+//*****************************************************************************
+//
+// Sends a TFTP error packet.
+//
+//*****************************************************************************
+static void
+TFTPErrorSend(tTFTPConnection *psTFTP, tTFTPError eError)
+{
+ uint32_t ui32Length;
+ uint8_t *pui8Data;
+ struct pbuf *p;
+
+ //
+ // How big is this packet going to be?
+ //
+ ui32Length = 5 + strlen(psTFTP->pcErrorString);
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, ui32Length, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet.
+ //
+ pui8Data[0] = (TFTP_ERROR >> 8) & 0xff;
+ pui8Data[1] = TFTP_ERROR & 0xff;
+ pui8Data[2] = ((uint32_t)eError >> 8) & 0xff;
+ pui8Data[3] = (uint32_t)eError & 0xff;
+ memcpy(&pui8Data[4], psTFTP->pcErrorString, ui32Length - 5);
+
+ //
+ // Send the data packet.
+ //
+ udp_send(psTFTP->psPCB, p);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Sends a TFTP data packet.
+//
+//*****************************************************************************
+static void
+TFTPDataSend(tTFTPConnection *psTFTP)
+{
+ uint32_t ui32Length;
+ uint8_t *pui8Data;
+ tTFTPError eError;
+ struct pbuf *p;
+
+ //
+ // Determine the number of bytes to place into this packet.
+ //
+ if(psTFTP->ui32DataRemaining < (psTFTP->ui32BlockNum * TFTP_BLOCK_SIZE))
+ {
+ ui32Length = psTFTP->ui32DataRemaining & (TFTP_BLOCK_SIZE - 1);
+ }
+ else
+ {
+ ui32Length = TFTP_BLOCK_SIZE;
+ }
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, ui32Length + 4, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet header.
+ //
+ pui8Data[0] = (TFTP_DATA >> 8) & 0xff;
+ pui8Data[1] = TFTP_DATA & 0xff;
+ pui8Data[2] = (psTFTP->ui32BlockNum >> 8) & 0xff;
+ pui8Data[3] = psTFTP->ui32BlockNum & 0xff;
+
+ //
+ // Ask the application to provide the data we need.
+ //
+ psTFTP->pui8Data = pui8Data + 4;
+ psTFTP->ui32DataLength = ui32Length;
+ eError = psTFTP->pfnGetData(psTFTP);
+
+ //
+ // Send the data packet or, if an error was reported, send an error.
+ //
+ if(eError == TFTP_OK)
+ {
+ udp_send(psTFTP->psPCB, p);
+ }
+ else
+ {
+ TFTPErrorSend(psTFTP, eError);
+ TFTPClose(psTFTP);
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Send an ACK packet back to the TFTP client.
+//
+//*****************************************************************************
+static void
+TFTPDataAck(tTFTPConnection *psTFTP)
+{
+ uint8_t *pui8Data;
+ struct pbuf *p;
+
+ //
+ // Allocate a pbuf for this data packet.
+ //
+ p = pbuf_alloc(PBUF_TRANSPORT, 4, PBUF_RAM);
+ if(!p)
+ {
+ return;
+ }
+
+ //
+ // Get a pointer to the data packet.
+ //
+ pui8Data = (uint8_t *)p->payload;
+
+ //
+ // Fill in the packet header.
+ //
+ pui8Data[0] = (TFTP_ACK >> 8) & 0xff;
+ pui8Data[1] = TFTP_ACK & 0xff;
+ pui8Data[2] = (psTFTP->ui32BlockNum >> 8) & 0xff;
+ pui8Data[3] = psTFTP->ui32BlockNum & 0xff;
+
+ //
+ // Send the data packet.
+ //
+ udp_send(psTFTP->psPCB, p);
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Handles datagrams received from the TFTP data connection.
+//
+//*****************************************************************************
+static void
+TFTPDataRecv(void *arg, struct udp_pcb *upcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ uint8_t *pui8Data;
+ uint32_t ui32Block;
+ struct pbuf *pBuf;
+ tTFTPConnection *psTFTP;
+ tTFTPError eRetcode;
+
+ //
+ // Initialize our return code.
+ //
+ eRetcode = TFTP_ERR_NOT_DEFINED;
+
+ //
+ // Get a pointer to the connection instance data.
+ //
+ psTFTP = (tTFTPConnection *)arg;
+
+ //
+ // Get a pointer to the TFTP packet.
+ //
+ pui8Data = (uint8_t *)(p->payload);
+
+ //
+ // If this is an ACK packet, send back the next block to satisfy an
+ // ongoing GET (read) request.
+ //
+ if((pui8Data[0] == ((TFTP_ACK >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_ACK & 0xff)))
+ {
+ //
+ // Extract the block number from the acknowledge.
+ //
+ ui32Block = (pui8Data[2] << 8) + pui8Data[3];
+
+ //
+ // DEBUG ONLY!
+ //
+ UARTprintf("ACK %d\n", ui32Block);
+
+ //
+ // See if there is more data to be sent. Note that we need the "<="
+ // here to ensure that we send back a zero length packet in the case
+ // that the file is a multiple of 512 bytes (in other words, the last
+ // packet of valid data was a full packet).
+ //
+ if((ui32Block * TFTP_BLOCK_SIZE) <= psTFTP->ui32DataRemaining)
+ {
+ //
+ // Send the next block of the file.
+ //
+ psTFTP->ui32BlockNum = ui32Block + 1;
+ TFTPDataSend(psTFTP);
+ }
+ else
+ {
+ //
+ // The transfer is complete, so close the data connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ else
+ {
+ //
+ // If this is a DATA packet, get the payload and write it to the
+ // appropriate location in the serial flash.
+ //
+ if((pui8Data[0] == ((TFTP_DATA >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_DATA & 0xff)))
+ {
+ //
+ // This is a data packet. Extract the block number from the packet
+ // and set the offset within the block (stored in
+ // ui32DataRemaining) to zero.
+ //
+ psTFTP->ui32BlockNum = (pui8Data[2] << 8) + pui8Data[3];
+ psTFTP->ui32DataRemaining = 0;
+ psTFTP->ui32DataLength = p->len - 4;
+
+ //
+ // Pass the data back to the application for handling. Remember
+ // that the data may be stored across several pbufs in the chain.
+ // We can't assume it is in a contiguous block.
+ //
+ psTFTP->pui8Data = pui8Data + 4;
+ pBuf = p;
+
+ //
+ // Keep writing until we run out of data.
+ //
+ while(pBuf)
+ {
+ //
+ // Pass this block to the application.
+ //
+ eRetcode = psTFTP->pfnPutData(psTFTP);
+
+ //
+ // Was the data written successfully?
+ //
+ if(eRetcode != TFTP_OK)
+ {
+ //
+ // No - drop out.
+ //
+ break;
+ }
+
+ //
+ // Update the offset so that it is correct for the next pbuf
+ // in the chain.
+ //
+ psTFTP->ui32DataRemaining += psTFTP->ui32DataLength;
+
+ //
+ // Move to the next pbuf in the chain
+ //
+ pBuf = pBuf->next;
+ if(pBuf)
+ {
+ psTFTP->pui8Data = pBuf->payload;
+ psTFTP->ui32DataLength = pBuf->len;
+ }
+ }
+
+ //
+ // If we get here and there was an error reported, pass the error
+ // back to the TFTP client.
+ //
+ if(psTFTP && (eRetcode != TFTP_OK))
+ {
+ //
+ // Send the error code to the client.
+ //
+ TFTPErrorSend(psTFTP, eRetcode);
+
+ //
+ // Close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ else
+ {
+ //
+ // Acknowledge this block.
+ //
+ TFTPDataAck(psTFTP);
+
+ //
+ // Is the transfer finished?
+ //
+ if(p->tot_len < (TFTP_BLOCK_SIZE + 4))
+ {
+ //
+ // We got a short packet so the transfer is complete.
+ // Close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Is the client reporting an error?
+ //
+ if((pui8Data[0] == ((TFTP_ERROR >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_ERROR & 0xff)))
+ {
+ //
+ // Yes - we got an error so close the connection.
+ //
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+// Parses the request string to determine the transfer mode, netascii, octet or
+// mail, for this request.
+//
+//*****************************************************************************
+static tTFTPMode
+TFTPModeGet(uint8_t *pui8Request, uint32_t ui32Len)
+{
+ uint32_t ui32Loop, ui32Max;
+
+ //
+ // Look for the first zero after the start of the filename string (skipping
+ // the first two bytes of the request packet).
+ //
+ for(ui32Loop = 2; ui32Loop < ui32Len; ui32Loop++)
+ {
+ if(pui8Request[ui32Loop] == (uint8_t)0)
+ {
+ break;
+ }
+ }
+
+ //
+ // Skip past the zero.
+ //
+ ui32Loop++;
+
+ //
+ // Did we run off the end of the string?
+ //
+ if(ui32Loop >= ui32Len)
+ {
+ //
+ // Yes - this appears to be an invalid request.
+ //
+ return(TFTP_MODE_INVALID);
+ }
+
+ //
+ // How much data do we have left to look for the mode string?
+ //
+ ui32Max = ui32Len - ui32Loop;
+
+ //
+ // Now determine which of the modes this request asks for. Is it ASCII?
+ //
+ if(!ustrncasecmp("netascii", (char *)&pui8Request[ui32Loop], ui32Max))
+ {
+ //
+ // This is an ASCII file transfer.
+ //
+ return(TFTP_MODE_NETASCII);
+ }
+
+ //
+ // Binary transfer?
+ //
+ if(!ustrncasecmp("octet", (char *)&pui8Request[ui32Loop], ui32Max))
+ {
+ //
+ // This is a binary file transfer.
+ //
+ return(TFTP_MODE_OCTET);
+ }
+
+ //
+ // All other strings are invalid or obsolete ("mail" for example).
+ //
+ return(TFTP_MODE_INVALID);
+}
+
+//*****************************************************************************
+//
+// Handles datagrams received on the TFTP server port.
+//
+//*****************************************************************************
+static void
+TFTPRecv(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr,
+ u16_t port)
+{
+ uint8_t *pui8Data;
+ bool bGetRequest;
+ tTFTPMode eMode;
+ tTFTPError eRetcode;
+ tTFTPConnection *psTFTP;
+
+ //
+ // Get a pointer to the TFTP packet.
+ //
+ pui8Data = (uint8_t *)(p->payload);
+
+ //
+ // Is this a read (GET) request?
+ //
+ if((pui8Data[0] == ((TFTP_RRQ >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_RRQ & 0xff)))
+ {
+ //
+ // Yes - remember that this is a GET request.
+ //
+ bGetRequest = true;
+ }
+
+ //
+ // Is this a write (PUT) request?
+ //
+ else if((pui8Data[0] == ((TFTP_WRQ >> 8) & 0xff)) &&
+ (pui8Data[1] == (TFTP_WRQ & 0xff)))
+ {
+ //
+ // Yes - remember that this is a PUT request.
+ //
+ bGetRequest = false;
+ }
+ else
+ {
+ //
+ // The request is neither GET nor PUT so just ignore it.
+ //
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // What is the mode for this request?
+ //
+ eMode = TFTPModeGet(pui8Data, p->len);
+
+ //
+ // Was the transfer mode valid?
+ //
+ if(eMode != TFTP_MODE_INVALID)
+ {
+ //
+ // The transfer mode is valid so allocate a new connection instance
+ // and pass this to the client to have it tell us how to proceed.
+ //
+ psTFTP = (tTFTPConnection *)mem_malloc(sizeof(tTFTPConnection));
+
+ //
+ // If we can't allocate the connection instance, all we can do is
+ // ignore the datagram.
+ //
+ if(!psTFTP)
+ {
+ pbuf_free(p);
+ return;
+ }
+
+ //
+ // Clear out the structure and initialize a few fields.
+ //
+ memset(psTFTP, 0, sizeof(tTFTPConnection));
+ psTFTP->pcErrorString = "Unknown error";
+
+ //
+ // Yes - create the new UDP connection and set things up to
+ // handle this request.
+ //
+ psTFTP->psPCB = udp_new();
+ udp_recv(psTFTP->psPCB, TFTPDataRecv, psTFTP);
+ udp_connect(psTFTP->psPCB, addr, port);
+
+ //
+ // Ask the application if it wants to proceed with this request.
+ //
+ eRetcode = g_pfnRequest(psTFTP, bGetRequest, (int8_t *)(pui8Data + 2),
+ eMode);
+
+ //
+ // Does it want to go on?
+ //
+ if(eRetcode == TFTP_OK)
+ {
+ //
+ // Yes - what kind of request is this?
+ //
+ if(bGetRequest)
+ {
+ //
+ // For a GET request, we send back the first block of data.
+ //
+ psTFTP->ui32BlockNum = 1;
+ TFTPDataSend(psTFTP);
+ }
+ else
+ {
+ //
+ // For a PUT request, we acknowledge the transfer which tells
+ // the TFTP client that it can start sending us data.
+ //
+ psTFTP->ui32BlockNum = 0;
+ TFTPDataAck(psTFTP);
+ }
+ }
+ else
+ {
+ //
+ // The application indicated that there was an error. Send the
+ // error report and close the connection.
+ //
+ TFTPErrorSend(psTFTP, eRetcode);
+ TFTPClose(psTFTP);
+ psTFTP = NULL;
+ }
+ }
+
+ //
+ // Free the pbuf.
+ //
+ pbuf_free(p);
+}
+
+//*****************************************************************************
+//
+//! Initializes the TFTP server module.
+//!
+//! \param pfnRequest - A pointer to the function which the server will call
+//! whenever a new incoming TFTP request is received. This function must
+//! determine whether the request can be handled and return a value telling the
+//! server whether to continue processing the request or ignore it.
+//!
+//! This function initializes the lwIP TFTP server and starts listening for
+//! incoming requests from clients. It must be called after the network stack
+//! is initialized using a call to lwIPInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TFTPInit(tTFTPRequest pfnRequest)
+{
+ void *pcb;
+
+ //
+ // Remember the application's notification callback.
+ //
+ g_pfnRequest = pfnRequest;
+
+ //
+ // Start listening for incoming TFTP requests.
+ //
+ pcb = udp_new();
+ udp_recv(pcb, TFTPRecv, NULL);
+ udp_bind(pcb, IP_ADDR_ANY, TFTP_PORT);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/tftp.h b/utils/tftp.h
new file mode 100644
index 0000000..b02b8ea
--- /dev/null
+++ b/utils/tftp.h
@@ -0,0 +1,215 @@
+//*****************************************************************************
+//
+// tftp.h - Public function prototypes and globals related to the lwIP TFTP
+// server.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup tftp_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! TFTP error codes. Note that this enum is mapped so that all positive
+//! values match the TFTP protocol-defined error codes.
+//
+//*****************************************************************************
+typedef enum
+{
+ TFTP_OK = -1,
+ TFTP_ERR_NOT_DEFINED = 0,
+ TFTP_FILE_NOT_FOUND = 1,
+ TFTP_ACCESS_VIOLATION = 2,
+ TFTP_DISK_FULL = 3,
+ TFTP_ILLEGAL_OP = 4,
+ TFTP_UNKNOWN_TID = 5,
+ TFTP_FILE_EXISTS = 6,
+ TFTP_NO_SUCH_USER = 7
+}
+tTFTPError;
+
+//*****************************************************************************
+//
+//! TFTP file transfer modes. This enum contains members defining ASCII
+//! text transfer mode (TFTP_MODE_NETASCII), binary transfer mode
+//! (TFTP_MODE_OCTET) and a marker for an invalid mode (TFTP_MODE_INVALID).
+//
+//*****************************************************************************
+typedef enum
+{
+ TFTP_MODE_NETASCII,
+ TFTP_MODE_OCTET,
+ TFTP_MODE_INVALID
+}
+tTFTPMode;
+
+//*****************************************************************************
+//
+//! Data transfer under TFTP is performed using fixed-size blocks. This label
+//! defines the size of a block of TFTP data.
+//
+//*****************************************************************************
+#define TFTP_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// Callback function prototypes passed to TFTPInit. These functions receive
+// notification of incoming GET and PUT requests, allowing the client to decide
+// whether to accept the request or not.
+//
+//*****************************************************************************
+struct _tTFTPConnection;
+
+typedef tTFTPError (*tTFTPRequest)(struct _tTFTPConnection *psTFTP, bool bGet,
+ int8_t *pui8FileName, tTFTPMode eMode);
+typedef tTFTPError (*tTFTPTransfer)(struct _tTFTPConnection *psTFTP);
+typedef void (*tTFTPClose)(struct _tTFTPConnection *psTFTP);
+
+//*****************************************************************************
+//
+//! The TFTP connection control structure. This is passed to a client on all
+//! callbacks relating to a given TFTP connection. Depending upon the
+//! callback, the client may need to fill in values to various fields or use
+//! field values to determine where to transfer data from or to.
+//
+//*****************************************************************************
+typedef struct _tTFTPConnection
+{
+ //
+ //! Pointer to the start of the buffer into which GET data should be copied
+ //! or from which PUT data should be read.
+ //
+ uint8_t *pui8Data;
+
+ //
+ //! The length of the data requested in response to a single pfnGetData
+ //! callback or the size of the received data for a pfnPutData callback.
+ //
+ uint32_t ui32DataLength;
+
+ //
+ //! Count of remaining bytes to send during a GET request or the byte
+ //! offset within a block during a PUT request. The application must set
+ //! this field to the size of the requested file during the tTFTPRequest
+ // callback if a GET request is to be accepted.
+ //
+ uint32_t ui32DataRemaining;
+
+ //
+ //! Application function which is called whenever more data is required to
+ //! satisfy a GET request. The function must copy ui32DataLength bytes
+ //! into the buffer pointed to by pui8Data.
+ //
+ tTFTPTransfer pfnGetData;
+
+ //
+ //! Application function which is called whenever a packet of file data is
+ //! received during a PUT request. The function must save the data to the
+ //! target file using ui32BlockNum and ui32DataRemaining to indicate the
+ //! position of the data in the file, and return an appropriate error code.
+ //! Note that several calls to this function may be made for a given
+ //! received TFTP block since the underlying networking stack may have
+ //! split the TFTP packet between several packets and a callback is made
+ //! for each of these. This avoids the need for a 512 byte buffer. The
+ //! ui32DataRemaining is used in these cases to indicate the offset of the
+ //! data within the current block.
+ //
+ tTFTPTransfer pfnPutData;
+
+ //
+ //! Application function which is called when the TFTP connection is to
+ //! be closed. The function should tidy up and free any resources
+ //! associated with the connection prior to returning.
+ //
+ tTFTPClose pfnClose;
+
+ //
+ //! This field may be used by the client to store an application-specific
+ //! pointer that will be accessible on all callbacks from the TFTP module
+ //! relating to this connection.
+ //
+ uint8_t *pui8User;
+
+ //
+ //! Pointer to an error string which the client must fill in if reporting
+ //! an error. This string will be sent to the TFTP client in any case
+ //! where pfnPutData or pfnGetData return a value other than TFTP_OK.
+ //
+ char *pcErrorString;
+
+ //
+ //! A pointer to the underlying UDP connection. Applications must not
+ //! modify this field.
+ //
+ struct udp_pcb *psPCB;
+
+ //
+ //! The current block number for an ongoing TFTP transfer. Applications
+ //! may read this value to determine which data to return on a pfnGetData
+ //! callback or where to write incoming data on a pfnPutData callback but
+ //! must not modify it.
+ //
+ uint32_t ui32BlockNum;
+}
+tTFTPConnection;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes.
+//
+//*****************************************************************************
+extern void TFTPInit(tTFTPRequest pfnRequest);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __TFTP_H__
diff --git a/utils/uartstdio.c b/utils/uartstdio.c
new file mode 100644
index 0000000..8ec2eaa
--- /dev/null
+++ b/utils/uartstdio.c
@@ -0,0 +1,1720 @@
+//*****************************************************************************
+//
+// uartstdio.c - Utility driver to provide simple UART console functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/uart.h"
+#include "utils/uartstdio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup uartstdio_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If buffered mode is defined, set aside RX and TX buffers and read/write
+// pointers to control them.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+
+//*****************************************************************************
+//
+// This global controls whether or not we are echoing characters back to the
+// transmitter. By default, echo is enabled but if using this module as a
+// convenient method of implementing a buffered serial interface over which
+// you will be running an application protocol, you are likely to want to
+// disable echo by calling UARTEchoSet(false).
+//
+//*****************************************************************************
+static bool g_bDisableEcho;
+
+//*****************************************************************************
+//
+// Output ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of
+// g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE];
+static volatile uint32_t g_ui32UARTTxWriteIndex = 0;
+static volatile uint32_t g_ui32UARTTxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Input ring buffer. Buffer is full if g_ui32UARTTxReadIndex is one ahead of
+// g_ui32UARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE];
+static volatile uint32_t g_ui32UARTRxWriteIndex = 0;
+static volatile uint32_t g_ui32UARTRxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Macros to determine number of free and used bytes in the transmit buffer.
+//
+//*****************************************************************************
+#define TX_BUFFER_USED (GetBufferCount(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex, \
+ UART_TX_BUFFER_SIZE))
+#define TX_BUFFER_FREE (UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
+#define TX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex))
+#define TX_BUFFER_FULL (IsBufferFull(&g_ui32UARTTxReadIndex, \
+ &g_ui32UARTTxWriteIndex, \
+ UART_TX_BUFFER_SIZE))
+#define ADVANCE_TX_BUFFER_INDEX(Index) \
+ (Index) = ((Index) + 1) % UART_TX_BUFFER_SIZE
+
+//*****************************************************************************
+//
+// Macros to determine number of free and used bytes in the receive buffer.
+//
+//*****************************************************************************
+#define RX_BUFFER_USED (GetBufferCount(&g_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex, \
+ UART_RX_BUFFER_SIZE))
+#define RX_BUFFER_FREE (UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
+#define RX_BUFFER_EMPTY (IsBufferEmpty(&g_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex))
+#define RX_BUFFER_FULL (IsBufferFull(&g_ui32UARTRxReadIndex, \
+ &g_ui32UARTRxWriteIndex, \
+ UART_RX_BUFFER_SIZE))
+#define ADVANCE_RX_BUFFER_INDEX(Index) \
+ (Index) = ((Index) + 1) % UART_RX_BUFFER_SIZE
+#endif
+
+//*****************************************************************************
+//
+// The base address of the chosen UART.
+//
+//*****************************************************************************
+static uint32_t g_ui32Base = 0;
+
+//*****************************************************************************
+//
+// A mapping from an integer between 0 and 15 to its ASCII character
+// equivalent.
+//
+//*****************************************************************************
+static const char * const g_pcHex = "0123456789abcdef";
+
+//*****************************************************************************
+//
+// The list of possible base addresses for the console UART.
+//
+//*****************************************************************************
+static const uint32_t g_ui32UARTBase[3] =
+{
+ UART0_BASE, UART1_BASE, UART2_BASE
+};
+
+#ifdef UART_BUFFERED
+//*****************************************************************************
+//
+// The list of possible interrupts for the console UART.
+//
+//*****************************************************************************
+static const uint32_t g_ui32UARTInt[3] =
+{
+ INT_UART0, INT_UART1, INT_UART2
+};
+
+//*****************************************************************************
+//
+// The port number in use.
+//
+//*****************************************************************************
+static uint32_t g_ui32PortNum;
+#endif
+
+//*****************************************************************************
+//
+// The list of UART peripherals.
+//
+//*****************************************************************************
+static const uint32_t g_ui32UARTPeriph[3] =
+{
+ SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2
+};
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is full or not.
+//!
+//! \param pui32Read points to the read index for the buffer.
+//! \param pui32Write points to the write index for the buffer.
+//! \param ui32Size is the size of the buffer in bytes.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure of the code is specifically to ensure that we do not
+//! see warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is full or \b false otherwise.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static bool
+IsBufferFull(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write, uint32_t ui32Size)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((((ui32Write + 1) % ui32Size) == ui32Read) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param pui32Read points to the read index for the buffer.
+//! \param pui32Write points to the write index for the buffer.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure of the code is specifically to ensure that we do not
+//! see warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is empty or \b false otherwise.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static bool
+IsBufferEmpty(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((ui32Write == ui32Read) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines the number of bytes of data contained in a ring buffer.
+//!
+//! \param pui32Read points to the read index for the buffer.
+//! \param pui32Write points to the write index for the buffer.
+//! \param ui32Size is the size of the buffer in bytes.
+//!
+//! This function is used to determine how many bytes of data a given ring
+//! buffer currently contains. The structure of the code is specifically to
+//! ensure that we do not see warnings from the compiler related to the order
+//! of volatile accesses being undefined.
+//!
+//! \return Returns the number of bytes of data currently in the buffer.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static uint32_t
+GetBufferCount(volatile uint32_t *pui32Read,
+ volatile uint32_t *pui32Write, uint32_t ui32Size)
+{
+ uint32_t ui32Write;
+ uint32_t ui32Read;
+
+ ui32Write = *pui32Write;
+ ui32Read = *pui32Read;
+
+ return((ui32Write >= ui32Read) ? (ui32Write - ui32Read) :
+ (ui32Size - (ui32Read - ui32Write)));
+}
+#endif
+
+//*****************************************************************************
+//
+// Take as many bytes from the transmit buffer as we have space for and move
+// them into the UART transmit FIFO.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static void
+UARTPrimeTransmit(uint32_t ui32Base)
+{
+ //
+ // Do we have any data to transmit?
+ //
+ if(!TX_BUFFER_EMPTY)
+ {
+ //
+ // Disable the UART interrupt. If we don't do this there is a race
+ // condition which can cause the read index to be corrupted.
+ //
+ MAP_IntDisable(g_ui32UARTInt[g_ui32PortNum]);
+
+ //
+ // Yes - take some characters out of the transmit buffer and feed
+ // them to the UART transmit FIFO.
+ //
+ while(MAP_UARTSpaceAvail(ui32Base) && !TX_BUFFER_EMPTY)
+ {
+ MAP_UARTCharPutNonBlocking(ui32Base,
+ g_pcUARTTxBuffer[g_ui32UARTTxReadIndex]);
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxReadIndex);
+ }
+
+ //
+ // Reenable the UART interrupt.
+ //
+ MAP_IntEnable(g_ui32UARTInt[g_ui32PortNum]);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Configures the UART console.
+//!
+//! \param ui32PortNum is the number of UART port to use for the serial console
+//! (0-2)
+//! \param ui32Baud is the bit rate that the UART is to be configured to use.
+//! \param ui32SrcClock is the frequency of the source clock for the UART
+//! module.
+//!
+//! This function will configure the specified serial port to be used as a
+//! serial console. The serial parameters are set to the baud rate
+//! specified by the \e ui32Baud parameter and use 8 bit, no parity, and 1 stop
+//! bit.
+//!
+//! This function must be called prior to using any of the other UART console
+//! functions: UARTprintf() or UARTgets(). This function assumes that the
+//! caller has previously configured the relevant UART pins for operation as a
+//! UART rather than as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTStdioConfig(uint32_t ui32PortNum, uint32_t ui32Baud, uint32_t ui32SrcClock)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32PortNum == 0) || (ui32PortNum == 1) ||
+ (ui32PortNum == 2));
+
+#ifdef UART_BUFFERED
+ //
+ // In buffered mode, we only allow a single instance to be opened.
+ //
+ ASSERT(g_ui32Base == 0);
+#endif
+
+ //
+ // Check to make sure the UART peripheral is present.
+ //
+ if(!MAP_SysCtlPeripheralPresent(g_ui32UARTPeriph[ui32PortNum]))
+ {
+ return;
+ }
+
+ //
+ // Select the base address of the UART.
+ //
+ g_ui32Base = g_ui32UARTBase[ui32PortNum];
+
+ //
+ // Enable the UART peripheral for use.
+ //
+ MAP_SysCtlPeripheralEnable(g_ui32UARTPeriph[ui32PortNum]);
+
+ //
+ // Configure the UART for 115200, n, 8, 1
+ //
+ MAP_UARTConfigSetExpClk(g_ui32Base, ui32SrcClock, ui32Baud,
+ (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
+ UART_CONFIG_WLEN_8));
+
+#ifdef UART_BUFFERED
+ //
+ // Set the UART to interrupt whenever the TX FIFO is almost empty or
+ // when any character is received.
+ //
+ MAP_UARTFIFOLevelSet(g_ui32Base, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
+
+ //
+ // Flush both the buffers.
+ //
+ UARTFlushRx();
+ UARTFlushTx(true);
+
+ //
+ // Remember which interrupt we are dealing with.
+ //
+ g_ui32PortNum = ui32PortNum;
+
+ //
+ // We are configured for buffered output so enable the master interrupt
+ // for this UART and the receive interrupts. We don't actually enable the
+ // transmit interrupt in the UART itself until some data has been placed
+ // in the transmit buffer.
+ //
+ MAP_UARTIntDisable(g_ui32Base, 0xFFFFFFFF);
+ MAP_UARTIntEnable(g_ui32Base, UART_INT_RX | UART_INT_RT);
+ MAP_IntEnable(g_ui32UARTInt[ui32PortNum]);
+#endif
+
+ //
+ // Enable the UART operation.
+ //
+ MAP_UARTEnable(g_ui32Base);
+}
+
+//*****************************************************************************
+//
+//! Writes a string of characters to the UART output.
+//!
+//! \param pcBuf points to a buffer containing the string to transmit.
+//! \param ui32Len is the length of the string to transmit.
+//!
+//! This function will transmit the string to the UART output. The number of
+//! characters transmitted is determined by the \e ui32Len parameter. This
+//! function does no interpretation or translation of any characters. Since
+//! the output is sent to a UART, any LF (/n) characters encountered will be
+//! replaced with a CRLF pair.
+//!
+//! Besides using the \e ui32Len parameter to stop transmitting the string, if
+//! a null character (0) is encountered, then no more characters will be
+//! transmitted and the function will return.
+//!
+//! In non-buffered mode, this function is blocking and will not return until
+//! all the characters have been written to the output FIFO. In buffered mode,
+//! the characters are written to the UART transmit buffer and the call returns
+//! immediately. If insufficient space remains in the transmit buffer,
+//! additional characters are discarded.
+//!
+//! \return Returns the count of characters written.
+//
+//*****************************************************************************
+int
+UARTwrite(const char *pcBuf, uint32_t ui32Len)
+{
+#ifdef UART_BUFFERED
+ unsigned int uIdx;
+
+ //
+ // Check for valid arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ui32Len; uIdx++)
+ {
+ //
+ // If the character to the UART is \n, then add a \r before it so that
+ // \n is translated to \n\r in the output.
+ //
+ if(pcBuf[uIdx] == '\n')
+ {
+ if(!TX_BUFFER_FULL)
+ {
+ g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = '\r';
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
+ }
+ else
+ {
+ //
+ // Buffer is full - discard remaining characters and return.
+ //
+ break;
+ }
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ if(!TX_BUFFER_FULL)
+ {
+ g_pcUARTTxBuffer[g_ui32UARTTxWriteIndex] = pcBuf[uIdx];
+ ADVANCE_TX_BUFFER_INDEX(g_ui32UARTTxWriteIndex);
+ }
+ else
+ {
+ //
+ // Buffer is full - discard remaining characters and return.
+ //
+ break;
+ }
+ }
+
+ //
+ // If we have anything in the buffer, make sure that the UART is set
+ // up to transmit it.
+ //
+ if(!TX_BUFFER_EMPTY)
+ {
+ UARTPrimeTransmit(g_ui32Base);
+ MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
+ }
+
+ //
+ // Return the number of characters written.
+ //
+ return(uIdx);
+#else
+ unsigned int uIdx;
+
+ //
+ // Check for valid UART base address, and valid arguments.
+ //
+ ASSERT(g_ui32Base != 0);
+ ASSERT(pcBuf != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ui32Len; uIdx++)
+ {
+ //
+ // If the character to the UART is \n, then add a \r before it so that
+ // \n is translated to \n\r in the output.
+ //
+ if(pcBuf[uIdx] == '\n')
+ {
+ MAP_UARTCharPut(g_ui32Base, '\r');
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ MAP_UARTCharPut(g_ui32Base, pcBuf[uIdx]);
+ }
+
+ //
+ // Return the number of characters written.
+ //
+ return(uIdx);
+#endif
+}
+
+//*****************************************************************************
+//
+//! A simple UART based get string function, with some line processing.
+//!
+//! \param pcBuf points to a buffer for the incoming string from the UART.
+//! \param ui32Len is the length of the buffer for storage of the string,
+//! including the trailing 0.
+//!
+//! This function will receive a string from the UART input and store the
+//! characters in the buffer pointed to by \e pcBuf. The characters will
+//! continue to be stored until a termination character is received. The
+//! termination characters are CR, LF, or ESC. A CRLF pair is treated as a
+//! single termination character. The termination characters are not stored in
+//! the string. The string will be terminated with a 0 and the function will
+//! return.
+//!
+//! In both buffered and unbuffered modes, this function will block until
+//! a termination character is received. If non-blocking operation is required
+//! in buffered mode, a call to UARTPeek() may be made to determine whether
+//! a termination character already exists in the receive buffer prior to
+//! calling UARTgets().
+//!
+//! Since the string will be null terminated, the user must ensure that the
+//! buffer is sized to allow for the additional null character.
+//!
+//! \return Returns the count of characters that were stored, not including
+//! the trailing 0.
+//
+//*****************************************************************************
+int
+UARTgets(char *pcBuf, uint32_t ui32Len)
+{
+#ifdef UART_BUFFERED
+ uint32_t ui32Count = 0;
+ int8_t cChar;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ui32Len != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ui32Len--;
+
+ //
+ // Process characters until a newline is received.
+ //
+ while(1)
+ {
+ //
+ // Read the next character from the receive buffer.
+ //
+ if(!RX_BUFFER_EMPTY)
+ {
+ cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // Stop processing the input and end the line.
+ //
+ break;
+ }
+
+ //
+ // Process the received character as long as we are not at the end
+ // of the buffer. If the end of the buffer has been reached then
+ // all additional characters are ignored until a newline is
+ // received.
+ //
+ if(ui32Count < ui32Len)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ui32Count] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ui32Count++;
+ }
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ui32Count] = 0;
+
+ //
+ // Return the count of int8_ts in the buffer, not counting the trailing 0.
+ //
+ return(ui32Count);
+#else
+ uint32_t ui32Count = 0;
+ int8_t cChar;
+ static int8_t bLastWasCR = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ui32Len != 0);
+ ASSERT(g_ui32Base != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ui32Len--;
+
+ //
+ // Process characters until a newline is received.
+ //
+ while(1)
+ {
+ //
+ // Read the next character from the console.
+ //
+ cChar = MAP_UARTCharGet(g_ui32Base);
+
+ //
+ // See if the backspace key was pressed.
+ //
+ if(cChar == '\b')
+ {
+ //
+ // If there are any characters already in the buffer, then delete
+ // the last.
+ //
+ if(ui32Count)
+ {
+ //
+ // Rub out the previous character.
+ //
+ UARTwrite("\b \b", 3);
+
+ //
+ // Decrement the number of characters in the buffer.
+ //
+ ui32Count--;
+ }
+
+ //
+ // Skip ahead to read the next character.
+ //
+ continue;
+ }
+
+ //
+ // If this character is LF and last was CR, then just gobble up the
+ // character because the EOL processing was taken care of with the CR.
+ //
+ if((cChar == '\n') && bLastWasCR)
+ {
+ bLastWasCR = 0;
+ continue;
+ }
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // If the character is a CR, then it may be followed by a LF which
+ // should be paired with the CR. So remember that a CR was
+ // received.
+ //
+ if(cChar == '\r')
+ {
+ bLastWasCR = 1;
+ }
+
+ //
+ // Stop processing the input and end the line.
+ //
+ break;
+ }
+
+ //
+ // Process the received character as long as we are not at the end of
+ // the buffer. If the end of the buffer has been reached then all
+ // additional characters are ignored until a newline is received.
+ //
+ if(ui32Count < ui32Len)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ui32Count] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ui32Count++;
+
+ //
+ // Reflect the character back to the user.
+ //
+ MAP_UARTCharPut(g_ui32Base, cChar);
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ui32Count] = 0;
+
+ //
+ // Send a CRLF pair to the terminal to end the line.
+ //
+ UARTwrite("\r\n", 2);
+
+ //
+ // Return the count of int8_ts in the buffer, not counting the trailing 0.
+ //
+ return(ui32Count);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Read a single character from the UART, blocking if necessary.
+//!
+//! This function will receive a single character from the UART and store it at
+//! the supplied address.
+//!
+//! In both buffered and unbuffered modes, this function will block until a
+//! character is received. If non-blocking operation is required in buffered
+//! mode, a call to UARTRxAvail() may be made to determine whether any
+//! characters are currently available for reading.
+//!
+//! \return Returns the character read.
+//
+//*****************************************************************************
+unsigned char
+UARTgetc(void)
+{
+#ifdef UART_BUFFERED
+ unsigned char cChar;
+
+ //
+ // Wait for a character to be received.
+ //
+ while(RX_BUFFER_EMPTY)
+ {
+ //
+ // Block waiting for a character to be received (if the buffer is
+ // currently empty).
+ //
+ }
+
+ //
+ // Read a character from the buffer.
+ //
+ cChar = g_pcUARTRxBuffer[g_ui32UARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxReadIndex);
+
+ //
+ // Return the character to the caller.
+ //
+ return(cChar);
+#else
+ //
+ // Block until a character is received by the UART then return it to
+ // the caller.
+ //
+ return(MAP_UARTCharGet(g_ui32Base));
+#endif
+}
+
+//*****************************************************************************
+//
+//! A simple UART based vprintf function supporting \%c, \%d, \%p, \%s, \%u,
+//! \%x, and \%X.
+//!
+//! \param pcString is the format string.
+//! \param vaArgP is a variable argument list pointer whose content will depend
+//! upon the format string passed in \e pcString.
+//!
+//! This function is very similar to the C library <tt>vprintf()</tt> function.
+//! All of its output will be sent to the UART. Only the following formatting
+//! characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%s, \%d, \%i, \%u, \%p, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeroes instead of spaces.
+//!
+//! The type of the arguments in the variable arguments list must match the
+//! requirements of the format string. For example, if an integer was passed
+//! where a string was expected, an error of some kind will most likely occur.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTvprintf(const char *pcString, va_list vaArgP)
+{
+ uint32_t ui32Idx, ui32Value, ui32Pos, ui32Count, ui32Base, ui32Neg;
+ char *pcStr, pcBuf[16], cFill;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcString != 0);
+
+ //
+ // Loop while there are more characters in the string.
+ //
+ while(*pcString)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ui32Idx = 0;
+ (pcString[ui32Idx] != '%') && (pcString[ui32Idx] != '\0');
+ ui32Idx++)
+ {
+ }
+
+ //
+ // Write this portion of the string.
+ //
+ UARTwrite(pcString, ui32Idx);
+
+ //
+ // Skip the portion of the string that was written.
+ //
+ pcString += ui32Idx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*pcString == '%')
+ {
+ //
+ // Skip the %.
+ //
+ pcString++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (in other words, to the defaults).
+ //
+ ui32Count = 0;
+ cFill = ' ';
+
+ //
+ // It may be necessary to get back here to process more characters.
+ // Goto's aren't pretty, but effective. I feel extremely dirty for
+ // using not one but two of the beasts.
+ //
+again:
+
+ //
+ // Determine how to handle the next character.
+ //
+ switch(*pcString++)
+ {
+ //
+ // Handle the digit characters.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ //
+ // If this is a zero, and it is the first digit, then the
+ // fill character is a zero instead of a space.
+ //
+ if((pcString[-1] == '0') && (ui32Count == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ui32Count *= 10;
+ ui32Count += pcString[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Print out the character.
+ //
+ UARTwrite((char *)&ui32Value, 1);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // If the value is negative, make it positive and indicate
+ // that a minus sign is needed.
+ //
+ if((int32_t)ui32Value < 0)
+ {
+ //
+ // Make the value positive.
+ //
+ ui32Value = -(int32_t)ui32Value;
+
+ //
+ // Indicate that the value is negative.
+ //
+ ui32Neg = 1;
+ }
+ else
+ {
+ //
+ // Indicate that the value is positive so that a minus
+ // sign isn't inserted.
+ //
+ ui32Neg = 0;
+ }
+
+ //
+ // Set the base to 10.
+ //
+ ui32Base = 10;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %s command.
+ //
+ case 's':
+ {
+ //
+ // Get the string pointer from the varargs.
+ //
+ pcStr = va_arg(vaArgP, char *);
+
+ //
+ // Determine the length of the string.
+ //
+ for(ui32Idx = 0; pcStr[ui32Idx] != '\0'; ui32Idx++)
+ {
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcStr, ui32Idx);
+
+ //
+ // Write any required padding spaces
+ //
+ if(ui32Count > ui32Idx)
+ {
+ ui32Count -= ui32Idx;
+ while(ui32Count--)
+ {
+ UARTwrite(" ", 1);
+ }
+ }
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // Set the base to 10.
+ //
+ ui32Base = 10;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ui32Neg = 0;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %x and %X commands. Note that they are treated
+ // identically; in other words, %X will use lower case letters
+ // for a-f instead of the upper case letters it should use. We
+ // also alias %p to %x.
+ //
+ case 'x':
+ case 'X':
+ case 'p':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ui32Value = va_arg(vaArgP, uint32_t);
+
+ //
+ // Reset the buffer position.
+ //
+ ui32Pos = 0;
+
+ //
+ // Set the base to 16.
+ //
+ ui32Base = 16;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ui32Neg = 0;
+
+ //
+ // Determine the number of digits in the string version of
+ // the value.
+ //
+convert:
+ for(ui32Idx = 1;
+ (((ui32Idx * ui32Base) <= ui32Value) &&
+ (((ui32Idx * ui32Base) / ui32Base) == ui32Idx));
+ ui32Idx *= ui32Base, ui32Count--)
+ {
+ }
+
+ //
+ // If the value is negative, reduce the count of padding
+ // characters needed.
+ //
+ if(ui32Neg)
+ {
+ ui32Count--;
+ }
+
+ //
+ // If the value is negative and the value is padded with
+ // zeros, then place the minus sign before the padding.
+ //
+ if(ui32Neg && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ui32Pos++] = '-';
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ui32Neg = 0;
+ }
+
+ //
+ // Provide additional padding at the beginning of the
+ // string conversion if needed.
+ //
+ if((ui32Count > 1) && (ui32Count < 16))
+ {
+ for(ui32Count--; ui32Count; ui32Count--)
+ {
+ pcBuf[ui32Pos++] = cFill;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ui32Neg)
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ui32Pos++] = '-';
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ui32Idx; ui32Idx /= ui32Base)
+ {
+ pcBuf[ui32Pos++] =
+ g_pcHex[(ui32Value / ui32Idx) % ui32Base];
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcBuf, ui32Pos);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %% command.
+ //
+ case '%':
+ {
+ //
+ // Simply write a single %.
+ //
+ UARTwrite(pcString - 1, 1);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle all other commands.
+ //
+ default:
+ {
+ //
+ // Indicate an error.
+ //
+ UARTwrite("ERROR", 5);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! A simple UART based printf function supporting \%c, \%d, \%p, \%s, \%u,
+//! \%x, and \%X.
+//!
+//! \param pcString is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>fprintf()</tt> function.
+//! All of its output will be sent to the UART. Only the following formatting
+//! characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%s, \%d, \%i, \%u, \%p, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeroes instead of spaces.
+//!
+//! The type of the arguments after \e pcString must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTprintf(const char *pcString, ...)
+{
+ va_list vaArgP;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(vaArgP, pcString);
+
+ UARTvprintf(pcString, vaArgP);
+
+ //
+ // We're finished with the varargs now.
+ //
+ va_end(vaArgP);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes available in the receive buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to determine the number
+//! of bytes of data currently available in the receive buffer.
+//!
+//! \return Returns the number of available bytes.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+int
+UARTRxBytesAvail(void)
+{
+ return(RX_BUFFER_USED);
+}
+#endif
+
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+//*****************************************************************************
+//
+//! Returns the number of bytes free in the transmit buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
+//! of space currently available in the transmit buffer.
+//!
+//! \return Returns the number of free bytes.
+//
+//*****************************************************************************
+int
+UARTTxBytesFree(void)
+{
+ return(TX_BUFFER_FREE);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Looks ahead in the receive buffer for a particular character.
+//!
+//! \param ucChar is the character that is to be searched for.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
+//! receive buffer for a particular character and report its position if found.
+//! It is typically used to determine whether a complete line of user input is
+//! available, in which case ucChar should be set to CR ('\\r') which is used
+//! as the line end marker in the receive buffer.
+//!
+//! \return Returns -1 to indicate that the requested character does not exist
+//! in the receive buffer. Returns a non-negative number if the character was
+//! found in which case the value represents the position of the first instance
+//! of \e ucChar relative to the receive buffer read pointer.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+int
+UARTPeek(unsigned char ucChar)
+{
+ int iCount;
+ int iAvail;
+ uint32_t ui32ReadIndex;
+
+ //
+ // How many characters are there in the receive buffer?
+ //
+ iAvail = (int)RX_BUFFER_USED;
+ ui32ReadIndex = g_ui32UARTRxReadIndex;
+
+ //
+ // Check all the unread characters looking for the one passed.
+ //
+ for(iCount = 0; iCount < iAvail; iCount++)
+ {
+ if(g_pcUARTRxBuffer[ui32ReadIndex] == ucChar)
+ {
+ //
+ // We found it so return the index
+ //
+ return(iCount);
+ }
+ else
+ {
+ //
+ // This one didn't match so move on to the next character.
+ //
+ ADVANCE_RX_BUFFER_INDEX(ui32ReadIndex);
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find the character in the receive
+ // buffer.
+ //
+ return(-1);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Flushes the receive buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to discard any data
+//! received from the UART but not yet read using UARTgets().
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTFlushRx(void)
+{
+ uint32_t ui32Int;
+
+ //
+ // Temporarily turn off interrupts.
+ //
+ ui32Int = MAP_IntMasterDisable();
+
+ //
+ // Flush the receive buffer.
+ //
+ g_ui32UARTRxReadIndex = 0;
+ g_ui32UARTRxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ui32Int)
+ {
+ MAP_IntMasterEnable();
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Flushes the transmit buffer.
+//!
+//! \param bDiscard indicates whether any remaining data in the buffer should
+//! be discarded (\b true) or transmitted (\b false).
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
+//! buffer, either discarding or transmitting any data received via calls to
+//! UARTprintf() that is waiting to be transmitted. On return, the transmit
+//! buffer will be empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTFlushTx(bool bDiscard)
+{
+ uint32_t ui32Int;
+
+ //
+ // Should the remaining data be discarded or transmitted?
+ //
+ if(bDiscard)
+ {
+ //
+ // The remaining data should be discarded, so temporarily turn off
+ // interrupts.
+ //
+ ui32Int = MAP_IntMasterDisable();
+
+ //
+ // Flush the transmit buffer.
+ //
+ g_ui32UARTTxReadIndex = 0;
+ g_ui32UARTTxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ui32Int)
+ {
+ MAP_IntMasterEnable();
+ }
+ }
+ else
+ {
+ //
+ // Wait for all remaining data to be transmitted before returning.
+ //
+ while(!TX_BUFFER_EMPTY)
+ {
+ }
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Enables or disables echoing of received characters to the transmitter.
+//!
+//! \param bEnable must be set to \b true to enable echo or \b false to
+//! disable it.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
+//! received characters are automatically echoed back to the transmitter. By
+//! default, echo is enabled and this is typically the desired behavior if
+//! the module is being used to support a serial command line. In applications
+//! where this module is being used to provide a convenient, buffered serial
+//! interface over which application-specific binary protocols are being run,
+//! however, echo may be undesirable and this function can be used to disable
+//! it.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTEchoSet(bool bEnable)
+{
+ g_bDisableEcho = !bEnable;
+}
+#endif
+
+//*****************************************************************************
+//
+//! Handles UART interrupts.
+//!
+//! This function handles interrupts from the UART. It will copy data from the
+//! transmit buffer to the UART transmit FIFO if space is available, and it
+//! will copy data from the UART receive FIFO to the receive buffer if data is
+//! available.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTStdioIntHandler(void)
+{
+ uint32_t ui32Ints;
+ int8_t cChar;
+ int32_t i32Char;
+ static bool bLastWasCR = false;
+
+ //
+ // Get and clear the current interrupt source(s)
+ //
+ ui32Ints = MAP_UARTIntStatus(g_ui32Base, true);
+ MAP_UARTIntClear(g_ui32Base, ui32Ints);
+
+ //
+ // Are we being interrupted because the TX FIFO has space available?
+ //
+ if(ui32Ints & UART_INT_TX)
+ {
+ //
+ // Move as many bytes as we can into the transmit FIFO.
+ //
+ UARTPrimeTransmit(g_ui32Base);
+
+ //
+ // If the output buffer is empty, turn off the transmit interrupt.
+ //
+ if(TX_BUFFER_EMPTY)
+ {
+ MAP_UARTIntDisable(g_ui32Base, UART_INT_TX);
+ }
+ }
+
+ //
+ // Are we being interrupted due to a received character?
+ //
+ if(ui32Ints & (UART_INT_RX | UART_INT_RT))
+ {
+ //
+ // Get all the available characters from the UART.
+ //
+ while(MAP_UARTCharsAvail(g_ui32Base))
+ {
+ //
+ // Read a character
+ //
+ i32Char = MAP_UARTCharGetNonBlocking(g_ui32Base);
+ cChar = (unsigned char)(i32Char & 0xFF);
+
+ //
+ // If echo is disabled, we skip the various text filtering
+ // operations that would typically be required when supporting a
+ // command line.
+ //
+ if(!g_bDisableEcho)
+ {
+ //
+ // Handle backspace by erasing the last character in the
+ // buffer.
+ //
+ if(cChar == '\b')
+ {
+ //
+ // If there are any characters already in the buffer, then
+ // delete the last.
+ //
+ if(!RX_BUFFER_EMPTY)
+ {
+ //
+ // Rub out the previous character on the users
+ // terminal.
+ //
+ UARTwrite("\b \b", 3);
+
+ //
+ // Decrement the number of characters in the buffer.
+ //
+ if(g_ui32UARTRxWriteIndex == 0)
+ {
+ g_ui32UARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1;
+ }
+ else
+ {
+ g_ui32UARTRxWriteIndex--;
+ }
+ }
+
+ //
+ // Skip ahead to read the next character.
+ //
+ continue;
+ }
+
+ //
+ // If this character is LF and last was CR, then just gobble up
+ // the character since we already echoed the previous CR and we
+ // don't want to store 2 characters in the buffer if we don't
+ // need to.
+ //
+ if((cChar == '\n') && bLastWasCR)
+ {
+ bLastWasCR = false;
+ continue;
+ }
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // If the character is a CR, then it may be followed by an
+ // LF which should be paired with the CR. So remember that
+ // a CR was received.
+ //
+ if(cChar == '\r')
+ {
+ bLastWasCR = 1;
+ }
+
+ //
+ // Regardless of the line termination character received,
+ // put a CR in the receive buffer as a marker telling
+ // UARTgets() where the line ends. We also send an
+ // additional LF to ensure that the local terminal echo
+ // receives both CR and LF.
+ //
+ cChar = '\r';
+ UARTwrite("\n", 1);
+ }
+ }
+
+ //
+ // If there is space in the receive buffer, put the character
+ // there, otherwise throw it away.
+ //
+ if(!RX_BUFFER_FULL)
+ {
+ //
+ // Store the new character in the receive buffer
+ //
+ g_pcUARTRxBuffer[g_ui32UARTRxWriteIndex] =
+ (unsigned char)(i32Char & 0xFF);
+ ADVANCE_RX_BUFFER_INDEX(g_ui32UARTRxWriteIndex);
+
+ //
+ // If echo is enabled, write the character to the transmit
+ // buffer so that the user gets some immediate feedback.
+ //
+ if(!g_bDisableEcho)
+ {
+ UARTwrite((const char *)&cChar, 1);
+ }
+ }
+ }
+
+ //
+ // If we wrote anything to the transmit buffer, make sure it actually
+ // gets transmitted.
+ //
+ UARTPrimeTransmit(g_ui32Base);
+ MAP_UARTIntEnable(g_ui32Base, UART_INT_TX);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/uartstdio.h b/utils/uartstdio.h
new file mode 100644
index 0000000..fbadabc
--- /dev/null
+++ b/utils/uartstdio.h
@@ -0,0 +1,86 @@
+//*****************************************************************************
+//
+// uartstdio.h - Prototypes for the UART console functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __UARTSTDIO_H__
+#define __UARTSTDIO_H__
+
+#include <stdarg.h>
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// If built for buffered operation, the following labels define the sizes of
+// the transmit and receive buffers respectively.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+#ifndef UART_RX_BUFFER_SIZE
+#define UART_RX_BUFFER_SIZE 128
+#endif
+#ifndef UART_TX_BUFFER_SIZE
+#define UART_TX_BUFFER_SIZE 1024
+#endif
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void UARTStdioConfig(uint32_t ui32Port, uint32_t ui32Baud,
+ uint32_t ui32SrcClock);
+extern int UARTgets(char *pcBuf, uint32_t ui32Len);
+extern unsigned char UARTgetc(void);
+extern void UARTprintf(const char *pcString, ...);
+extern void UARTvprintf(const char *pcString, va_list vaArgP);
+extern int UARTwrite(const char *pcBuf, uint32_t ui32Len);
+#ifdef UART_BUFFERED
+extern int UARTPeek(unsigned char ucChar);
+extern void UARTFlushTx(bool bDiscard);
+extern void UARTFlushRx(void);
+extern int UARTRxBytesAvail(void);
+extern int UARTTxBytesFree(void);
+extern void UARTEchoSet(bool bEnable);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UARTSTDIO_H__
diff --git a/utils/ustdlib.c b/utils/ustdlib.c
new file mode 100644
index 0000000..0fa6f05
--- /dev/null
+++ b/utils/ustdlib.c
@@ -0,0 +1,1826 @@
+//*****************************************************************************
+//
+// ustdlib.c - Simple standard library functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "driverlib/debug.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ustdlib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A mapping from an integer between 0 and 15 to its ASCII character
+// equivalent.
+//
+//*****************************************************************************
+static const char * const g_pcHex = "0123456789abcdef";
+
+//*****************************************************************************
+//
+//! Copies a certain number of characters from one string to another.
+//!
+//! \param s1 is a pointer to the destination buffer into which characters
+//! are to be copied.
+//! \param s2 is a pointer to the string from which characters are to be
+//! copied.
+//! \param n is the number of characters to copy to the destination buffer.
+//!
+//! This function copies at most \e n characters from the string pointed to
+//! by \e s2 into the buffer pointed to by \e s1. If the end of \e s2 is found
+//! before \e n characters have been copied, remaining characters in \e s1
+//! will be padded with zeroes until \e n characters have been written. Note
+//! that the destination string will only be NULL terminated if the number of
+//! characters to be copied is greater than the length of \e s2.
+//!
+//! \return Returns \e s1.
+//
+//*****************************************************************************
+char *
+ustrncpy(char * restrict s1, const char * restrict s2, size_t n)
+{
+ size_t count;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s1);
+ ASSERT(s2);
+
+ //
+ // Start at the beginning of the source string.
+ //
+ count = 0;
+
+ //
+ // Copy the source string until we run out of source characters or
+ // destination space.
+ //
+ while(n && s2[count])
+ {
+ s1[count] = s2[count];
+ count++;
+ n--;
+ }
+
+ //
+ // Pad the destination if we are not yet done.
+ //
+ while(n)
+ {
+ s1[count++] = (char)0;
+ n--;
+ }
+
+ //
+ // Pass the destination pointer back to the caller.
+ //
+ return(s1);
+}
+
+//*****************************************************************************
+//
+//! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param s points to the buffer where the converted string is stored.
+//! \param n is the size of the buffer.
+//! \param format is the format string.
+//! \param arg is the list of optional arguments, which depend on the
+//! contents of the format string.
+//!
+//! This function is very similar to the C library <tt>vsnprintf()</tt>
+//! function. Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeroes instead of spaces.
+//!
+//! The type of the arguments after \e format must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The \e n parameter limits the number of characters that will be
+//! stored in the buffer pointed to by \e s to prevent the possibility of
+//! a buffer overflow. The buffer size should be large enough to hold the
+//! expected converted output string, including the null termination character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+uvsnprintf(char * restrict s, size_t n, const char * restrict format,
+ va_list arg)
+{
+ unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg;
+ char *pcStr, cFill;
+ int iConvertCount = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s);
+ ASSERT(n);
+ ASSERT(format);
+
+ //
+ // Adjust buffer size limit to allow one space for null termination.
+ //
+ if(n)
+ {
+ n--;
+ }
+
+ //
+ // Initialize the count of characters converted.
+ //
+ iConvertCount = 0;
+
+ //
+ // Loop while there are more characters in the format string.
+ //
+ while(*format)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ulIdx = 0; (format[ulIdx] != '%') && (format[ulIdx] != '\0');
+ ulIdx++)
+ {
+ }
+
+ //
+ // Write this portion of the string to the output buffer. If there are
+ // more characters to write than there is space in the buffer, then
+ // only write as much as will fit in the buffer.
+ //
+ if(ulIdx > n)
+ {
+ ustrncpy(s, format, n);
+ s += n;
+ n = 0;
+ }
+ else
+ {
+ ustrncpy(s, format, ulIdx);
+ s += ulIdx;
+ n -= ulIdx;
+ }
+
+ //
+ // Update the conversion count. This will be the number of characters
+ // that should have been written, even if there was not room in the
+ // buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // Skip the portion of the format string that was written.
+ //
+ format += ulIdx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*format == '%')
+ {
+ //
+ // Skip the %.
+ //
+ format++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (that is, to the defaults).
+ //
+ ulCount = 0;
+ cFill = ' ';
+
+ //
+ // It may be necessary to get back here to process more characters.
+ // Goto's aren't pretty, but effective. I feel extremely dirty for
+ // using not one but two of the beasts.
+ //
+again:
+
+ //
+ // Determine how to handle the next character.
+ //
+ switch(*format++)
+ {
+ //
+ // Handle the digit characters.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ //
+ // If this is a zero, and it is the first digit, then the
+ // fill character is a zero instead of a space.
+ //
+ if((format[-1] == '0') && (ulCount == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ulCount *= 10;
+ ulCount += format[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // Copy the character to the output buffer, if there is
+ // room. Update the buffer size remaining.
+ //
+ if(n != 0)
+ {
+ *s++ = (char)ulValue;
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // If the value is negative, make it positive and indicate
+ // that a minus sign is needed.
+ //
+ if((long)ulValue < 0)
+ {
+ //
+ // Make the value positive.
+ //
+ ulValue = -(long)ulValue;
+
+ //
+ // Indicate that the value is negative.
+ //
+ ulNeg = 1;
+ }
+ else
+ {
+ //
+ // Indicate that the value is positive so that a
+ // negative sign isn't inserted.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %s command.
+ //
+ case 's':
+ {
+ //
+ // Get the string pointer from the varargs.
+ //
+ pcStr = va_arg(arg, char *);
+
+ //
+ // Determine the length of the string.
+ //
+ for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
+ {
+ }
+
+ //
+ // Update the convert count to include any padding that
+ // should be necessary (regardless of whether we have space
+ // to write it or not).
+ //
+ if(ulCount > ulIdx)
+ {
+ iConvertCount += (ulCount - ulIdx);
+ }
+
+ //
+ // Copy the string to the output buffer. Only copy as much
+ // as will fit in the buffer. Update the output buffer
+ // pointer and the space remaining.
+ //
+ if(ulIdx > n)
+ {
+ ustrncpy(s, pcStr, n);
+ s += n;
+ n = 0;
+ }
+ else
+ {
+ ustrncpy(s, pcStr, ulIdx);
+ s += ulIdx;
+ n -= ulIdx;
+
+ //
+ // Write any required padding spaces assuming there is
+ // still space in the buffer.
+ //
+ if(ulCount > ulIdx)
+ {
+ ulCount -= ulIdx;
+ if(ulCount > n)
+ {
+ ulCount = n;
+ }
+ n = -ulCount;
+
+ while(ulCount--)
+ {
+ *s++ = ' ';
+ }
+ }
+ }
+
+ //
+ // Update the conversion count. This will be the number of
+ // characters that should have been written, even if there
+ // was not room in the buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %x and %X commands. Note that they are treated
+ // identically; that is, %X will use lower case letters for a-f
+ // instead of the upper case letters is should use. We also
+ // alias %p to %x.
+ //
+ case 'x':
+ case 'X':
+ case 'p':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(arg, unsigned long);
+
+ //
+ // Set the base to 16.
+ //
+ ulBase = 16;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Determine the number of digits in the string version of
+ // the value.
+ //
+convert:
+ for(ulIdx = 1;
+ (((ulIdx * ulBase) <= ulValue) &&
+ (((ulIdx * ulBase) / ulBase) == ulIdx));
+ ulIdx *= ulBase, ulCount--)
+ {
+ }
+
+ //
+ // If the value is negative, reduce the count of padding
+ // characters needed.
+ //
+ if(ulNeg)
+ {
+ ulCount--;
+ }
+
+ //
+ // If the value is negative and the value is padded with
+ // zeros, then place the minus sign before the padding.
+ //
+ if(ulNeg && (n != 0) && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *s++ = '-';
+ n--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // See if there are more characters in the specified field
+ // width than there are in the conversion of this value.
+ //
+ if((ulCount > 1) && (ulCount < 65536))
+ {
+ //
+ // Loop through the required padding characters.
+ //
+ for(ulCount--; ulCount; ulCount--)
+ {
+ //
+ // Copy the character to the output buffer if there
+ // is room.
+ //
+ if(n != 0)
+ {
+ *s++ = cFill;
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ulNeg && (n != 0))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *s++ = '-';
+ n--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ulIdx; ulIdx /= ulBase)
+ {
+ //
+ // Copy the character to the output buffer if there is
+ // room.
+ //
+ if(n != 0)
+ {
+ *s++ = g_pcHex[(ulValue / ulIdx) % ulBase];
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %% command.
+ //
+ case '%':
+ {
+ //
+ // Simply write a single %.
+ //
+ if(n != 0)
+ {
+ *s++ = format[-1];
+ n--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle all other commands.
+ //
+ default:
+ {
+ //
+ // Indicate an error.
+ //
+ if(n >= 5)
+ {
+ ustrncpy(s, "ERROR", 5);
+ s += 5;
+ n -= 5;
+ }
+ else
+ {
+ ustrncpy(s, "ERROR", n);
+ s += n;
+ n = 0;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount += 5;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Null terminate the string in the buffer.
+ //
+ *s = 0;
+
+ //
+ // Return the number of characters in the full converted string.
+ //
+ return(iConvertCount);
+}
+
+//*****************************************************************************
+//
+//! A simple sprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X.
+//!
+//! \param s is the buffer where the converted string is stored.
+//! \param format is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeros instead of spaces.
+//!
+//! The type of the arguments after \e format must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The caller must ensure that the buffer \e s is large enough to hold the
+//! entire converted string, including the null termination character.
+//!
+//! \return Returns the count of characters that were written to the output
+//! buffer, not including the NULL termination character.
+//
+//*****************************************************************************
+int
+usprintf(char * restrict s, const char *format, ...)
+{
+ va_list arg;
+ int ret;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(arg, format);
+
+ //
+ // Call vsnprintf to perform the conversion. Use a large number for the
+ // buffer size.
+ //
+ ret = uvsnprintf(s, 0xffff, format, arg);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(arg);
+
+ //
+ // Return the conversion count.
+ //
+ return(ret);
+}
+
+//*****************************************************************************
+//
+//! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param s is the buffer where the converted string is stored.
+//! \param n is the size of the buffer.
+//! \param format is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeros instead of spaces.
+//!
+//! The type of the arguments after \e format must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The function will copy at most \e n - 1 characters into the buffer
+//! \e s. One space is reserved in the buffer for the null termination
+//! character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+usnprintf(char * restrict s, size_t n, const char * restrict format, ...)
+{
+ va_list arg;
+ int ret;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(arg, format);
+
+ //
+ // Call vsnprintf to perform the conversion.
+ //
+ ret = uvsnprintf(s, n, format, arg);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(arg);
+
+ //
+ // Return the conversion count.
+ //
+ return(ret);
+}
+
+//*****************************************************************************
+//
+// This array contains the number of days in a year at the beginning of each
+// month of the year, in a non-leap year.
+//
+//*****************************************************************************
+static const time_t g_psDaysToMonth[12] =
+{
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+//*****************************************************************************
+//
+//! Converts from seconds to calendar date and time.
+//!
+//! \param timer is the number of seconds.
+//! \param tm is a pointer to the time structure that is filled in with the
+//! broken down date and time.
+//!
+//! This function converts a number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch) into the equivalent month, day, year, hours,
+//! minutes, and seconds representation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ulocaltime(time_t timer, struct tm *tm)
+{
+ time_t temp, months;
+
+ //
+ // Extract the number of seconds, converting time to the number of minutes.
+ //
+ temp = timer / 60;
+ tm->tm_sec = timer - (temp * 60);
+ timer = temp;
+
+ //
+ // Extract the number of minutes, converting time to the number of hours.
+ //
+ temp = timer / 60;
+ tm->tm_min = timer - (temp * 60);
+ timer = temp;
+
+ //
+ // Extract the number of hours, converting time to the number of days.
+ //
+ temp = timer / 24;
+ tm->tm_hour = timer - (temp * 24);
+ timer = temp;
+
+ //
+ // Compute the day of the week.
+ //
+ tm->tm_wday = (timer + 4) % 7;
+
+ //
+ // Compute the number of leap years that have occurred since 1968, the
+ // first leap year before 1970. For the beginning of a leap year, cut the
+ // month loop below at March so that the leap day is classified as February
+ // 29 followed by March 1, instead of March 1 followed by another March 1.
+ //
+ timer += 366 + 365;
+ temp = timer / ((4 * 365) + 1);
+ if((timer - (temp * ((4 * 365) + 1))) > (31 + 28))
+ {
+ temp++;
+ months = 12;
+ }
+ else
+ {
+ months = 2;
+ }
+
+ //
+ // Extract the year.
+ //
+ tm->tm_year = ((timer - temp) / 365) + 68;
+ timer -= ((tm->tm_year - 68) * 365) + temp;
+
+ //
+ // Extract the month.
+ //
+ for(temp = 0; temp < months; temp++)
+ {
+ if(g_psDaysToMonth[temp] > timer)
+ {
+ break;
+ }
+ }
+ tm->tm_mon = temp - 1;
+
+ //
+ // Extract the day of the month.
+ //
+ tm->tm_mday = timer - g_psDaysToMonth[temp - 1] + 1;
+}
+
+//*****************************************************************************
+//
+//! Compares two time structures and determines if one is greater than,
+//! less than, or equal to the other.
+//!
+//! \param t1 is the first time structure to compare.
+//! \param t2 is the second time structure to compare.
+//!
+//! This function compares two time structures and returns a signed number
+//! to indicate the result of the comparison. If the time represented by
+//! \e t1 is greater than the time represented by \e t2 then a positive
+//! number is returned. Likewise if \e t1 is less than \e t2 then a
+//! negative number is returned. If the two times are equal then the function
+//! returns 0.
+//!
+//! \return Returns 0 if the two times are equal, +1 if \e t1 is greater
+//! than \e t2, and -1 if \e t1 is less than \e t2.
+//
+//*****************************************************************************
+static int
+ucmptime(struct tm *t1, struct tm *t2)
+{
+ //
+ // Compare each field in descending signficance to determine if
+ // greater than, less than, or equal.
+ //
+ if(t1->tm_year > t2->tm_year)
+ {
+ return(1);
+ }
+ else if(t1->tm_year < t2->tm_year)
+ {
+ return(-1);
+ }
+ else if(t1->tm_mon > t2->tm_mon)
+ {
+ return(1);
+ }
+ else if(t1->tm_mon < t2->tm_mon)
+ {
+ return(-1);
+ }
+ else if(t1->tm_mday > t2->tm_mday)
+ {
+ return(1);
+ }
+ else if(t1->tm_mday < t2->tm_mday)
+ {
+ return(-1);
+ }
+ else if(t1->tm_hour > t2->tm_hour)
+ {
+ return(1);
+ }
+ else if(t1->tm_hour < t2->tm_hour)
+ {
+ return(-1);
+ }
+ else if(t1->tm_min > t2->tm_min)
+ {
+ return(1);
+ }
+ else if(t1->tm_min < t2->tm_min)
+ {
+ return(-1);
+ }
+ else if(t1->tm_sec > t2->tm_sec)
+ {
+ return(1);
+ }
+ else if(t1->tm_sec < t2->tm_sec)
+ {
+ return(-1);
+ }
+ else
+ {
+ //
+ // Reaching this branch of the conditional means that all of the
+ // fields are equal, and thus the two times are equal.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts calendar date and time to seconds.
+//!
+//! \param timeptr is a pointer to the time structure that is filled in with
+//! the broken down date and time.
+//!
+//! This function converts the date and time represented by the \e timeptr
+//! structure pointer to the number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch).
+//!
+//! \return Returns the calendar time and date as seconds. If the conversion
+//! was not possible then the function returns (uint32_t)(-1).
+//
+//*****************************************************************************
+time_t
+umktime(struct tm *timeptr)
+{
+ struct tm sTimeGuess;
+ unsigned long ulTimeGuess = 0x80000000;
+ unsigned long ulAdjust = 0x40000000;
+ int iSign;
+
+ //
+ // Seed the binary search with the first guess.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(timeptr, &sTimeGuess);
+
+ //
+ // While the time is not yet found, execute a binary search.
+ //
+ while(iSign && ulAdjust)
+ {
+ //
+ // Adjust the time guess up or down depending on the result of the
+ // last compare.
+ //
+ ulTimeGuess = ((iSign > 0) ? (ulTimeGuess + ulAdjust) :
+ (ulTimeGuess - ulAdjust));
+ ulAdjust /= 2;
+
+ //
+ // Compare the new time guess against the time pointed at by the
+ // function parameters.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(timeptr, &sTimeGuess);
+ }
+
+ //
+ // If the above loop was exited with iSign == 0, that means that the
+ // time in seconds was found, so return that value to the caller.
+ //
+ if(iSign == 0)
+ {
+ return(ulTimeGuess);
+ }
+
+ //
+ // Otherwise the time could not be converted so return an error.
+ //
+ else
+ {
+ return((unsigned long)-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts a string into its numeric equivalent.
+//!
+//! \param nptr is a pointer to the string containing the integer.
+//! \param endptr is a pointer that will be set to the first character past
+//! the integer in the string.
+//! \param base is the radix to use for the conversion; can be zero to
+//! auto-select the radix or between 2 and 16 to explicitly specify the radix.
+//!
+//! This function is very similar to the C library <tt>strtoul()</tt> function.
+//! It scans a string for the first token (that is, non-white space) and
+//! converts the value at that location in the string into an integer value.
+//!
+//! \return Returns the result of the conversion.
+//
+//*****************************************************************************
+unsigned long
+ustrtoul(const char * restrict nptr, const char ** restrict endptr, int base)
+{
+ unsigned long ulRet, ulDigit, ulNeg, ulValid;
+ const char *pcPtr;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(nptr);
+ ASSERT((base == 0) || ((base > 1) && (base <= 16)));
+
+ //
+ // Initially, the result is zero.
+ //
+ ulRet = 0;
+ ulNeg = 0;
+ ulValid = 0;
+
+ //
+ // Skip past any leading white space.
+ //
+ pcPtr = nptr;
+ while((*pcPtr == ' ') || (*pcPtr == '\t'))
+ {
+ pcPtr++;
+ }
+
+ //
+ // Take a leading + or - from the value.
+ //
+ if(*pcPtr == '-')
+ {
+ ulNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // See if the radix was not specified, or is 16, and the value starts with
+ // "0x" or "0X" (to indicate a hex value).
+ //
+ if(((base == 0) || (base == 16)) && (*pcPtr == '0') &&
+ ((pcPtr[1] == 'x') || (pcPtr[1] == 'X')))
+ {
+ //
+ // Skip the leading "0x".
+ //
+ pcPtr += 2;
+
+ //
+ // Set the radix to 16.
+ //
+ base = 16;
+ }
+
+ //
+ // See if the radix was not specified.
+ //
+ if(base == 0)
+ {
+ //
+ // See if the value starts with "0".
+ //
+ if(*pcPtr == '0')
+ {
+ //
+ // Values that start with "0" are assumed to be radix 8.
+ //
+ base = 8;
+ }
+ else
+ {
+ //
+ // Otherwise, the values are assumed to be radix 10.
+ //
+ base = 10;
+ }
+ }
+
+ //
+ // Loop while there are more valid digits to consume.
+ //
+ while(1)
+ {
+ //
+ // See if this character is a number.
+ //
+ if((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - '0';
+ }
+
+ //
+ // Otherwise, see if this character is an upper case letter.
+ //
+ else if((*pcPtr >= 'A') && (*pcPtr <= 'Z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'A' + 10;
+ }
+
+ //
+ // Otherwise, see if this character is a lower case letter.
+ //
+ else if((*pcPtr >= 'a') && (*pcPtr <= 'z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'a' + 10;
+ }
+
+ //
+ // Otherwise, this is not a valid character.
+ //
+ else
+ {
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // See if this digit is valid for the chosen radix.
+ //
+ if(ulDigit >= base)
+ {
+ //
+ // Since this was not a valid digit, move the pointer back to the
+ // character that therefore should not have been consumed.
+ //
+ pcPtr--;
+
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // Add this digit to the converted value.
+ //
+ ulRet *= base;
+ ulRet += ulDigit;
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+
+ //
+ // Set the return string pointer to the first character not consumed.
+ //
+ if(endptr)
+ {
+ *endptr = ulValid ? pcPtr : nptr;
+ }
+
+ //
+ // Return the converted value.
+ //
+ return(ulNeg ? (0 - ulRet) : ulRet);
+}
+
+//*****************************************************************************
+//
+// An array of the value of ten raised to the power-of-two exponents. This is
+// used for converting the decimal exponent into the floating-point value of
+// 10^exp.
+//
+//*****************************************************************************
+static const float g_pfExponents[] =
+{
+ 1.0e+01,
+ 1.0e+02,
+ 1.0e+04,
+ 1.0e+08,
+ 1.0e+16,
+ 1.0e+32,
+};
+
+//*****************************************************************************
+//
+//! Converts a string into its floating-point equivalent.
+//!
+//! \param nptr is a pointer to the string containing the floating-point
+//! value.
+//! \param endptr is a pointer that will be set to the first character past
+//! the floating-point value in the string.
+//!
+//! This function is very similar to the C library <tt>strtof()</tt> function.
+//! It scans a string for the first token (that is, non-white space) and
+//! converts the value at that location in the string into a floating-point
+//! value.
+//!
+//! \return Returns the result of the conversion.
+//
+//*****************************************************************************
+float
+ustrtof(const char *nptr, const char **endptr)
+{
+ unsigned long ulNeg, ulExp, ulExpNeg, ulValid, ulIdx;
+ float fRet, fDigit, fExp;
+ const char *pcPtr;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(nptr);
+
+ //
+ // Initially, the result is zero.
+ //
+ fRet = 0;
+ ulNeg = 0;
+ ulValid = 0;
+
+ //
+ // Skip past any leading white space.
+ //
+ pcPtr = nptr;
+ while((*pcPtr == ' ') || (*pcPtr == '\t'))
+ {
+ pcPtr++;
+ }
+
+ //
+ // Take a leading + or - from the value.
+ //
+ if(*pcPtr == '-')
+ {
+ ulNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // Loop while there are valid digits to consume.
+ //
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ fRet *= 10;
+ fRet += *pcPtr++ - '0';
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+
+ //
+ // See if the next character is a period and the character after that is a
+ // digit, indicating the start of the fractional portion of the value.
+ //
+ if((*pcPtr == '.') && (pcPtr[1] >= '0') && (pcPtr[1] <= '9'))
+ {
+ //
+ // Skip the period.
+ //
+ pcPtr++;
+
+ //
+ // Loop while there are valid fractional digits to consume.
+ //
+ fDigit = 0.1;
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ fRet += (*pcPtr++ - '0') * fDigit;
+ fDigit /= (float)10.0;
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+ }
+
+ //
+ // See if the next character is an "e" and a valid number has been
+ // converted, indicating the start of the exponent.
+ //
+ if(((pcPtr[0] == 'e') || (pcPtr[0] == 'E')) && (ulValid == 1) &&
+ (((pcPtr[1] >= '0') && (pcPtr[1] <= '9')) ||
+ (((pcPtr[1] == '+') || (pcPtr[1] == '-')) &&
+ (pcPtr[2] >= '0') && (pcPtr[2] <= '9'))))
+ {
+ //
+ // Skip the "e".
+ //
+ pcPtr++;
+
+ //
+ // Take a leading + or - from the exponenet.
+ //
+ ulExpNeg = 0;
+ if(*pcPtr == '-')
+ {
+ ulExpNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // Loop while there are valid digits in the exponent.
+ //
+ ulExp = 0;
+ while((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Add this digit to the converted value.
+ //
+ ulExp *= 10;
+ ulExp += *pcPtr++ - '0';
+ }
+
+ //
+ // Raise ten to the power of the exponent. Do this via binary
+ // decomposition; for each binary bit set in the exponent, multiply the
+ // floating-point representation by ten raised to that binary value
+ // (extracted from the table above).
+ //
+ fExp = 1;
+ for(ulIdx = 0; ulIdx < 7; ulIdx++)
+ {
+ if(ulExp & (1 << ulIdx))
+ {
+ fExp *= g_pfExponents[ulIdx];
+ }
+ }
+
+ //
+ // If the exponent is negative, then the exponent needs to be inverted.
+ //
+ if(ulExpNeg == 1)
+ {
+ fExp = 1 / fExp;
+ }
+
+ //
+ // Multiply the result by the computed exponent value.
+ //
+ fRet *= fExp;
+ }
+
+ //
+ // Set the return string pointer to the first character not consumed.
+ //
+ if(endptr)
+ {
+ *endptr = ulValid ? pcPtr : nptr;
+ }
+
+ //
+ // Return the converted value.
+ //
+ return(ulNeg ? (0 - fRet) : fRet);
+}
+
+//*****************************************************************************
+//
+//! Returns the length of a null-terminated string.
+//!
+//! \param s is a pointer to the string whose length is to be found.
+//!
+//! This function is very similar to the C library <tt>strlen()</tt> function.
+//! It determines the length of the null-terminated string passed and returns
+//! this to the caller.
+//!
+//! This implementation assumes that single byte character strings are passed
+//! and will return incorrect values if passed some UTF-8 strings.
+//!
+//! \return Returns the length of the string pointed to by \e s.
+//
+//*****************************************************************************
+size_t
+ustrlen(const char *s)
+{
+ size_t len;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(s);
+
+ //
+ // Initialize the length.
+ //
+ len = 0;
+
+ //
+ // Step throug the string looking for a zero character (marking its end).
+ //
+ while(s[len])
+ {
+ //
+ // Zero not found so move on to the next character.
+ //
+ len++;
+ }
+
+ return(len);
+}
+
+//*****************************************************************************
+//
+//! Finds a substring within a string.
+//!
+//! \param s1 is a pointer to the string that will be searched.
+//! \param s2 is a pointer to the substring that is to be found within
+//! \e s1.
+//!
+//! This function is very similar to the C library <tt>strstr()</tt> function.
+//! It scans a string for the first instance of a given substring and returns
+//! a pointer to that substring. If the substring cannot be found, a NULL
+//! pointer is returned.
+//!
+//! \return Returns a pointer to the first occurrence of \e s2 within
+//! \e s1 or NULL if no match is found.
+//
+//*****************************************************************************
+char *
+ustrstr(const char *s1, const char *s2)
+{
+ size_t n;
+
+ //
+ // Get the length of the string to be found.
+ //
+ n = ustrlen(s2);
+
+ //
+ // Loop while we have not reached the end of the string.
+ //
+ while(*s1)
+ {
+ //
+ // Check to see if the substring appears at this position.
+ //
+ if(ustrncmp(s2, s1, n) == 0)
+ {
+ //
+ // It does so return the pointer.
+ //
+ return((char *)s1);
+ }
+
+ //
+ // Move to the next position in the string being searched.
+ //
+ s1++;
+ }
+
+ //
+ // We reached the end of the string without finding the substring so
+ // return NULL.
+ //
+ return((char *)0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//! \param n is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strncasecmp()</tt>
+//! function. It compares at most \e n characters of two strings without
+//! regard to case. The comparison ends if a terminating NULL character is
+//! found in either string before \e n characters are compared. In this case,
+//! the shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrncasecmp(const char *s1, const char *s2, size_t n)
+{
+ char c1, c2;
+
+ //
+ // Loop while there are more characters to compare.
+ //
+ while(n)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so
+ // we end the comparison and return 0
+ //
+ if(!*s1 && !*s2)
+ {
+ return(0);
+ }
+
+ //
+ // Lower case the characters at the current position before we compare.
+ //
+ c1 = (((*s1 >= 'A') && (*s1 <= 'Z')) ? (*s1 + ('a' - 'A')) : *s1);
+ c2 = (((*s2 >= 'A') && (*s2 <= 'Z')) ? (*s2 + ('a' - 'A')) : *s2);
+
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(c2 < c1)
+ {
+ return(1);
+ }
+ if(c1 < c2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ s1++;
+ s2++;
+ n--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first n
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcasecmp()</tt>
+//! function. It compares two strings without regard to case. The comparison
+//! ends if a terminating NULL character is found in either string. In this
+//! case, the int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrcasecmp(const char *s1, const char *s2)
+{
+ //
+ // Just let ustrncasecmp() handle this.
+ //
+ return(ustrncasecmp(s1, s2, (size_t)-1));
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//! \param n is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strncmp()</tt> function.
+//! It compares at most \e n characters of two strings taking case into
+//! account. The comparison ends if a terminating NULL character is found in
+//! either string before \e n characters are compared. In this case, the
+//! int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrncmp(const char *s1, const char *s2, size_t n)
+{
+ //
+ // Loop while there are more characters.
+ //
+ while(n)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so we end
+ // the comparison and return 0
+ //
+ if(!*s1 && !*s2)
+ {
+ return(0);
+ }
+
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(*s2 < *s1)
+ {
+ return(1);
+ }
+ if(*s1 < *s2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ s1++;
+ s2++;
+ n--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first n
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param s1 points to the first string to be compared.
+//! \param s2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcmp()</tt>
+//! function. It compares two strings, taking case into account. The
+//! comparison ends if a terminating NULL character is found in either string.
+//! In this case, the int16_ter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less
+//! than \e s2 and 1 if \e s1 is greater than \e s2.
+//
+//*****************************************************************************
+int
+ustrcmp(const char *s1, const char *s2)
+{
+ //
+ // Pass this on to ustrncmp.
+ //
+ return(ustrncmp(s1, s2, (size_t)-1));
+}
+
+//*****************************************************************************
+//
+// Random Number Generator Seed Value
+//
+//*****************************************************************************
+static unsigned int g_iRandomSeed = 1;
+
+//*****************************************************************************
+//
+//! Set the random number generator seed.
+//!
+//! \param seed is the new seed value to use for the random number
+//! generator.
+//!
+//! This function is very similar to the C library <tt>srand()</tt> function.
+//! It will set the seed value used in the <tt>urand()</tt> function.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+usrand(unsigned int seed)
+{
+ g_iRandomSeed = seed;
+}
+
+//*****************************************************************************
+//
+//! Generate a new (pseudo) random number
+//!
+//! This function is very similar to the C library <tt>rand()</tt> function.
+//! It will generate a pseudo-random number sequence based on the seed value.
+//!
+//! \return A pseudo-random number will be returned.
+//
+//*****************************************************************************
+int
+urand(void)
+{
+ //
+ // Generate a new pseudo-random number with a linear congruence random
+ // number generator. This new random number becomes the seed for the next
+ // random number.
+ //
+ g_iRandomSeed = (g_iRandomSeed * 1664525) + 1013904223;
+
+ //
+ // Return the new random number.
+ //
+ return((int)g_iRandomSeed);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ustdlib.h b/utils/ustdlib.h
new file mode 100644
index 0000000..b9227f9
--- /dev/null
+++ b/utils/ustdlib.h
@@ -0,0 +1,82 @@
+//*****************************************************************************
+//
+// ustdlib.h - Prototypes for simple standard library functions.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef __USTDLIB_H__
+#define __USTDLIB_H__
+
+//*****************************************************************************
+//
+// Include the standard C headers upon which these replacements are based.
+//
+//*****************************************************************************
+#include <stdarg.h>
+#include <time.h>
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void ulocaltime(time_t timer, struct tm *tm);
+extern time_t umktime(struct tm *timeptr);
+extern int urand(void);
+extern int usnprintf(char * restrict s, size_t n, const char * restrict format,
+ ...);
+extern int usprintf(char * restrict s, const char * restrict format, ...);
+extern void usrand(unsigned int seed);
+extern int ustrcasecmp(const char *s1, const char *s2);
+extern int ustrcmp(const char *s1, const char *s2);
+extern size_t ustrlen(const char *s);
+extern int ustrncasecmp(const char *s1, const char *s2, size_t n);
+extern int ustrncmp(const char *s1, const char *s2, size_t n);
+extern char *ustrncpy(char * restrict s1, const char * restrict s2, size_t n);
+extern char *ustrstr(const char *s1, const char *s2);
+extern float ustrtof(const char * restrict nptr,
+ const char ** restrict endptr);
+extern unsigned long int ustrtoul(const char * restrict nptr,
+ const char ** restrict endptr, int base);
+extern int uvsnprintf(char * restrict s, size_t n,
+ const char * restrict format, va_list arg);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USTDLIB_H__
diff --git a/utils/wavfile.c b/utils/wavfile.c
new file mode 100644
index 0000000..b2ce150
--- /dev/null
+++ b/utils/wavfile.c
@@ -0,0 +1,291 @@
+//******************************************************************************
+//
+// wavfile.c - This file supports reading audio data from a .wav file and
+// reading the file format.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//******************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "third_party/fatfs/src/ff.h"
+#include "third_party/fatfs/src/diskio.h"
+#include "wavfile.h"
+
+//******************************************************************************
+//
+// The flag values for the ui32Flags member of the tWavFile structure.
+//
+//******************************************************************************
+#define WAV_FLAG_FILEOPEN 0x00000001
+
+//******************************************************************************
+//
+// Basic wav file RIFF header information used to open and read a wav file.
+//
+//******************************************************************************
+#define RIFF_CHUNK_ID_RIFF 0x46464952
+#define RIFF_CHUNK_ID_FMT 0x20746d66
+#define RIFF_CHUNK_ID_DATA 0x61746164
+#define RIFF_TAG_WAVE 0x45564157
+#define RIFF_FORMAT_UNKNOWN 0x0000
+#define RIFF_FORMAT_PCM 0x0001
+#define RIFF_FORMAT_MSADPCM 0x0002
+#define RIFF_FORMAT_IMAADPCM 0x0011
+
+//******************************************************************************
+//
+// This function returns the format of a wav file that has been opened with
+// the WavOpen() function.
+//
+// \param psWavData is the structure that was passed to the WavOpen() function.
+// \param psWavHeader is the structure to fill with the format of the wav file.
+//
+// This function is used to get the audio format of a file that was opened
+// with the WavOpen() function. The \e psWavData parameter should be the
+// same structure that was passed to the WavOpen() function. The
+// \e psWavHeader function will be filled with the format of the open file if
+// the \e psWavData is a valid open file. If this function is called with
+// an invalid \e psWavData then the results will be undetermined.
+//
+// \return None.
+//
+//******************************************************************************
+void
+WavGetFormat(tWavFile *psWavData, tWavHeader *psWavHeader)
+{
+ //
+ // Only return data if the file is open.
+ //
+ psWavHeader->ui32DataSize = psWavData->sWavHeader.ui32DataSize;
+ psWavHeader->ui16NumChannels = psWavData->sWavHeader.ui16NumChannels;
+ psWavHeader->ui32SampleRate = psWavData->sWavHeader.ui32SampleRate;
+ psWavHeader->ui32AvgByteRate = psWavData->sWavHeader.ui32AvgByteRate;
+ psWavHeader->ui16BitsPerSample = psWavData->sWavHeader.ui16BitsPerSample;
+}
+
+//******************************************************************************
+//
+// This function is called to open and determine if a file is a valid .wav
+// file.
+//
+// \param pcFileName is the null terminated string for the file to open.
+// \param psWavData is the structure used to hold the file state information.
+//
+// This function is used to open a file and determine if it is a valid .wav
+// file. The \e pcFileName will be opened and read to look for a valid .wav
+// file header and prepared for calling the WavRead() or WavGetFormat()
+// functions. When an application is done with the .wav file it should call
+// the WavClose() function to free up the file. The function will return
+// zero if the function successfully opened a .wav file and a non-zero value
+// indicates that the file was a valid .wav file or the file could not be
+// opened.
+//
+// \return A value of zero indicates that the file was successfully opened and
+// any other value indicates that the file was not opened.
+//
+//******************************************************************************
+int
+WavOpen(const char *pcFileName, tWavFile *psWavData)
+{
+ unsigned char pucBuffer[16];
+ uint32_t *pui32Buffer;
+ uint16_t *pui16Buffer;
+ uint32_t ui32ChunkSize;
+ uint32_t ui32Count;
+
+ //
+ // Create some local pointers using in parsing values.
+ //
+ pui32Buffer = (uint32_t *)pucBuffer;
+ pui16Buffer = (uint16_t *)pucBuffer;
+
+ //
+ // Open the file as read only.
+ //
+ if(f_open(&psWavData->i16File, pcFileName, FA_READ) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // File is open.
+ //
+ psWavData->ui32Flags = WAV_FLAG_FILEOPEN;
+
+ //
+ // Read the first 12 bytes.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 12, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Look for RIFF tag.
+ //
+ if((pui32Buffer[0] != RIFF_CHUNK_ID_RIFF) ||
+ (pui32Buffer[2] != RIFF_TAG_WAVE))
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 8, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Now look for the RIFF ID format tag.
+ //
+ if(pui32Buffer[0] != RIFF_CHUNK_ID_FMT)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the format chunk size and insure that it is 16.
+ //
+ ui32ChunkSize = pui32Buffer[1];
+
+ if(ui32ChunkSize > 16)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, ui32ChunkSize,
+ (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Save the audio format data so that it can be returned later if
+ // requested.
+ //
+ psWavData->sWavHeader.ui16Format = pui16Buffer[0];
+ psWavData->sWavHeader.ui16NumChannels = pui16Buffer[1];
+ psWavData->sWavHeader.ui32SampleRate = pui32Buffer[1];
+ psWavData->sWavHeader.ui32AvgByteRate = pui32Buffer[2];
+ psWavData->sWavHeader.ui16BitsPerSample = pui16Buffer[7];
+
+ //
+ // Only mono and stereo supported.
+ //
+ if(psWavData->sWavHeader.ui16NumChannels > 2)
+ {
+ return(-1);
+ }
+
+ //
+ // Read the next chunk header.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, 8, (UINT *)&ui32Count) != FR_OK)
+ {
+ return(-1);
+ }
+
+ //
+ // Now make sure that the file has a data chunk.
+ //
+ if(pui32Buffer[0] != RIFF_CHUNK_ID_DATA)
+ {
+ return(-1);
+ }
+
+ //
+ // Save the size of the data.
+ //
+ psWavData->sWavHeader.ui32DataSize = pui32Buffer[1];
+
+ return(0);
+}
+
+//******************************************************************************
+//
+// This is used to close a .wav file that was opened with WavOpen().
+//
+// \param psWavData is the file structure that was passed into the WavOpen()
+// function.
+//
+// This function should be called when a function has completed using a .wav
+// file that was opened with the WavOpen() function. This will free up any
+// file system data that is held while the file is open.
+//
+// \return None.
+//
+//******************************************************************************
+void
+WavClose(tWavFile *psWavData)
+{
+ if(psWavData->ui32Flags & WAV_FLAG_FILEOPEN)
+ {
+ //
+ // Close out the file.
+ //
+ f_close(&psWavData->i16File);
+
+ //
+ // Mark file as no longer open.
+ //
+ psWavData->ui32Flags &= ~WAV_FLAG_FILEOPEN;
+ }
+}
+
+//******************************************************************************
+//
+// This function is used to read audio data from a file that was opened with
+// the WavOpen() function.
+//
+// \param psWavData is the file structure that was passed into the WavOpen()
+// function.
+// \param pucBuffer is the buffer to read data into.
+// \param ui32Size is the amount of data to read in bytes.
+//
+//
+// This function handles reading data from a .wav file that was opened with
+// the WavOpen() function. The function will return the actual number of
+// of bytes read from the file.
+//
+// \return This function returns the number of bytes read from the file.
+//
+//******************************************************************************
+uint16_t
+WavRead(tWavFile *psWavData, unsigned char *pucBuffer, uint32_t ui32Size)
+{
+ uint32_t ui32Count;
+
+ //
+ // Read in another buffer from the file.
+ //
+ if(f_read(&psWavData->i16File, pucBuffer, ui32Size,
+ (UINT *)&ui32Count) != FR_OK)
+ {
+ return(0);
+ }
+
+ return(ui32Count);
+}
diff --git a/utils/wavfile.h b/utils/wavfile.h
new file mode 100644
index 0000000..f044301
--- /dev/null
+++ b/utils/wavfile.h
@@ -0,0 +1,97 @@
+//*****************************************************************************
+//
+// wavfile.h - This file supports reading audio data from a .wav file and
+// reading the file format.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#ifndef WAVEFILE_H_
+#define WAVEFILE_H_
+
+//*****************************************************************************
+//
+// The wav file header information.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // Sample rate in bytes per second.
+ //
+ uint32_t ui32SampleRate;
+
+ //
+ // The average byte rate for the wav file.
+ //
+ uint32_t ui32AvgByteRate;
+
+ //
+ // The size of the wav data in the file.
+ //
+ uint32_t ui32DataSize;
+
+ //
+ // The number of bits per sample.
+ //
+ uint16_t ui16BitsPerSample;
+
+ //
+ // The wav file format.
+ //
+ uint16_t ui16Format;
+
+ //
+ // The number of audio channels.
+ //
+ uint16_t ui16NumChannels;
+}
+tWavHeader;
+
+//*****************************************************************************
+//
+// The structure used to hold the wav file state.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The wav files header information
+ //
+ tWavHeader sWavHeader;
+
+ //
+ // The file information for the current file.
+ //
+ FIL i16File;
+
+ //
+ // Current state flags, a combination of the WAV_FLAG_* values.
+ //
+ uint32_t ui32Flags;
+} tWavFile;
+
+void WavGetFormat(tWavFile *psWavData, tWavHeader *psWaveHeader);
+int WavOpen(const char *pcFileName, tWavFile *psWavData);
+void WavClose(tWavFile *psWavData);
+uint16_t WavRead(tWavFile *psWavData, unsigned char *pucBuffer,
+ uint32_t ui32Size);
+
+#endif