Update repo

This commit is contained in:
2026-08-30 23:04:35 -07:00
parent 749dab5721
commit ce65a0f59a
14950 changed files with 4408250 additions and 1 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,669 @@
//#############################################################################
// FILE: usbcdesc.c
// TITLE: Config descriptor parsing functions
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "debug.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/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.
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,600 @@
//#############################################################################
// FILE: usbdconfig.c
// TITLE: High level USB device configuration function
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "debug.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/device/usbdevice.h"
#include "include/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.
//
#ifdef __TMS320C28XX__
*pui32MaxPktSize = readusb16_t(&(psEndpoint->wMaxPacketSize)) & USB_EP_MAX_PACKET_COUNT_M;
#else
*pui32MaxPktSize = psEndpoint->wMaxPacketSize & USB_EP_MAX_PACKET_COUNT_M;
#endif
//
// 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.
//!
//! USBDCDConfig() is an optional call and applications may chose to make
//! direct calls to SysCtlPeripheralEnable(),
//! USBDevEndpointConfigSet() and USBFIFOConfigSet() instead of using this
//! function. If this function is used, it must be called prior to
//! USBDCDInit() since this call assumes that the low level hardware
//! configuration has been completed before it is made.
//!
//! \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?
//
#ifdef __TMS320C28XX__
if(readusb16_t(&(psEndpoint->wMaxPacketSize)) >
#else
if(psEndpoint->wMaxPacketSize >
#endif
psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType])
{
//
// Yes - remember the new maximum packet size.
//
psEPInfo[ui32EpIndex - 1].pui32Size[ui32EpType] =
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpoint->wMaxPacketSize));
#else
psEndpoint->wMaxPacketSize;
#endif
}
}
//
// 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(USB_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(USB_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(USB_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(USB_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.
//! @}
//
//*****************************************************************************
@@ -0,0 +1,705 @@
//#############################################################################
// FILE: usbddfu_rt.c
// TITLE: USB Device Firmware Update runtime device class driver.
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "debug.h"
#include "usb.h"
#include "cputimer.h"
#include "sysctl.h"
#include "interrupt.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/usbdfu.h"
#include "include/usb_ids.h"
#include "include/device/usbdevice.h"
#include "include/device/usbddfu_rt.h"
#include "include/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.
//
#ifdef __TMS320C28XX__
if(((readusb16_t(&(psUSBRequest->wValue)) >> 8) == USB_DFU_FUNC_DESCRIPTOR_TYPE) &&
((readusb16_t(&(psUSBRequest->wValue)) & 0xFF) == 0))
#else
if(((psUSBRequest->wValue >> 8) == USB_DFU_FUNC_DESCRIPTOR_TYPE) &&
((psUSBRequest->wValue & 0xFF) == 0))
#endif
{
//
// If there is more data to send than the host requested then just
// send the requested amount of data.
//
#ifdef __TMS320C28XX__
if((uint16_t)g_pui8DFUFunctionalDesc[0] > readusb16_t(&(psUSBRequest->wLength)))
{
ui32Size = (uint32_t)readusb16_t(&(psUSBRequest->wLength));
#else
if((uint16_t)g_pui8DFUFunctionalDesc[0] > psUSBRequest->wLength)
{
ui32Size = (uint32_t)psUSBRequest->wLength;
#endif
}
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.
//
#ifdef __TMS320C28XX__
if(readusb16_t(&(psUSBRequest->wIndex)) != psInst->ui8Interface)
#else
if(psUSBRequest->wIndex != psInst->ui8Interface)
#endif
{
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 = USB_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);
#ifdef __TMS320C28XX__
//
// Disable all interrupts.
//
Interrupt_disableGlobal();
#endif
//
// We must make sure we turn off Timer and its interrupt
// before entering the boot loader!
//
CPUTimer_disableInterrupt(CPUTIMER0_BASE);
CPUTimer_stopTimer(CPUTIMER0_BASE);
//
// Reset the USB peripheral
//
#ifdef __TMS320C28XX__
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_USBA);
SysCtl_resetPeripheral(SYSCTL_PERIPH_RES_USBA);
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_USBA);
#else
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_USB);
SysCtl_resetPeripheral(SYSCTL_PERIPH_RES_USB);
SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_USB);
#endif
//
// Wait for about a second.
//
#ifdef __TMS320C28XX__
SysCtl_delay(SysCtl_getClock(DEVICE_OSC_FREQ) / 3);
#else
SysCtl_delay(CM_CLK_FREQ / 3);
#endif
#ifdef __TMS320C28XX__
//
// Re-enable interrupts at the NVIC level.
//
Interrupt_enableGlobal();
#endif
//
// 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.
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,109 @@
//#############################################################################
// FILE: usbhandler.c
// TITLE: General USB handling routines
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/device/usbdevice.h"
#include "include/device/usbdevicepriv.h"
#include "include/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;
uint32_t ui32IntStatusEP;
//
// Get the controller interrupt status.
//
ui32Status = USBIntStatus(USB_BASE, &ui32IntStatusEP);
//
// Call the internal handler.
//
USBDeviceIntHandlerInternal(0, ui32Status, ui32IntStatusEP);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,780 @@
//#############################################################################
// FILE: usbhhid.c
// TITLE: This file contains the host HID driver
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/usbhid.h"
#include "include/host/usbhost.h"
#include "include/host/usbhostpriv.h"
#include "include/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] =
{
{0, 0, 0, eUSBHHIDClassNone, 0},
{0, 0, 0, eUSBHHIDClassNone, 0},
{0, 0, 0, eUSBHHIDClassNone, 0},
{0, 0, 0, eUSBHHIDClassNone, 0},
{0, 0, 0, eUSBHHIDClassNone, 0}
};
//*****************************************************************************
//
//! 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,
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
#else
psEndpointDescriptor->wMaxPacketSize,
#endif
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.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.bRequest), USBREQ_SET_IDLE);
#else
sSetupPacket.bRequest = USBREQ_SET_IDLE;
#endif
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), ((uint32_t)ui8Duration << 8) | ui8ReportID);
#else
sSetupPacket.wValue = (ui8Duration << 8) | ui8ReportID;
#endif
//
// Set this on interface 1.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wIndex), 0);
#else
sSetupPacket.wIndex = 0;
#endif
//
// This is always 0 for this request.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wLength), 0);
#else
sSetupPacket.wLength = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), (uint32_t)USB_HID_DTYPE_REPORT << 8);
#else
sSetupPacket.wValue = USB_HID_DTYPE_REPORT << 8;
#endif
//
// Index is always 0 for device requests.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wIndex), 0);
#else
sSetupPacket.wIndex = 0;
#endif
//
// All devices must have at least an 8 byte max packet size so just ask
// for 8 bytes to start with.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wLength), ui32Size);
#else
sSetupPacket.wLength = ui32Size;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), 0);
#else
sSetupPacket.wValue = 0;
#endif
}
else
{
//
// Report Protocol.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), 1);
#else
sSetupPacket.wValue = 1;
#endif
}
//
// Index is always 0 for device requests.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wIndex), 0);
#else
sSetupPacket.wIndex = 0;
#endif
//
// Always 0.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wLength), 0);
#else
sSetupPacket.wLength = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), (uint32_t)USB_HID_REPORT_OUTPUT << 8);
#else
sSetupPacket.wValue = USB_HID_REPORT_OUTPUT << 8;
#endif
//
// Index is always 0 for device requests.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wIndex), (uint16_t)ui32Interface);
#else
sSetupPacket.wIndex = (uint16_t)ui32Interface;
#endif
//
// Always 0.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wLength), ui32Size);
#else
sSetupPacket.wLength = ui32Size;
#endif
//
// 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);
}
//*****************************************************************************
//
//! @}
//
//*****************************************************************************
@@ -0,0 +1,718 @@
//#############################################################################
// FILE: usbhhidkeyboard.c
// TITLE: This file holds the application interfaces for USB
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "include/usblib.h"
#include "include/host/usbhost.h"
#include "include/usbhid.h"
#include "include/host/usbhhid.h"
#include "include/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 = 2; i32OldKey < 8; 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 = 2; i32OldKey < 8; 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 == 8)
{
//
// Look for a free location to store this key usage code.
//
for(i32OldKey = 2; i32OldKey < 8; 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);
}
//*****************************************************************************
//
//! @}
//
//*****************************************************************************
@@ -0,0 +1,418 @@
//#############################################################################
// FILE: usbhhidmouse.c
// TITLE: This file holds the application interfaces for USB
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "include/usblib.h"
#include "include/host/usbhost.h"
#include "include/usbhid.h"
#include "include/host/usbhhid.h"
#include "include/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);
}
//*****************************************************************************
//
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,751 @@
//#############################################################################
// FILE: usbhmsc.c
// TITLE: USB MSC host driver
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
#include "include/usbmsc.h"
#include "include/host/usbhost.h"
#include "include/host/usbhostpriv.h"
#include "include/host/usbhmsc.h"
#include "include/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, 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,
psDevice,
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
#else
psEndpointDescriptor->wMaxPacketSize,
#endif
0);
//
// Configure the USB pipe as a Bulk IN endpoint.
//
USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkInPipe,
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
#else
psEndpointDescriptor->wMaxPacketSize,
#endif
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,
psDevice,
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
#else
psEndpointDescriptor->wMaxPacketSize,
#endif
0);
//
// Configure the USB pipe as a Bulk OUT endpoint.
//
USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkOutPipe,
#ifdef __TMS320C28XX__
readusb16_t(&(psEndpointDescriptor->wMaxPacketSize)),
#else
psEndpointDescriptor->wMaxPacketSize,
#endif
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;
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wValue), 0);
#else
sSetupPacket.wValue = 0;
#endif
//
// Indicate the interface to use.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wIndex), (uint16_t)ui32Interface);
#else
sSetupPacket.wIndex = (uint16_t)ui32Interface;
#endif
//
// Only request a single byte of data.
//
#ifdef __TMS320C28XX__
writeusb16_t(&(sSetupPacket.wLength), 1);
#else
sSetupPacket.wLength = 1;
#endif
//
// 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] | ((uint32_t)pui8Buffer[6] << 8) | (uint32_t)pui8Buffer[5] << 16 |
((uint32_t)pui8Buffer[4] << 24));
//
// Read the block size out.
//
psMSCInstance->ui32NumBlocks =
(pui8Buffer[3] | ((uint32_t)pui8Buffer[2] << 8) | (uint32_t)pui8Buffer[1] << 16 |
((uint32_t)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);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,912 @@
//#############################################################################
// FILE: usbhscsi.c
// TITLE: USB host SCSI layer used by the USB host MSC driver
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "include/usblib.h"
#include "include/usbmsc.h"
#include "include/host/usbhost.h"
#include "include/host/usbhmsc.h"
#include "include/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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(sCmdStatus.dCSWSignature), 0);
writeusb32_t(&(sCmdStatus.dCSWTag), 0);
#else
sCmdStatus.dCSWSignature = 0;
sCmdStatus.dCSWTag = 0;
#endif
sCmdStatus.bCSWStatus = SCSI_CMD_STATUS_FAIL;
//
// Set the CBW signature and tag.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(psSCSICmd->dCBWSignature), CBW_SIGNATURE);
writeusb32_t(&(psSCSICmd->dCBWTag), CBW_TAG_VALUE);
#else
psSCSICmd->dCBWSignature = CBW_SIGNATURE;
psSCSICmd->dCBWTag = CBW_TAG_VALUE;
#endif
//
// Set the size of the data to be returned by the device.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(psSCSICmd->dCBWDataTransferLength), *pui32Size);
#else
psSCSICmd->dCBWDataTransferLength = *pui32Size;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
if(readusb32_t(&(psSCSICmd->dCBWDataTransferLength)) != 0)
#else
if(psSCSICmd->dCBWDataTransferLength != 0)
#endif
{
//
// 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.
//
#ifdef __TMS320C28XX__
if((ui32Bytes == 0) || (readusb32_t(&(sCmdStatus.dCSWSignature)) != CSW_SIGNATURE) ||
(readusb32_t(&(sCmdStatus.dCSWTag)) != CBW_TAG_VALUE))
#else
if((ui32Bytes == 0) || (sCmdStatus.dCSWSignature != CSW_SIGNATURE) ||
(sCmdStatus.dCSWTag != CBW_TAG_VALUE))
#endif
{
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;
#ifdef __TMS320C28XX__
usb32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (usb32_t *)sSCSICmd.CBWCB;
#else
uint32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (uint32_t *)sSCSICmd.CBWCB;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), SCSI_INQUIRY_CMD);
#else
pui32Data[0] = SCSI_INQUIRY_CMD;
#endif
//
// Allocation length.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[1]), SCSI_INQUIRY_DATA_SZ);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[1] = SCSI_INQUIRY_DATA_SZ;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
usb32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (usb32_t *)sSCSICmd.CBWCB;
#else
uint32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (uint32_t *)sSCSICmd.CBWCB;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), SCSI_READ_CAPACITY);
writeusb32_t(&(pui32Data[1]), 0);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[0] = SCSI_READ_CAPACITY;
pui32Data[1] = 0;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
usb32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (usb32_t *)sSCSICmd.CBWCB;
#else
uint32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (uint32_t *)sSCSICmd.CBWCB;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), SCSI_READ_CAPACITIES);
writeusb32_t(&(pui32Data[1]), 0);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[0] = SCSI_READ_CAPACITIES;
pui32Data[1] = 0;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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).
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), (SCSI_MODE_SENSE_6 | ui32Flags));
writeusb32_t(&(pui32Data[1]), (uint8_t)*pui32Size);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[0] = (SCSI_MODE_SENSE_6 | ui32Flags);
pui32Data[1] = (uint8_t)*pui32Size;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
usb32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (usb32_t *)sSCSICmd.CBWCB;
#else
uint32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (uint32_t *)sSCSICmd.CBWCB;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), SCSI_TEST_UNIT_READY);
writeusb32_t(&(pui32Data[1]), 0);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[0] = SCSI_TEST_UNIT_READY;
pui32Data[1] = 0;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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;
#ifdef __TMS320C28XX__
usb32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (usb32_t *)sSCSICmd.CBWCB;
#else
uint32_t *pui32Data;
//
// Create a local 32-bit pointer to the command.
//
pui32Data = (uint32_t *)sSCSICmd.CBWCB;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
writeusb32_t(&(pui32Data[0]), SCSI_REQUEST_SENSE);
writeusb32_t(&(pui32Data[1]), 18);
writeusb32_t(&(pui32Data[2]), 0);
writeusb32_t(&(pui32Data[3]), 0);
#else
pui32Data[0] = SCSI_REQUEST_SENSE;
pui32Data[1] = 18;
pui32Data[2] = 0;
pui32Data[3] = 0;
#endif
//
// 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;
//
// 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;
//
// 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;
//
// Transfer length in blocks starts at offset 2.
// This also sets the Control value to 0 at offset 9.
//
sSCSICmd.CBWCB[7] = (ui32NumBlocks & 0xFF00) >> 8;
*((uint32_t *)&sSCSICmd.CBWCB[8]) = (ui32NumBlocks & 0xFF);
*((uint32_t *)&sSCSICmd.CBWCB[12]) = 0;
//
// 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;
//
// 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 byte offset 8 or word address 4 (on C28x).
//
*((uint32_t *)&sSCSICmd.CBWCB[8]) = (ui32NumBlocks & 0xFF);
//
// The blocks go into byte offset 12 or word address 6 (on C28x).
//
*((uint32_t *)&sSCSICmd.CBWCB[12]) = 0;
//
// Send the command and get the results.
//
return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
pui32Size));
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,518 @@
//#############################################################################
// FILE: usbdesc.c
// TITLE: USB descriptor parsing functions
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "include/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.
//
#ifdef __TMS320C28XX__
while(ui32TotLength < (uint32_t)readusb16_t(&(psConfig->wTotalLength)))
#else
while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
#endif
{
//
// 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.
//
#ifdef __TMS320C28XX__
while(ui32TotLength < (uint32_t)readusb16_t(&(psConfig->wTotalLength)))
#else
while(ui32TotLength < (uint32_t)psConfig->wTotalLength)
#endif
{
//
// 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,
#ifdef __TMS320C28XX__
(uint32_t)readusb16_t(&(psConfig->wTotalLength)),
#else
(uint32_t)psConfig->wTotalLength,
#endif
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.
//! @}
//
//*****************************************************************************
@@ -0,0 +1,366 @@
//#############################################################################
// FILE: usbdma.c
// TITLE: USB Library DMA handling functions.
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "debug.h"
#include "interrupt.h"
#include "usb.h"
#include "include/usblib.h"
#include "include/usblibpriv.h"
//*****************************************************************************
//
//! \addtogroup usblib_dma_api Internal USB DMA functions
//! @{
//
//*****************************************************************************
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;
return(ui32Status);
}
//*****************************************************************************
//
// USBLibDMAIntStatus() for USB controllers that use uDMA.
//
//*****************************************************************************
static uint32_t
uDMAUSBIntStatus(tUSBDMAInstance *psUSBDMAInst)
{
return(0);
}
//*****************************************************************************
//
// USBLibDMAIntStatusClear() for USB controllers that use uDMA for DMA.
//
//*****************************************************************************
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.
//
//*****************************************************************************
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 &= ~((uint32_t)1 << ui32Channel);
psUSBDMAInst->ui32Complete |= ((uint32_t)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)
{
}
//*****************************************************************************
//
// USBLibDMAChannelDisable() for USB controllers that use uDMA.
//
//*****************************************************************************
static void
uDMAUSBChannelDisable(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel)
{
}
//*****************************************************************************
//
// 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.
//
}
//*****************************************************************************
//
// 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.
//
}
//*****************************************************************************
//
// USBLibDMATransfer() for USB controllers that use the uDMA controller.
//
//*****************************************************************************
static uint32_t
uDMAUSBTransfer(tUSBDMAInstance *psUSBDMAInst, uint32_t ui32Channel,
void *pvBuffer, uint32_t ui32Size)
{
return(0);
}
//*****************************************************************************
//
// USBLibDMAChannelAllocate() for USB controllers that use uDMA for DMA.
//
//*****************************************************************************
static uint32_t
uDMAUSBChannelAllocate(tUSBDMAInstance *psUSBDMAInst, uint8_t ui8Endpoint,
uint32_t ui32MaxPacketSize, uint32_t ui32Config)
{
return(0);
}
//*****************************************************************************
//
// USBLibDMAChannelRelease() for USB controllers that use uDMA for DMA.
//
//*****************************************************************************
static void
uDMAUSBChannelRelease(tUSBDMAInstance *psUSBDMAInst, uint8_t ui32Channel)
{
}
//*****************************************************************************
//
// USBLibDMAUnitSizeSet() for USB controllers that use uDMA for DMA.
//
//*****************************************************************************
static void
uDMAUSBUnitSizeSet(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)
{
}
//*****************************************************************************
//
// USBLibDMAStatus() for USB controllers that use uDMA for DMA.
//
//*****************************************************************************
static uint32_t
DMAUSBStatus(tUSBDMAInstance *psUSBDMAInst)
{
return(0);
}
//*****************************************************************************
//
//! 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 == USB_BASE);
//
// Save the base address of the USB controller.
//
g_psUSBDMAInst[0].ui32Base = ui32Index;
//
// Save the interrupt number for the USB controller.
//
g_psUSBDMAInst[0].ui32IntNum = INT_USB;
//
// 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;
//
// 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.
//! @}
//
//*****************************************************************************
@@ -0,0 +1,170 @@
//#############################################################################
// FILE: usbkeyboardmap.c
// TITLE: This file holds the table to enable USB keyboard usage
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "include/usblib.h"
#include "include/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
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,784 @@
//#############################################################################
// FILE: usbringbuf.c
// TITLE: USB library ring buffer management utilities
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "debug.h"
#include "interrupt.h"
#include "include/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)
{
#ifdef __TMS320C28XX__
bool bIntsOff;
#endif
#ifdef __TMS320C28XX__
//
// Turn interrupts off temporarily.
//
bIntsOff = Interrupt_disableGlobal();
#endif
//
// 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;
}
#ifdef __TMS320C28XX__
//
// Restore the interrupt state
//
if(!bIntsOff)
{
Interrupt_enableGlobal();
}
#endif
}
//*****************************************************************************
//
//! 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)
{
#ifdef __TMS320C28XX__
bool bIntsOff;
#endif
//
// 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.
//
#ifdef __TMS320C28XX__
bIntsOff = Interrupt_disableGlobal();
#endif
psUSBRingBuf->ui32ReadIndex = psUSBRingBuf->ui32WriteIndex;
#ifdef __TMS320C28XX__
if(!bIntsOff)
{
Interrupt_enableGlobal();
}
#endif
}
//*****************************************************************************
//
//! 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;
#ifdef __TMS320C28XX__
bool bIntsOff;
#endif
//
// Check the arguments.
//
ASSERT(psUSBRingBuf != NULL);
ASSERT(pui8Data != NULL);
ASSERT(ui32Length != 0);
#ifdef __TMS320C28XX__
//
// Turn interrupts off temporarily.
//
bIntsOff = Interrupt_disableGlobal();
#endif
//
// Write the data into the ring buffer.
//
for(ui32Temp = 0; ui32Temp < ui32Length; ui32Temp++)
{
//
// Write the data byte.
//
psUSBRingBuf->pui8Buf[psUSBRingBuf->ui32WriteIndex] =
pui8Data[ui32Temp];
//
// Increment the write index.
//
psUSBRingBuf->ui32WriteIndex++;
if (psUSBRingBuf->ui32WriteIndex >= psUSBRingBuf->ui32Size)
{
psUSBRingBuf->ui32WriteIndex = 0U;
}
}
#ifdef __TMS320C28XX__
//
// Restore the interrupt state
//
if(!bIntsOff)
{
Interrupt_enableGlobal();
}
#endif
}
//*****************************************************************************
//
//! 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.
//! @}
//
//*****************************************************************************
@@ -0,0 +1,245 @@
//#############################################################################
// FILE: usbtick.c
// TITLE: Functions related to USB stack tick timer handling
//#############################################################################
//!
//! Copyright: Copyright (C) 2023 Texas Instruments Incorporated -
//! All rights reserved not granted herein.
//! Limited License.
//!
//! Texas Instruments Incorporated grants a world-wide, royalty-free,
//! non-exclusive license under copyrights and patents it now or hereafter
//! owns or controls to make, have made, use, import, offer to sell and sell
//! ("Utilize") this software subject to the terms herein. With respect to the
//! foregoing patent license, such license is granted solely to the extent that
//! any such patent is necessary to Utilize the software alone. The patent
//! license shall not apply to any combinations which include this software,
//! other than combinations with devices manufactured by or for TI
//! ("TI Devices").
//! No hardware patent is licensed hereunder.
//!
//! Redistributions must preserve existing copyright notices and reproduce this
//! license (including the above copyright notice and the disclaimer and
//! (if applicable) source code license limitations below) in the documentation
//! and/or other materials provided with the distribution.
//!
//! Redistribution and use in binary form, without modification, are permitted
//! provided that the following conditions are met:
//!
//! * No reverse engineering, decompilation, or disassembly of this software is
//! permitted with respect to any software provided in binary form.
//! * Any redistribution and use are licensed by TI for use only
//! with TI Devices.
//! * Nothing shall obligate TI to provide you with source code for the
//! software licensed and provided to you in object code.
//!
//! If software source code is provided to you, modification and redistribution
//! of the source code are permitted provided that the following conditions
//! are met:
//!
//! * any redistribution and use of the source code, including any resulting
//! derivative works, are licensed by TI for use only with TI Devices.
//! * any redistribution and use of any object code compiled from the source
//! code and any resulting derivative works, are licensed by TI for use
//! only with TI Devices.
//!
//! Neither the name of Texas Instruments Incorporated nor the names of its
//! suppliers may be used to endorse or promote products derived from this
//! software without specific prior written permission.
//#############################################################################
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_types.h"
#include "debug.h"
#include "include/usblib.h"
#include "include/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.
//! @}
//
//*****************************************************************************