summaryrefslogtreecommitdiff
path: root/usblib/usbmode.c
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
committerYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
commitc241dbd7e78c50327781a35d88d9f2db7ff2b271 (patch)
tree2c84fe512c0cd3ee328244bca2f8ed4f9622074d /usblib/usbmode.c
parent4ba8614c006f9828f0796c140bc3e13c9e67938c (diff)
Added usblib
Diffstat (limited to 'usblib/usbmode.c')
-rw-r--r--usblib/usbmode.c1115
1 files changed, 1115 insertions, 0 deletions
diff --git a/usblib/usbmode.c b/usblib/usbmode.c
new file mode 100644
index 0000000..10ece23
--- /dev/null
+++ b/usblib/usbmode.c
@@ -0,0 +1,1115 @@
+//*****************************************************************************
+//
+// usbmode.c - Functions related to dual mode USB device/host operation.
+//
+// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library.
+//
+//*****************************************************************************
+
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.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/device/usbdevice.h"
+#include "usblib/host/usbhost.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_eUSBMode = USB_MODE_NONE;
+
+//*****************************************************************************
+//
+// The default and the current polling rate for the USB OTG library.
+//
+//*****************************************************************************
+volatile unsigned long g_ulPollRate;
+
+//*****************************************************************************
+//
+// The current time remaining in milliseconds before checking the cable
+// connection.
+//
+//*****************************************************************************
+volatile unsigned long g_ulWaitTicks = 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.
+ //
+ USB_OTG_MODE_IDLE,
+
+ //
+ // Waiting on ID mode detection.
+ //
+ USB_OTG_MODE_WAITID,
+
+ //
+ // Waiting for next poll interval.
+ //
+ USB_OTG_MODE_WAIT,
+
+ //
+ // Now in B-side wait for connect.
+ //
+ USB_OTG_MODE_B_WAITCON,
+
+ //
+ // Now in A-side device mode.
+ //
+ USB_OTG_MODE_B_DEVICE,
+
+ //
+ // Now in A-side host mode.
+ //
+ USB_OTG_MODE_A_HOST,
+}
+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_eDualMode = USB_MODE_NONE;
+
+static void USBOTGRemovePower(unsigned long ulIndex);
+
+//*****************************************************************************
+//
+// 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 eUSBMode is one of USB_MODE_HOST, USB_MODE_DEVICE, or USB_MODE_NONE.
+//
+// Based on the current state held in g_eDualMode 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 eUSBMode)
+{
+ if((g_eDualMode != eUSBMode) || (g_eDualMode == USB_MODE_NONE))
+ {
+ //
+ // If going from host mode to unconfigured mode then remove power.
+ //
+ if((g_eDualMode == USB_MODE_HOST) && (eUSBMode == USB_MODE_NONE))
+ {
+ //
+ // 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_eDualMode == USB_MODE_DEVICE) && (eUSBMode == USB_MODE_NONE))
+ {
+ //
+ // End the current session.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+ }
+
+ //
+ // Reset the delay whenever returning to USB_MODE_NONE.
+ //
+ if(eUSBMode == USB_MODE_NONE)
+ {
+ g_ulWaitTicks = g_ulPollRate;
+ }
+
+ //
+ // Do we have a mode change callback installed?
+ //
+ if((g_pfnUSBModeCallback) && (g_eDualMode != eUSBMode))
+ {
+ //
+ // Inform the callback of the new operating mode.
+ //
+ g_pfnUSBModeCallback(0, eUSBMode);
+ }
+
+ //
+ // Save the new mode.
+ //
+ g_eDualMode = eUSBMode;
+ }
+}
+
+//*****************************************************************************
+//
+//! 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 ulIndex specifies the USB controller whose mode of operation is to
+//! be set. This parameter must be set to 0.
+//! \param eUSBMode indicates the mode that the application wishes to operate
+//! in. Valid values are \b USB_MODE_DEVICE to operate as a USB device and
+//! \b USB_MODE_HOST 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 eUSBMode is set to either \b USB_MODE_DEVICE or
+//! \b USB_MODE_HOST, 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.
+//!
+//! \note Forcing of the USB controller mode feature is not available on all
+//! Stellaris microcontrollers. Consult the data sheet for the microcontroller
+//! that the application is using to determine if this feature is available.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBStackModeSet(unsigned long ulIndex, tUSBMode eUSBMode,
+ tUSBModeCallback pfnCallback)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // Remember the mode so that we can steer the interrupts appropriately.
+ //
+ g_eUSBMode = eUSBMode;
+
+ //
+ // 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((eUSBMode == USB_MODE_DEVICE) || (eUSBMode == USB_MODE_HOST))
+ {
+ //
+ // Make sure that a callback was provided.
+ //
+ if(g_pfnUSBModeCallback)
+ {
+ g_pfnUSBModeCallback(0, eUSBMode);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! 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)
+{
+ unsigned long ulStatus;
+
+ //
+ // Read the USB interrupt status.
+ //
+ ulStatus = 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(ulStatus & USB_HOST_INTS)
+ {
+ //
+ // Call the host's interrupt handler.
+ //
+ USBHostIntHandlerInternal(0, ulStatus & USB_HOST_INTS);
+
+ //
+ // We have already processed these interrupts so clear them
+ // from the status.
+ //
+ ulStatus &= ~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 ulStatus parameter since the USB interrupt register is
+ // clear-on-read.
+ //
+ switch(g_eUSBMode)
+ {
+ case USB_MODE_NONE:
+ {
+ //
+ // No mode is set yet so we have no idea what to do. Just ignore
+ // the interrupt.
+ //
+ break;
+ }
+
+ //
+ // Operating in pure host mode.
+ //
+ case USB_MODE_HOST:
+ {
+ //
+ // Call the host interrupt handler if there is anything still to
+ // process.
+ //
+ USBHostIntHandlerInternal(0, ulStatus);
+
+ break;
+ }
+
+ //
+ // Operating in pure device mode.
+ //
+ case USB_MODE_DEVICE:
+ {
+ //
+ // Call the device interrupt handler.
+ //
+ USBDeviceIntHandlerInternal(0, ulStatus);
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the USB controller for dual mode operation.
+//!
+//! \param ulIndex 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(unsigned long ulIndex)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ulIndex == 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(INT_USB0);
+
+ //
+ // Turn on session request to enable ID pin checking.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+
+ //
+ // Initialize the power configuration.
+ //
+ USBHostPwrConfig(USB0_BASE, USBHCDPowerConfigGet(ulIndex));
+
+ //
+ // 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(ulIndex))
+ {
+ //
+ // 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 ulIndex 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(unsigned long ulIndex)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(INT_USB0);
+
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+//! \addtogroup usblib_otg
+//! @{
+//
+//*****************************************************************************
+
+
+//*****************************************************************************
+//
+//! Returns the USB controller to and inactive state when in OTG mode operation.
+//!
+//! \param ulIndex 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(unsigned long ulIndex)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(INT_USB0);
+
+ //
+ // 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(USB_MODE_NONE);
+}
+
+//*****************************************************************************
+//
+//! Initializes the USB controller for OTG mode operation.
+//!
+//! \param ulIndex specifies the USB controller that is to be initialized for
+//! OTG mode operation.
+//! \param ulPollingRate 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 ulPoolSize is the size in bytes of the buffer passed in as 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 ulPollingRate 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 ulPoolSize 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(unsigned long ulIndex, unsigned long ulPollingRate,
+ void *pvPool, unsigned long ulPoolSize)
+{
+ //
+ // We only support a single USB controller.
+ //
+ ASSERT(ulIndex == 0);
+
+ //
+ // This should never be called if not in OTG mode.
+ //
+ ASSERT(g_eUSBMode == USB_MODE_OTG);
+
+ //
+ // 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_eUSBMode = USB_MODE_OTG;
+
+ //
+ // Remember that we have not yet determined whether we are device or
+ // host.
+ //
+ g_eDualMode = USB_MODE_NONE;
+
+ //
+ // Set the default polling rate.
+ //
+ g_ulPollRate = ulPollingRate;
+
+ //
+ // Enable the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Initialize the host controller stack.
+ //
+ USBHCDInit(ulIndex, pvPool, ulPoolSize);
+
+ //
+ // 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(ulIndex, USBHCDPowerConfigGet(ulIndex));
+
+ //
+ // 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(ulIndex))
+ {
+ //
+ // 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.
+ //
+ OS_INT_ENABLE(INT_USB0);
+}
+
+//*****************************************************************************
+//
+// This function handles the steps required to remove power in OTG mode.
+//
+// \param ulIndex 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(unsigned long ulIndex)
+{
+ 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(ulIndex) == 0)
+ {
+ //
+ // Call the registered event driver to allow it to disable power.
+ //
+ sEvent.ulEvent = USB_EVENT_POWER_DISABLE;
+ sEvent.ulInstance = 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 ulIndex specifies which USB controller to set the polling rate.
+//! \param ulPollRate 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 ulPollRate 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 ulPollRate 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(unsigned long ulIndex, unsigned long ulPollRate)
+{
+ //
+ // Save the timeout.
+ //
+ g_ulPollRate = ulPollRate;
+}
+
+//*****************************************************************************
+//
+//! 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)
+{
+ unsigned long ulStatus;
+ tEventInfo sEvent;
+
+ //
+ // Read the USB interrupt status.
+ //
+ ulStatus = USBIntStatusControl(USB0_BASE);
+
+ //
+ // Check if this was an mode detect interrupt and under manual power
+ // control.
+ //
+ if((ulStatus & USB_INTCTRL_MODE_DETECT) &&
+ (USBHCDPowerAutomatic(0) == 0))
+ {
+ unsigned long ulMode;
+
+ ulMode = USBModeGet(USB0_BASE);
+
+ switch(ulMode)
+ {
+ //
+ // 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.ulEvent = USB_EVENT_POWER_ENABLE;
+ sEvent.ulInstance = 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 = USB_OTG_MODE_B_WAITCON;
+
+ break;
+ }
+
+ //
+ // Any other mode detect indicates USB_MODE_NONE.
+ //
+ default:
+ {
+ //
+ // Just inform the application that the mode was not device
+ // or host.
+ //
+ USBOTGSetMode(USB_MODE_NONE);
+
+ 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(ulStatus & USB_INTCTRL_VBUS_ERR)
+ {
+ //
+ // Just inform the application that the mode was not device
+ // or host.
+ //
+ USBOTGSetMode(USB_MODE_NONE);
+
+ //
+ // Return to idle mode.
+ //
+ g_eOTGModeState = USB_OTG_MODE_WAIT;
+ }
+
+ //
+ // 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((ulStatus & USB_INTCTRL_DISCONNECT) &&
+ (g_eOTGModeState == USB_OTG_MODE_B_DEVICE))
+ {
+ //
+ // No longer a device so switch to unconfigured mode.
+ //
+ USBOTGSetMode(USB_MODE_NONE);
+
+ //
+ // Return to idle mode.
+ //
+ g_eOTGModeState = USB_OTG_MODE_WAIT;
+
+ return;
+ }
+
+ //
+ // Handle receiving a reset.
+ //
+ if((ulStatus & USB_INTCTRL_RESET)&&
+ (g_eOTGModeState != USB_OTG_MODE_B_DEVICE))
+ {
+ //
+ // 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 = USB_OTG_MODE_B_DEVICE;
+
+ //
+ // Save the new mode.
+ //
+ USBOTGSetMode(USB_MODE_DEVICE);
+ }
+
+ //
+ // If there is a connect interrupt while the library is waiting for
+ // one then move to full host mode state.
+ //
+ if(ulStatus & USB_INTCTRL_CONNECT)
+ {
+ //
+ // Move to A side host state.
+ //
+ g_eOTGModeState = USB_OTG_MODE_A_HOST;
+
+ //
+ // Inform the application that controller is in host mode.
+ //
+ USBOTGSetMode(USB_MODE_HOST);
+ }
+
+ //
+ // Call the correct device or host interrupt handler based on the current
+ // mode of operation.
+ //
+ switch(g_eOTGModeState)
+ {
+ case USB_OTG_MODE_A_HOST:
+ {
+ //
+ // Call the host interrupt handler if there is anything still to
+ // process.
+ //
+ USBHostIntHandlerInternal(0, ulStatus);
+
+ break;
+ }
+
+ //
+ // Operating in pure device mode.
+ //
+ case USB_OTG_MODE_B_DEVICE:
+ {
+ //
+ // Call the device interrupt handler.
+ //
+ USBDeviceIntHandlerInternal(0, ulStatus);
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function is called by the USB host stack code to indicated that it
+// has compeleted handing the device disconnection.
+//
+// \param ulIndex 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(unsigned long ulIndex)
+{
+ //
+ // This function is only valid when called in host mode.
+ //
+ if(g_eOTGModeState == USB_OTG_MODE_A_HOST)
+ {
+ //
+ // No longer a host so switch to unconfigured mode.
+ //
+ USBOTGSetMode(USB_MODE_NONE);
+
+ g_eOTGModeState = USB_OTG_MODE_WAIT;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is the main routine for the OTG Controller Driver.
+//!
+//! \param ulMsTicks 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 ulMsTicks 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(unsigned long ulMsTicks)
+{
+ tEventInfo sEvent;
+
+ if(ulMsTicks > g_ulWaitTicks)
+ {
+ g_ulWaitTicks = 0;
+ }
+ else
+ {
+ g_ulWaitTicks -= ulMsTicks;
+ }
+
+ switch(g_eOTGModeState)
+ {
+ case USB_OTG_MODE_IDLE:
+ {
+ g_eOTGModeState = USB_OTG_MODE_WAITID;
+
+ //
+ // Initiate a session request and check the ID pin.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+ break;
+ }
+ case USB_OTG_MODE_WAIT:
+ case USB_OTG_MODE_WAITID:
+ {
+ //
+ // If reached the timeout and polling is enabled then look again.
+ //
+ if((g_ulWaitTicks == 0) && (g_ulPollRate != 0))
+ {
+ //
+ // Remove the session request.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+
+ //
+ // Return to idle mode.
+ //
+ USBOTGSetMode(USB_MODE_NONE);
+
+ //
+ // 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.ulEvent = USB_EVENT_POWER_DISABLE;
+ sEvent.ulInstance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWRDIS);
+ }
+
+ //
+ // Go back to the idle state.
+ //
+ g_eOTGModeState = USB_OTG_MODE_IDLE;
+ }
+ break;
+ }
+ case USB_OTG_MODE_A_HOST:
+ {
+ //
+ // Call the host main routine when acting as a host.
+ //
+ USBHCDMain();
+ break;
+ }
+ case USB_OTG_MODE_B_WAITCON:
+ case USB_OTG_MODE_B_DEVICE:
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************