This commit is contained in:
Steven Dan
2025-12-11 09:43:42 +08:00
commit d8b2974133
1822 changed files with 280037 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "XUD_USB_Defines.h"

View File

@@ -0,0 +1,4 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xud_device.h"

View File

@@ -0,0 +1,4 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xud_std_descriptors.h"

View File

@@ -0,0 +1,4 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xud_std_requests.h"

520
lib_xud/lib_xud/api/xud.h Normal file
View File

@@ -0,0 +1,520 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/*
* \brief User defines and functions for XMOS USB Device library
*/
#ifndef _XUD_H_
#define _XUD_H_
#include <platform.h>
#if !defined(__XS2A__)
#define XUD_OPT_SOFTCRC5 (1)
#else
#define XUD_OPT_SOFTCRC5 (0)
#endif
#ifdef __xud_conf_h_exists__
#include "xud_conf.h"
#endif
#ifndef XUD_STARTUP_ADDRESS
#define XUD_STARTUP_ADDRESS (0)
#endif
#ifndef __ASSEMBLER__
#include <xs1.h>
#include <platform.h>
#include <print.h>
#include <xccompat.h>
#ifndef XUD_WEAK_API
#define XUD_WEAK_API (0)
#endif
#if defined(__STDC__) && XUD_WEAK_API
#define ATTRIB_WEAK __attribute__((weak));
#else
#define ATTRIB_WEAK
#endif
#if !defined(USB_TILE)
#define USB_TILE tile[0]
#endif
#ifndef XUD_CORE_CLOCK
#ifdef __XS2A__
//#warning XUD_CORE_CLOCK not defined, using default (500MHz)
#define XUD_CORE_CLOCK (500)
#else
//#warning XUD_CORE_CLOCK not defined, using default (600MHz)
#define XUD_CORE_CLOCK (600)
#endif
#endif
#if !defined(PORT_USB_CLK)
/* Ports have not been defined in the .xn file */
#define PORT_USB_CLK on USB_TILE: XS1_PORT_1J
#define PORT_USB_TXD on USB_TILE: XS1_PORT_8A
#define PORT_USB_RXD on USB_TILE: XS1_PORT_8B
#define PORT_USB_TX_READYOUT on USB_TILE: XS1_PORT_1K
#define PORT_USB_TX_READYIN on USB_TILE: XS1_PORT_1H
#define PORT_USB_RX_READY on USB_TILE: XS1_PORT_1I
#define PORT_USB_FLAG0 on USB_TILE: XS1_PORT_1E
#define PORT_USB_FLAG1 on USB_TILE: XS1_PORT_1F
#ifdef __XS2A__
/* XS2A has an additional flag port */
#define PORT_USB_FLAG2 on USB_TILE: XS1_PORT_1G
#endif
#endif // PORT_USB_CLK
/**
* \var typedef XUD_EpTransferType
* \brief Typedef for endpoint data transfer types. Note: it is important that ISO is 0
*/
typedef enum XUD_EpTransferType
{
XUD_EPTYPE_ISO = 0, /**< Isoc */
XUD_EPTYPE_INT, /**< Interrupt */
XUD_EPTYPE_BUL, /**< Bulk */
XUD_EPTYPE_CTL, /**< Control */
XUD_EPTYPE_DIS, /**< Disabled */
} XUD_EpTransferType;
/**
* \var typedef XUD_EpType
* \brief Typedef for endpoint type
*/
typedef unsigned int XUD_EpType;
/**
* \var typedef XUD_ep
* \brief Typedef for endpoint identifiers
*/
typedef unsigned int XUD_ep;
/* Value to be or'ed in with EpTransferType to enable bus state notifications */
#define XUD_STATUS_ENABLE 0x80000000
typedef enum XUD_BusSpeed
{
XUD_SPEED_FS = 1,
XUD_SPEED_HS = 2,
XUD_SPEED_KILL = 3
} XUD_BusSpeed_t;
typedef enum XUD_PwrConfig
{
XUD_PWR_BUS,
XUD_PWR_SELF
} XUD_PwrConfig;
typedef enum XUD_Result
{
XUD_RES_RST = -1,
XUD_RES_OKAY = 0,
//XUD_RES_CTL = 1, /* Received a control trans */
XUD_RES_ERR = 2,
} XUD_Result_t;
/** This performs the low-level USB I/O operations. Note that this
* needs to run in a thread with at least 80 MIPS worst case execution
* speed.
*
* \param c_epOut An array of channel ends, one channel end per
* output endpoint (USB OUT transaction); this includes
* a channel to obtain requests on Endpoint 0.
* \param noEpOut The number of output endpoints, should be at least 1 (for Endpoint 0).
* \param c_epIn An array of channel ends, one channel end per input endpoint (USB IN transaction);
* this includes a channel to respond to requests on Endpoint 0.
* \param noEpIn The number of input endpoints, should be at least 1 (for Endpoint 0).
* \param c_sof A channel to receive SOF tokens on. This channel must be connected to a process that
* can receive a token once every 125 ms. If tokens are not read, the USB layer will lock up.
* If no SOF tokens are required ``null`` should be used for this parameter.
*
* \param epTypeTableOut See ``epTypeTableIn``.
* \param epTypeTableIn This and ``epTypeTableOut`` are two arrays
* indicating the type of the endpoint.
* Legal types include:
* ``XUD_EPTYPE_CTL`` (Endpoint 0),
* ``XUD_EPTYPE_BUL`` (Bulk endpoint),
* ``XUD_EPTYPE_ISO`` (Isochronous endpoint),
* ``XUD_EPTYPE_INT`` (Interrupt endpoint),
* ``XUD_EPTYPE_DIS`` (Endpoint not used).
* The first array contains the
* endpoint types for each of the OUT
* endpoints, the second array contains the
* endpoint types for each of the IN
* endpoints.
* \param desiredSpeed This parameter specifies what speed the device will attempt to run at
* i.e. full-speed (ie 12Mbps) or high-speed (480Mbps) if supported
* by the host. Pass ``XUD_SPEED_HS`` if high-speed is desired or ``XUD_SPEED_FS``
* if not. Low speed USB is not supported by XUD.
* \param pwrConfig Specifies whether the device is bus or self-powered. When self-powered the XUD
* will monitor the VBUS line for host disconnections. This is required for compliance reasons.
* Valid values are XUD_PWR_SELF and XUD_PWR_BUS.
*
*/
int XUD_Main(/*tileref * unsafe usbtileXUD_res_t &xudres, */
chanend c_epOut[], int noEpOut,
chanend c_epIn[], int noEpIn,
NULLABLE_RESOURCE(chanend, c_sof),
XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
XUD_BusSpeed_t desiredSpeed,
XUD_PwrConfig pwrConfig);
/* Legacy API support */
int XUD_Manager(chanend c_epOut[], int noEpOut,
chanend c_epIn[], int noEpIn,
NULLABLE_RESOURCE(chanend, c_sof),
XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
NULLABLE_RESOURCE(port, p_usb_rst),
NULLABLE_RESOURCE(xcore_clock_t, clk),
unsigned rstMask,
XUD_BusSpeed_t desiredSpeed,
XUD_PwrConfig pwrConfig);
/**
* \brief This function must be called by a thread that deals with an OUT endpoint.
* When the host sends data, the low-level driver will fill the buffer. It
* pauses until data is available.
* \param ep_out The OUT endpoint identifier (created by ``XUD_InitEP``).
* \param buffer The buffer in which to store data received from the host.
* The buffer is assumed to be word aligned.
* \param length The number of bytes written to the buffer
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`_.
**/
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length)) ATTRIB_WEAK;
/**
* \brief Request setup data from usb buffer for a specific endpoint, pauses until data is available.
* \param ep_out The OUT endpoint identifier (created by ``XUD_InitEP``).
* \param buffer A char buffer passed by ref into which data is returned.
* \param length Length of the buffer received (expect 8 bytes)
* \return XUD_RES_OKAY on success, for errors see ``Status Reporting``_.
**/
XUD_Result_t XUD_GetSetupBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length)) ATTRIB_WEAK;
/**
* \brief This function must be called by a thread that deals with an IN endpoint.
* When the host asks for data, the low-level driver will transmit the buffer
* to the host.
* \param ep_in The endpoint identifier (created by ``XUD_InitEp``).
* \param buffer The buffer of data to transmit to the host.
* \param datalength The number of bytes in the buffer.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`_.
*/
XUD_Result_t XUD_SetBuffer(XUD_ep ep_in, unsigned char buffer[], unsigned datalength) ATTRIB_WEAK;
/**
* \brief Similar to XUD_SetBuffer but breaks up data transfers into smaller packets.
* This function must be called by a thread that deals with an IN endpoint.
* When the host asks for data, the low-level driver will transmit the buffer
* to the host.
* \param ep_in The IN endpoint identifier (created by ``XUD_InitEp``).
* \param buffer The buffer of data to transmit to the host.
* \param datalength The number of bytes in the buffer.
* \param epMax The maximum packet size in bytes.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`_.
*/
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax) ATTRIB_WEAK;
/**
* \brief Performs a combined ``XUD_SetBuffer`` and ``XUD_GetBuffer``.
* It transmits the buffer of the given length over the ``ep_in`` endpoint to
* answer an IN request, and then waits for a 0 length Status OUT transaction on ``ep_out``.
* This function is normally called to handle Get control requests to Endpoint 0.
*
* \param ep_out The endpoint identifier that handles Endpoint 0 OUT data in the XUD manager.
* \param ep_in The endpoint identifier that handles Endpoint 0 IN data in the XUD manager.
* \param buffer The data to send in response to the IN transaction. Note that this data
* is chopped up in fragments of at most 64 bytes.
* \param length Length of data to be sent.
* \param requested The length that the host requested, (Typically pass the value ``wLength``).
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`_
**/
XUD_Result_t XUD_DoGetRequest(XUD_ep ep_out, XUD_ep ep_in, unsigned char buffer[], unsigned length, unsigned requested) ATTRIB_WEAK;
/**
* \brief This function sends an empty packet back on the next IN request with
* PID1. It is normally used by Endpoint 0 to acknowledge success of a control transfer.
* \param ep_in The Endpoint 0 IN identifier to the XUD manager.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`_.
**/
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in) ATTRIB_WEAK;
/**
* \brief This function will complete a reset on an endpoint. Can take
* one or two ``XUD_ep`` as parameters (the second parameter can be set to ``null``).
* The return value should be inspected to find the new bus-speed.
* In Endpoint 0 typically two endpoints are reset (IN and OUT).
* In other endpoints ``null`` can be passed as the second parameter.
* \param one IN or OUT endpoint identifier to perform the reset on.
* \param two Optional second IN or OUT endpoint structure to perform a reset on.
* \return Either ``XUD_SPEED_HS`` - the host has accepted that this device can execute
* at high speed, ``XUD_SPEED_FS`` - the device is running at full speed,
* or ``XUD_SPEED_KILL`` to indicate that the USB stack has been shut down
* by another part of the user code (using XUD_Kill). If the last value is
* returned, the endpoint code should call XUD_CloseEndpoint and then
* terminate.
*/
XUD_BusSpeed_t XUD_ResetEndpoint(XUD_ep one, NULLABLE_REFERENCE_PARAM(XUD_ep, two));
/**
* \brief This function closes an endpoint. It should be called when the USB stack
* is shutting down. It should be called on all endpoints, either in parallel
* or in numerical order, first all OUT and then all IN endpoints
* \param one endpoint to close.
*/
void XUD_CloseEndpoint(XUD_ep one);
/**
* \brief Initialises an XUD_ep
* \param c_ep Endpoint channel to be connected to the XUD library.
* \return Endpoint identifier
*/
XUD_ep XUD_InitEp(chanend c_ep);
/**
* \brief Mark an endpoint as STALL based on its EP address. Cleared automatically if a SETUP received on the endpoint.
* Note: the IN bit of the endpoint address is used.
* \param epNum Endpoint number.
* \warning Must be run on same tile as XUD core
*/
void XUD_SetStallByAddr(int epNum);
/**
* \brief Mark an endpoint as NOT STALLed based on its EP address.
* Note: the IN bit of the endpoint address is used.
* \param epNum Endpoint number.
* \warning Must be run on same tile as XUD core
*/
void XUD_ClearStallByAddr(int epNum);
/**
* \brief Mark an endpoint as STALLed. It is cleared automatically if a SETUP received on the endpoint.
* \param ep XUD_ep type.
* \warning Must be run on same tile as XUD core
*/
void XUD_SetStall(XUD_ep ep);
/**
* \brief Mark an endpoint as NOT STALLed
* \param ep XUD_ep type.
* \warning Must be run on same tile as XUD core
*/
void XUD_ClearStall(XUD_ep ep);
/* USB 2.0 Spec 9.1.1.5 states that configuring a device should cause all
* the status and configuration values associated with the endpoints in the
* affected interfaces to be set to their default values. This includes setting
* the data toggle of any endpoint using data toggles to the value DATA0 */
/**
* \brief Reset an Endpoints state including data PID toggle
* Note: the IN bit of the endpoint address is used.
* \param epNum Endpoint number (including IN bit)
* \warning Must be run on same tile as XUD core
*/
void XUD_ResetEpStateByAddr(unsigned epNum);
/**
* \brief Enable a specific USB test mode in XUD
* \param ep XUD_ep type (must be endpoint 0 in or out)
* \param testMode The desired test-mode
* \warning Must be run on same tile as XUD core
*/
void XUD_SetTestMode(XUD_ep ep, unsigned testMode);
/**
* \brief Terminate XUD core
* \param ep XUD_ep type (must be endpoint 0 in or out)
* \warning Must be run on same tile as XUD core
*/
void XUD_Kill(XUD_ep ep);
/***********************************************************************************************/
/*
* Advanced functions for supporting multple Endpoints in a single core
*/
/**
* \brief Marks an OUT endpoint as ready to receive data
* \param ep The OUT endpoint identifier (created by ``XUD_InitEp``).
* \param addr The address of the buffer in which to store data received from the host.
* The buffer is assumed to be word aligned.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
#if (XUD_WEAK_API)
XUD_Result_t XUD_SetReady_OutPtr(XUD_ep ep, unsigned addr);
#else
static inline XUD_Result_t XUD_SetReady_OutPtr(XUD_ep ep, unsigned addr)
{
int chan_array_ptr;
int reset;
/* Firstly check if we have missed a USB reset - endpoint may would not want receive after a reset */
asm volatile("ldw %0, %1[9]":"=r"(reset):"r"(ep));
if(reset)
{
return XUD_RES_RST;
}
asm volatile("ldw %0, %1[0]":"=r"(chan_array_ptr):"r"(ep));
asm volatile("stw %0, %1[3]"::"r"(addr),"r"(ep)); // Store buffer
asm volatile("stw %0, %1[0]"::"r"(ep),"r"(chan_array_ptr));
return XUD_RES_OKAY;
}
#endif
/**
* \brief Marks an OUT endpoint as ready to receive data
* \param ep The OUT endpoint identifier (created by ``XUD_InitEp``).
* \param buffer The buffer in which to store data received from the host.
* The buffer is assumed to be word aligned.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
int XUD_SetReady_Out(XUD_ep ep, unsigned char buffer[]) ATTRIB_WEAK;
/**
* \brief Marks an IN endpoint as ready to transmit data
* \param ep The IN endpoint identifier (created by ``XUD_InitEp``).
* \param addr The address of the buffer to transmit to the host.
* The buffer is assumed be word aligned.
* \param len The length of the data to transmit.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
#if (XUD_WEAK_API)
XUD_Result_t XUD_SetReady_InPtr(XUD_ep ep, unsigned addr, int len);
#else
static inline XUD_Result_t XUD_SetReady_InPtr(XUD_ep ep, unsigned addr, int len)
{
int chan_array_ptr;
int tmp, tmp2;
int wordLength;
int tailLength;
int reset;
/* Firstly check if we have missed a USB reset - endpoint may not want to send out old data after a reset */
asm volatile("ldw %0, %1[9]":"=r"(reset):"r"(ep));
if(reset)
{
return XUD_RES_RST;
}
/* Tail length bytes to bits */
#ifdef __XC__
tailLength = zext((len << 3),5);
#else
tailLength = (len << 3) & 0x1F;
#endif
/* Datalength (bytes) --> datalength (words) */
wordLength = len >> 2;
/* If tail-length is 0 and word-length not 0. Make tail-length 32 and word-length-- */
if ((tailLength == 0) && (wordLength != 0))
{
wordLength = wordLength - 1;
tailLength = 32;
}
/* Get end off buffer address */
asm volatile("add %0, %1, %2":"=r"(tmp):"r"(addr),"r"(wordLength << 2));
/* Produce negative offset from end of buffer */
asm volatile("neg %0, %1":"=r"(tmp2):"r"(wordLength));
/* Store neg index */
asm volatile("stw %0, %1[6]"::"r"(tmp2),"r"(ep));
/* Store buffer pointer */
asm volatile("stw %0, %1[3]"::"r"(tmp),"r"(ep));
/* Store tail len */
asm volatile("stw %0, %1[7]"::"r"(tailLength),"r"(ep));
/* Finally, mark ready */
asm volatile("ldw %0, %1[0]":"=r"(chan_array_ptr):"r"(ep));
asm volatile("stw %0, %1[0]"::"r"(ep),"r"(chan_array_ptr));
return XUD_RES_OKAY;
}
#endif
/**
* \brief Marks an IN endpoint as ready to transmit data
* \param ep The IN endpoint identifier (created by ``XUD_InitEp``).
* \param buffer The buffer to transmit to the host.
* The buffer is assumed be word aligned.
* \param len The length of the data to transmit.
* \return XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
static inline XUD_Result_t XUD_SetReady_In(XUD_ep ep, unsigned char buffer[], int len)
{
unsigned addr;
asm volatile("mov %0, %1":"=r"(addr):"r"(buffer));
return XUD_SetReady_InPtr(ep, addr, len);
}
/**
* \brief Select handler function for receiving OUT endpoint data in a select.
* \param c The chanend related to the endpoint
* \param ep The OUT endpoint identifier (created by ``XUD_InitEp``).
* \param length Passed by reference. The number of bytes written to the buffer (that was passed into
* XUD_SetReady_Out())
* \param result XUD_Result_t passed by reference. XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
#ifdef __XC__
#pragma select handler
#endif
void XUD_GetData_Select(chanend c, XUD_ep ep, REFERENCE_PARAM(unsigned, length), REFERENCE_PARAM(XUD_Result_t, result));
/**
* \brief Select handler function for transmitting IN endpoint data in a select.
* \param c The chanend related to the endpoint
* \param ep The IN endpoint identifier (created by ``XUD_InitEp``).
* \param result Passed by reference. XUD_RES_OKAY on success, for errors see `Status Reporting`.
*/
#ifdef __XC__
#pragma select handler
#endif
void XUD_SetData_Select(chanend c, XUD_ep ep, REFERENCE_PARAM(XUD_Result_t, result));
/* Control token defines - used to inform EPs of bus-state types */
#define USB_RESET_TOKEN 8 /* Control token value that signals RESET */
#ifndef XUD_OSC_MHZ
#define XUD_OSC_MHZ (24)
#endif
/* TODO pack this to save mem
* TODO size of this hardcoded in ResetEpStateByAddr_
*/
typedef struct XUD_ep_info
{
unsigned int array_ptr; // 0
unsigned int xud_chanend; // 1
unsigned int client_chanend; // 2
unsigned int buffer; // 3 Pointer to buffer
unsigned int pid; // 4 Expected out PID
unsigned int epType; // 5 Data
unsigned int actualPid; // 6 Actual OUT PID received for OUT, Length (words) for IN.
unsigned int tailLength; // 7 "tail" length for IN (bytes)
unsigned int epAddress; // 8 EP address assigned by XUD (Used for marking stall etc)
unsigned int resetting; // 9 Flag to indicate to EP a bus-reset occured.
unsigned int halted; // 10 NAK or STALL
unsigned int saved_array_ptr; // 11
unsigned int array_ptr_setup; // 12
} XUD_ep_info;
#endif
#endif // _XUD_H_

View File

@@ -0,0 +1,11 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __XUD_CONF_DEFAULT_H__
#define __XUD_CONF_DEFAULT_H__
#ifdef __xud_conf_h_exists__
#include "xud_conf.h"
#endif
#endif

View File

@@ -0,0 +1,87 @@
// Copyright 2015-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/*
* @brief USB Device helper functions
*/
#ifndef _USB_DEVICE_H_
#define _USB_DEVICE_H_
#include <xccompat.h>
/* Low level XUD API for USB Device */
#include "xud.h"
/* Generic USB defines */
#include "XUD_USB_Defines.h"
/* Generic USB descriptor defines */
#include "xud_std_descriptors.h"
/* Generic USB descriptor defines */
#include "xud_std_requests.h"
/**
* \brief This function deals with common requests This includes Standard Device Requests listed
* in table 9-3 of the USB 2.0 Spec all devices must respond to these requests, in some
* cases a bare minimum implementation is provided and should be extended in the devices EP0 code
* It handles the following standard requests appropriately using values passed to it:
*
* Get Device Descriptor (using devDesc_hs/devDesc_fs arguments)
*
* Get Configuration Descriptor (using cfgDesc_hs/cfgDesc_fs arguments)
*
* String requests (using strDesc argument)
*
* Get Device_Qualifier Descriptor
*
* Get Other-Speed Configuration Descriptor
*
* Set/Clear Feature (Endpoint Halt)
*
* Get/Set Interface
*
* Set Configuration
*
* If the request is not recognised the endpoint is marked STALLED
*
*
* \param ep_out Endpoint from XUD (ep 0)
* \param ep_in Endpoint from XUD (ep 0)
* \param devDesc_hs The Device descriptor to use, encoded according to the USB standard
* \param devDescLength_hs Length of device descriptor in bytes
* \param cfgDesc_hs Configuration descriptor
* \param cfgDescLength_hs Length of config descriptor in bytes
* \param devDesc_fs The Device descriptor to use, encoded according to the USB standard
* \param devDescLength_fs Length of device descriptor in bytes. If 0 the HS device descriptor is used.
* \param cfgDesc_fs Configuration descriptor
* \param cfgDescLength_fs Length of config descriptor in bytes. If 0 the HS config descriptor is used.
* \param strDescs
* \param strDescsLength
* \param sp ``USB_SetupPacket_t`` (passed by ref) in which the setup data is returned
* \param usbBusSpeed The current bus speed (XUD_SPEED_HS or XUD_SPEED_FS)
*
* \return Returns XUD_RES_OKAY on success.
*/
XUD_Result_t USB_StandardRequests(XUD_ep ep_out, XUD_ep ep_in,
NULLABLE_ARRAY_OF(unsigned char, devDesc_hs), int devDescLength_hs,
NULLABLE_ARRAY_OF(unsigned char, cfgDesc_hs), int cfgDescLength_hs,
NULLABLE_ARRAY_OF(unsigned char, devDesc_fs), int devDescLength_fs,
NULLABLE_ARRAY_OF(unsigned char, cfgDesc_fs), int cfgDescLength_fs,
#ifdef __XC__
char * unsafe strDescs[],
#else
char * strDescs[],
#endif
int strDescsLength, REFERENCE_PARAM(USB_SetupPacket_t, sp), XUD_BusSpeed_t usbBusSpeed);
/**
* \brief Receives a Setup data packet and parses it into the passed USB_SetupPacket_t structure.
* \param ep_out OUT endpint from XUD
* \param ep_in IN endpoint to XUD
* \param sp SetupPacket structure to be filled in (passed by ref)
* \return Returns XUD_RES_OKAY on success, XUD_RES_RST on bus reset
*/
XUD_Result_t USB_GetSetupPacket(XUD_ep ep_out, XUD_ep ep_in, REFERENCE_PARAM(USB_SetupPacket_t, sp));
#endif

View File

@@ -0,0 +1,191 @@
// Copyright 2015-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _USB_DESCRIPTORS_H_
#define _USB_DESCRIPTORS_H_
#if !defined (__ASSEMBLER__)
/* USB Class Codes (from usb.org) */
typedef enum
{
USB_CLASS_USE_CLASS = 0x00, /* Use class information in the interface descriptors */
USB_CLASS_AUDIO = 0x01,
USB_CLASS_COMMUNICATIONS = 0x02,
USB_CLASS_HID = 0x03,
USB_CLASS_PHYSICAL = 0x05,
USB_CLASS_IMAGE = 0x06,
USB_CLASS_PRINTER = 0x07,
USB_CLASS_MASS_STORAGE = 0x08,
USB_CLASS_HUB = 0x09,
USB_CLASS_CDC_DATA = 0x0A,
USB_CLASS_SMART_CARD = 0x0B,
USB_CLASS_RESERVED = 0x0C,
USB_CLASS_CONTENT_SECURITY = 0x0D,
USB_CLASS_VIDEO = 0x0E,
USB_CLASS_PERSONAL_HEALTHCARE = 0x0F,
USB_CLASS_AUDIO_VIDEO = 0x10,
//...
USB_CLASS_MAPPED_INDEX_END = 17,
USB_CLASS_VENDOR_SPECIFIC = 0xFF
} USB_ClassCode_t;
#endif
/* USB Standard Descriptor types (Section 9.4, table 9-5) */
enum USB_DescriptorTypes_t
{
USB_DESCTYPE_DEVICE = 0x01, /* Device descriptor */
USB_DESCTYPE_CONFIGURATION = 0x02, /* Configuration descriptor */
USB_DESCTYPE_STRING = 0x03, /* String descriptor */
USB_DESCTYPE_INTERFACE = 0x04, /* Interface descriptor */
USB_DESCTYPE_ENDPOINT = 0x05, /* Endpoint descriptor */
USB_DESCTYPE_DEVICE_QUALIFIER = 0x06, /* Device qualifier descriptor */
USB_DESCTYPE_OTHER_SPEED = 0x07,
USB_DESCTYPE_INTERFACE_POWER = 0x08, /* Interface power descriptor */
USB_DESCTYPE_OTG = 0x09,
USB_DESCTYPE_DEBUG = 0x0A,
USB_DESCTYPE_INTERFACE_ASSOCIATION = 0x0B, /* Interface association descriptor */
};
#ifdef __STDC__
/* No current support for __attribute((packed)) in XC */
/* Generic USB Descriptor Header */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Descriptor type, either a value. See \ref USB_DescriptorTypes_t or
* a value given by the specific class */
} __attribute__((packed)) USB_Descriptor_Header_t;
/* USB Standard Device Descriptor (section 9.6.1, table 9-8) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Descriptor type, either a value in \ref USB_DescriptorTypes_t
* or a value given by the specific class */
unsigned short bcdUSB; /* Supported USB version */
unsigned char bDeviceClass; /* USB device class code */
unsigned char bDeviceSubClass; /* USB device subclass code */
unsigned char bDeviceProtocol; /* USB device protocol code */
unsigned char bMaxPacketSize0; /* Maximum packet size for endpoint 0 (bytes) */
unsigned short idVendor; /* Vendor ID */
unsigned short idProduct; /* Product ID */
unsigned short bcdDevice; /* Device release number in binary-coded decimal */
unsigned char iManufacturer; /* Index of string descriptor describing manufacturer */
unsigned char iProduct; /* Index of string descriptor describing product */
unsigned char iSerialNumber; /* Index of String descriptor describing the devices serial number */
unsigned char bNumConfigurations; /* Total number of configurations supported by the device */
} __attribute__((packed)) USB_Descriptor_Device_t;
/* USB Interface Association Descriptor (See IAD Engineering Change Notice) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Descriptor type, either a value in \ref USB_DescriptorTypes_t
or a value given by the specific class */
unsigned char bFirstInterface; /* Index of the first associated interface */
unsigned char bInterfaceCount; /* Total number of associated interfaces */
unsigned char bFunctionClass; /* Interface class ID */
unsigned char bFunctionSubClass; /* Interface subclass ID */
unsigned char bFunctionProtocol; /* Interface protocol ID */
unsigned char iFunction; /* Index of the string descriptor describing the
* interface association */
} __attribute__((packed)) USB_Descriptor_Interface_Association_t;
/* USB Standard Interface Descriptor (section 9.6.1 table 9-12) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Type of the descriptor, either a value in \ref USB_DescriptorTypes_t
* or a value given by the specific class */
unsigned char bInterfaceNumber; /* Index of the interface in the current config */
unsigned char bAlternateSetting; /* Alternate setting for this interface number. Multiple alternatives
* are supported per interface (with different EP configs) */
unsigned char bNumEndpoints; /* Total endpoint count in this interface */
unsigned char bInterfaceClass; /* Interface class code */
unsigned char bInterfaceSubClass; /* Interface subclass code */
unsigned char bInterfaceProtocol; /* Interface protocol code */
unsigned char iInterface; /* Index of the string descriptor in the string table */
} __attribute__((packed)) USB_Descriptor_Interface_t;
/* USB Standard Configuration Descriptor (section 9.6.1 table 9-10) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Type of the descriptor, either a value in \ref USB_DescriptorTypes_t or a value
* given by the specific class */
unsigned short wTotalLength; /* Size of the configuration descriptor header and all sub descriptors inside
* the configuration */
unsigned char bNumInterfaces; /* Total interface count in the configuration */
unsigned char bConfigurationValue; /* Value to use as an argument to the SetConfiguration() request to select this
* configuration */
unsigned char iConfiguration; /* Index of string descriptor describing this configuration */
unsigned char bmAttributes; /* Configuration characteristics
* D7: Reserved (set to one)
* D6: Self-powered
* D5: Remote Wakeup
* D4...0: Reserved (reset to zero)
*/
unsigned char bMaxPower; /* Maximum power consumption of the USB device from the bus in this specific
* configuration when the device is fully operational. Expressed in 2 mA units
* (i.e., 50 = 100 mA) */
} __attribute__((packed)) USB_Descriptor_Configuration_Header_t;
/* USB Standard Endpoint Descriptor (section 9.6.1 table 9-13) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Descriptor type, either a value. See \ref USB_DescriptorTypes_t or
* a value given by the specific class */
unsigned char bEndpointAddress; /* Address of the endpoint, includes a direction mask */
unsigned char bmAttributes; /* Endpoint attributes, comprised of a mask of the endpoint type
* See EP_TYPE_ ad EP_ADDR) */
unsigned short wMaxPacketSize; /* Maximum packet size (bytes) that the endpoint can receive */
unsigned char bInterval; /* Polling interval in milliseconds for the endpoint.
* Relevant to Isochronous and Interrupt endpoints only */
} __attribute__((packed)) USB_Descriptor_Endpoint_t;
/* USB Standard Endpoint Descriptor (Section 9.6.6, table 9-13) */
enum USB_Endpoint_TransType_t
{
USB_ENDPOINT_TRANSTYPE_CTRL = 0x0,
USB_ENDPOINT_TRANSTYPE_ISO = 0x1,
USB_ENDPOINT_TRANSTYPE_BULK = 0x2,
USB_ENDPOINT_TRANSTYPE_INT = 0x3
};
#define USB_ENDPOINT_TRANSTYPE_SHIFT (0)
enum USB_Endpoint_SyncType_t
{
USB_ENDPOINT_SYNCTYPE_NONE = 0x0,
USB_ENDPOINT_SYNCTYPE_ASYNC = 0x1,
USB_ENDPOINT_SYNCTYPE_ADAPT = 0x2,
USB_ENDPOINT_SYNCTYPE_SYNC = 0x3
};
#define USB_ENDPOINT_SYNCTYPE_SHIFT (2)
enum USB_Endpoint_UsageType_t
{
USB_ENDPOINT_USAGETYPE_DATA = 0x0,
USB_ENDPOINT_USAGETYPE_FEEDBACK = 0x1,
USB_ENDPOINT_USAGETYPE_IMPLICIT = 0x2,
USB_ENDPOINT_USAGETYPE_RESERVED = 0x3
};
#define USB_ENDPOINT_USAGETYPE_SHIFT (4)
/* USB String Descriptor (Section 9.6.7 table 9-15) */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType; /* Descriptor type, either a value in \ref USB_DescriptorTypes_t
* or a value given by the specific class */
unsigned short bString[]; /* String data, (as unicode characters) - use array of chars instead of string.
* In GCC prefix string with "L" */
} __attribute__((packed)) USB_Descriptor_String_t;
#endif
#endif

View File

@@ -0,0 +1,120 @@
// Copyright 2015-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _USB_STD_REQUESTS_H_
#define _USB_STD_REQUESTS_H_
#include <xccompat.h>
#include "XUD_USB_Defines.h"
/* 9.3 USB Device Requests: Table 9-2 Format of Setup Data */
/* bmRequestType: */
#define USB_BM_REQTYPE_DIRECTION_H2D 0 /* Host to device */
#define USB_BM_REQTYPE_DIRECTION_D2H 1 /* Device to host */
#define USB_BM_REQTYPE_TYPE_STANDARD 0x00
#define USB_BM_REQTYPE_TYPE_CLASS 0x01
#define USB_BM_REQTYPE_TYPE_VENDOR 0x02
#define USB_BM_REQTYPE_RECIP_DEV 0x00
#define USB_BM_REQTYPE_RECIP_INTER 0x01
#define USB_BM_REQTYPE_RECIP_EP 0x02
#define USB_BM_REQTYPE_RECIP_OTHER 0x03
#define USB_BMREQ_H2D_STANDARD_DEV ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_DEV))
#define USB_BMREQ_D2H_STANDARD_DEV ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_DEV))
#define USB_BMREQ_H2D_STANDARD_INT ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_INTER))
#define USB_BMREQ_D2H_STANDARD_INT ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_INTER))
#define USB_BMREQ_H2D_STANDARD_EP ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_EP))
#define USB_BMREQ_D2H_STANDARD_EP ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_STANDARD << 5) | \
(USB_BM_REQTYPE_RECIP_EP))
#define USB_BMREQ_H2D_CLASS_INT ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_CLASS << 5) | \
(USB_BM_REQTYPE_RECIP_INTER))
#define USB_BMREQ_D2H_CLASS_INT ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_CLASS << 5) | \
(USB_BM_REQTYPE_RECIP_INTER))
#define USB_BMREQ_H2D_CLASS_EP ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_CLASS << 5) | \
(USB_BM_REQTYPE_RECIP_EP))
#define USB_BMREQ_D2H_CLASS_EP ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_CLASS << 5) | \
(USB_BM_REQTYPE_RECIP_EP))
#define USB_BMREQ_H2D_VENDOR_DEV ((USB_BM_REQTYPE_DIRECTION_H2D << 7) | \
(USB_BM_REQTYPE_TYPE_VENDOR << 5) | \
(USB_BM_REQTYPE_RECIP_DEV))
#define USB_BMREQ_D2H_VENDOR_DEV ((USB_BM_REQTYPE_DIRECTION_D2H << 7) | \
(USB_BM_REQTYPE_TYPE_VENDOR << 5) | \
(USB_BM_REQTYPE_RECIP_DEV))
/* Table 9-4. Standard Request Codes */
/* bRequest */
#define USB_GET_STATUS 0x00
#define USB_CLEAR_FEATURE 0x01
#define USB_SET_FEATURE 0x03
#define USB_SET_ADDRESS 0x05
#define USB_GET_DESCRIPTOR 0x06
#define USB_SET_DESCRIPTOR 0x07
#define USB_GET_CONFIGURATION 0x08
#define USB_SET_CONFIGURATION 0x09
#define USB_GET_INTERFACE 0x0A
#define USB_SET_INTERFACE 0x0B
#define USB_SYNCH_FRAME 0x0C
/**
* \var typedef USB_BmRequestType_t
* \brief Defines the Recepient, Type and Direction of a USB request.
*/
typedef struct USB_BmRequestType
{
unsigned char Recipient; // [4..0] Request directed to:
// 0b00000: Device
// 0b00001: Specific interface
// 0b00010: Specific endpoint
// 0b00011: Other element in device
unsigned char Type; // [6..5] 0b00: Standard request
// 0b01: Class specific request
// 0b10: Request by vendor specific driver
unsigned char Direction; // [7] 0 (Host->Dev)
// 1 (Dev->Host)
} USB_BmRequestType_t;
/**
* \var typedef USB_SetupPacket_t
* \brief Typedef for setup packet structure */
typedef struct USB_SetupPacket
{
USB_BmRequestType_t bmRequestType; /* (1 byte) Specifies direction of dataflow,
type of rquest and recipient */
unsigned char bRequest; /* Specifies the request */
unsigned short wValue; /* Host can use this to pass info to the
device in its own way */
unsigned short wIndex; /* Typically used to pass index/offset such
as interface or EP no */
unsigned short wLength; /* Number of data bytes in the data stage
(for Host -> Device this this is exact
count, for Dev->Host is a max. */
} USB_SetupPacket_t;
/**
* \brief Prints out passed ``USB_SetupPacket_t`` struct using debug IO
*/
void USB_PrintSetupPacket(USB_SetupPacket_t sp);
void USB_ComposeSetupBuffer(USB_SetupPacket_t sp, unsigned char buffer[]);
void USB_ParseSetupPacket(unsigned char b[], REFERENCE_PARAM(USB_SetupPacket_t, p));
#endif

View File

@@ -0,0 +1,33 @@
set(LIB_NAME lib_xud)
set(LIB_VERSION 2.4.0)
set(LIB_INCLUDES api src/user api/legacy src/core src/user/class)
set(LIB_DEPENDENT_MODULES "")
set(LIB_OPTIONAL_HEADERS xud_conf.h)
set(LIB_ASM_SRCS src/core/XUD_IoLoop.S
src/core/XUD_TestMode.S
src/core/XUD_CRC5_Table.S
src/core/XUD_USBTile_Support.S
src/core/XUD_CRC5_Table_Addr.S
src/user/client/XUD_EpFuncs.S)
set(LIB_COMPILER_FLAGS -O3
-fasm-linenum
-fcomment-asm
-DXUD_FULL_PIDTABLE=1
-g)
set(LIB_COMPILER_FLAGS_XUD_IoLoop.S ${LIB_COMPILER_FLAGS} -fschedule)
set(LIB_COMPILER_FLAGS_XUD_Client.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_Main.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_PhyResetUser.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_Support.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_IOLoopCall.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_Signalling.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue -Wno-return-type)
set(LIB_COMPILER_FLAGS_XUD_TestMode.xc ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_SetCrcTableAddr.c ${LIB_COMPILER_FLAGS} -mno-dual-issue)
set(LIB_COMPILER_FLAGS_XUD_User.c ${LIB_COMPILER_FLAGS} -mno-dual-issue)
XMOS_REGISTER_MODULE()

View File

@@ -0,0 +1,47 @@
VERSION = 2.4.0
MODULE_XCC_FLAGS = $(XCC_FLAGS) \
-O3 \
-fasm-linenum \
-fcomment-asm \
-DXUD_FULL_PIDTABLE=1 \
-g
XCC_FLAGS_XUD_IoLoop.S = $(MODULE_XCC_FLAGS) -fschedule
XCC_FLAGS_XUD_Client.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_Main.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_PhyResetUser.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_Support.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_IOLoopCall.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_Signalling.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue -Wno-return-type
XCC_FLAGS_XUD_TestMode.xc = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_SetCrcTableAddr.c = $(MODULE_XCC_FLAGS) -mno-dual-issue
XCC_FLAGS_XUD_User.c = $(MODULE_XCC_FLAGS) -mno-dual-issue
OPTIONAL_HEADERS += xud_conf.h
DEPENDENT_MODULES =
EXPORT_INCLUDE_DIRS = api \
src/user \
api/legacy
INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \
src/core \
src/user/class
SOURCE_DIRS = src/core \
src/user/client \
src/user/control
EXCLUDE_FILES += XUD_CrcAddrCheck.S \
XUD_PidJumpTable.S \
XUD_PidJumpTable_RxData.S \
XUD_RxData.S \
XUD_Token_In_DI.S \
XUD_Token_Out_DI.S \
XUD_Token_Ping.S \
XUD_Token_SOF.S \
XUD_Token_Setup_DI.S \
XUD_TokenJmp.S

View File

@@ -0,0 +1,23 @@
// Copyright 2021-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* XUD_AlignmentDefines.h
* @brief Architecture-specific ASM function alignment
*/
#ifndef _XUD_ALIGNMENT_DEFINES_
#define _XUD_ALIGNMENT_DEFINES_
#if !defined(__XS2A__)
#define IBUFFER_FETCH_CORRECTION 1
#else
#define IBUFFER_FETCH_CORRECTION 0
#endif
#if IBUFFER_FETCH_CORRECTION == 1
#define FUNCTION_ALIGNMENT 16
#elif IBUFFER_FETCH_CORRECTION == 0
#define FUNCTION_ALIGNMENT 4
#else
#error IBUFFER_FETCH_CORRECTION not defined
#endif
#endif // _XUD_ALIGNMENT_DEFINES_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
// On Entry:
// r0: rxd port
// r8: 16 (XS3 only)
// Required on exit:
// r4: 0
// r10: Extracted EP number
#if !defined(__XS2A__)
{in r10, res[RXD]; sub r1, r8, 5} // ldc r1 11
{shr r10, r10, 16; mkmsk r11, r1}
{and r11, r10, r11; ldw r8, sp[STACK_CRC5TABLE_ADDR]}
{shr r4, r10, r1 // r4: Received CRC
ld8u r8, r8[r11]} // r8: Expected CRC
// R4 set to 0 in L code with in from valid tok port
{eq r4, r4, r8; shr r10, r11, 7} // Extract EP number
BRFT_ru6 r4, 5
ldw r11, sp[STACK_RXA_PORT] // Wait for RXA to gow low (i.e. end of packet)
in r10, res[r11]
bt r10, waitforRXALow0
setc res[RXD], XS1_SETC_RUN_CLRBUF
bu Loop_BadPid
#else
// __XS2A__
inpw r10, res[RXD], 8; // Read EP Number
shr r10, r10, 24; // Shift off junk
in r4, res[r1];
bt r4, XUD_InvalidToken; // If VALID_TOKEN not high, ignore token - PORT INVERTED! */
#endif

View File

@@ -0,0 +1,9 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** @brief Does high speed device attach
* @return non-zero for error
**/
int XUD_DeviceAttachHS(XUD_PwrConfig p);

View File

@@ -0,0 +1,154 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if !defined(XUD_BYPASS_RESET)
#include <xs1.h>
#include <platform.h>
#include "xud.h"
#include "XUD_USB_Defines.h"
#include "XUD_TimingDefines.h"
#include "XUD_HAL.h"
extern in port flag0_port;
extern in port flag1_port;
extern in port flag2_port;
extern out buffered port:32 p_usb_txd;
#define TUCHEND_DELAY_us (1500) // 1.5ms
#define TUCHEND_DELAY (TUCHEND_DELAY_us * PLATFORM_REFERENCE_MHZ)
#ifndef INVALID_DELAY_us
#define INVALID_DELAY_us (2500) // 2.5ms
#endif
#define INVALID_DELAY (INVALID_DELAY_us * PLATFORM_REFERENCE_MHZ)
extern int resetCount;
/* Assumptions:
* - In full speed mode
* - No flags sticky
* - Flag 0 port inverted
*/
int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
{
unsigned tmp;
timer t;
int start_time;
int detecting_k = 1;
int tx;
unsigned int chirpCount = 0;
clearbuf(p_usb_txd);
/* On detecting the SE0 move into chirp mode */
XUD_HAL_EnterMode_PeripheralChirp();
/* output k-chirp for required time */
#if defined(XUD_SIM_RTL) || (XUD_SIM_XSIM)
for (int i = 0; i < 800; i++)
#else
for (int i = 0; i < 16000; i++) // 16000 words @ 480 MBit = 1.066 ms
#endif
{
p_usb_txd <: 0;
}
// J, K, SE0 on flag ports 0, 1, 2 respectively (on XS2)
// XS3 has raw linestate on flag port 0 and 1
// Wait for fs chirp k (i.e. HS chirp j)
#if defined(__XS2A__)
flag1_port when pinseq(0) :> tmp; // Wait for out k to go
#endif
t :> start_time;
while(1)
{
select
{
case t when timerafter(start_time + INVALID_DELAY) :> void:
/* Go into full speed mode: XcvrSelect and Term Select (and suspend) high */
XUD_HAL_EnterMode_PeripheralFullSpeed();
/* Wait for end of SE0 */
while(1)
{
/* TODO Use a timer to save some juice...*/
#if !defined(__XS2A__)
unsigned dp, dm;
flag0_port :> dm;
flag1_port :> dp;
if(dp || dm)
{
/* SE0 gone, return 0 to indicate FULL SPEED */
return 0;
}
#else
flag2_port :> tmp;
if(!tmp)
{
/* SE0 gone, return 0 to indicate FULL SPEED */
return 0;
}
#endif
if(pwrConfig == XUD_PWR_SELF)
{
if(!XUD_HAL_GetVBusState())
{
XUD_HAL_EnterMode_TristateDrivers();
return -1; // VBUS gone, handshake fails completely.
}
}
}
break;
#if !defined(__XS2A__)
// Note, J and K definitions are reversed in XS3A
#define j_port flag1_port
#define k_port flag0_port
#else
#define k_port flag1_port
#define j_port flag0_port
#endif
case detecting_k => k_port when pinseq(1):> void @ tx: // K Chirp
k_port @ tx + T_FILT_ticks :> tmp;
if (tmp)
{
detecting_k = 0;
}
break;
case !detecting_k => j_port when pinseq(1) :> void @ tx: // J Chirp
j_port @ tx + T_FILT_ticks :> tmp;
if (tmp == 1)
{
chirpCount++; // Seen an extra K-J pair
detecting_k = 1;
if (chirpCount == 3)
{
/* Three pairs of KJ received. Enter high-speed mode */
XUD_HAL_EnterMode_PeripheralHighSpeed();
// Wait for SE0 (TODO consume other chirps?)
#if !defined(__XS2A__)
// TODO ideally dont use a polling loop here
while (XUD_HAL_GetLineState() != XUD_LINESTATE_SE0);
#else
flag2_port when pinseq(1) :> tmp;
#endif
/* Return 1 to indicate successful HS handshake*/
return 1;
}
}
break;
}
}
// Unreachable
return -1;
}
#endif

View File

@@ -0,0 +1,11 @@
// Copyright 2019-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* See XUD_HAL.xc */
unsigned int XUD_HAL_GetVBusState_(void);
unsigned int XUD_HAL_GetVBusState(void) __attribute__((weak));
unsigned int XUD_HAL_GetVBusState(void)
{
return XUD_HAL_GetVBusState_();
}

View File

@@ -0,0 +1,95 @@
// Copyright 2019-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @file XUD_HAL.h
* \brief USB HAL Layer
**/
#include <xccompat.h>
#include "xud.h"
#include <platform.h>
#define USB_TILE_REF usb_tile
#if !defined(__XS2A__)
#include <xs1.h>
// TODO should be properly in HAL
unsigned XtlSelFromMhz(unsigned m);
#else
#include "XUD_USBTile_Support.h"
#include "xs1_to_glx.h"
#include "xs2_su_registers.h"
#endif
/**
* \enum XUD_LineState_t
* \brief USB Line States
*/
typedef enum XUD_LineState_t
{
XUD_LINESTATE_SE0 = 0, /**< SE0 State */
XUD_LINESTATE_HS_J_FS_K = 1,/**< J/K State */
XUD_LINESTATE_HS_K_FS_J = 2,/**< K/J State */
XUD_LINESTATE_SE1 = 3 /**< Invalid bus state - both lines high **/
} XUD_LineState_t;
void XUD_HAL_EnterMode_PeripheralChirp();
void XUD_HAL_EnterMode_PeripheralFullSpeed();
void XUD_HAL_EnterMode_PeripheralHighSpeed();
#ifdef __XS2A__
/* Special case for __XS2A__ where writing to USB register is relatively slow */
void XUD_HAL_EnterMode_PeripheralHighSpeed_Start();
void XUD_HAL_EnterMode_PeripheralHighSpeed_Complete();
#endif
void XUD_HAL_EnterMode_PeripheralTestJTestK();
void XUD_HAL_EnterMode_TristateDrivers();
/**
* \brief Get current linestate status
* \return XUD_LineState_t representing current line status
**/
XUD_LineState_t XUD_HAL_GetLineState();
/**
* \brief Wait for a change in linestate and return, or timeout
* \param Reference to current linestate (updated with new linestate
* \return 1 for timed out, otherwise 0
**/
unsigned XUD_HAL_WaitForLineStateChange(REFERENCE_PARAM(XUD_LineState_t, currentLs), unsigned timeout);
/**
* \brief HAL function to set xCORE into signalling mode
* (as opposed to "data transfer" mode)
*
* TODO Should this be combined with EnterMode_PeripheralChirp()?
**/
void XUD_HAL_Mode_Signalling();
/**
* \brief HAL function to set xCORE into data transfer mode
* (as opposed to "signalling" mode )
*
* TODO Should this be combined with EnterMode_PeripheralHigh/FullSpeed()?
**/
void XUD_HAL_Mode_DataTransfer();
/**
* \brief HAL function to set xCORE to correct USB device address
* \param address The new address
* \return void
**/
void XUD_HAL_SetDeviceAddress(unsigned char address);
/**
* \brief Enable USB funtionality in the device
**/
void XUD_HAL_EnableUsb(unsigned pwrConfig);
/**
* \brief HAL funtion to get state of VBUS line, if any
* \param none
* \return unsigned int non-zero if VBUS asserted, zero otherwise
**/
unsigned int XUD_HAL_GetVBusState(void);

View File

@@ -0,0 +1,451 @@
// Copyright 2019-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include "xud.h"
#include "XUD_HAL.h"
#ifdef __XS2A__
#include "xs1_to_glx.h"
#include "xs2_su_registers.h"
#include "XUD_USBTile_Support.h"
extern in port flag0_port;
extern in port flag1_port;
extern in port flag2_port;
extern buffered in port:32 p_usb_clk;
#else
extern in port flag0_port; /* For XS3: RXA or DP */
extern in port flag1_port; /* For XS3: RXE or DM */
extern buffered in port:32 p_usb_clk;
void XUD_SetCrcTableAddr(unsigned addr);
unsigned XtlSelFromMhz(unsigned m)
{ // NOCOVER
switch(m) //NOCOVER
{
case 10:
return 0b000;
case 12:
return 0b001;
case 25:
return 0b010;
case 30:
return 0b011;
case 19: /*.2*/
return 0b100;
case 24:
return 0b101;
case 27:
return 0b110;
case 40:
return 0b111;
default:
/* Panic */
while(1); //NOCOVER
break;
}
return 0b000;
}
#endif
extern clock rx_usb_clk;
unsigned int XUD_EnableUsbPortMux();
void XUD_HAL_EnableUsb(unsigned pwrConfig)
{
/* For xCORE-200 enable USB port muxing before enabling phy etc */
XUD_EnableUsbPortMux(); //setps(XS1_PS_XCORE_CTRL0, UIFM_MODE);
#ifndef XUD_SIM_XSIM
#ifdef __XS2A__
/* Enable the USB clock */
write_sswitch_reg(get_tile_id(USB_TILE_REF), XS1_SU_CFG_RST_MISC_NUM, ( 1 << XS1_SU_CFG_USB_CLK_EN_SHIFT));
/* Now reset the phy */
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_GLX_PER_UIFM_PHY_CONTROL_NUM, 0); //(0<<XS1_UIFM_PHY_CONTROL_FORCERESET));
/* Keep usb clock active, enter active mode */
write_sswitch_reg(get_tile_id(USB_TILE_REF), XS1_SU_CFG_RST_MISC_NUM, (1 << XS1_SU_CFG_USB_CLK_EN_SHIFT) | (1<<XS1_SU_CFG_USB_EN_SHIFT) );
/* Clear OTG control reg - incase we were running as host previously.. */
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_OTG_CONTROL_NUM, 0);
#else
unsigned d = 0;
/* Enable wphy and take out of reset */
read_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG2_NUM, d);
d = XS1_USB_PHY_CFG2_PONRST_SET(d, 1);
d = XS1_USB_PHY_CFG2_UTMI_RESET_SET(d, 0);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG2_NUM, d);
/* Setup clocking appropriately */
read_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d);
unsigned xtlselVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlselVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d);
#endif
/* Wait for USB clock (typically 1ms after reset) */
p_usb_clk when pinseq(1) :> int _;
p_usb_clk when pinseq(0) :> int _;
p_usb_clk when pinseq(1) :> int _;
p_usb_clk when pinseq(0) :> int _;
#ifdef __XS2A__
/* Some extra settings are required for proper operation on XS2A */
#define XS1_UIFM_USB_PHY_EXT_CTRL_REG 0x50
#define XS1_UIFM_USB_PHY_EXT_CTRL_VBUSVLDEXT_MASK 0x4
/* Remove requirement for VBUS in bus-powered mode */
if(pwrConfig == XUD_PWR_BUS)
{
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_UIFM_USB_PHY_EXT_CTRL_REG, XS1_UIFM_USB_PHY_EXT_CTRL_VBUSVLDEXTSEL_MASK | XS1_UIFM_USB_PHY_EXT_CTRL_VBUSVLDEXT_MASK);
}
#define PHYTUNEREGVAL 0x0093B264
#define XS1_UIFM_USB_PHY_TUNE_REG 0x4c
/* Phy Tuning parameters */
/* OTG TUNE: 3b'100
* TXFSLSTUNE: 4b'1001
* TXVREFTUNE:4b'1001 -- +1.25% adjustment in HS DC voltage level
* BIASTUNE: 1b'0
* COMDISTUNE:3b'011 -- -1.5% adjustment from default (disconnect threshold adjustment)
* SQRXTUNE:3b'010 -- +5% adjustment from default (Squelch Threshold)
* TXRISETUNE: 1b'0
* TXPREEMPHASISTUNE:1b'1 -- enabled (default is disabled)
* TXHSXVTUNE: 2b'11
*/
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_UIFM_USB_PHY_TUNE_REG, PHYTUNEREGVAL);
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_CONTROL_NUM, (1<<XS1_SU_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT));
#endif
#endif
}
void XUD_HAL_EnterMode_PeripheralFullSpeed()
{
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM,
(1<<XS1_SU_UIFM_FUNC_CONTROL_XCVRSELECT_SHIFT) | (1<<XS1_SU_UIFM_FUNC_CONTROL_TERMSELECT_SHIFT));
#else
unsigned d = 0;
d = XS1_USB_PHY_CFG0_UTMI_XCVRSELECT_SET(d, 1);
d = XS1_USB_PHY_CFG0_UTMI_TERMSELECT_SET(d, 1);
d = XS1_USB_PHY_CFG0_UTMI_OPMODE_SET(d, 0);
d = XS1_USB_PHY_CFG0_DMPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_DPPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_SUSPENDM_SET(d, 1);
d = XS1_USB_PHY_CFG0_TXBITSTUFF_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_PLL_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_LPM_ALIVE_SET(d, 0);
d = XS1_USB_PHY_CFG0_IDPAD_EN_SET(d, 0);
unsigned xtlSelVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlSelVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d);
#endif
}
void XUD_HAL_EnterMode_PeripheralChirp()
{
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 0b1010);
#else
unsigned d = 0;
d = XS1_USB_PHY_CFG0_UTMI_XCVRSELECT_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_TERMSELECT_SET(d, 1);
d = XS1_USB_PHY_CFG0_UTMI_OPMODE_SET(d, 0b10);
d = XS1_USB_PHY_CFG0_DMPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_DPPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_SUSPENDM_SET(d, 1);
d = XS1_USB_PHY_CFG0_TXBITSTUFF_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_PLL_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_LPM_ALIVE_SET(d, 0);
d = XS1_USB_PHY_CFG0_IDPAD_EN_SET(d, 0);
unsigned xtlselVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlselVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d);
#endif
}
void XUD_HAL_EnterMode_PeripheralHighSpeed()
{
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 0b0000);
#else
unsigned d = 0;
d = XS1_USB_PHY_CFG0_UTMI_XCVRSELECT_SET(d, 0); // HS
d = XS1_USB_PHY_CFG0_UTMI_TERMSELECT_SET(d, 0); // HS
d = XS1_USB_PHY_CFG0_UTMI_OPMODE_SET(d, 0b00); // Normal operation
d = XS1_USB_PHY_CFG0_DMPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_DPPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_SUSPENDM_SET(d, 1);
d = XS1_USB_PHY_CFG0_TXBITSTUFF_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_PLL_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_LPM_ALIVE_SET(d, 0);
d = XS1_USB_PHY_CFG0_IDPAD_EN_SET(d, 0);
unsigned xtlselVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlselVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d);
#endif
}
#ifdef __XS2A__
/* Special case for XSA when exiting resume back to HS - breaks standard HAL API */
unsafe chanend c;
void XUD_HAL_EnterMode_PeripheralHighSpeed_Start()
{
unsafe
{
asm("getr %0, 2" : "=r"(c)); // XS1_RES_TYPE_CHANEND=2 (no inline assembly immediate operands in xC)
write_periph_word_two_part_start((chanend)c, USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 0);
}
}
void XUD_HAL_EnterMode_PeripheralHighSpeed_Complete()
{
unsafe
{
write_periph_word_two_part_end((chanend)c, 0);
asm("freer res[%0]" :: "r"(c));
}
}
#endif
void XUD_HAL_EnterMode_PeripheralTestJTestK()
{ // NOCOVER
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_GLX_PER_UIFM_FUNC_CONTROL_NUM, 0b1000);
#else
/* From ULPI Specification Revsion 1.1, table 41
* XcvrSelect: 00b
* TermSelect: 0b
* OpMode: 10b
* DpPullDown 0b
* DmPullDown: 0b
*/
unsigned d = 0;
d = XS1_USB_PHY_CFG0_UTMI_XCVRSELECT_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_TERMSELECT_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_OPMODE_SET(d, 2);
d = XS1_USB_PHY_CFG0_DMPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_DPPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_SUSPENDM_SET(d, 1);
d = XS1_USB_PHY_CFG0_TXBITSTUFF_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_PLL_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_LPM_ALIVE_SET(d, 0);
d = XS1_USB_PHY_CFG0_IDPAD_EN_SET(d, 0);
unsigned xtlSelVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlSelVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d); // NOCOVER
#endif
}
void XUD_HAL_EnterMode_TristateDrivers()
{ // NOCOVER
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 4);
#else
/* From ULPI Specification Revsion 1.1, table 41
* XcvrSelect: XXb
* TermSelect: Xb
* OpMode: 01b
* DpPullDown Xb
* DmPullDown: Xb
*/
unsigned d = 0;
d = XS1_USB_PHY_CFG0_UTMI_XCVRSELECT_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_TERMSELECT_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_OPMODE_SET(d, 1);
d = XS1_USB_PHY_CFG0_DMPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_DPPULLDOWN_SET(d, 0);
d = XS1_USB_PHY_CFG0_UTMI_SUSPENDM_SET(d, 1);
d = XS1_USB_PHY_CFG0_TXBITSTUFF_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_PLL_EN_SET(d, 1);
d = XS1_USB_PHY_CFG0_LPM_ALIVE_SET(d, 0);
d = XS1_USB_PHY_CFG0_IDPAD_EN_SET(d, 0);
unsigned xtlSelVal = XtlSelFromMhz(XUD_OSC_MHZ);
d = XS1_USB_PHY_CFG0_XTLSEL_SET(d, xtlSelVal);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_PHY_CFG0_NUM, d); //NOCOVER
#endif
}
void XUD_HAL_Mode_Signalling()
{
/* Reset port to use XS1_CLKBLK_REF (from rx_usb_clk) */
set_port_use_on(flag1_port);
#ifdef __XS2A__
/* For XS2 we invert VALID_TOKEN port for data-transfer mode, so undo this for signalling */
set_port_no_inv(flag2_port);
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_GLX_PER_UIFM_MASK_NUM,
((1<<XS1_UIFM_IFM_FLAGS_SE0_SHIFT)<<16)
| ((1<<XS1_UIFM_IFM_FLAGS_K_SHIFT)<<8)
| (1 << XS1_UIFM_IFM_FLAGS_J_SHIFT));
#else
unsigned d = 0;
d = XS1_USB_SHIM_CFG_FLAG_MODE_SET(d, 1);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_SHIM_CFG_NUM, d);
#endif
}
void XUD_HAL_Mode_DataTransfer()
{
configure_in_port(flag1_port, rx_usb_clk);
set_pad_delay(flag1_port, 2);
#ifdef __XS2A__
/* Set UIFM to CHECK TOKENS mode and enable LINESTATE_DECODE
* NOTE: Need to do this every iteration since CHKTOK would break power signaling */
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_CONTROL_NUM,
(1<<XS1_SU_UIFM_IFM_CONTROL_DOTOKENS_SHIFT)
| (1<< XS1_SU_UIFM_IFM_CONTROL_CHECKTOKENS_SHIFT)
| (1<< XS1_SU_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT)
| (1<< XS1_SU_UIFM_IFM_CONTROL_SOFISTOKEN_SHIFT));
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_MASK_NUM,
((1<<XS1_SU_UIFM_IFM_FLAGS_RXERROR_SHIFT)
| ((1<<XS1_SU_UIFM_IFM_FLAGS_RXACTIVE_SHIFT)<<8)
| ((1<<XS1_SU_UIFM_IFM_FLAGS_NEWTOKEN_SHIFT)<<16)));
/* Flag 2 (VALID_TOKEN) port is inverted as an optimisation (having a zero is useful) */
set_port_inv(flag2_port);
#else
unsigned d = 0;
d = XS1_USB_SHIM_CFG_FLAG_MODE_SET(d, 0);
write_sswitch_reg(get_local_tile_id(), XS1_SSWITCH_USB_SHIM_CFG_NUM, d);
#endif
}
/* In full-speed and low-speed mode, LineState(0) always reflects DP and LineState(1) reflects DM */
/* Note, this port ordering is the opposite of what might be expected - but linestate is swapped in the USB shim */
#define dp_port flag0_port // DP: LINESTATE[0]
#define dm_port flag1_port // DM: LINESTATE[1]
{unsigned, unsigned} LineStateToLines(XUD_LineState_t ls)
{
return {ls & 1, (ls >> 1) & 1};
}
static inline XUD_LineState_t LinesToLineState(unsigned dp, unsigned dm)
{
return (XUD_LineState_t) (dp & 1) | ((dm & 1)<< 1);
}
/* TODO pass structure */
XUD_LineState_t XUD_HAL_GetLineState(/*XUD_HAL_t &xudHal*/)
{
#ifdef __XS2A__
unsigned j, k, se0;
flag0_port :> j;
flag1_port :> k;
flag2_port :> se0;
if(j)
return XUD_LINESTATE_HS_J_FS_K;
if(k)
return XUD_LINESTATE_HS_K_FS_J;
if(se0)
return XUD_LINESTATE_SE0;
return XUD_LINESTATE_SE1;
#else
unsigned dp, dm;
dp_port :> dp;
dm_port :> dm;
return LinesToLineState(dp, dm);
#endif
}
// TODO debounce?
unsigned XUD_HAL_WaitForLineStateChange(XUD_LineState_t &currentLs, unsigned timeout)
{
unsigned time;
timer t;
if (timeout != null)
t :> time;
#ifdef __XS2A__
unsigned se0 = currentLs == XUD_LINESTATE_SE0;
unsigned j = currentLs == XUD_LINESTATE_HS_J_FS_K;
unsigned k = currentLs == XUD_LINESTATE_HS_K_FS_J;
/* Wait for a change on any flag port */
select
{
case flag0_port when pinsneq(j) :> void:
break;
case flag1_port when pinsneq(k) :> void:
break;
case flag2_port when pinsneq(se0) :> void:
break;
case timeout != null => t when timerafter(time + timeout) :> int _:
return 1;
}
/* Read current line state - two lines may have change e.g k/j to SE0 */
currentLs = XUD_HAL_GetLineState();
return 0;
#else
unsigned dp, dm;
/* Look up line values from linestate */
{dp, dm} = LineStateToLines(currentLs);
/* Wait for change */
select
{
case dp_port when pinsneq(dp) :> dp:
dm_port :> dm; //Both might have changed!
break;
case dm_port when pinsneq(dm) :> dm:
dp_port :> dp; //Both might have changed!
break;
case timeout != null => t when timerafter(time + timeout) :> int _:
return 1;
}
/* Return new linestate */
currentLs = LinesToLineState(dp, dm);
return 0;
#endif
}
void XUD_HAL_SetDeviceAddress(unsigned char address)
{
#ifdef __XS2A__
write_periph_word(USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_DEVICE_ADDRESS_NUM, address);
#else
XUD_SetCrcTableAddr(address);
#endif
}
/* Note, this is called from XUA_HAL.c (weak symbol) */
unsigned int XUD_HAL_GetVBusState_(void)
{
#ifdef __XS2A__
unsigned int x;
read_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_GLX_PER_UIFM_OTG_FLAGS_NUM, x);
return x & (1 << XS1_UIFM_OTG_FLAGS_SESSVLDB_SHIFT);
#else
return 1u;
#endif
}

View File

@@ -0,0 +1,380 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
// XUD_IoLoop.S
// Main USB interfacing loop
//
// XMOS Ltd
// Ross Owen
//
///////////////////////////////////////////////////////
#include <xs1.h>
#include "xud.h"
#include "XUD_USB_Defines.h"
#include "XUD_TimingDefines.h"
#include "XUD_AlignmentDefines.h"
.section .cp.const4,"aMc",@progbits,4
.cc_top suspendTimeout.data
.align 4
suspendTimeout:
.long SUSPEND_TIMEOUT_ticks
.cc_bottom suspendTimeout.data
.text
.section .cp.const4,"aMc",@progbits,4
.cc_top suspend_t_wtwrsths.data
.align 4
suspend_t_wtwrsths:
.long SUSPEND_T_WTWRSTHS_ticks
.cc_bottom suspend_t_wtwrsths.data
.text
#define STACK_EXTEND 32
// Stack frame:
// 0
// 1..7: : Reg save
// 8 : Unused
#define STACK_OUT_TIMER (9) // Used for out data timeout
#define STACK_RXA_PORT (10) // RXA_port
// 11 : Unused
// 12 : Unused
#define STACK_SUSPEND_TIMEOUT (13)
#define STACK_SUSPEND_TIMER (14)
#define STACK_RXE_PORT (15)
#define STACK_RXCRC_TAIL0 (16)
#define STACK_RXCRC_TAIL1 (17)
#define STACK_RXCRC_TAIL2 (18)
#define STACK_RXCRC_TAIL3 (19)
#define STACK_TXCRC_INIT (20)
#define STACK_RXCRC_INIT (21)
#define STACK_PIDJUMPTABLE (22)
#define STACK_PIDJUMPTABLE_RXDATA (23)
#define STACK_CRC5TABLE_ADDR (24)
// Params
#define STACK_VTOK_PORT (STACK_EXTEND + 1)
#define STACK_EPTYPES_OUT (STACK_EXTEND + 2) // STACK_EXTEND + 6 : EP Type table (out)
#define STACK_EPTYPES_IN (STACK_EXTEND + 3) // EP Type table (in)
#define STACK_EPCHANS (STACK_EXTEND + 4)
#define SP_EPCOUNT (STACK_EXTEND + 5)
#define STACK_SOFCHAN (STACK_EXTEND + 6)
#ifndef XUD_TEST_MODE_SUPPORT_DISABLED
//////////////////////////////////////////////////////////////////////////
// void UsbTestModeHandler()
// Interrupt handler for entering USB Test mode
// ASM level for low-level interrupt handling.
.globl UsbTestModeHandler_asm.nstackwords
.linkset UsbTestModeHandler_asm.nstackwords, 0
.globl UsbTestModeHandler_asm
.type UsbTestModeHandler_asm, @function
.text
.cc_top UsbTestModeHandler_asm.func, UsbTestModeHandler_asm
.issue_mode single
.align FUNCTION_ALIGNMENT
UsbTestModeHandler_asm:
ENTSP_lu6 0
clrsr 0x18
clrsr 0x2
clre // clear all events
get r11, ed
chkct res[r11], XS1_CT_END
outct res[r11], XS1_CT_END
in r0, res[r11]
chkct res[r11], XS1_CT_END
outct res[r11], XS1_CT_END
bf r0, Return // Special case for Exit
bl XUD_UsbTestModeHandler
retsp 0
.cc_bottom UsbTestModeHandler_asm.func
#endif
/////////////////////////////////////////////////////////////////////////
// void ResetIntHandler()
// Interupt handler for reset/suspend timer
.globl ResetIntHandler.nstackwords
.linkset ResetIntHandler.nstackwords, 0
.globl ResetIntHandler
.type ResetIntHandler, @function
.text
.cc_top ResetIntHandler.func, ResetIntHandler
.issue_mode dual
.align FUNCTION_ALIGNMENT
ResetIntHandler:
DUALENTSP_lu6 0
clrsr 0x18 // Clear InInterrupt bit (and InKernel)
clrsr 0x3 // Clear thread events and interrupts
get r11, ed // Get timer resource ID
setc res[r11], XS1_SETC_IE_MODE_EVENT // Set IE mode back to events
clre // Clear all events
ldw r10, dp[SavedSp] // Restore stack pointer
set sp, r10
ldc r0, 1 // Load non-zero (zero is kill)
bu Return
.cc_bottom ResetIntHandler.func
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// void XUD_LLD_IoLoop(in port rxd_port, in port rxa_port, out port txd_port, in port rxe_port, in port flag0_port,
// chanend c_out, chanend c_in, chanend c_con_io, chanend c_ctl_buf,
// XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], XUD_chan epChans[], epCount, c_sof) ;
.globl XUD_LLD_IoLoop.nstackwords
.globl XUD_LLD_IoLoop.maxthreads
.globl XUD_LLD_IoLoop.maxtimers
.globl XUD_LLD_IoLoop.maxchanends
.linkset XUD_LLD_IoLoop.nstackwords, STACK_EXTEND
.linkset XUD_LLD_IoLoop.maxchanends, 0
.linkset XUD_LLD_IoLoop.maxtimers, 2
.linkset XUD_LLD_IoLoop.maxthreads, 0
.globl XUD_LLD_IoLoop
.type XUD_LLD_IoLoop, @function
.text
.cc_top XUD_LLD_IoLoop.func, XUD_LLD_IoLoop
.issue_mode dual
// Note, included here so in same elimination blocks to avoid long jumps
#include "./included/XUD_Token_In_DI.S"
#include "./included/XUD_Token_Setup_DI.S"
#include "./included/XUD_Token_Out_DI.S"
#include "./included/XUD_RxData.S"
#include "./included/XUD_Token_Ping.S"
#include "./included/XUD_Token_SOF.S"
BadCrcAddr:
// zext r11, 8
// ldc r10, PIDn_SOF
// eq r11, r11, r10
//ecallt r11
//bt r11, Pid_Sof_NoChan // TODO we should really CRC SOFs
ldw r11, sp[STACK_RXA_PORT]
waitforRXALow0:
in r10, res[r11]
bt r10, waitforRXALow0
setc res[RXD], XS1_SETC_RUN_CLRBUF
bu Loop_BadPid
.align FUNCTION_ALIGNMENT
XUD_LLD_IoLoop:
DUALENTSP_lu6 STACK_EXTEND
stw r4, sp[1]
stw r5, sp[2]
stw r6, sp[3]
stw r7, sp[4]
stw r8, sp[5]
stw r9, sp[6]
stw r10, sp[7]
PortsOnStack: // Put ports on stack (loads therefore short insts)
stw r1, sp[STACK_RXA_PORT]
stw r3, sp[STACK_RXE_PORT]
SaveStackPointer:
ldaw r11, sp[0]
stw r11, dp[SavedSp]
ldw r11, cp[suspendTimeout]
stw r11, sp[STACK_SUSPEND_TIMEOUT]
ConfigRxDEventVector: // Configure event on RXD port for receiveing a handshake after Tx
setc res[RXD], XS1_SETC_IE_MODE_EVENT
ldap r11, TxHandShakeReceived
setv res[RXD], r11
ConfigRxA: // Configure a event on RXA going low, used during packet reception
setc res[RXA], XS1_SETC_COND_EQ
setc res[RXA], XS1_SETC_IE_MODE_EVENT
ldc r11, 0
setd res[RXA], r11
ldap r11, RxALow
setv res[RXA], r11
eeu res[RXA]
ConfigValidToken:
#ifdef __XS2A__
ldw r10, sp[STACK_VTOK_PORT] // ValidToken is used for timing timeout period when expecting an ack after tx
#else
ldw r10, dp[rx_rdy] // TODO use from stack
#endif
setc res[r10], XS1_SETC_COND_NONE
ldap r11, TxHandshakeTimeOut
setv res[r10], r11
#ifndef XUD_TEST_MODE_SUPPORT_DISABLED
SetupUsbTestMode:
// Enable test mode interrupt on Endpoint 0 chanends. IN + OUT
ldaw r9, dp[epChans0]
ldw r10, r9[0] // Load channel 0
ldap r11, UsbTestModeHandler_asm
setc res[r10], XS1_SETC_IE_MODE_INTERRUPT
setv res[r10], r11
eeu res[r10]
ldc r10, 16
ldw r10, r9[r10] // Load channel for EP 0 in
setc res[r10], XS1_SETC_IE_MODE_INTERRUPT
setv res[r10], r11
eeu res[r10]
#endif
CrcRxResidualsOnStack:
ldc r11, 0x7000
stw r11, sp[STACK_RXCRC_TAIL0]
ldc r11, 0x80be
stw r11, sp[STACK_RXCRC_TAIL1]
ldc r11, 0x3ffe
stw r11, sp[STACK_RXCRC_TAIL2]
ldc r11, 0x3ffe
stw r11, sp[STACK_RXCRC_TAIL3]
ldc r11, 0xf335 // CRC16 init (in)
stw r11, sp[STACK_TXCRC_INIT]
ldc r11, 0x3334 // CRC16 init (out)
stw r11, sp[STACK_RXCRC_INIT]
ldw r11, sp[STACK_EPCHANS]
stw r11, dp[chanArray]
ConfigSofJump:
ldw r11, sp[STACK_SOFCHAN]
ldaw r10, dp[PidJumpTable]
bt r11, ConfigSofJump_Done
ldap r11, Pid_Sof_NoChan
#ifdef __XS2A__
stw r11, r10[5]
#else
ldc r9, 0xa5
stw r11, r10[r9]
#endif
ConfigSofJump_Done:
stw r10, sp[STACK_PIDJUMPTABLE]
ldaw r10, dp[PidJumpTable_RxData]
stw r10, sp[STACK_PIDJUMPTABLE_RXDATA]
ldaw r10, dp[crc5Table_Addr]
stw r10, sp[STACK_CRC5TABLE_ADDR]
ConfigRxErrEventVector:
setc res[r3], XS1_SETC_COND_EQ
setc res[r3], XS1_SETC_IE_MODE_INTERRUPT
ldap r11, Err_RxErr
setv res[r3], r11
ldc r11, 1
setd res[r3], r11 // Set event cond data to 1
eeu res[r3]
SetupSuspendResetTimer:
getr r10, XS1_RES_TYPE_TIMER
ecallf r10
stw r10, sp[STACK_SUSPEND_TIMER]
ldap r11, ResetIntHandler
setv res[r10], r11
setc res[r10], XS1_SETC_COND_NONE
in r11, res[r10] // Get current time
ldw r9, cp[suspendTimeout]
add r11, r11, r9
setd res[r10], r11
setc res[r10], XS1_SETC_COND_AFTER
setc res[r10], XS1_SETC_IE_MODE_INTERRUPT
eeu res[r10] // Enable events/interupts on resource
setc res[RXD], XS1_SETC_RUN_CLRBUF
clre
setsr 0x2 // Enable thread interrupts
bu NextToken
// Main IO Loop
.align FUNCTION_ALIGNMENT
.skip 0
NextToken:
ldc r9, 0xa001 // CRC16 poly, used in doRxData
ldw r5, sp[(STACK_EXTEND+4)] // EP structures array - pointers to EP tables or 0
NextTokenAfterOut:
ldc r7, 0xf335 // TX Crc init
ldc r6, 0x3334 // CRC16 init (out) - Needs reseting after an out
#ifdef __XS2A__
ldw r1, sp[STACK_VTOK_PORT]
#endif
Loop_BadPid:
NextTokenAfterPing:
setsr 1 // Enable thread events
#include "XUD_TokenJmp.S"
// Un-implemented PID list
Pid_Reserved:
Pid_Ack:
Pid_NYet:
Pid_Nyet:
Pid_Data2:
Pid_Split:
Pid_Nak:
Pid_Pre:
Pid_Stall:
Pid_MData:
Pid_Datam:
Pid_Data0:
Pid_Data1:
Pid_Bad: // Bad PID received, ignore
XUD_InvalidToken:
ldw r10, sp[STACK_RXA_PORT] // Load RxA Port ID (r1)
XUD_InvalidTok_waitforRXALow:
in r11, res[r10]
bt r11, XUD_InvalidTok_waitforRXALow
setc res[RXD], XS1_SETC_RUN_CLRBUF
bu Loop_BadPid // Invalid token received Ignore unknown toks
.align FUNCTION_ALIGNMENT
Return:
clre
ldw r11, sp[STACK_SUSPEND_TIMER] // Free suspend/reset timer
edu res[r11]
freer res[r11]
ldw r11, sp[STACK_RXE_PORT] // Put RxE IE mode back to events..
setc res[r11], XS1_SETC_COND_NONE
edu res[r11]
setc res[r11], XS1_SETC_IE_MODE_EVENT
ldw r11, sp[STACK_RXA_PORT]
edu res[r11]
ldw r4, sp[1] // Register restore
ldw r5, sp[2]
ldw r6, sp[3]
ldw r7, sp[4]
ldw r8, sp[5]
ldw r9, sp[6]
ldw r10, sp[7]
retsp STACK_EXTEND
.cc_bottom XUD_LLD_IoLoop.func
// Tables of tables...
#include "./included/XUD_PidJumpTable.S"
#include "./included/XUD_PidJumpTable_RxData.S"

View File

@@ -0,0 +1,616 @@
// Copyright 2011-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @file XUD_Main.xc
* @brief XMOS USB Device (XUD) Layer
* @author Ross Owen
**/
#include <xs1.h>
#include <print.h>
#include <xclib.h>
#include <platform.h>
#include "xud.h" /* External user include file */
#include "XUD_USB_Defines.h"
#include "XUD_Support.h"
#include "XUD_DeviceAttach.h"
#include "XUD_Signalling.h"
#include "XUD_HAL.h"
#include "XUD_TimingDefines.h"
#if (USB_MAX_NUM_EP_IN != 16)
#error USB_MAX_NUM_EP_IN must be 16!
#endif
#if (USB_MAX_NUM_EP_OUT != 16)
#error USB_MAX_NUM_EP_OUT must be 16!
#endif
void XUD_UserSuspend();
void XUD_UserResume();
void XUD_PhyReset_User();
#define HS_TX_HANDSHAKE_TIMEOUT (167)
#define FS_TX_HANDSHAKE_TIMEOUT (5000)
/* Global vars for current and desired USB speed */
unsigned g_curSpeed;
unsigned g_desSpeed;
unsigned g_txHandshakeTimeout;
in port flag0_port = PORT_USB_FLAG0; /* For XS3: Mission: RXE, XS2 is configurable and set to RXE in mission mode */
in port flag1_port = PORT_USB_FLAG1; /* For XS3: Mission: RXA, XS2 is configuratble and set to RXA in mission mode*/
/* XS2A has an additonal flag port. In Mission mode this is set to VALID_TOKEN */
#ifdef __XS2A__
in port flag2_port = PORT_USB_FLAG2;
#else
#define flag2_port null
#endif
in buffered port:32 p_usb_clk = PORT_USB_CLK;
out buffered port:32 p_usb_txd = PORT_USB_TXD;
in buffered port:32 p_usb_rxd = PORT_USB_RXD;
out port tx_readyout = PORT_USB_TX_READYOUT;
in port tx_readyin = PORT_USB_TX_READYIN;
in port rx_rdy = PORT_USB_RX_READY;
on USB_TILE: clock tx_usb_clk = XS1_CLKBLK_4;
on USB_TILE: clock rx_usb_clk = XS1_CLKBLK_5;
// We use a single array instrad of two here and append epAddr_Ready_setup on the end to save some instructions in the Setup
// token handling code. i.e. what we really want is the following, but's less efficient.
// unsigned epAddr_Ready[USB_MAN_NUM_EP]
// unsigned epAddr_Ready[USB_MAX_NUM_EP_OUT]
unsigned epAddr[USB_MAX_NUM_EP]; // Used to store the addr of each EP in ep_info array
unsigned epAddr_Ready[USB_MAX_NUM_EP + USB_MAX_NUM_EP_OUT]; // Used by the EP to mark itself as ready, essentially same as epAddr with 0 entries.
XUD_chan epChans0[USB_MAX_NUM_EP];
XUD_ep_info ep_info[USB_MAX_NUM_EP];
/* Location to store stack pointer (required for interrupt handler) */
unsigned SavedSp;
/* Tables storing if EP's are signed up to bus state updates */
int epStatFlagTableIn[USB_MAX_NUM_EP_IN];
int epStatFlagTableOut[USB_MAX_NUM_EP_OUT];
unsigned sentReset = 0;
unsigned chanArray;
#define RESET_TIME_us (5)
#define RESET_TIME (RESET_TIME_us * PLATFORM_REFERENCE_MHZ)
extern unsigned XUD_LLD_IoLoop(
in buffered port:32 rxd_port,
in port rxa_port,
out buffered port:32 txd_port,
in port rxe_port, in port ?valtok_port,
XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], XUD_chan epAddr_Ready[],
int epCount, chanend? c_sof) ;
#if (XUD_OPT_SOFTCRC5 == 1)
extern unsigned char crc5Table[2048];
extern unsigned char crc5Table_Addr[2048];
void XUD_SetCrcTableAddr(unsigned addr);
#endif
static int one = 1;
#pragma unsafe arrays
static void SendResetToEps(XUD_chan c[], XUD_chan epAddr_Ready[], XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], int nOut, int nIn, int token)
{
for(int i = 0; i < nOut; i++)
{
if(epTypeTableOut[i] != XUD_EPTYPE_DIS && epStatFlagTableOut[i])
{
/* Set EP resetting flag. EP uses this to check if it missed a reset before setting ready */
ep_info[i].resetting = 1;
/* Clear EP ready. Note. small race since EP might set ready after XUD sets resetting to 1
* but this should be caught in time (EP gets CT) */
epAddr_Ready[i] = 0;
epAddr_Ready[i+ USB_MAX_NUM_EP] = 0;
XUD_Sup_outct(c[i], token);
}
}
for(int i = 0; i < nIn; i++)
{
if(epTypeTableIn[i] != XUD_EPTYPE_DIS && epStatFlagTableIn[i])
{
ep_info[i + USB_MAX_NUM_EP_OUT].resetting = 1;
epAddr_Ready[i + USB_MAX_NUM_EP_OUT] = 0;
XUD_Sup_outct(c[i + USB_MAX_NUM_EP_OUT], token);
}
}
}
static void SendSpeed(XUD_chan c[], XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], int nOut, int nIn, int speed)
{
for(int i = 0; i < nOut; i++)
{
if(epTypeTableOut[i] != XUD_EPTYPE_DIS && epStatFlagTableOut[i])
{
XUD_Sup_outuint(c[i], speed);
}
}
for(int i = 0; i < nIn; i++)
{
if(epTypeTableIn[i] != XUD_EPTYPE_DIS && epStatFlagTableIn[i])
{
XUD_Sup_outuint(c[i + USB_MAX_NUM_EP_OUT], speed);
}
}
}
// Main XUD loop
static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epAddr_Ready[], chanend ?c_sof, XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[], int noEpOut, int noEpIn, XUD_PwrConfig pwrConfig)
{
int reset = 1; /* Flag for if device is returning from a reset */
/* Make sure ports are on and reset port states */
set_port_use_on(p_usb_clk);
set_port_use_on(p_usb_txd);
set_port_use_on(p_usb_rxd);
set_port_use_on(flag0_port);
set_port_use_on(flag1_port);
#if defined(__XS2A__)
/* Extra flag port in XS2 */
set_port_use_on(flag2_port);
#endif
#if !defined(__XS2A__)
#ifndef XUD_CORE_CLOCK
#error XUD_CORE_CLOCK not defined (in MHz)
#endif
#ifdef XUD_SIM_XSIM
#if (XUD_CORE_CLOCK >= 700)
#define RX_RISE_DELAY 0
#define RX_FALL_DELAY 0
#define TX_RISE_DELAY 0
#define TX_FALL_DELAY 7
#elif (XUD_CORE_CLOCK >= 600)
#define RX_RISE_DELAY 0
#define RX_FALL_DELAY 0
#define TX_RISE_DELAY 0
#define TX_FALL_DELAY 5
#else
#error XUD_CORE_CLOCK must be >= 600
#endif
#else
#if (XUD_CORE_CLOCK >= 600)
#define RX_RISE_DELAY 1
#define RX_FALL_DELAY 1
#define TX_RISE_DELAY 1
#define TX_FALL_DELAY 1
#elif (XUD_CORE_CLOCK >= 500)
#define RX_RISE_DELAY 1
#define RX_FALL_DELAY 0
#define TX_RISE_DELAY 1
#define TX_FALL_DELAY 1
#else
#error XUD_CORE_CLOCK must be >= 500
#endif
#endif
#else
#define RX_RISE_DELAY 1
#define RX_FALL_DELAY 5
#define TX_RISE_DELAY 5
#define TX_FALL_DELAY 1
#endif
// Handshaken ports need USB clock
configure_clock_src(tx_usb_clk, p_usb_clk);
configure_clock_src(rx_usb_clk, p_usb_clk);
// This, along with the following delays, forces the clock
// to the ports to be effectively controlled by the
// previous usb clock edges
set_port_inv(p_usb_clk);
set_port_sample_delay(p_usb_clk);
// This delay controls the capture of rdy
set_clock_rise_delay(tx_usb_clk, TX_RISE_DELAY);
// This delay controls the launch of data.
set_clock_fall_delay(tx_usb_clk, TX_FALL_DELAY);
// This delay the capture of the rdyIn and data.
set_clock_rise_delay(rx_usb_clk, RX_RISE_DELAY);
set_clock_fall_delay(rx_usb_clk, RX_FALL_DELAY);
set_pad_delay(flag1_port, 2);
start_clock(tx_usb_clk);
start_clock(rx_usb_clk);
configure_out_port_handshake(p_usb_txd, tx_readyin, tx_readyout, tx_usb_clk, 0);
configure_in_port_strobed_slave(p_usb_rxd, rx_rdy, rx_usb_clk);
/* Clock RxA port from USB clock - helps fall event */
configure_in_port(flag1_port, rx_usb_clk);
unsigned noExit = 1;
while(noExit)
{
unsigned settings[] = {0};
/* Enable USB funcitonality in the device */
XUD_HAL_EnableUsb(pwrConfig);
while(1)
{
{
/* Wait for VBUS before enabling pull-up. The USB Spec (page 150) allows 100ms
* between vbus valid and signalling attach */
if(pwrConfig == XUD_PWR_SELF)
{
while(1)
{
unsigned time;
timer t;
if(XUD_HAL_GetVBusState())
{
break;
}
t :> time;
time += (200 * PLATFORM_REFERENCE_MHZ); // 200us poll
t when timerafter(time):> void;
}
}
/* Go into full speed mode: XcvrSelect and Term Select (and suspend) high */
XUD_HAL_EnterMode_PeripheralFullSpeed();
/* Setup flags for power signalling - i.e. J/K/SE0 line state*/
XUD_HAL_Mode_Signalling();
if (one)
{
#if defined(XUD_BYPASS_CONNECT)
reset = 1;
#else
reset = XUD_Init();
#endif
one = 0;
}
else
{
timer t; unsigned time;
t :> time;
t when timerafter(time + SUSPEND_T_WTWRSTHS_ticks) :> int _;// T_WTRSTHS: 100-875us
/* Sample line state and check for reset (or suspend) */
XUD_LineState_t ls = XUD_HAL_GetLineState();
if(ls == XUD_LINESTATE_SE0)
reset = 1;
else
reset = 0;
}
/* Inspect for suspend or reset */
if(!reset)
{
/* Run user suspend code */
XUD_UserSuspend();
/* Run suspend code, returns 1 if reset from suspend, 0 for resume, -1 for invalid vbus */
reset = XUD_Suspend(pwrConfig);
if((pwrConfig == XUD_PWR_SELF) && (reset==-1))
{
/* Lost VBUS */
continue;
}
/* Run user resume code */
XUD_UserResume();
}
/* Test if coming back from reset or suspend */
if(reset == 1)
{
if(!sentReset)
{
SendResetToEps(epChans0, epAddr_Ready, epTypeTableOut, epTypeTableIn, noEpOut, noEpIn, USB_RESET_TOKEN);
sentReset = 1;
}
/* Reset the OUT ep structures */
for(int i = 0; i< noEpOut; i++)
{
#if !defined(__XS2A__)
ep_info[i].pid = USB_PIDn_DATA0;
#else
ep_info[i].pid = USB_PID_DATA0;
#endif
}
/* Reset in the ep structures */
for(int i = 0; i< noEpIn; i++)
{
ep_info[USB_MAX_NUM_EP_OUT+i].pid = USB_PIDn_DATA0;
}
/* Set default device address - note, for normal operation this is 0, but can be other values for testing */
XUD_HAL_SetDeviceAddress(XUD_STARTUP_ADDRESS);
#ifdef XUD_BYPASS_RESET
if(XUD_TEST_SPEED == XUD_SPEED_HS)
{
g_curSpeed = XUD_SPEED_HS;
g_txHandshakeTimeout = HS_TX_HANDSHAKE_TIMEOUT;
XUD_HAL_EnterMode_PeripheralHighSpeed();
}
else
{
g_curSpeed = XUD_SPEED_FS;
g_txHandshakeTimeout = FS_TX_HANDSHAKE_TIMEOUT;
XUD_HAL_EnterMode_PeripheralFullSpeed(); //Technically not required since we should already be in FS mode..
}
#else
if(g_desSpeed == XUD_SPEED_HS)
{
unsigned tmp = 0;
tmp = XUD_DeviceAttachHS(pwrConfig);
if(tmp == -1)
{
XUD_UserSuspend();
continue;
}
else if (!tmp)
{
/* HS handshake fail, mark as running in FS */
g_curSpeed = XUD_SPEED_FS;
g_txHandshakeTimeout = FS_TX_HANDSHAKE_TIMEOUT;
}
else
{
g_curSpeed = XUD_SPEED_HS;
g_txHandshakeTimeout = HS_TX_HANDSHAKE_TIMEOUT;
}
}
else
{
g_curSpeed = XUD_SPEED_FS;
g_txHandshakeTimeout = FS_TX_HANDSHAKE_TIMEOUT;
}
#endif
/* Send speed to EPs */
SendSpeed(epChans0, epTypeTableOut, epTypeTableIn, noEpOut, noEpIn, g_curSpeed);
sentReset=0;
}
}
XUD_HAL_Mode_DataTransfer();
set_thread_fast_mode_on();
/* Run main IO loop */
/* flag0: Rx Error
flag1: Rx Active
flag2: Null / Valid Token */
noExit = XUD_LLD_IoLoop(p_usb_rxd, flag1_port, p_usb_txd, flag0_port, flag2_port, epTypeTableOut, epTypeTableIn, epAddr_Ready, noEpOut, c_sof);
set_thread_fast_mode_off();
if(!noExit)
break;
}
}
/* TODO stop clock blocks */
/* Turn ports off */
set_port_use_off(p_usb_txd);
set_port_use_off(p_usb_rxd);
set_port_use_off(flag0_port);
set_port_use_off(flag1_port);
#ifdef __XS2A__
set_port_use_off(flag2_port);
#endif
set_port_use_off(p_usb_clk);
return 0;
}
void _userTrapHandleRegister(void);
#pragma unsafe arrays
static void drain(chanend chans[], int n, int op, XUD_EpType epTypeTable[])
{
for(int i = 0; i < n; i++)
{
if(epTypeTable[i] != XUD_EPTYPE_DIS)
{
switch(op)
{
case 0:
outct(chans[i], XS1_CT_END);
outuint(chans[i], XUD_SPEED_KILL);
break;
case 1:
outct(chans[i], XS1_CT_END);
while (!testct(chans[i]))
inuchar(chans[i]);
chkct(chans[i], XS1_CT_END);
break;
}
}
}
}
#pragma unsafe arrays
void SetupEndpoints(chanend c_ep_out[], int noEpOut, chanend c_ep_in[], int noEpIn, XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[])
{
for(int i = 0; i < USB_MAX_NUM_EP_OUT; i++)
{
unsigned x;
epAddr_Ready[i] = 0;
epAddr_Ready[i+USB_MAX_NUM_EP] = 0; //epAddr_Ready_Setup
ep_info[i].epAddress = i;
ep_info[i].resetting = 0;
/* Mark all EP's as halted, we might later clear this if the EP is in use */
ep_info[i].halted = USB_PIDn_STALL;
asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"(i*sizeof(XUD_ep_info)/sizeof(unsigned)));
epAddr[i] = x;
}
for(int i = 0; i < USB_MAX_NUM_EP_IN; i++)
{
unsigned x;
ep_info[i].epAddress = i;
epAddr_Ready[USB_MAX_NUM_EP_OUT+i] = 0;
ep_info[USB_MAX_NUM_EP_OUT+i].epAddress = (i | 0x80);
ep_info[USB_MAX_NUM_EP_OUT+i].resetting = 0;
ep_info[USB_MAX_NUM_EP_OUT+i].halted = USB_PIDn_STALL;
asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"((USB_MAX_NUM_EP_OUT+i)*sizeof(XUD_ep_info)/sizeof(unsigned)));
epAddr[USB_MAX_NUM_EP_OUT+i] = x;
}
/* Populate arrays of channels and status flag tables */
/* Note, if the epTypeTables don't match the provided size there could be trouble.. */
for(int i = 0; i < noEpOut; i++)
{
if(epTypeTableOut[i] != XUD_EPTYPE_DIS)
{
unsigned x;
epChans0[i] = XUD_Sup_GetResourceId(c_ep_out[i]);
asm("ldaw %0, %1[%2]":"=r"(x):"r"(epAddr_Ready),"r"(i));
ep_info[i].array_ptr = x;
ep_info[i].saved_array_ptr = 0;
asm("ldaw %0, %1[%2]":"=r"(x):"r"(epAddr_Ready),"r"(i+USB_MAX_NUM_EP)); //epAddr_Ready_Setup
ep_info[i].array_ptr_setup = x;
asm("mov %0, %1":"=r"(x):"r"(c_ep_out[i]));
ep_info[i].xud_chanend = x;
asm("getd %0, res[%1]":"=r"(x):"r"(c_ep_out[i]));
ep_info[i].client_chanend = x;
epStatFlagTableOut[i] = epTypeTableOut[i] & XUD_STATUS_ENABLE;
epTypeTableOut[i] = epTypeTableOut[i] & 0x7FFFFFFF;
ep_info[i].epType = epTypeTableOut[i];
ep_info[i].halted = USB_PIDn_NAK; // Mark EP as not halted
#if !defined(__XS2A__)
ep_info[i].pid = USB_PIDn_DATA0;
#else
ep_info[i].pid = USB_PID_DATA0;
#endif
asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"(i*sizeof(XUD_ep_info)/sizeof(unsigned)));
outuint(c_ep_out[i], x);
}
}
for(int i = 0; i< noEpIn; i++)
{
if(epTypeTableIn[i] != XUD_EPTYPE_DIS)
{
int x;
epChans0[i+USB_MAX_NUM_EP_OUT] = XUD_Sup_GetResourceId(c_ep_in[i]);
asm("ldaw %0, %1[%2]":"=r"(x):"r"(epAddr_Ready),"r"(USB_MAX_NUM_EP_OUT+i));
ep_info[USB_MAX_NUM_EP_OUT+i].array_ptr = x;
ep_info[USB_MAX_NUM_EP_OUT+i].saved_array_ptr = 0;
asm("mov %0, %1":"=r"(x):"r"(c_ep_in[i]));
ep_info[USB_MAX_NUM_EP_OUT+i].xud_chanend = x;
asm("getd %0, res[%1]":"=r"(x):"r"(c_ep_in[i]));
ep_info[USB_MAX_NUM_EP_OUT+i].client_chanend = x;
ep_info[USB_MAX_NUM_EP_OUT+i].pid = USB_PIDn_DATA0;
epStatFlagTableIn[i] = epTypeTableIn[i] & XUD_STATUS_ENABLE;
epTypeTableIn[i] = epTypeTableIn[i] & 0x7FFFFFFF;
ep_info[USB_MAX_NUM_EP_OUT+i].epType = epTypeTableIn[i];
ep_info[USB_MAX_NUM_EP_OUT+i].halted = 0; // Mark EP as not halted
asm("ldaw %0, %1[%2]":"=r"(x):"r"(ep_info),"r"((USB_MAX_NUM_EP_OUT+i)*sizeof(XUD_ep_info)/sizeof(unsigned)));
outuint(c_ep_in[i], x);
}
}
/* EpTypeTable Checks. Note, currently this is not too crucial since we only really care if the EP is ISO or not */
/* Check for control on IN/OUT 0 */
if(epTypeTableOut[0] != XUD_EPTYPE_CTL || epTypeTableIn[0] != XUD_EPTYPE_CTL)
{
__builtin_trap();
}
}
#pragma unsafe arrays
int XUD_Main(chanend c_ep_out[], int noEpOut,
chanend c_ep_in[], int noEpIn,
chanend ?c_sof,
XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
XUD_BusSpeed_t speed, XUD_PwrConfig pwrConfig)
{
g_desSpeed = speed;
SetupEndpoints(c_ep_out, noEpOut, c_ep_in, noEpIn, epTypeTableOut, epTypeTableIn);
#if 0
/* Check that if the required channel has a destination if the EP is marked as in use */
for( int i = 0; i < noEpOut + noEpIn; i++ )
{
if( XUD_Sup_getd( epAddr_Ready[i] ) == 0 && epTypeTableOut[i] != XUD_EPTYPE_DIS )
XUD_Error_hex("XUD_Manager: OUT Ep marked as in use but chanend has no dest: ", i);
}
for( int i = 0; i < noEpOut + noEpIn; i++ )
{
if( XUD_Sup_getd( epAddr_Ready[i + XUD_EP_COUNT ] ) == 0 && epTypeTableIn[i] != XUD_EPTYPE_DIS )
XUD_Error_hex("XUD_Manager: IN Ep marked as in use but chanend has no dest: ", i);
}
#endif
/* Run the main XUD loop */
XUD_Manager_loop(epChans0, epAddr_Ready, c_sof, epTypeTableOut, epTypeTableIn, noEpOut, noEpIn, pwrConfig);
// Need to close, drain, and check - three stages.
for(int i = 0; i < 2; i++)
{
drain(c_ep_out, noEpOut, i, epTypeTableOut); // On all inputs
drain(c_ep_in, noEpIn, i, epTypeTableIn); // On all output
}
return 0;
}
/* Legacy API support */
int XUD_Manager(chanend c_epOut[], int noEpOut,
chanend c_epIn[], int noEpIn,
NULLABLE_RESOURCE(chanend, c_sof),
XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
NULLABLE_RESOURCE(port, p_usb_rst),
NULLABLE_RESOURCE(clock, clk),
unsigned rstMask,
XUD_BusSpeed_t desiredSpeed,
XUD_PwrConfig pwrConfig)
{
return XUD_Main(c_epOut, noEpOut, c_epIn, noEpIn, c_sof, epTypeTableOut, epTypeTableIn, desiredSpeed, pwrConfig); //NOCOVER
}

View File

@@ -0,0 +1,33 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** @file XUD_SetCrcTableAddr.c
* @author Ross Owen, XMOS Limited
*/
#include <string.h>
/* Global table used to store complete valid CRC5 table */
extern unsigned char crc5Table[2048];
/* Global table used to store valid CRCs for current address, all other address is this table are invalidated */
extern unsigned char crc5Table_Addr[2048];
/** XUD_SetCrcTableAddress
* @brief Copies CRCs from original valid table to the table we use. Invalidates entries
* which correspnds to the wrong address
* @param addr new device address
* @return void
*/
void XUD_SetCrcTableAddr(unsigned addr)
{
unsigned index;
/* Set whole table to invalid CRC */
memset(crc5Table_Addr, 0xff, 2048);
/* Copy over relevant entries */
for(unsigned ep = 0; ep <= 0xF; ep++)
{
index = addr + (ep << 7);
crc5Table_Addr[index] = crc5Table[index];
}
}

View File

@@ -0,0 +1,11 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUD_PWRSIG_H_
#define _XUD_PWRSIG_H_
void XUD_PhyReset(out port p_rst, int resetTime, unsigned rstMask);
int XUD_Init();
int XUD_Suspend(XUD_PwrConfig pwrConfig);
#endif

View File

@@ -0,0 +1,185 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include "xud.h"
#include "XUD_Support.h"
#include "XUD_USB_Defines.h"
#include "XUD_HAL.h"
#define T_WTRSTFS_us 26 // 26us
#ifndef T_WTRSTFS
#define T_WTRSTFS (T_WTRSTFS_us * PLATFORM_REFERENCE_MHZ)
#endif
#define STATE_START_TO_us 3000 // 3ms
#define STATE_START_TO (STATE_START_TO_us * PLATFORM_REFERENCE_MHZ)
#define DELAY_6ms_us 6000
#define DELAY_6ms (DELAY_6ms_us * PLATFORM_REFERENCE_MHZ)
#define T_FILTSE0 250
#ifndef SUSPEND_VBUS_POLL_TIMER_TICKS
#define SUSPEND_VBUS_POLL_TIMER_TICKS (500000)
#endif
extern unsigned g_curSpeed;
int XUD_Init()
{
/* Wait for host */
while (1)
{
XUD_LineState_t currentLs = XUD_HAL_GetLineState();
switch (currentLs)
{
/* SE0 State */
case XUD_LINESTATE_SE0:
unsigned timedOut = XUD_HAL_WaitForLineStateChange(currentLs, T_WTRSTFS);
/* If no change in LS then return 1 for reset */
if(timedOut)
return 1;
/* Otherwise SE0 went away.. keep looking */
break;
/* J State */
case XUD_LINESTATE_HS_K_FS_J:
unsigned timedOut = XUD_HAL_WaitForLineStateChange(currentLs, STATE_START_TO);
/* If no change in LS then return 0 for suspend */
if(timedOut)
return 0;
/* Otherwise J went away.. keep looking */
break;
default:
/* Shouldn't expect to get here, but ignore anyway */
break;
}
}
__builtin_trap();
return -1;
}
/** XUD_Suspend
* @brief Function called when device is suspended. This should include any clock down code etc.
* @return non-zero if reset detected during resume */
int XUD_Suspend(XUD_PwrConfig pwrConfig)
{
timer t;
unsigned time;
XUD_LineState_t currentLs = XUD_LINESTATE_HS_K_FS_J;
while(1)
{
unsigned timeOutTime = 0;
if(pwrConfig == XUD_PWR_SELF)
timeOutTime = SUSPEND_VBUS_POLL_TIMER_TICKS;
unsigned timedOut = XUD_HAL_WaitForLineStateChange(currentLs, timeOutTime);
if(timedOut)
{
if(!XUD_HAL_GetVBusState())
{
/* VBUS not valid */
XUD_HAL_EnterMode_TristateDrivers();
return -1;
}
else
{
/* VBUS still valid, keep looking for LS change */
continue;
}
}
switch(currentLs)
{
/* Reset signalliung */
case XUD_LINESTATE_SE0:
timedOut = XUD_HAL_WaitForLineStateChange(currentLs, T_FILTSE0);
if(timedOut)
{
/* Consider 2.5ms a complete reset */
t :> time;
t when timerafter(time + 250000) :> void;
/* Return 1 for reset */
return 1;
}
/* If didnt timeout then keep looping...*/
break;
/* K, start of resume */
case XUD_LINESTATE_HS_J_FS_K:
#ifdef __XS2A__
if (g_curSpeed == XUD_SPEED_HS)
{
/* Special case for XS2A - start high-speed switch so it is completed as soon as possible after end of resume is seen */
XUD_HAL_EnterMode_PeripheralHighSpeed_Start();
}
#endif
while(1)
{
XUD_HAL_WaitForLineStateChange(currentLs, 0);
switch(currentLs)
{
/* J, unexpected, return */
case XUD_LINESTATE_HS_K_FS_J:
#ifdef __XS2A__
/* For XS2 we have to complete the high-speed switch now, since we started it already..
we then revert to full speed straight away - causes a blip on the bus, non-ideal */
if (g_curSpeed == XUD_SPEED_HS)
{
unsafe
{
XUD_HAL_EnterMode_PeripheralHighSpeed_Complete();
}
}
XUD_HAL_EnterMode_PeripheralFullSpeed();
#endif
return 0;
/* SE0, end of resume */
case XUD_LINESTATE_SE0:
if (g_curSpeed == XUD_SPEED_HS)
{
#ifdef __XS2A__
/* For XS2 we now have to complete the switch back to high-speed */
XUD_HAL_EnterMode_PeripheralHighSpeed_Complete();
#else
/* Move back into high-speed mode - Notes, writes to XS3A registers orders of magnitude faster than XS2A */
XUD_HAL_EnterMode_PeripheralHighSpeed();
#endif
}
/* Return 0 for resumed */
return 0;
default:
// Keep looping
break;
}
}
break;
default:
break;
}
}
return 0; // unreachable
}

View File

@@ -0,0 +1,63 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** @file XUD_Support.h
* @brief Various support functions used in XUD
* @author Ross Owen, XMOS Limited
*/
#ifndef _XUD_SUPPORT_H_
#define _XUD_SUPPORT_H_ 1
/* Typedefs for resources */
typedef unsigned XUD_lock;
typedef unsigned XUD_chan;
// Delay execution (Uses timer)
void XUD_Sup_Delay(unsigned x);
inline unsigned XUD_Sup_GetResourceId(chanend c)
{
unsigned id;
asm ("mov %0, %1" : "=r"(id) : "r"(c));
return id;
}
// Channel comms - In
inline unsigned char XUD_Sup_inct(XUD_chan c)
{
unsigned char x;
asm volatile("inct %0, res[%1]" : "=r"(x) : "r"(c));
return x;
}
inline unsigned char XUD_Sup_int(XUD_chan c)
{
unsigned char x;
asm volatile("int %0, res[%1]" : "=r"(x) : "r"(c));
return x;
}
inline unsigned char XUD_Sup_testct(XUD_chan c)
{
unsigned char x;
asm volatile("testct %0, res[%1]" : "=r"(x) : "r"(c));
return x;
}
// Channel comms - Out
inline void XUD_Sup_outuint(XUD_chan c, unsigned x)
{
asm volatile("out res[%0], %1" : /* no outputs */ : "r"(c), "r"(x));
}
inline void XUD_Sup_outuchar(XUD_chan c, unsigned char x)
{
asm volatile("outt res[%0], %1" : /* no outputs */ : "r"(c), "r"(x));
}
inline void XUD_Sup_outct(XUD_chan c, unsigned char x)
{
asm volatile("outct res[%0], %1" : /* no outputs */ : "r"(c), "r"(x));
}
#endif

View File

@@ -0,0 +1,13 @@
// Copyright 2013-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "XUD_Support.h"
#include <xs1.h>
// Force external definitions of inline functions in this file.
extern inline unsigned XUD_Sup_GetResourceId(chanend c);
extern inline unsigned char XUD_Sup_inct(XUD_chan c);
extern inline unsigned char XUD_Sup_int(XUD_chan c);
extern inline unsigned char XUD_Sup_testct(XUD_chan c);
extern inline void XUD_Sup_outuint(XUD_chan c, unsigned x);
extern inline void XUD_Sup_outct(XUD_chan c, unsigned char x);

View File

@@ -0,0 +1,78 @@
// Copyright 2020-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include "XUD_USB_Defines.h"
#include "XUD_AlignmentDefines.h"
.issue_mode dual
.globl XUD_UsbTestSE0.nstackwords
.linkset XUD_UsbTestSE0.nstackwords, 0
.globl XUD_UsbTestSE0
.text
.cc_top XUD_UsbTestSE0.func, XUD_UsbTestSE0
// NAK every IN token if the CRC is correct.
.align FUNCTION_ALIGNMENT
XUD_UsbTestSE0:
DUALENTSP_lu6 0 // Note, don't really need DI here..
// TODO ideally don't load these from dp..
ldw r0, dp[p_usb_rxd] // Load RXD port
ldw r2, dp[p_usb_txd] // Load TXD port
ldw r3, dp[flag1_port] // Load RXA port
XUD_UsbTestSE0_loop:
#ifdef __XS2A__
ldw r1, dp[flag2_port] // Valid token port
inpw r11, res[r0], 8 // Read 8 bit PID
shr r11, r11, 24 // shift off junk
inpw r9, res[r0], 8 // Read EP Number (dont care)
in r9, res[r1]
bt r9, InvalidTestToken // If VALID_TOKEN high, ignore token
eq r10, r11, USB_PID_IN
bf r10, XUD_UsbTestSE0_loop
#else
ldc r8, 16
inpw r9, res[r0], 8 // Read 3 byte token from data port | CRC[5] | EP[4] | ADDR[7] | PID[8] | junk
{setpsc res[r0], r8; shr r9, r9, 24} // r9: PID
// TODO ideally share this with XUD_CrcAddrCheck rather than a duplication here..
{in r10, res[r0]; sub r1, r8, 5} // ldc r1, 11
{shr r10, r10, 16; mkmsk r11, r1}
{and r11, r10, r11; shr r4, r10, r1} // r4: Received CRC
ldaw r8, dp[crc5Table] // Note, accepting any address
ld8u r8, r8[r11] // Correct CRC
xor r4, r4, r8 // Check received CRC against expected CRC
bt r4, InvalidTestToken; // Note, EP number is ignored
ldc r4, USB_PIDn_IN
eq r9, r9, r4 // Check received PID
bf r9, XUD_UsbTestSE0_loop
#endif
nop // If all is well respond with a NAK to any IN token..
nop
nop
nop
nop
ldc r11, USB_PIDn_NAK
outpw res[r2], r11, 8
syncr res[r2]
bu XUD_UsbTestSE0_loop
InvalidTestToken:
in r11, res[r3]
bt r11, InvalidTestToken
setc res[r0], XS1_SETC_RUN_CLRBUF // Clear RXD port
bu XUD_UsbTestSE0_loop
.cc_bottom XUD_UsbTestSE0.func

View File

@@ -0,0 +1,19 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __XUD_TESTMODE_H__
#define __XUD_TESTMODE_H__
#include <xs1.h>
#include "XUD_HAL.h"
#include "XUD_USB_Defines.h"
unsigned UsbTestModeHandler_asm();
unsigned XUD_UsbTestSE0();
int XUD_TestMode_TestJ () ;
int XUD_TestMode_TestK () ;
int XUD_TestMode_TestSE0NAK () ;
int XUD_TestMode_TestPacket () ;
#endif

View File

@@ -0,0 +1,117 @@
// Copyright 2011-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include "xud.h"
#include "XUD_TestMode.h"
extern out buffered port:32 p_usb_txd;
#define T_INTER_TEST_PACKET_us 2
#define T_INTER_TEST_PACKET (T_INTER_TEST_PACKET_us * PLATFORM_REFERENCE_MHZ)
#ifndef XUD_TEST_MODE_SUPPORT_DISABLED
unsigned int test_packet[] =
{
0x000000c3,
0x00000000,
0xaaaa0000,
0xaaaaaaaa,
0xeeeeaaaa,
0xeeeeeeee,
0xfffeeeee,
0xffffffff,
0xffffffff,
0xbf7fffff,
0xfbf7efdf,
0xbf7efcfd,
0xfbf7efdf,
0xceb67efd
};
// Runs in XUD thread with interrupt on entering testmode.
int XUD_UsbTestModeHandler(unsigned cmd)
{
switch(cmd)
{
case USB_WINDEX_TEST_J:
XUD_HAL_EnterMode_PeripheralTestJTestK();
while(1)
{
p_usb_txd <: 0xffffffff;
}
break;
case USB_WINDEX_TEST_K:
XUD_HAL_EnterMode_PeripheralTestJTestK();
while(1)
{
p_usb_txd <: 0;
}
break;
case USB_WINDEX_TEST_SE0_NAK:
XUD_HAL_EnterMode_PeripheralHighSpeed();
/* Drop into asm to deal with this mode */
XUD_UsbTestSE0();
break;
case USB_WINDEX_TEST_PACKET:
{
XUD_HAL_EnterMode_PeripheralHighSpeed();
// Repetitively transmit specific test packet forever.
// Timings must still meet minimum interpacket gap
// Have to relate KJ pairings to data.
unsigned i;
timer test_packet_timer;
#pragma unsafe arrays
while (1)
{
#pragma loop unroll
for (i=0; i < sizeof(test_packet)/sizeof(test_packet[0]); i++)
{
p_usb_txd <: test_packet[i];
};
sync(p_usb_txd);
test_packet_timer :> i;
test_packet_timer when timerafter (i + T_INTER_TEST_PACKET) :> int _;
}
}
break;
case USB_WINDEX_TEST_XMOS_IN_ADDR1:
{
XUD_HAL_EnterMode_PeripheralHighSpeed();
// This isn't a USB test mode but useful for internal testing as the
// source of IN packets for the receiver sensitivty compliance test.
// Repetitively transmit specific IN packet forever. (PID = IN, Address = 1, Endpoint = 0, CRC = 0x1D)
// Not to be used in normal use.
unsigned i;
timer test_packet_timer;
while (1)
{
partout(p_usb_txd, 24, 0xE80169);
sync(p_usb_txd);
test_packet_timer :> i;
test_packet_timer when timerafter (i + T_INTER_TEST_PACKET) :> int _;
}
}
break;
default:
break;
}
while(1);
return -1; // Unreachable
}
#endif

View File

@@ -0,0 +1,33 @@
// Copyright 2015-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUD_TIMING_DEFINES_H_
#define _XUD_TIMING_DEFINES_H_
#include <platform.h>
// Defines relating to USB/ULPI/UTMI/Phy specs
#ifndef SUSPEND_TIMEOUT_us
#define SUSPEND_TIMEOUT_us (3000)
#endif
#define SUSPEND_TIMEOUT_ticks (SUSPEND_TIMEOUT_us * PLATFORM_REFERENCE_MHZ)
// Device attach timing defines
#define T_UCHEND_T_UCH_us (1000000) // 1000ms
#define T_UCHEND_T_UCH (T_UCHEND_T_UCH_us * PLATFORM_REFERENCE_MHZ)
#ifndef T_FILT_us
#define T_FILT_us (3) // 2.5us
#endif
#define T_FILT_ticks (T_FILT_us * PLATFORM_REFERENCE_MHZ)
#ifndef SUSPEND_T_WTWRSTHS_us
#define SUSPEND_T_WTWRSTHS_us (200) // 200us Time beforechecking for J after asserting XcvrSelect and Termselect: T_WTRSTHS: 100-875us
#endif
#define SUSPEND_T_WTWRSTHS_ticks (SUSPEND_T_WTWRSTHS_us * PLATFORM_REFERENCE_MHZ)
#define OUT_TIMEOUT_us (500) // How long we wait for data after OUT token
#define OUT_TIMEOUT_ticks (OUT_TIMEOUT_us * PLATFORM_REFERENCE_MHZ)
#define TX_HANDSHAKE_TIMEOUT_us (5) // How long we wait for handshake after sending tx data
#define TX_HANDSHAKE_TIMEOUT_ticks (TX_HANDSHAKE_TIMEOUT_us * PLATFORM_REFERENCE_MHZ)
#endif

View File

@@ -0,0 +1,23 @@
// Copyright 2013-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if defined(__XS2A__)
ldaw r10, dp[PidJumpTable] // TODO Could load from sp here
// We receive: | 0000 4-bit EP | 0000 4-bit PID |
inpw r11, res[RXD], 8 // Read 8 bit PID
shr r11, r11, 24 // Shift off junk
ldw r10, r10[r11] // Load relevant branch address
bau r10
#else
{ldw r10, sp[STACK_PIDJUMPTABLE]
ldc r8, 16}
inpw r11, res[RXD], 8 // Read 3 byte token from data port | CRC[5] | EP[4] | ADDR[7] | PID[8] | junk
{setpsc res[RXD], r8; shr r11, r11, 24}
ldw r11, r10[r11]
bau r11 // Branch to Pid_Out, Pid_Sof, Pid_In, Pid_Setup etc
#endif

View File

@@ -0,0 +1,75 @@
// Copyright 2015-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** XUD_USBTile_Support.S
* @brief Support functions for USB Tile use
* @author Ross Owen, XMOS Limited
*/
#ifdef __XS2A__
#include <xs2a_registers.h>
#endif
#if !defined(__XS2A__)
#include <xs1.h>
#endif
#include <XUD_AlignmentDefines.h>
.text
.globl XUD_EnableUsbPortMux, "f{ui}()"
.type XUD_EnableUsbPortMux, @function
.cc_top XUD_EnableUsbPortMux.function
.align FUNCTION_ALIGNMENT
// void XUD_EnableUsbPortMux (unsigned mode);
XUD_EnableUsbPortMux:
.issue_mode single
ENTSP_lu6 0
ldc r1, XS1_PS_XCORE_CTRL0
get r0, ps[r1]
ldc r2, 2
or r0, r0, r2
set ps[r1], r0
//Sanity check, read back and check
//get r1, ps[r1]
//eq r1, r0, r1
//ecallf r1
retsp 0
.size XUD_EnableUsbPortMux, .-XUD_EnableUsbPortMux
.cc_bottom XUD_EnableUsbPortMux.function
.globl XUD_EnableUsbPortMux.nstackwords
.globl XUD_EnableUsbPortMux.maxchanends
.globl XUD_EnableUsbPortMux.maxtimers
.globl XUD_EnableUsbPortMux.maxcores
.set XUD_EnableUsbPortMux.nstackwords, 0
.set XUD_EnableUsbPortMux.maxchanends, 0
.set XUD_EnableUsbPortMux.maxtimers, 0
.set XUD_EnableUsbPortMux.maxcores, 1
.set XUD_EnableUsbPortMux.locnochandec, 1
.globl XUD_DisableUsbPortMux, "f{ui}()"
.type XUD_DisableUsbPortMux, @function
.cc_top XUD_DisableUsbPortMux.function
.align FUNCTION_ALIGNMENT
// void XUD_DisableUsbPortMux (unsigned mode);
XUD_DisableUsbPortMux:
ldc r1, XS1_PS_XCORE_CTRL0
ldc r0, 0
set ps[r1], r0
//Sanity check, read back and check
//get r1, ps[r1]
//eq r1, r0, r1
//ecallf r1
retsp 0
.size XUD_DisableUsbPortMux, .-XUD_DisableUsbPortMux
.cc_bottom XUD_DisableUsbPortMux.function
.globl XUD_DisableUsbPortMux.nstackwords
.globl XUD_DisableUsbPortMux.maxchanends
.globl XUD_DisableUsbPortMux.maxtimers
.globl XUD_DisableUsbPortMux.maxcores
.set XUD_DisableUsbPortMux.nstackwords, 0
.set XUD_DisableUsbPortMux.maxchanends, 0
.set XUD_DisableUsbPortMux.maxtimers, 0
.set XUD_DisableUsbPortMux.maxcores, 1
.set XUD_DisableUsbPortMux.locnochandec, 1

View File

@@ -0,0 +1,22 @@
// Copyright 2015-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XUD_USBTILE_SUPPORT_H_
#define _XUD_USBTILE_SUPPORT_H_ 1
#include "XUD_Support.h"
unsigned XUD_EnableUsbPortMux();
unsigned XUD_DisableUsbPortMux();
int write_periph_word(tileref tile, unsigned peripheral, unsigned addr, unsigned data);
int read_periph_word(tileref tile, unsigned peripheral, unsigned addr, unsigned &data);
unsigned get_tile_id(tileref ref);
void write_periph_word_two_part_start(chanend tmpchan, tileref tile, unsigned peripheral,
unsigned base_address, unsigned data);
void write_periph_word_two_part_end(chanend tmpchan, unsigned data);
#endif

View File

@@ -0,0 +1,67 @@
// Copyright 2013-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifdef __XS2A__
#include <xs1.h>
#define STRINGIFY0(x) #x
#define STRINGIFY(x) STRINGIFY0(x)
#define ENABLE_INTERRUPTS() asm("setsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
#define DISABLE_INTERRUPTS() asm("clrsr " STRINGIFY(XS1_SR_IEBLE_SET(0, 1)))
#define CT_PERIPH_WRITE 0x24
#define JUNK_RETURN_ADDRESS 0xFF
unsigned getsr_int();
int write_periph_word(tileref tile, unsigned peripheral, unsigned addr, unsigned data)
{
unsigned tmp[1];
tmp[0] = data;
return write_periph_32(tile, peripheral, addr, 1, tmp);
}
int read_periph_word(tileref tile, unsigned peripheral, unsigned addr, unsigned &data)
{
unsigned tmp[1];
unsigned prevSr = 0;
/* Get current interrupt bit from SR */
asm volatile("getsr r11, 2; mov %0, r11" :"=r"(prevSr) :: "r11");
/* Clear the interrupt bit in SR */
DISABLE_INTERRUPTS();
int retval = read_periph_32(tile, peripheral, addr, 1, tmp);
/* Re-enable interrupts if they were previously enabled */
if(prevSr)
ENABLE_INTERRUPTS();
data = tmp[0];
return retval;
}
void write_periph_word_two_part_start(chanend tmpchan, tileref tile, unsigned peripheral,
unsigned base_address, unsigned data)
{
asm("setd res[%0], %1" ::
"r"(tmpchan),
"r"((get_tile_id(tile) << 16) | (peripheral << 8) | XS1_RES_TYPE_CHANEND));
/* Preload as much as possible, everything up to last byte of data */
outct(tmpchan, CT_PERIPH_WRITE);
outuint(tmpchan, (JUNK_RETURN_ADDRESS << 8) | (base_address & 0xFF));
outuchar(tmpchan, sizeof(unsigned));
outuchar(tmpchan, data >> 24);
outuchar(tmpchan, data >> 16);
outuchar(tmpchan, data >> 8);
}
void write_periph_word_two_part_end(chanend tmpchan, unsigned data)
{
/* Send last byte of data to bring the write to effect */
outuchar(tmpchan, data);
outct(tmpchan, XS1_CT_END);
}
#endif

View File

@@ -0,0 +1,20 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/* User functions to be overridden by app */
#include "xud.h"
void XUD_UserSuspend(void) __attribute__ ((weak));
void XUD_UserSuspend()
{
return;
}
void XUD_UserResume(void) __attribute__ ((weak));
void XUD_UserResume()
{
return;
}

View File

@@ -0,0 +1,558 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if defined (__XS2A__)
// PID jump table
.section .dp.data, "adw", @progbits
.globl PidJumpTable
.type PidJumpTable, @object
.cc_top PidJumpTable.func, PidJumpTable
.align 4
PidJumpTable:
.word Pid_Reserved // 0 0x00
.word Pid_Out // 1 0x01
.word Pid_Ack // 2 0x02
.word Pid_Data0 // 3 0x03
.word Pid_Ping // 4 0x04
.word Pid_Sof // 5 0x05
.word Pid_Nyet // 6 0x06
.word Pid_Data2 // 7 0x07
.word Pid_Split // 8 0x08
.word Pid_In // 9 0x09
.word Pid_Nak // 10 0x0a
.word Pid_Data1 // 11 0x0b
.word Pid_Pre // 12 0x0c
.word Pid_Setup // 13 0x0d
.word Pid_Stall // 14 0x0e
.word Pid_Datam // 15 0x0f
#if defined(XUD_DEBUG_VERSION) || defined(XUD_FULL_PIDTABLE)
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad //31
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
.word Pid_Bad
#endif
.size PidJumpTable, .-PidJumpTable
.cc_bottom PidJumpTable.func
#endif
#if !defined(__XS2A__)
// Generated using genpidtable.c
.section .dp.data, "adw", @progbits
.globl PidJumpTable
.type PidJumpTable, @function
//.cc_top PidJumpTable.func, PidJumpTableFull
.cc_top PidJumpTable.func, PidJumpTable
.align 4
PidJumpTable:
.word Pid_Bad // 0 0x00
.word Pid_Bad // 1 0x01
.word Pid_Bad // 2 0x02
.word Pid_Bad // 3 0x03
.word Pid_Bad // 4 0x04
.word Pid_Bad // 5 0x05
.word Pid_Bad // 6 0x06
.word Pid_Bad // 7 0x07
.word Pid_Bad // 8 0x08
.word Pid_Bad // 9 0x09
.word Pid_Bad // 10 0x0a
.word Pid_Bad // 11 0x0b
.word Pid_Bad // 12 0x0c
.word Pid_Bad // 13 0x0d
.word Pid_Bad // 14 0x0e
.word Pid_MData // 15 0x0f
.word Pid_Bad // 16 0x10
.word Pid_Bad // 17 0x11
.word Pid_Bad // 18 0x12
.word Pid_Bad // 19 0x13
.word Pid_Bad // 20 0x14
.word Pid_Bad // 21 0x15
.word Pid_Bad // 22 0x16
.word Pid_Bad // 23 0x17
.word Pid_Split // 24 0x1
.word Pid_Bad // 25 0x19
.word Pid_Bad // 26 0x1a
.word Pid_Bad // 27 0x1b
.word Pid_Bad // 28 0x1c
.word Pid_Bad // 29 0x1d
.word Pid_Stall // 30 0x1e
.word Pid_Bad // 31 0x1f
.word Pid_Bad // 32 0x20
.word Pid_Bad // 33 0x21
.word Pid_Bad // 34 0x22
.word Pid_Bad // 35 0x23
.word Pid_Bad // 36 0x24
.word Pid_Bad // 37 0x25
.word Pid_Bad // 38 0x26
.word Pid_Bad // 39 0x27
.word Pid_Bad // 40 0x28
.word Pid_Bad // 41 0x29
.word Pid_Bad // 42 0x2a
.word Pid_Bad // 43 0x2b
.word Pid_Bad // 44 0x2c
.word Pid_Setup // 45 0x2d
.word Pid_Bad // 46 0x2e
.word Pid_Bad // 47 0x2f
.word Pid_Bad // 48 0x30
.word Pid_Bad // 49 0x31
.word Pid_Bad // 50 0x32
.word Pid_Bad // 51 0x33
.word Pid_Bad // 52 0x34
.word Pid_Bad // 53 0x35
.word Pid_Bad // 54 0x36
.word Pid_Bad // 55 0x37
.word Pid_Bad // 56 0x38
.word Pid_Bad // 57 0x39
.word Pid_Bad // 58 0x3a
.word Pid_Bad // 59 0x3b
.word Pid_Pre // 60 0x3c
.word Pid_Bad // 61 0x3d
.word Pid_Bad // 62 0x3e
.word Pid_Bad // 63 0x3f
.word Pid_Bad // 64 0x40
.word Pid_Bad // 65 0x41
.word Pid_Bad // 66 0x42
.word Pid_Bad // 67 0x43
.word Pid_Bad // 68 0x44
.word Pid_Bad // 69 0x45
.word Pid_Bad // 70 0x46
.word Pid_Bad // 71 0x47
.word Pid_Bad // 72 0x48
.word Pid_Bad // 73 0x49
.word Pid_Bad // 74 0x4a
.word Pid_Data1 // 75 0x4b
.word Pid_Bad // 76 0x4c
.word Pid_Bad // 77 0x4d
.word Pid_Bad // 78 0x4e
.word Pid_Bad // 79 0x4f
.word Pid_Bad // 80 0x50
.word Pid_Bad // 81 0x51
.word Pid_Bad // 82 0x52
.word Pid_Bad // 83 0x53
.word Pid_Bad // 84 0x54
.word Pid_Bad // 85 0x55
.word Pid_Bad // 86 0x56
.word Pid_Bad // 87 0x57
.word Pid_Bad // 88 0x58
.word Pid_Bad // 89 0x59
.word Pid_Nak // 90 0x5a
.word Pid_Bad // 91 0x5b
.word Pid_Bad // 92 0x5c
.word Pid_Bad // 93 0x5d
.word Pid_Bad // 94 0x5e
.word Pid_Bad // 95 0x5f
.word Pid_Bad // 96 0x60
.word Pid_Bad // 97 0x61
.word Pid_Bad // 98 0x62
.word Pid_Bad // 99 0x63
.word Pid_Bad // 100 0x64
.word Pid_Bad // 101 0x65
.word Pid_Bad // 102 0x66
.word Pid_Bad // 103 0x67
.word Pid_Bad // 104 0x68
.word Pid_In // 105 0x69
.word Pid_Bad // 106 0x6a
.word Pid_Bad // 107 0x6b
.word Pid_Bad // 108 0x6c
.word Pid_Bad // 109 0x6d
.word Pid_Bad // 110 0x6e
.word Pid_Bad // 111 0x6f
.word Pid_Bad // 112 0x70
.word Pid_Bad // 113 0x71
.word Pid_Bad // 114 0x72
.word Pid_Bad // 115 0x73
.word Pid_Bad // 116 0x74
.word Pid_Bad // 117 0x75
.word Pid_Bad // 118 0x76
.word Pid_Bad // 119 0x77
.word Pid_Bad // 120 0x78
.word Pid_Bad // 121 0x79
.word Pid_Bad // 122 0x7a
.word Pid_Bad // 123 0x7b
.word Pid_Bad // 124 0x7c
.word Pid_Bad // 125 0x7d
.word Pid_Bad // 126 0x7e
.word Pid_Bad // 127 0x7f
.word Pid_Bad // 128 0x80
.word Pid_Bad // 129 0x81
.word Pid_Bad // 130 0x82
.word Pid_Bad // 131 0x83
.word Pid_Bad // 132 0x84
.word Pid_Bad // 133 0x85
.word Pid_Bad // 134 0x86
.word Pid_Data2 // 135 0x87
.word Pid_Bad // 136 0x88
.word Pid_Bad // 137 0x89
.word Pid_Bad // 138 0x8a
.word Pid_Bad // 139 0x8b
.word Pid_Bad // 140 0x8c
.word Pid_Bad // 141 0x8d
.word Pid_Bad // 142 0x8e
.word Pid_Bad // 143 0x8f
.word Pid_Bad // 144 0x90
.word Pid_Bad // 145 0x91
.word Pid_Bad // 146 0x92
.word Pid_Bad // 147 0x93
.word Pid_Bad // 148 0x94
.word Pid_Bad // 149 0x95
.word Pid_NYet // 150 0x96
.word Pid_Bad // 151 0x97
.word Pid_Bad // 152 0x98
.word Pid_Bad // 153 0x99
.word Pid_Bad // 154 0x9a
.word Pid_Bad // 155 0x9b
.word Pid_Bad // 156 0x9c
.word Pid_Bad // 157 0x9d
.word Pid_Bad // 158 0x9e
.word Pid_Bad // 159 0x9f
.word Pid_Bad // 160 0xa0
.word Pid_Bad // 161 0xa1
.word Pid_Bad // 162 0xa2
.word Pid_Bad // 163 0xa3
.word Pid_Bad // 164 0xa4
.word Pid_Sof // 165 0xa5
.word Pid_Bad // 166 0xa6
.word Pid_Bad // 167 0xa7
.word Pid_Bad // 168 0xa8
.word Pid_Bad // 169 0xa9
.word Pid_Bad // 170 0xaa
.word Pid_Bad // 171 0xab
.word Pid_Bad // 172 0xac
.word Pid_Bad // 173 0xad
.word Pid_Bad // 174 0xae
.word Pid_Bad // 175 0xaf
.word Pid_Bad // 176 0xb0
.word Pid_Bad // 177 0xb1
.word Pid_Bad // 178 0xb2
.word Pid_Bad // 179 0xb3
.word Pid_Ping // 180 0xb4
.word Pid_Bad // 181 0xb5
.word Pid_Bad // 182 0xb6
.word Pid_Bad // 183 0xb7
.word Pid_Bad // 184 0xb8
.word Pid_Bad // 185 0xb9
.word Pid_Bad // 186 0xba
.word Pid_Bad // 187 0xbb
.word Pid_Bad // 188 0xbc
.word Pid_Bad // 189 0xbd
.word Pid_Bad // 190 0xbe
.word Pid_Bad // 191 0xbf
.word Pid_Bad // 192 0xc0
.word Pid_Bad // 193 0xc1
.word Pid_Bad // 194 0xc2
.word Pid_Data0 // 195 0xc3
.word Pid_Bad // 196 0xc4
.word Pid_Bad // 197 0xc5
.word Pid_Bad // 198 0xc6
.word Pid_Bad // 199 0xc7
.word Pid_Bad // 200 0xc8
.word Pid_Bad // 201 0xc9
.word Pid_Bad // 202 0xca
.word Pid_Bad // 203 0xcb
.word Pid_Bad // 204 0xcc
.word Pid_Bad // 205 0xcd
.word Pid_Bad // 206 0xce
.word Pid_Bad // 207 0xcf
.word Pid_Bad // 208 0xd0
.word Pid_Bad // 209 0xd1
.word Pid_Ack // 210 0xd2
.word Pid_Bad // 211 0xd3
.word Pid_Bad // 212 0xd4
.word Pid_Bad // 213 0xd5
.word Pid_Bad // 214 0xd6
.word Pid_Bad // 215 0xd7
.word Pid_Bad // 216 0xd8
.word Pid_Bad // 217 0xd9
.word Pid_Bad // 218 0xda
.word Pid_Bad // 219 0xdb
.word Pid_Bad // 220 0xdc
.word Pid_Bad // 221 0xdd
.word Pid_Bad // 222 0xde
.word Pid_Bad // 223 0xdf
.word Pid_Bad // 224 0xe0
.word Pid_Out // 225 0xe1
.word Pid_Bad // 226 0xe2
.word Pid_Bad // 227 0xe3
.word Pid_Bad // 228 0xe4
.word Pid_Bad // 229 0xe5
.word Pid_Bad // 230 0xe6
.word Pid_Bad // 231 0xe7
.word Pid_Bad // 232 0xe8
.word Pid_Bad // 233 0xe9
.word Pid_Bad // 234 0xea
.word Pid_Bad // 235 0xeb
.word Pid_Bad // 236 0xec
.word Pid_Bad // 237 0xed
.word Pid_Bad // 238 0xee
.word Pid_Bad // 239 0xef
.word Pid_Bad // 240 0xf0
.word Pid_Bad // 241 0xf1
.word Pid_Bad // 242 0xf2
.word Pid_Bad // 243 0xf3
.word Pid_Bad // 244 0xf4
.word Pid_Bad // 245 0xf5
.word Pid_Bad // 246 0xf6
.word Pid_Bad // 247 0xf7
.word Pid_Bad // 248 0xf8
.word Pid_Bad // 249 0xf9
.word Pid_Bad // 250 0xfa
.word Pid_Bad // 251 0xfb
.word Pid_Bad // 252 0xfc
.word Pid_Bad // 253 0xfd
.word Pid_Bad // 254 0xfe
.word Pid_Bad // 255 0xff
.size PidJumpTable, .-PidJumpTable
.cc_bottom PidJumpTable.func
//.cc_bottom PidJumpTableFull.func
#endif

View File

@@ -0,0 +1,556 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#if defined (__XS2A__)
// PID jump table
.section .dp.data, "adw", @progbits
.globl PidJumpTable_RxData
.type PidJumpTable_RxData, @object
.cc_top PidJumpTable_RxData.func, PidJumpTable_RxData
.align 4
PidJumpTable_RxData:
.word Pid_Reserved // 0 0x00
.word Pid_Out // 1 0x01
.word Pid_Ack // 2 0x02
.word Pid_Data0_RxData // 3 0x03
.word Pid_Ping // 4 0x04
.word Pid_Sof // 5 0x05
.word Pid_Nyet // 6 0x06
.word Pid_Data2_RxData // 7 0x07
.word Pid_Split // 8 0x08
.word Pid_In // 9 0x09
.word Pid_Nak // 10 0x0a
.word Pid_Data1_RxData // 11 0x0b
.word Pid_Pre // 12 0x0c
.word Pid_Setup // 13 0x0d
.word Pid_Stall // 14 0x0e
.word Pid_Datam_RxData // 15 0x0f
#if defined(XUD_DEBUG_VERSION) || defined(XUD_FULL_PIDTABLE)
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
.word Pid_Bad_RxData
#endif
.size PidJumpTable_RxData, .-PidJumpTable_RxData
.cc_bottom PidJumpTable_RxData.func
#endif
#if !defined(__XS2A__)
// Generated using genpidtable.c
.section .dp.data, "adw", @progbits
.globl PidJumpTable_RxData
.type PidJumpTable_RxData, @function
.cc_top PidJumpTable_RxData.func, PidJumpTable_RxData
.align 4
PidJumpTable_RxData:
.word Pid_Bad_RxData // 0 0x00
.word Pid_Bad_RxData // 1 0x01
.word Pid_Bad_RxData // 2 0x02
.word Pid_Bad_RxData // 3 0x03
.word Pid_Bad_RxData // 4 0x04
.word Pid_Bad_RxData // 5 0x05
.word Pid_Bad_RxData // 6 0x06
.word Pid_Bad_RxData // 7 0x07
.word Pid_Bad_RxData // 8 0x08
.word Pid_Bad_RxData // 9 0x09
.word Pid_Bad_RxData // 10 0x0a
.word Pid_Bad_RxData // 11 0x0b
.word Pid_Bad_RxData // 12 0x0c
.word Pid_Bad_RxData // 13 0x0d
.word Pid_Bad_RxData // 14 0x0e
.word Pid_MData // 15 0x0f
.word Pid_Bad_RxData // 16 0x10
.word Pid_Bad_RxData // 17 0x11
.word Pid_Bad_RxData // 18 0x12
.word Pid_Bad_RxData // 19 0x13
.word Pid_Bad_RxData // 20 0x14
.word Pid_Bad_RxData // 21 0x15
.word Pid_Bad_RxData // 22 0x16
.word Pid_Bad_RxData // 23 0x17
.word Pid_Bad_RxData // 24 0x1
.word Pid_Bad_RxData // 25 0x19
.word Pid_Bad_RxData // 26 0x1a
.word Pid_Bad_RxData // 27 0x1b
.word Pid_Bad_RxData // 28 0x1c
.word Pid_Bad_RxData // 29 0x1d
.word Pid_Bad_RxData // 30 0x1e
.word Pid_Bad_RxData // 31 0x1f
.word Pid_Bad_RxData // 32 0x20
.word Pid_Bad_RxData // 33 0x21
.word Pid_Bad_RxData // 34 0x22
.word Pid_Bad_RxData // 35 0x23
.word Pid_Bad_RxData // 36 0x24
.word Pid_Bad_RxData // 37 0x25
.word Pid_Bad_RxData // 38 0x26
.word Pid_Bad_RxData // 39 0x27
.word Pid_Bad_RxData // 40 0x28
.word Pid_Bad_RxData // 41 0x29
.word Pid_Bad_RxData // 42 0x2a
.word Pid_Bad_RxData // 43 0x2b
.word Pid_Bad_RxData // 44 0x2c
.word Pid_Bad_RxData // 45 0x2d
.word Pid_Bad_RxData // 46 0x2e
.word Pid_Bad_RxData // 47 0x2f
.word Pid_Bad_RxData // 48 0x30
.word Pid_Bad_RxData // 49 0x31
.word Pid_Bad_RxData // 50 0x32
.word Pid_Bad_RxData // 51 0x33
.word Pid_Bad_RxData // 52 0x34
.word Pid_Bad_RxData // 53 0x35
.word Pid_Bad_RxData // 54 0x36
.word Pid_Bad_RxData // 55 0x37
.word Pid_Bad_RxData // 56 0x38
.word Pid_Bad_RxData // 57 0x39
.word Pid_Bad_RxData // 58 0x3a
.word Pid_Bad_RxData // 59 0x3b
.word Pid_Bad_RxData // 60 0x3c
.word Pid_Bad_RxData // 61 0x3d
.word Pid_Bad_RxData // 62 0x3e
.word Pid_Bad_RxData // 63 0x3f
.word Pid_Bad_RxData // 64 0x40
.word Pid_Bad_RxData // 65 0x41
.word Pid_Bad_RxData // 66 0x42
.word Pid_Bad_RxData // 67 0x43
.word Pid_Bad_RxData // 68 0x44
.word Pid_Bad_RxData // 69 0x45
.word Pid_Bad_RxData // 70 0x46
.word Pid_Bad_RxData // 71 0x47
.word Pid_Bad_RxData // 72 0x48
.word Pid_Bad_RxData // 73 0x49
.word Pid_Bad_RxData // 74 0x4a
.word Pid_Data1_RxData // 75 0x4b
.word Pid_Bad_RxData // 76 0x4c
.word Pid_Bad_RxData // 77 0x4d
.word Pid_Bad_RxData // 78 0x4e
.word Pid_Bad_RxData // 79 0x4f
.word Pid_Bad_RxData // 80 0x50
.word Pid_Bad_RxData // 81 0x51
.word Pid_Bad_RxData // 82 0x52
.word Pid_Bad_RxData // 83 0x53
.word Pid_Bad_RxData // 84 0x54
.word Pid_Bad_RxData // 85 0x55
.word Pid_Bad_RxData // 86 0x56
.word Pid_Bad_RxData // 87 0x57
.word Pid_Bad_RxData // 88 0x58
.word Pid_Bad_RxData // 89 0x59
.word Pid_Bad_RxData // 90 0x5a
.word Pid_Bad_RxData // 91 0x5b
.word Pid_Bad_RxData // 92 0x5c
.word Pid_Bad_RxData // 93 0x5d
.word Pid_Bad_RxData // 94 0x5e
.word Pid_Bad_RxData // 95 0x5f
.word Pid_Bad_RxData // 96 0x60
.word Pid_Bad_RxData // 97 0x61
.word Pid_Bad_RxData // 98 0x62
.word Pid_Bad_RxData // 99 0x63
.word Pid_Bad_RxData // 100 0x64
.word Pid_Bad_RxData // 101 0x65
.word Pid_Bad_RxData // 102 0x66
.word Pid_Bad_RxData // 103 0x67
.word Pid_Bad_RxData // 104 0x68
.word Pid_Bad_RxData // 105 0x69
.word Pid_Bad_RxData // 106 0x6a
.word Pid_Bad_RxData // 107 0x6b
.word Pid_Bad_RxData // 108 0x6c
.word Pid_Bad_RxData // 109 0x6d
.word Pid_Bad_RxData // 110 0x6e
.word Pid_Bad_RxData // 111 0x6f
.word Pid_Bad_RxData // 112 0x70
.word Pid_Bad_RxData // 113 0x71
.word Pid_Bad_RxData // 114 0x72
.word Pid_Bad_RxData // 115 0x73
.word Pid_Bad_RxData // 116 0x74
.word Pid_Bad_RxData // 117 0x75
.word Pid_Bad_RxData // 118 0x76
.word Pid_Bad_RxData // 119 0x77
.word Pid_Bad_RxData // 120 0x78
.word Pid_Bad_RxData // 121 0x79
.word Pid_Bad_RxData // 122 0x7a
.word Pid_Bad_RxData // 123 0x7b
.word Pid_Bad_RxData // 124 0x7c
.word Pid_Bad_RxData // 125 0x7d
.word Pid_Bad_RxData // 126 0x7e
.word Pid_Bad_RxData // 127 0x7f
.word Pid_Bad_RxData // 128 0x80
.word Pid_Bad_RxData // 129 0x81
.word Pid_Bad_RxData // 130 0x82
.word Pid_Bad_RxData // 131 0x83
.word Pid_Bad_RxData // 132 0x84
.word Pid_Bad_RxData // 133 0x85
.word Pid_Bad_RxData // 134 0x86
.word Pid_Data2 // 135 0x87
.word Pid_Bad_RxData // 136 0x88
.word Pid_Bad_RxData // 137 0x89
.word Pid_Bad_RxData // 138 0x8a
.word Pid_Bad_RxData // 139 0x8b
.word Pid_Bad_RxData // 140 0x8c
.word Pid_Bad_RxData // 141 0x8d
.word Pid_Bad_RxData // 142 0x8e
.word Pid_Bad_RxData // 143 0x8f
.word Pid_Bad_RxData // 144 0x90
.word Pid_Bad_RxData // 145 0x91
.word Pid_Bad_RxData // 146 0x92
.word Pid_Bad_RxData // 147 0x93
.word Pid_Bad_RxData // 148 0x94
.word Pid_Bad_RxData // 149 0x95
.word Pid_Bad_RxData // 150 0x96
.word Pid_Bad_RxData // 151 0x97
.word Pid_Bad_RxData // 152 0x98
.word Pid_Bad_RxData // 153 0x99
.word Pid_Bad_RxData // 154 0x9a
.word Pid_Bad_RxData // 155 0x9b
.word Pid_Bad_RxData // 156 0x9c
.word Pid_Bad_RxData // 157 0x9d
.word Pid_Bad_RxData // 158 0x9e
.word Pid_Bad_RxData // 159 0x9f
.word Pid_Bad_RxData // 160 0xa0
.word Pid_Bad_RxData // 161 0xa1
.word Pid_Bad_RxData // 162 0xa2
.word Pid_Bad_RxData // 163 0xa3
.word Pid_Bad_RxData // 164 0xa4
.word Pid_Bad_RxData // 165 0xa5
.word Pid_Bad_RxData // 166 0xa6
.word Pid_Bad_RxData // 167 0xa7
.word Pid_Bad_RxData // 168 0xa8
.word Pid_Bad_RxData // 169 0xa9
.word Pid_Bad_RxData // 170 0xaa
.word Pid_Bad_RxData // 171 0xab
.word Pid_Bad_RxData // 172 0xac
.word Pid_Bad_RxData // 173 0xad
.word Pid_Bad_RxData // 174 0xae
.word Pid_Bad_RxData // 175 0xaf
.word Pid_Bad_RxData // 176 0xb0
.word Pid_Bad_RxData // 177 0xb1
.word Pid_Bad_RxData // 178 0xb2
.word Pid_Bad_RxData // 179 0xb3
.word Pid_Bad_RxData // 180 0xb4
.word Pid_Bad_RxData // 181 0xb5
.word Pid_Bad_RxData // 182 0xb6
.word Pid_Bad_RxData // 183 0xb7
.word Pid_Bad_RxData // 184 0xb8
.word Pid_Bad_RxData // 185 0xb9
.word Pid_Bad_RxData // 186 0xba
.word Pid_Bad_RxData // 187 0xbb
.word Pid_Bad_RxData // 188 0xbc
.word Pid_Bad_RxData // 189 0xbd
.word Pid_Bad_RxData // 190 0xbe
.word Pid_Bad_RxData // 191 0xbf
.word Pid_Bad_RxData // 192 0xc0
.word Pid_Bad_RxData // 193 0xc1
.word Pid_Bad_RxData // 194 0xc2
.word Pid_Data0_RxData // 195 0xc3
.word Pid_Bad_RxData // 196 0xc4
.word Pid_Bad_RxData // 197 0xc5
.word Pid_Bad_RxData // 198 0xc6
.word Pid_Bad_RxData // 199 0xc7
.word Pid_Bad_RxData // 200 0xc8
.word Pid_Bad_RxData // 201 0xc9
.word Pid_Bad_RxData // 202 0xca
.word Pid_Bad_RxData // 203 0xcb
.word Pid_Bad_RxData // 204 0xcc
.word Pid_Bad_RxData // 205 0xcd
.word Pid_Bad_RxData // 206 0xce
.word Pid_Bad_RxData // 207 0xcf
.word Pid_Bad_RxData // 208 0xd0
.word Pid_Bad_RxData // 209 0xd1
.word Pid_Bad_RxData // 210 0xd2
.word Pid_Bad_RxData // 211 0xd3
.word Pid_Bad_RxData // 212 0xd4
.word Pid_Bad_RxData // 213 0xd5
.word Pid_Bad_RxData // 214 0xd6
.word Pid_Bad_RxData // 215 0xd7
.word Pid_Bad_RxData // 216 0xd8
.word Pid_Bad_RxData // 217 0xd9
.word Pid_Bad_RxData // 218 0xda
.word Pid_Bad_RxData // 219 0xdb
.word Pid_Bad_RxData // 220 0xdc
.word Pid_Bad_RxData // 221 0xdd
.word Pid_Bad_RxData // 222 0xde
.word Pid_Bad_RxData // 223 0xdf
.word Pid_Bad_RxData // 224 0xe0
.word Pid_Bad_RxData // 225 0xe1
.word Pid_Bad_RxData // 226 0xe2
.word Pid_Bad_RxData // 227 0xe3
.word Pid_Bad_RxData // 228 0xe4
.word Pid_Bad_RxData // 229 0xe5
.word Pid_Bad_RxData // 230 0xe6
.word Pid_Bad_RxData // 231 0xe7
.word Pid_Bad_RxData // 232 0xe8
.word Pid_Bad_RxData // 233 0xe9
.word Pid_Bad_RxData // 234 0xea
.word Pid_Bad_RxData // 235 0xeb
.word Pid_Bad_RxData // 236 0xec
.word Pid_Bad_RxData // 237 0xed
.word Pid_Bad_RxData // 238 0xee
.word Pid_Bad_RxData // 239 0xef
.word Pid_Bad_RxData // 240 0xf0
.word Pid_Bad_RxData // 241 0xf1
.word Pid_Bad_RxData // 242 0xf2
.word Pid_Bad_RxData // 243 0xf3
.word Pid_Bad_RxData // 244 0xf4
.word Pid_Bad_RxData // 245 0xf5
.word Pid_Bad_RxData // 246 0xf6
.word Pid_Bad_RxData // 247 0xf7
.word Pid_Bad_RxData // 248 0xf8
.word Pid_Bad_RxData // 249 0xf9
.word Pid_Bad_RxData // 250 0xfa
.word Pid_Bad_RxData // 251 0xfb
.word Pid_Bad_RxData // 252 0xfc
.word Pid_Bad_RxData // 253 0xfd
.word Pid_Bad_RxData // 254 0xfe
.word Pid_Bad_RxData // 255 0xff
.size PidJumpTable_RxData, .-PidJumpTable_RxData
.cc_bottom PidJumpTable_RxData.func
#endif

View File

@@ -0,0 +1,133 @@
// Copyright 2019-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define LABEL(fun) fun
// r0: RXD: Rx Data port
// r1: Buffer
// r2: Tx Port
// r3: Ep structure
// r4: Zero (set in XUD_CrcAddCheck.S) then buffer index
// r5: EP structures array
// r6: CRC Rx init
// r7: CRC Tx init
// r9: CRC poly
// r8: Scratch
// r10: EP number
// r11: Scratch
// On exit require:
// r4: Datalength (words)
// r8: Taillength (bits)
// r11: Expected CRC
Pid_Bad_RxData:
ldaw r10, dp[PidJumpTable]
{ldw r11, r10[r4]; ldc r8, 16}
{bau r11; setpsc res[RXD], r8} // XUD_CrcAddrCheck.S requires 16 in r8
doRXData:
inpw r4, res[r0], 8 // Input PID
ldw r8, sp[STACK_RXA_PORT]
#ifdef __XS2A__
// If pid != DATAx then jump and handle as a token. DATA0, DATA1, DATA2 & MDATA all of the form 0bxx11.
// This is a fast alternative to a "timeout"
// Note, this doesn't check that PID[0:3] = ~PID[4:7] - which is an issue for XS3
{mkmsk r11, 2; shr r4, r4, 24}
and r11, r11, r4 // Store PID into EP structure,
eq r11, r11, 3
bf r11, Pid_Bad_RxData
#else
{shr r4, r4, 24; ldw r11, sp[STACK_PIDJUMPTABLE_RXDATA]}
ldw r11, r11[r4]
bau r11
#endif
Pid_Datam_RxData:
Pid_Data0_RxData:
Pid_Data1_RxData:
Pid_Data2_RxData:
{stw r4, r3[6]; setsr 1} // Store PID into EP structure
GotRxPid:
{eeu res[r8]; mkmsk r4, 32} // Enable events on RxA
// Init buffer index to -1
NextRxWord: // Partially un-rolled to assist with timing
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
in r11, res[r0]
crc32_inc r6, r11, r9, r4, 1
stw r11, r1[r4]
bu NextRxWord
/////////////////////////////////////////////////////////////////////////////
.align 32
.skip 16
RxALow:
stw r11, r1[r4] // Extra stw, if not enough MIPS STW in loop above may not have chance to run
{in r8, res[r8]; add r4, r4, 1} // Clear event data on RXA
endin r8, res[r0]
LABEL(RxTail):
{in r11, res[r0]; bru r8}
// Word aligned data (0 byte tail)
.align 32
OutTail0:
crc32 r6, r8, r9 // CRC zero step
ldw r11, sp[STACK_RXCRC_TAIL0]
{RETSP_u6 0; ldc r1, 0}
// 1 Tail Byte
.align 32
OutTail1:
shr r11, r11, 24 // Shift off junk
crc32 r6, r11, r9
stw r11, r1[r4] // Store last data
LDWSP_ru6 r11, sp[STACK_RXCRC_TAIL1]
{RETSP_u6 0; ldc r1, 0}
// Two Tail Bytes
.align 32
OutTail2:
shr r11, r11, 16
crc32 r6, r11, r9
stw r11, r1[r4] // Store last data
ldw r11, sp[STACK_RXCRC_TAIL2]
{RETSP_u6 0; ldc r1, 0}
// Three Tail Bytes
.align 32
OutTail3:
shr r11, r11, 8
stw r11, r1[r4] // Store last data
crc32 r6, r11, r9
LDWSP_ru6 r11, sp[STACK_RXCRC_TAIL3]
crc8 r6, r1, r2, r9 // Use the fact the the bottom byte of port id is 0.. saves us an ldc
{RETSP_u6 0; ldc r1, 0}

View File

@@ -0,0 +1,221 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <xs1.h>
#include "XUD_AlignmentDefines.h"
// Ports
#define RXD r0
#define RXA r1
#define TXD r2
// On entry:
// R11: Branch address (now free)
// R10: EP number (used here)
// R9 : CRC16 Poly (used here)
// R8 :
// R7 : Tx CRC init
// R6 : ep_pid_sequence_table_IN_A
// R5 : EP structures array
// R4 :
// R3 : 0
// R2 : TXD
// R1 : XS2: Valid Token Port, XS3: Spare!
// R0 : RXD
.align FUNCTION_ALIGNMENT
XUD_IN_NotReady:
ldw r11, sp[STACK_EPTYPES_IN]
ldw r11, r11[r10] // Load EP Type
bt r11, XUD_IN_TxHandshake
ldc r11, 0xc3 // Create 0-length packet
outpw res[TXD], r11, 24
#include "XUD_TokenJmp.S"
XUD_IN_TxHandshake: // Non-Iso
ldaw r11, dp[epAddr]
ldw r11, r11[r3]
ldw r11, r11[10]
bf r11, XUD_IN_TxNak
XUD_IN_TxStall:
outpw res[TXD], r11, 8 // Output STALL
#include "XUD_TokenJmp.S"
XUD_IN_TxNak:
ldc r11, USB_PIDn_NAK
outpw res[TXD], r11, 8
#include "XUD_TokenJmp.S"
.align FUNCTION_ALIGNMENT
Pid_In:
#include "XUD_CrcAddrCheck.S"
ldaw r3, r10[4] // R3 = R10 + 16
ldw r4, r5[r3] // Load EP structure address
bf r4, XUD_IN_NotReady
ldw r1, r4[4] // Load PID from structure
XUD_IN_Ready:
ldw r8, r4[3] // Load buffer
ldw r6, r4[7] // Load tail length (bytes)
ldw r4, r4[6] // Load data length (words)
bf r4, XUD_IN_SmallTxPacket // Check for Short packet
XUD_IN_Tx:
ldw r11, r8[r4] // Load first data word
crc32_inc r7, r11, r9, r4, 1
outpw res[TXD], r1, 8 // Out PID
XUD_IN_Loop0:
{out res[TXD], r11; bf r4, XUD_IN_TxLoopEnd}
XUD_IN_TxLoop:
ldw r11, r8[r4] // Load first data word
crc32_inc r7, r11, r9, r4, 1
{out res[TXD], r11; bt r4, XUD_IN_TxLoop}
XUD_IN_TxLoopEnd:
ldw r11, r8[r4] // Load tail
crcn r7, r11, r9, r6
XUD_IN_TxLoopEnd_CrcCalc:
crc32 r7, r4, r9 // r4: 0 (from bf)
outpw res[TXD], r11, r6
not r7, r7
XUD_IN_TxCrc:
outpw res[TXD], r7, 16 // Output 16-bit CRC
.scheduling default
// Wait for handshake... or timeout
DoneTail:
ldw r11, sp[STACK_EPTYPES_IN]
ldw r11, r11[r10] // Load EP Type
bt r11, SetupReceiveHandShake
bu XUD_IN_DoneTx
SetupReceiveHandShake:
ldc r11, 8
setpsc res[RXD], r11 // Set port shift count (expect 8 bit handshake)
SetupTimeout: // Timeout done using another port we dont happen to already be using events on. Cunning.
#ifdef __XS2A__
ldw r1, sp[STACK_VTOK_PORT] // Load saved ValidToken port. Event vector already set.
#else
ldw r1, dp[rx_rdy] // TODO load from stack
#endif
eeu res[RXD] // Events on RXD always enabled - Can't be any more due to using events on channels
in r11, res[r1] // Do input and get port time/timestamps
getts r11, res[r1]
ldw r9, dp[g_txHandshakeTimeout]
add r11, r11, r9
setpt res[r1], r11 // Set port time and enable events
eeu res[r1]
WaitForHandshake: // Wait for timeout or handshake
.xtabranch TxHandshakeTimeOut, TxHandShakeReceived
waiteu
// We sent some data but the host didn't handshake in time. Needs a re-send.
.align FUNCTION_ALIGNMENT
TxHandshakeTimeOut:
clre
in r11, res[r1] // This will clear port time
bu BadHandshake
// Transmitted data, and got something back within the timeout. Check for valid handshake...
.align FUNCTION_ALIGNMENT
TxHandShakeReceived:
clre
in r11, res[RXD] // Input data from RXD port
{clrpt res[r1]; // Clear port time on valid token port
shr r11, r11, 24} // Shift off junk data to leave ACK
#if defined(__XS2A__)
ldc r9, USB_PID_ACK // Check for good ACK (L series strips negated bits from PID)
#else
ldc r9, USB_PIDn_ACK
#endif
xor r9, r11, r9
bt r9, BadHandshake
XUD_IN_DoneTx:
ClearInEpReady: // TODO Tidy this up
ldc r9, 0 // TODO
ldw r10, r5[r3] // Load the EP struct
stw r9, r5[r3] // Clear the ready
ldw r11, r10[1] // Load channel
out res[r11], r11 // Output word to signal packet sent okay
bu NextToken
BadHandshake:
bu NextToken
.align 64
.skip 56
XUD_IN_SmallTxPacket:
ldw r8, r8[r4] // Load first data word
bru r6 // Branch on tail-length
//--------------------------------------------------------------------------
.align 32
.skip 0
TxTail0s: // We know this is a < 4 byte packet, so is 0 length packet
// So crc = 0. Note our normal crc calculation works for this, it is
// Not a special CRC case, but helps with timing.
XUD_IN_TxPid_TailS0:
outpw res[TXD], r1, 8 // PID
XUD_IN_TxCrc_TailS0:
outpw res[TXD], r4, 16 // Output CRC
bu DoneTail
.align 32
.skip 0
TxTail1s: // One tail byte
crcn r7, r8, r9, r6
crc32 r7, r4, r9 // r4: 0
XUD_IN_TxPid_TailS1:
not r7, r7
outpw res[TXD], r1, 8 // Output PID
outpw res[TXD], r8, 8 // Output data[0]
XUD_IN_TxCrc_TailS1:
outpw res[TXD], r7, 16
bu DoneTail
.align 32
.skip 0
TxTail2s: // Two tail byte
crcn r7, r8, r9, r6
crc32 r7, r4, r9 // r4: 0
XUD_IN_TxPid_TailS2:
outpw res[TXD], r1, 8 // Output PID
outpw res[TXD], r8, 16 // Output data[0:1]
not r7, r7
XUD_IN_TxCrc_TailS2:
outpw res[TXD], r7, 16 // Output CRC16
bu DoneTail
.align 32
.skip 0
TxTail3s: // Three tail byte
XUD_IN_TxPid_TailS3:
outpw res[TXD], r1, 8 // PID
outpw res[TXD], r8, 24
crcn r7, r8, r9, r6
crc32 r7, r4, r9 // r4: 0
not r7, r7
XUD_IN_TxCrc_TailS3:
outpw res[TXD], r7, 16
bu DoneTail
.align 32
.skip 0
TxTail4s: // Four tail byte
XUD_IN_TxPid_TailS4:
outpw res[TXD], r1, 8 // PID
out res[TXD], r8
crc32 r7, r8, r9
crc32 r7, r4, r9 // r4: 0
not r7, r7
XUD_IN_TxCrc_TailS4:
outpw res[TXD], r7, 16
bu DoneTail

View File

@@ -0,0 +1,104 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
// r10: EP number
// OUT Token Packet -----------------------------------------------------------------------------
#include "XUD_AlignmentDefines.h"
.align FUNCTION_ALIGNMENT
.skip 0
Pid_Out:
#include "XUD_CrcAddrCheck.S"
ldw r3, r5[r10] // Load relevant EP pointer
bf r3, XUD_TokenOut_BufferFull
ldw r1, r3[3] // Load buffer from EP structure
CheckEpTypeOut:
ldw r11, r3[5] // Load EP type
BRFT_ru6 r11, DoOutNonIso // ISO endpoint
OutReady:
BLRF_u10 doRXData // Leaves r1: 0
{clre;
ldw r11, r3[1]} // Load EP chanend
InformEP_Iso: // Iso EP - no handshake
out res[r11], r4; // Output datalength (words)
stw r1, r5[r10] // Clear ready (r1: 0)
{outt res[r11], r8; ldw r6, sp[STACK_RXCRC_INIT]} // CRC16 init (out) - Needs reseting after an out & Send tail length
#if defined(__XS2A__)
ldw r1, sp[STACK_VTOK_PORT]
#endif
#include "XUD_TokenJmp.S"
.align FUNCTION_ALIGNMENT
.skip 0
DoOutNonIso:
bl doRXData
{clre; eq r11, r6, r11} // Check for good CRC16
doRXDataReturn_NonIso:
bf r11, NextTokenAfterOut // Check for bad crc
ldc r11, USB_PIDn_ACK // Data CRC good, EP not Iso, and EP not halted: Send Ack
outpw res[TXD], r11, 8
syncr res[TXD]
StoreTailDataOut:
stw r1, r5[r10] // Clear ready (r1: 0)
ldw r11, r3[1] // Load EP chanend
out res[r11], r4 // Output datalength (words)
outt res[r11], r8 // Send tail length
bu NextTokenAfterOut
// Various Error handling functions -------------------------------------------------------------------
.align FUNCTION_ALIGNMENT
Err_RxErr: // RxError signal high during data packet receive:
DUALENTSP_lu6 0
clrsr 3
clre
ldw r10, sp[STACK_RXE_PORT] // Read out data from RxE port
in r11, res[r10]
eeu res[r10]
ldw r10, sp[STACK_RXA_PORT]
in r11, res[r10] // Wait for rxa low and ignore packet (let transaction timout)
setsr 3 // Re-enable thread interrupts
bu NextToken
XUD_TokenOut_BufferFull:
ldw r9, sp[STACK_RXA_PORT]
setc res[r9], XS1_SETC_RUN_CLRBUF
inpw r4, res[r0], 8 // Input PID of next packet.
// TODO catch case where PID is not DATA
XUD_TokenOut_WaitForPacketEnd: // Wait for end of data then send NAK
in r11, res[r9]
#ifndef XUD_NAK_ISO_OUT
ldw r4, sp[STACK_EPTYPES_OUT] // Load ep type table
ldw r4, r4[r10] // load EP type
bf r4, PrimaryBufferFull_NoNak
#endif
// Load handshake (ACK or STALL)
XUD_TokenOut_Handshake:
ldaw r6, dp[epAddr]
ldw r6, r6[r10]
ldw r11, r6[10]
outpw res[TXD], r11, 8
syncr res[TXD]
PrimaryBufferFull_NoNak:
setc res[RXD], XS1_SETC_RUN_CLRBUF
bu NextToken
// Timedout waiting for data after OUT... go back to waiting for tokens
//OutDataTimeOut:
//clre
//bl ERR_OutDataTimeout
//bu NextToken

View File

@@ -0,0 +1,42 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "XUD_AlignmentDefines.h"
.align FUNCTION_ALIGNMENT
Pid_Ping:
#include "XUD_CrcAddrCheck.S"
LoadStatTablePing:
ldw r11, r5[r10] // Load relevant EP chanend
bf r11, PrimaryBufferFull_PING
.scheduling off
PrimaryBufferEmpty_PING: // Send ACK
#if (XUD_CORE_CLOCK > 400)
nop
nop
nop
#endif
nop
nop
nop
nop
ldc r11, USB_PIDn_ACK
outpw res[TXD], r11, 8
bu NextTokenAfterPing
PrimaryBufferFull_PING: // Send NAK (or STALL)
#if (XUD_CORE_CLOCK > 400)
nop
nop
nop
#endif
ldaw r11, dp[epAddr]
ldw r11, r11[r10]
ldw r11, r11[10]
outpw res[TXD], r11, 8
bu NextTokenAfterPing
.scheduling default

View File

@@ -0,0 +1,69 @@
// Copyright 2011-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "XUD_AlignmentDefines.h"
// Received SOF token: Reset suspend/reset detection timer
.align FUNCTION_ALIGNMENT
Pid_Sof:
#ifdef __XS2A__
inpw r10, res[RXD], 8 // Read EP Number
shr r10, r10, 24; // Shift off junk
in r11, res[r1];
bt r11, XUD_InvalidToken; // If VALID_TOKEN not high, ignore token
#else
// NOTE: we are not CRC checking SOF's
in r10, res[RXD] // Input Frame number
shr r10 , r10, 16 // Shift off port junk
ldc r11, 0x7ff // Remove CRC5
and r10, r10, r11
#endif
clrsr 0x3
ldw r11, sp[STACK_SOFCHAN]
out res[r11], r10
ldw r10, sp[STACK_SUSPEND_TIMER] // Load timer from stack
setc res[r10], XS1_SETC_COND_NONE // Read current time
ldw r8, sp[STACK_SUSPEND_TIMEOUT] // Add suspend timeout to current time
in r11, res[r10]
add r11, r11, r8
setd res[r10], r11
setc res[r10], XS1_SETC_COND_AFTER // Re-enable thread interrupts
setsr 0x3
bu Loop_BadPid
// Received SOF token: Reset suspend/reset detection timer
.align FUNCTION_ALIGNMENT
Pid_Sof_NoChan:
#ifdef __XS2A__
inpw r10, res[RXD], 8; /* Read EP Number */
shr r10, r10, 24; /* Shift off junk */
in r11, res[r1];
bt r11, XUD_InvalidToken; /* If VALID_TOKEN not high, ignore token */
#else
in r10, res[RXD] // Input Frame number
#endif
clrsr 0x3
ldw r10, sp[STACK_SUSPEND_TIMER] // Load timer from stack
setc res[r10], XS1_SETC_COND_NONE // Read current time
ldw r8, sp[STACK_SUSPEND_TIMEOUT]
in r11, res[r10]
add r11, r11, r8
setd res[r10], r11
ldw r8, sp[STACK_SUSPEND_TIMEOUT]
setc res[r10], XS1_SETC_COND_AFTER // Re-enable thread interrupts
setsr 0x3
bu Loop_BadPid

View File

@@ -0,0 +1,59 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "XUD_AlignmentDefines.h"
// We received a setup token. This is much the same as out token, apart from:
// - Can't NAK a setup
// - Data PID will always be DATA0
// - Payload will always be 8 bytes
.align FUNCTION_ALIGNMENT
Pid_Setup:
#include "XUD_CrcAddrCheck.S"
ldaw r7, r10[8] // R3 = R10 + 32. Read Past end of epAddr to epAddr_Setup
ldw r3, r5[r7] // Load relevant EP pointer
bf r3, XUD_Setup_BuffFull
ldw r1, r3[3] // Load buffer
XUD_Setup_LoadBuffer:
bl doRXData // RXData writes available data to buffer and does crc check.
// r8: Data tail size (bytes)
xor r1, r6, r11 // Check for good CRC16
{clre;
bt r1, XUD_Setup_NotReady} // Branch based on CRC good/bad
XUD_Setup_ClearStall: // CRC OK
// Have received a Setup so clear any STALL condition on IN/OUT endpoint.
// Note, we can speed this up by assuming Setup only received on EP 0
ldaw r6, dp[epAddr]
ldaw r11, r10[4] // R11 = R10 + 16
ldw r11, r6[r11]
stw r1, r11[10] // r1: 0
ldw r11, r6[r10]
ldc r6, USB_PIDn_NAK
stw r6, r11[10]
XUD_Setup_SendSetupAck:
ldc r11, USB_PIDn_ACK
outpw res[TXD], r11, 8
XUD_Setup_StoreTailData: // TODO: don't assume setups are 8 bytes + crc
stw r1, r5[r7] // Clear ready
ldw r11, r3[1] // Load chanend
out res[r11], r4
outct res[r11], 0 // Send zero control token for Setup. Tail ignored since always expect 8 bytes
bu NextTokenAfterOut // Go to next wait for next token
XUD_Setup_BuffFull:
ldw r10, sp[STACK_RXA_PORT] // Load RxA Port ID (r1)
in r11, res[r10] // RXA event cond = 0 TODO: Wait for RXA high first?
endin r11, res[RXD]
in r11, res[RXD]
bu NextTokenAfterOut
.align FUNCTION_ALIGNMENT
XUD_Setup_NotReady:
bu NextTokenAfterOut

View File

@@ -0,0 +1,43 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _XS1_TO_GLX_H_
#define _XS1_TO_GLX_H_
/* Workaround for tools issue #17048 */
#define XS1_SU_PER_UIFM_CHANEND_NUM XS1_GLX_PER_UIFM_CHANEND_NUM
#define XS1_SU_PER_UIFM_CONTROL_NUM XS1_GLX_PER_UIFM_CONTROL_NUM
#define XS1_SU_CFG_RST_MISC_NUM XS1_GLX_CFG_RST_MISC_NUM
#define XS1_SU_CFG_USB_CLK_EN_SHIFT XS1_GLX_CFG_USB_CLK_EN_SHIFT
#define XS1_SU_CFG_USB_CLK_EN_SHIFT XS1_GLX_CFG_USB_CLK_EN_SHIFT
#define XS1_SU_CFG_USB_EN_SHIFT XS1_GLX_CFG_USB_EN_SHIFT
#define XS1_SU_PER_UIFM_OTG_CONTROL_NUM XS1_GLX_PER_UIFM_OTG_CONTROL_NUM
#define XS1_SU_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT XS1_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT
#define XS1_SU_PER_UIFM_FUNC_CONTROL_NUM XS1_GLX_PER_UIFM_FUNC_CONTROL_NUM
#define XS1_SU_UIFM_FUNC_CONTROL_XCVRSELECT_SHIFT XS1_UIFM_FUNC_CONTROL_XCVRSELECT_SHIFT
#define XS1_SU_UIFM_FUNC_CONTROL_TERMSELECT_SHIFT XS1_UIFM_FUNC_CONTROL_TERMSELECT_SHIFT
#define XS1_SU_PER_UIFM_DEVICE_ADDRESS_NUM XS1_GLX_PER_UIFM_DEVICE_ADDRESS_NUM
#define XS1_SU_UIFM_IFM_CONTROL_DOTOKENS_SHIFT XS1_UIFM_IFM_CONTROL_DOTOKENS_SHIFT
#define XS1_SU_UIFM_IFM_CONTROL_CHECKTOKENS_SHIFT XS1_UIFM_IFM_CONTROL_CHECKTOKENS_SHIFT
#define XS1_SU_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT XS1_UIFM_IFM_CONTROL_DECODELINESTATE_SHIFT
#define XS1_SU_UIFM_IFM_CONTROL_SOFISTOKEN_SHIFT XS1_UIFM_IFM_CONTROL_SOFISTOKEN_SHIFT
#define XS1_SU_PER_UIFM_MASK_NUM XS1_GLX_PER_UIFM_MASK_NUM
#define XS1_SU_UIFM_IFM_FLAGS_NEWTOKEN_SHIFT XS1_UIFM_IFM_FLAGS_NEWTOKEN_SHIFT
#define XS1_SU_UIFM_IFM_FLAGS_RXACTIVE_SHIFT XS1_UIFM_IFM_FLAGS_RXACTIVE_SHIFT
#define XS1_SU_UIFM_IFM_FLAGS_RXERROR_SHIFT XS1_UIFM_IFM_FLAGS_RXERROR_SHIFT
#define XS1_SU_PER_UIFM_OTG_FLAGS_NUM XS1_GLX_PER_UIFM_OTG_FLAGS_NUM
#define XS1_SU_UIFM_OTG_FLAGS_SESSVLDB_SHIFT XS1_UIFM_OTG_FLAGS_SESSVLDB_SHIFT
#endif

View File

@@ -0,0 +1,71 @@
// Copyright 2015-2024 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Defines from the Universal Serial Bus Specification Revision 2.0
**/
#ifndef _USB_DEFS_H_
#define _USB_DEFS_H_
/* Table 8-1. PID Types */
#define USB_PID_OUT 0x1 /* Tokens */
#define USB_PID_IN 0x9
#define USB_PID_SOF 0x5
#define USB_PID_SETUP 0xD
#define USB_PID_DATA0 0x3 /* Data packet PID even */
#define USB_PID_DATA1 0xB /* Data packet PID odd */
#define USB_PID_DATA2 0x7 /* Data packet PID high-speed, high bandwidth isoc transaction in a microframe */
#define USB_PID_MDATA 0xF /* Data packet PID high-speed and high bandwidth isoc transactions */
#define USB_PID_ACK 0x2 /* Receiver accepts error-free data packet */
#define USB_PID_NAK 0xA /* Receiving device cannot accept data of transmitting device cannot send data */
#define USB_PID_STALL 0xE /* Endpoint is halted or a control pipe request is not supported */
#define USB_PID_PRE 0xC
#define USB_PID_ERR 0xC
#define USB_PID_SPLIT 0x8
#define USB_PID_PING 0x4 /* Hign-speed flow control probe for bulk/control endpoint */
/* PID with error check */
#define USB_PID_NEGATE(PID) ((PID) | (((~PID) & 0xf) << 4))
#define USB_PIDn_OUT 0xe1
#define USB_PIDn_IN 0x69
#define USB_PIDn_SOF 0xa5
#define USB_PIDn_SETUP 0x2d
#define USB_PIDn_DATA0 0xc3
#define USB_PIDn_DATA1 USB_PID_NEGATE(USB_PID_DATA1)
#define USB_PIDn_DATA2 USB_PID_NEGATE(USB_PID_DATA2)
#define USB_PIDn_ACK 0xd2
#define USB_PIDn_NAK 0x5a
#define USB_PIDn_STALL 0x1e
/* Table 9-6. Standard Feature Selectors (wValue) */
#define USB_DEVICE_REMOTE_WAKEUP 0x01 /* Recipient: Device */
#define USB_ENDPOINT_HALT 0x00 /* Recipient: Endpoint */
#define USB_TEST_MODE 0x02 /* Recipient: Device */
#define USB_STANDARD_DEVICE_REQUEST 0x00
#define USB_STANDARD_INTERFACE_REQUEST 0x01
#define USB_STANDARD_ENDPOINT_REQUEST 0x02
#define USB_VENDOR_DEVICE_REQUEST 0x40
#define USB_VENDOR_ENDPOINT_REQUEST 0x42
#define USB_CLASS_INTERFACE_REQUEST 0x21
#define USB_CLASS_ENDPOINT_REQUEST 0x22
#define USB_WVAL_EP_HALT 0
// Low byte values:
//#define USB_WVALUE_GETDESC_STRING_LANGIDS 0x0
//#define USB_WVALUE_GETDESC_STRING_IPRODUCT 0x2
// Test selector defines for Test mode
#define USB_WINDEX_TEST_J (0x1<<8)
#define USB_WINDEX_TEST_K (0x2<<8)
#define USB_WINDEX_TEST_SE0_NAK (0x3<<8)
#define USB_WINDEX_TEST_PACKET (0x4<<8)
#define USB_WINDEX_TEST_FORCE_ENABLE (0x5<<8)
#define USB_WINDEX_TEST_XMOS_IN_ADDR1 (0x6<<8)
#define USB_MAX_NUM_EP_OUT (16)
#define USB_MAX_NUM_EP_IN (16)
#define USB_MAX_NUM_EP (32)
#endif

View File

@@ -0,0 +1,23 @@
// Copyright 2015-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/*
* @brief Defines from USB Device Class Definition for Human Interface Devices Specification
*/
/* 7. Requests */
/* 7.1 Standard Requests - Class Descriptor Types - High byte of wValue
* The following defines valid types of Class descriptors */
#define HID_HID 0x2100
#define HID_REPORT 0x2200
#define HID_PHYSICAL_DESCRIPTOR 0x2300
/*0x24 - 0x2F: Reserved */
/* 7.2 Class-Specific Requests - bRequest values */
#define HID_GET_REPORT 0x01 /* Mandatory */
#define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03 /* Required only for boot devices */
/* Ox04 - 0x08 reserved */
#define HID_SET_REPORT 0x09
#define HID_SET_IDLE 0x0A
#define HID_SET_PROTOCOL 0x0B /* Required only for boot devices */

View File

@@ -0,0 +1,30 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _AUDIO10_H_
#define _AUDIO10_H_ 1
/**
* @brief Defines from the USB Audio 1.0 Specifications
* @author Ross Owen, XMOS Limited
*/
/* A.9. Audio Class-Specific Request Codes */
#define UAC_B_REQ_SET_CUR 0x01
#define UAC_B_REQ_GET_CUR 0x81
#define UAC_B_REQ_SET_MIN 0x02
#define UAC_B_REQ_GET_MIN 0x82
#define UAC_B_REQ_SET_MAX 0x03
#define UAC_B_REQ_GET_MAX 0x83
#define UAC_B_REQ_SET_RES 0x04
#define UAC_B_REQ_GET_RES 0x84
#define UAC_B_REQ_SET_MEM 0x05
#define UAC_B_REQ_GET_MEM 0x85
#define UAC_B_REQ_GET_STAT 0xFF
/* A.10.5 Endpoint Control Selectors: Table A-19 */
#define EP_CONTROL_UNDEFINED 0x00
#define SAMPLING_FREQ_CONTROL 0x01
#define PITCH_CONTROL 0x02
#endif

View File

@@ -0,0 +1,357 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Defines from the USB Audio 2.0 Specifications
* @author Ross Owen, XMOS Limited
*/
#ifndef _USBAUDIO20_H_
#define _USBAUDIO20_H_
#include "usbaudiocommon.h"
/***********************************************************************/
/* USB Audio 2.0 Class Specification */
/* A.1 Audio Function Class Code */
#define AUDIO_FUNCTION AUDIO
/* A.2 Audio Function Subclass Codes */
#define FUNCTION_SUBCLASS_UNDEFINED 0x00
/* A.3 Audio Function Protocol Codes */
enum USB_Audio_FuncProtocolCodes_t
{
UAC_FUNC_PROTOCOL_UNDEFINED = 0x00,
UAC_FUNC_PROTOCOL_AF_VERSION_02_00 = 0x20
};
/* A.4 Audio Interface Class Code */
#define AUDIO 0x01
/* A.5 Audio Interface Subclass Codes */
enum UAC_IntSubclassCodes_t
{
UAC_INT_SUBCLASS_AUDIOCONTROL = 0x01,
UAC_INT_SUBCLASS_AUDIOSTREAMING = 0x02,
UAC_INT_SUBCLASS_MIDISTREAMING = 0x03
};
/* A.6 Audio Interface Protocol Codes */
enum UAC_IntProtocolCodes_t
{
UAC_INT_PROTOCOL_UNDEFINED = 0x00,
UAC_INT_PROTOCOL_IP_VERSION_02_00 = 0x20
};
/* A.7 Audio Function Category Codes */
enum UAC_AudioFunctionCategory_t
{
UAC_FUNCTION_SUBCLASS_UNDEFINED = 0x00,
UAC_FUNCTION_DESKTOP_SPEAKER = 0x01,
UAC_FUNCITON_HOME_THEATER = 0x02,
UAC_FUNCTION_MICROPHONE = 0x03,
UAC_FUNCITON_HEADSET = 0x04,
UAC_FUNCTION_TELEPHONE = 0x05,
UAC_FUNCTION_CONVERTER = 0x06,
UAC_FUNCTION_VOICE_SOUND_RECORDER = 0x07,
UAC_FUNCTION_IO_BOX = 0x08,
UAC_FUNCTION_MUSICAL_INTRUMENT = 0x09,
UAC_FUNCTION_PRO_AUDIO = 0x0A,
UAC_FUNCTION_AUDIO_VIDEO = 0x0B,
UAC_FUNCTION_CONTROL_PANEL = 0x0C,
UAC_FUNCITON_OTHER = 0xFF
};
/* A.8 Audio Class-Specific Descriptor Types */
/* Shared with Audio Class 1.0 */
enum UAC_CSDescriptorTypes_t
{
UAC_CS_DESCTYPE_UNDEFINED = 0x20,
UAC_CS_DESCTYPE_DEVICE = 0x21,
UAC_CS_DESCTYPE_CONFIGURATION = 0x22,
UAC_CS_DESCTYPE_STRING = 0x23,
UAC_CS_DESCTYPE_INTERFACE = 0x24,
UAC_CS_DESCTYPE_ENDPOINT = 0x25,
};
/* A.9 Audio Class-Specific AC Interface Descriptor Subtypes */
enum UAC_CS_AC_InterfaceDescriptorSubtype_t
{
UAC_CS_AC_INTERFACE_SUBTYPE_AC_DESCRIPTOR_UNDEFINED = 0x00,
UAC_CS_AC_INTERFACE_SUBTYPE_HEADER = 0x01,
UAC_CS_AC_INTERFACE_SUBTYPE_INPUT_TERMINAL = 0x02,
UAC_CS_AC_INTERFACE_SUBTYPE_OUTPUT_TERMINAL = 0x03,
UAC_CS_AC_INTERFACE_SUBTYPE_MIXER_UNIT = 0x04,
UAC_CS_AC_INTERFACE_SUBTYPE_SELECTOR_UNIT = 0x05,
UAC_CS_AC_INTERFACE_SUBTYPE_FEATURE_UNIT = 0x06,
UAC_CS_AC_INTERFACE_SUBTYPE_EFFECT_UNIT = 0x07,
UAC_CS_AC_INTERFACE_SUBTYPE_PROCESSING_UNIT = 0x08,
UAC_CS_AC_INTERFACE_SUBTYPE_EXTENSION_UNIT = 0x09,
UAC_CS_AC_INTERFACE_SUBTYPE_CLOCK_SOURCE = 0x0A,
UAC_CS_AC_INTERFACE_SUBTYPE_CLOCK_SELECTOR = 0x0B,
UAC_CS_AC_INTERFACE_SUBSYPE_CLOCK_MULTIPLIER = 0x0C,
UAC_CS_AC_INTERFACE_SUBTYPE_SAMPLE_RATE_CONVERTER = 0x0D
};
/* A.10 Audio Class Specific AS Interface Descriptor Subtypes */
enum UAC_CS_AS_InterfaceDescriptorSubtype_t
{
UAC_CS_AS_INTERFACE_SUBTYPE_UNDEFINED = 0x00,
UAC_CS_AS_INTERFACE_SUBTYPE_AS_GENERAL = 0x01,
UAC_CS_AS_INTERFACE_SUBTYPE_FORMAT_TYPE = 0x02,
UAC_CS_AS_INTERFACE_SUBTYPE_ENCODER = 0x03,
UAC_CS_AS_INTERFACE_SUBTYPE_DECODER = 0x04
};
/* A.11 Effect Unit Effect Types */
#define EFFECT_UNDEFINED 0x00
#define PARAM_EQ_SECTION_EFFECT 0x01
#define REVERBERATION_EFFECT 0x02
#define MOD_DELAY_EFFECT 0x03
#define DYN_RANGE_COMP_EFFECT 0x04
/* A.12 Processing Unit Process Types */
#define PROCESS_UNDEFINED 0x00
#define UP_DOWNMIX_PROCESS 0x01
#define DOLBY_PROLOGIC_PROCESS 0x02
#define STEREO_EXTENDER_PROCESS 0x03
/* A.13 Audio Class-Specific Endpoint Descriptor Subtypes */
enum UAC_CS_EndpointDescriptorSubtype_t
{
UAC_CS_ENDPOINT_SUBTYPE_UNDEFINED = 0x00,
UAC_CS_ENDPOINT_SUBTYPE_EP_GENERAL = 0x01
};
/* A.14 Audio Class-Specific Request Codes */
#define REQUEST_CODE_UNDEFINED 0x00
#define CUR 0x01
#define RANGE 0x02
#define MEM 0x03
/* A.15 Encoder Type Codes */
#define ENCODER_UNDEFINED 0x00
#define OTHER_ENCODER 0x01
#define MPEG_ENCODER 0x02
#define AC_3_ENCODER 0x03
#define WMA_ENCODER 0x04
#define DTS_ENCODER 0x05
/* A.17 Control Selector Codes */
/* A.17.1 Clock Source Control Selectors */
#define CS_CONTROL_UNDEFINED 0x00
#define CS_SAM_FREQ_CONTROL 0x01
#define CS_CLOCK_VALID_CONTROL 0x02
/* A.17.2 Clock Selector Control Selectors */
#define CX_CONTROL_UNDEFINED 0x00
#define CX_CLOCK_SELECTOR_CONTROL 0x01
/* A.17.7 Feature Unit Control Selectors */
#define FU_CONTROL_UNDEFINED 0x00
#define FU_MUTE_CONTROL 0x01
#define FU_VOLUME_CONTROL 0x02
/* A.17.11 Audio Streaming Interface Control Selectors */
#define AS_CONTROL_UNDEFINED 0x00
#define AS_ACT_ALT_SETTING_CONTROL 0x01
#define AS_VAL_ALT_SETTINGS_CONTROL 0x02
#define AS_AUDIO_DATA_FORMAT_CONTROL 0x03
#ifdef __STDC__
/* Clock Source Descriptor (Table 4-6) */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bClockID;
unsigned char bmAttributes;
unsigned char bmControls;
unsigned char bAssocTerminal;
unsigned char iClockSource;
} __attribute__((packed)) USB_Descriptor_Audio_ClockSource_t;
/* Clock Selector Descriptor (Table 4-7) */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bClockID;
unsigned char bNrPins;
unsigned char baCSourceId[1];
unsigned char bmControl; /* bmControls
* D[1:0] : Clock Selector Control
* D[7:4] : Reserved (0) */
unsigned char iClockSelector;
} __attribute__((packed)) USB_Descriptor_Audio_ClockSelector_1_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bClockID;
unsigned char bNrPins;
unsigned char baCSourceId[2];
unsigned char bmControl; /* bmControls
* D[1:0] : Clock Selector Control
* D[7:4] : Reserved (0) */
unsigned char iClockSelector;
} __attribute__((packed)) USB_Descriptor_Audio_ClockSelector_2_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bClockID;
unsigned char bNrPins;
unsigned char baCSourceId[3];
unsigned char bmControl; /* bmControls
* D[1:0] : Clock Selector Control
* D[7:4] : Reserved (0) */
unsigned char iClockSelector;
} __attribute__((packed)) USB_Descriptor_Audio_ClockSelector_3_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bFormatType; /* Format of the audio stream, see Audio Device Formats specification */
unsigned char bSubslotSize; /* Number of bytes for each channels subslot */
unsigned char bBitResolution; /* Number of bits used in the above slot for sample */
} __attribute__((packed)) USB_Descriptor_Audio_Format_Type1_t;
/* Table 4-11: Mixer Unit Descriptor */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bUnitID;
unsigned char bNrInPins;
unsigned char baSourceID;
unsigned char bNrChannels;
unsigned bmChannelConfig;
unsigned char iChannelNames;
unsigned char bmMixerControls[18]; /* FIXME */
unsigned char bmControls;
unsigned char iMixer;
} __attribute__((packed)) USB_Descriptor_Audio_MixerUnit_t;
/* Table 4-24: Extension Unit Descriptor */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bUnitID;
unsigned short wExtensionCode;
unsigned char bNrInPins;
unsigned char baSourceID[1];
unsigned char bNrChannels;
unsigned bmChannelConfig;
unsigned char iChannelNames;
unsigned char bmControls;
unsigned char iExtension;
} __attribute__((packed)) USB_Descriptor_Audio_ExtensionUnit_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bUnitID;
unsigned short wExtensionCode;
unsigned char bNrInPins;
unsigned char baSourceID[2];
unsigned char bNrChannels;
unsigned bmChannelConfig;
unsigned char iChannelNames;
unsigned char bmControls;
unsigned char iExtension;
} __attribute__((packed)) USB_Descriptor_Audio_ExtensionUnit2_t;
#endif
/***********************************************************************/
/** USB Device Class Definition for Audio Data Formats **/
/* A.1 Format Type Codes */
enum USB_audio_Fmt_FormatType_t
{
UAC_FORMAT_TYPE_UNDEFINED = 0x00,
UAC_FORMAT_TYPE_I = 0x01,
UAC_FORMAT_TYPE_II = 0x02,
UAC_FORMAT_TYPE_III = 0x03,
UAC_FORMAT_TYPE_IV = 0x04,
UAC_EXT_FORMAT_TYPE_I = 0x81,
UAC_EXT_FORMAT_TYPE_II = 0x82,
UAC_EXT_FORMAT_TYPE_III = 0x83
};
/* A.2 AudioData Format Bit Allocation in the bmFormats field */
/* A.2.1 Audio Data Format Type I Bit Allocations */
enum USB_Audio_Fmt_DataFormat_TypeI_t
{
UAC_FORMAT_TYPEI_PCM = 0x00000001,
UAC_FORMAT_TYPEI_PCM8 = 0x00000002,
UAC_FORMAT_TYPEI_IEEE_FLOAT = 0x00000004,
UAC_FORMAT_TYPEI_RAW_DATA = 0x80000000,
};
/* A.2.2 Audio Data Format Type II Bit Allocations */
enum USB_Audio_Fmt_DataFormat_TypeII_t
{
UAC_FORMAT_TYPEII_MPEG = 0x00000001,
UAC_FORMAT_TYPEII_AC3 = 0x00000002,
UAC_FORMAT_TYPEII_WMA = 0x00000004,
UAC_FORMAT_TYPEII_DTS = 0x00000008,
UAC_FORMAT_TYPEII_RAW_DATA = 0x80000000
};
/* A.3 Side Band Protocol Codes */
#define PROTOCOL_UNDEFINED 0x00
#define PRESS_TIMESTAMP_PROTOCOL 0x01
/***********************************************************************/
/* Univeral Serial Bus Device Class Definition for Terminal Types */
/* 2.1 USB Terminal Types */
/* Terminal Types that describe Terminals that handle signals carried over USB */
#define USB_TERMTYPE_UNDEFINED 0x0100
#define USB_TERMTYPE_USB_STREAMING 0x0101
#define USB_TERMTYPE_VENDOR_SPECIFIC 0x01FF
/* 2.2 Input Terminal Types */
/* Terminal Types that describe Terminals that are designed to record sounds */
enum USB_Audio_TT_InputTermType_t
{
UAC_TT_INPUT_TERMTYPE_INPUT_UNDEFINED = 0x0200,
UAC_TT_INPUT_TERMTYPE_MICROPHONE = 0x0201,
UAC_TT_INPUT_TERMTYPE_DESKTOP_MICROPHONE = 0x0202,
UAC_TT_INPUT_TERMTYPE_PERSONAL_MICROPHONE = 0x0203,
UAC_TT_INPUT_TERMTYPE_OMNIDIRECTIONAL_MICROPHONE = 0x0204,
UAC_TT_INPUT_TERMTYPE_MICROPHONE_ARRAY = 0x0205,
UAC_TT_INPUT_TERMTYPE_PROCESSING_MICROPHONE_ARRAY = 0x0206
};
/* 2.3 Output Terminal Types */
/* These Terminal Types describe Terminals that produce audible signals that are intended to
* be heard by the user of the audio function */
enum USB_Audio_TT_OutputTermType_t
{
UAC_TT_OUTPUT_TERMTYPE_SPEAKER = 0x0301,
UAC_TT_OUTPUT_TERMTYPE_HEADPHONES = 0x0302,
UAC_TT_OUTPUT_TERMTYPE_HEAD_MOUNTED_DISPLAY = 0x0303,
UAC_TT_OUTPUT_TERMTYPE_DESKTOP_SPEAKER = 0x0304,
UAC_TT_OUTPUT_TERMTYPE_ROOM_SPEAKER = 0x0305,
UAC_TT_OUTPUT_TERMTYPE_COMMUNICATION_SPEAKER = 0x0306,
UAC_TT_OUTPUT_TERMTYPE_LOW_FREQ_EFFECTS_SPEAKER = 0x0307
};
#endif

View File

@@ -0,0 +1,168 @@
// Copyright 2017-2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef _USBAUDIOCOMMON_H_
#define _USBAUDIOCOMMON_H_
#include "xud_conf_default.h"
#ifdef __STDC__
typedef struct
{
unsigned char bLength; /* Size of descriptor (bytes) */
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned short bcdADC; /* Binary coded decimal indicating the supported Audio Class version */
unsigned char bCatagory; /* Primary use of this audio function. See Audio Function Category Codes */
unsigned short wTotalLength; /* Total length of the Audio class-specific descriptors, including this descriptor */
unsigned char bmControls; /* D[1:0]: Latency control. D[7:2]: Reserved. Must be set to 0 */
} __attribute__((packed)) UAC_Descriptor_Interface_AC_t;
/* Table 4-9: Input Terminal Descriptor */
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bTerminalID; /* Unique ID of this terminal unit */
unsigned short wTerminalType;
unsigned char bAssocTerminal; /* ID of associated output terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset */
unsigned char bCSourceID; /* ID of the clock entity to which this Input Terminal is connected */
unsigned char bNrChannels; /* Number of logicial output channels in the Terminal's
output audio channel cluster */
unsigned bmChannelConfig; /* Channel layout supported by this terminal */
unsigned char iChannelNames; /* Index in string table describing channels (points to first channel) */
unsigned short bmControls; /* Bitmap */
unsigned char iTerminal; /* Index of string descriptor describing this terminal */
} __attribute__((packed))USB_Descriptor_Audio_InputTerminal_t;
#if 0
//UAC 1.0 version
typedef struct
{
unsigned char bLength; /* Size of the descriptor (bytes) */
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bTerminalID; /* Unique ID of this terminal unit */
unsigned short wTerminalType;
unsigned char bAssocTerminal; /* ID of associated output terminal, for physically grouped terminals
* such as the speaker and microphone of a phone handset */
unsigned char bNrChannels; /* Total number of separate audio channels within this interface */
unsigned short wChannelConfig; /* Channel layout supported by this terminal */
unsigned char iChannelNames; /* Index in string table describing channels (points to first channel */
unsigned char iTerminal; /* Index of string descriptor describing this terminal */
} USB_Descriptor_Audio_InputTerminal_t;
#endif
/* Table 4-10: Output Terminal Descriptor */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bTerminalID;
unsigned short wTerminalType;
unsigned char bAssocTerminal;
unsigned char bSourceID;
unsigned char bCSourceID;
unsigned short bmControls;
unsigned char iTerminal;
} __attribute__((packed)) USB_Descriptor_Audio_OutputTerminal_t;
#if 0
/* UAC 1.0 Version */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bTerminalID;
unsigned short wTerminalType;
unsigned char bAssocTerminal;
unsigned char bSourceID;
unsigned char iTerminal;
} USB_Descriptor_Audio_OutputTerminal_t;
#endif
/* Note, we need seperate _out and _in structs due to varying channel count */
/* Table 4-13: Feature Unit Descriptor */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bUnitID; /* Unique ID for this feature unit */
unsigned char bSourceID; /* Source ID value of the audio source input into this feature unit */
unsigned bmaControls[NUM_USB_CHAN_OUT+1]; /* Feature masks for the control channel, and each separate audio channel */
unsigned char iFeature; /* String table index describing this feature unit */
} __attribute__((packed)) USB_Descriptor_Audio_FeatureUnit_Out_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bUnitID; /* Unique ID for this feature unit */
unsigned char bSourceID; /* Source ID value of the audio source input into this feature unit */
unsigned bmaControls[NUM_USB_CHAN_IN+1]; /* Feature masks for the control channel, and each separate audio channel */
unsigned char iFeature; /* String table index describing this feature unit */
} __attribute__((packed)) USB_Descriptor_Audio_FeatureUnit_In_t;
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bTerminalLink;
unsigned char bmControls;
unsigned char bFormatType;
unsigned bmFormats;
unsigned char bNrChannels;
unsigned bmChannelConfig;
unsigned char iChannelNames;
} __attribute__((packed)) USB_Descriptor_Audio_Interface_AS_t;
#if 0
/* UAC1 Version */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubType;
unsigned char bTerminalLink;
unsigned char bmControls;
unsigned char bFormatType;
unsigned bmFormats;
unsigned char bNrChannels;
unsigned char bmChannelConfig;
} __attribute__((packed)) USB_Descriptor_Audio_Interface_AS_t;
#endif
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bmAttributes;
unsigned char bmControls;
unsigned char bLockDelayUnits;
unsigned short wLockDelay;
} __attribute__((packed)) USB_Descriptor_Audio_Class_AS_Endpoint_t;
#if 0
/* UAC1.0 Version */
typedef struct
{
unsigned char bLength;
unsigned char bDescriptorType;
unsigned char bDescriptorSubtype;
unsigned char bmAttributes;
unsigned char bLockDelayUnits;
unsigned short wLockDelay;
} __attribute__((packed)) USB_Descriptor_Audio_Class_AS_Endpoint_t;
#endif
#endif
#endif

View File

@@ -0,0 +1,50 @@
// Copyright 2011-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** XUD_EpFuncs.S
* @brief ASM functions for data transfer to/from XUD
* @author Ross Owen, XMOS Limited
*/
#include "XUD_USB_Defines.h"
#include "XUD_AlignmentDefines.h"
#if defined __XS2A__
.set too_many_cores, main.maxcores > 6
.assert 0, too_many_cores, "Warning: More than 6 cores used on a tile. Ensure this is not the case on tile running XUD."
#endif
//void XUD_SetTestMode(XUD_ep ep, unsigned testMode);
.globl XUD_SetTestMode
.type XUD_SetTestMode, @function
.cc_top XUD_SetTestMode.func
.align FUNCTION_ALIGNMENT
XUD_SetTestMode:
.issue_mode single
ENTSP_lu6 0
ldw r0, r0[2] // Load our chanend ID to use
outct res[r0], 1
chkct res[r0], 1
out res[r0], r1 // Output test mode
outct res[r0], 1
chkct res[r0], 1
retsp 0
.size XUD_SetTestMode, .-XUD_SetTestMode
.cc_bottom XUD_SetTestMode.func
.globl XUD_SetTestMode.nstackwords
.globl XUD_SetTestMode.maxchanends
.globl XUD_SetTestMode.maxtimers
.globl XUD_SetTestMode.maxcores
.set XUD_SetTestMode.nstackwords, 0
.set XUD_SetTestMode.maxchanends, 0
.set XUD_SetTestMode.maxtimers, 0
.set XUD_SetTestMode.maxcores, 1
.globl XUD_SetTestMode.locnoside
.globl XUD_SetTestMode.locnochandec
.globl XUD_SetTestMode.locnoglobalaccess
.globl XUD_SetTestMode.locnointerfaceaccess
.globl XUD_SetTestMode.locnonotificationselect
.set XUD_SetTestMode.locnoside, 1
.set XUD_SetTestMode.locnochandec, 1
.set XUD_SetTestMode.locnoglobalaccess, 1
.set XUD_SetTestMode.locnointerfaceaccess, 1
.set XUD_SetTestMode.locnonotificationselect, 1

View File

@@ -0,0 +1,406 @@
// Copyright 2021-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "xud.h"
#include "XUD_USB_Defines.h"
extern XUD_ep_info ep_info[USB_MAX_NUM_EP];
void XUD_ResetEpStateByAddr(unsigned epAddr)
{
unsigned pid = USB_PIDn_DATA0;
#if defined(__XS2A__)
/* Check IN bit of address */
if((epAddr & 0x80) == 0)
{
pid = USB_PID_DATA0;
}
#endif
if(epAddr & 0x80)
{
epAddr &= 0x7F;
epAddr += USB_MAX_NUM_EP_OUT;
}
XUD_ep_info *ep = &ep_info[epAddr];
ep->pid = pid;
}
void XUD_SetStallByAddr(int epNum)
{
if(epNum & 0x80)
{
epNum &= 0x7f;
epNum += 16;
}
XUD_ep_info *ep = &ep_info[epNum];
unsigned *epReadyEntry = (unsigned *)ep->array_ptr;
if(*epReadyEntry != 0)
{
/* Mark EP as not ready (and save that it was ready at Halting */
ep->saved_array_ptr = *epReadyEntry;
*epReadyEntry = 0;
}
ep->halted = USB_PIDn_STALL;
}
void XUD_SetStall(XUD_ep e)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
XUD_SetStallByAddr(ep->epAddress);
}
void XUD_ClearStallByAddr(int epNum)
{
unsigned handshake = USB_PIDn_NAK;
/* Reset data PID */
XUD_ResetEpStateByAddr(epNum);
if(epNum & 0x80)
{
epNum &= 0x7F;
epNum += USB_MAX_NUM_EP_OUT;
handshake = 0;
}
XUD_ep_info *ep = &ep_info[epNum];
/* Re-mark as ready if was ready before halting */
if(ep->saved_array_ptr != 0)
{
unsigned *epReadyEntry = (unsigned *)ep->array_ptr;
*epReadyEntry = ep->saved_array_ptr;
ep->saved_array_ptr = 0;
}
/* Mark EP as un-halted */
ep->halted = handshake;
}
void XUD_ClearStall(XUD_ep e)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
XUD_ClearStallByAddr(ep->epAddress);
}
/* ignoreHalted should only be used for Setup data */
static inline XUD_Result_t XUD_GetBuffer_Start(volatile XUD_ep_info *ep, unsigned char buffer[])
{
/* If EP is marked as halted do not mark as ready.. */
do
{
/* Check if we missed a reset */
if(ep->resetting)
{
return XUD_RES_RST;
}
}
while(ep->halted == USB_PIDn_STALL);
/* Store buffer address in EP structure */
ep->buffer = (unsigned) &buffer[0];
/* Mark EP as ready */
unsigned * array_ptr = (unsigned *)ep->array_ptr;
*array_ptr = (unsigned) ep;
return XUD_RES_OKAY;
}
XUD_Result_t XUD_GetBuffer_Finish(chanend c, XUD_ep e, unsigned *datalength)
{ // NOCOVER
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
unsigned length;
unsigned lengthTail;
unsigned isReset;
/* Wait for XUD response */
asm volatile("testct %0, res[%1]" : "=r"(isReset) : "r"(c));
if(isReset)
{
return XUD_RES_RST;
}
/* Input packet length (words) */
asm volatile("in %0, res[%1]" : "=r"(length) : "r"(c));
/* Input tail length (bytes) */
asm volatile("int %0, res[%1]" : "=r"(lengthTail) : "r"(c));
/* Bits to bytes */
lengthTail >>= 3;
/* Words to bytes */
length <<= 2;
/* -2 length correction for CRC */
*datalength = length + lengthTail - 2;
/* Load received PID */
unsigned receivedPid = ep->actualPid;
/* Check received PID vs expected PID */
if(receivedPid != ep->pid)
{
*datalength = 0; /* Extra safety measure */
return XUD_RES_ERR;
}
/* ISO == 0 */
if(ep->epType != XUD_EPTYPE_ISO)
{
#ifdef __XS2A__
ep->pid ^= 0x8;
#else
ep->pid ^= 0x88;
#endif
}
return XUD_RES_OKAY;
} // NOCOVER
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)
{
unsigned char tmp[8];
/* Send 0 length packet */
return XUD_SetBuffer(ep_in, tmp, 0);
}
XUD_Result_t XUD_GetBuffer(XUD_ep e, unsigned char buffer[], unsigned *datalength)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
while(1)
{
XUD_Result_t result = XUD_GetBuffer_Start(ep, buffer);
if(result == XUD_RES_RST)
{
return XUD_RES_RST;
}
result = XUD_GetBuffer_Finish(ep->client_chanend, e, datalength);
/* If error (e.g. bad PID seq) try again */
if(result != XUD_RES_ERR)
{
return result;
}
}
}
int XUD_SetReady_Out(XUD_ep e, unsigned char buffer[])
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
return XUD_GetBuffer_Start(ep, buffer);
}
void XUD_GetData_Select(chanend c, XUD_ep e, unsigned *datalength, XUD_Result_t *result)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
*result = XUD_GetBuffer_Finish(ep->client_chanend, e, datalength);
}
XUD_Result_t XUD_GetSetupBuffer(XUD_ep e, unsigned char buffer[], unsigned *datalength)
{
volatile XUD_ep_info *ep = (XUD_ep_info*) e;
unsigned isReset;
unsigned length;
unsigned lengthTail;
/* Check if we missed a reset */
if(ep->resetting)
{
return XUD_RES_RST;
}
/* Store buffer address in EP structure */
ep->buffer = (unsigned) &buffer[0];
/* Mark EP as ready for SETUP data */
unsigned * array_ptr_setup = (unsigned *)ep->array_ptr_setup;
*array_ptr_setup = (unsigned) ep;
/* Wait for XUD response */
asm volatile("testct %0, res[%1]" : "=r"(isReset) : "r"(ep->client_chanend));
if(isReset)
{
return XUD_RES_RST;
}
/* Input packet length (words) */
asm volatile("in %0, res[%1]" : "=r"(length) : "r"(ep->client_chanend));
/* Input tail length (bytes) */
/* TODO Check CT vs T */
asm volatile("inct %0, res[%1]" : "=r"(lengthTail) : "r"(ep->client_chanend));
/* Reset PID toggling on receipt of SETUP (both IN and OUT) */
#ifdef __XS2A__
ep->pid = USB_PID_DATA1;
#else
ep->pid = USB_PIDn_DATA1;
#endif
/* Reset IN EP PID */
XUD_ep_info *ep_in = (XUD_ep_info*) ((unsigned)ep + (USB_MAX_NUM_EP_OUT * sizeof(XUD_ep_info)));
ep_in->pid = USB_PIDn_DATA1;
/* TODO check that this is the case */
*datalength = 8;
return XUD_RES_OKAY;
}
XUD_Result_t XUD_SetBuffer_Start(XUD_ep e, unsigned char buffer[], unsigned datalength)
{ // NOCOVER
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
while(1)
{
/* Check if we missed a reset */
if(ep->resetting)
{
return XUD_RES_RST;
}
/* If EP is marked as halted do not mark as ready.. */
if(ep->halted != USB_PIDn_STALL)
{
break;
}
}
int lengthWords = datalength >> 2;
unsigned lengthTail = (datalength << 3) & 0x1f; // zext(5)?
if((lengthTail == 0) && (lengthWords != 0))
{
lengthWords -= 1;
lengthTail = 32;
}
/* Store end of buffer address in EP structure */
ep->buffer = (unsigned) &buffer[0] + (lengthWords * 4);
/* XUD uses negative index */
lengthWords *= -1;
ep->actualPid = lengthWords; /* Re-use of actualPid entry - TODO rename */
ep->tailLength = lengthTail;
unsigned * array_ptr = (unsigned *)ep->array_ptr;
*array_ptr = (unsigned) ep;
return XUD_RES_OKAY;
}
XUD_Result_t XUD_SetBuffer_Finish(chanend c, XUD_ep e)
{ // NOCOVER
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
unsigned isReset;
unsigned tmp;
/* Wait for XUD response */
asm volatile("testct %0, res[%1]" : "=r"(isReset) : "r"(ep->client_chanend));
if(isReset)
{
return XUD_RES_RST;
}
/* Data sent okay */
asm volatile("in %0, res[%1]" : "=r"(tmp) : "r"(ep->client_chanend));
/* Don't do any PID toggling for Iso EP's */
if(ep->epType != XUD_EPTYPE_ISO)
{
ep->pid ^= 0x88;
}
return XUD_RES_OKAY;
} // NOCOVER
XUD_Result_t XUD_SetBuffer(XUD_ep e, unsigned char buffer[], unsigned datalength)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
XUD_Result_t result = XUD_SetBuffer_Start(e, buffer, datalength);
if(result == XUD_RES_RST)
{
return result;
}
return XUD_SetBuffer_Finish(ep->client_chanend, e);
}
void XUD_SetData_Select(chanend c, XUD_ep e, XUD_Result_t *result)
{
volatile XUD_ep_info * ep = (XUD_ep_info*) e;
*result = XUD_SetBuffer_Finish(ep->client_chanend, e);
}
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)
{
int i = 0;
XUD_Result_t result;
/* Note: We could encompass this in the SetData function */
if (datalength <= epMax)
{
/* Datalength is less than the maximum per transaction of the EP, so just send */
result = XUD_SetBuffer(ep_in, buffer, datalength);
return result;
}
else
{
/* Send first packet out and reset PID */
if((result = XUD_SetBuffer(ep_in, buffer, epMax)) != XUD_RES_OKAY)
{
return result;
}
i += epMax;
datalength -= epMax;
while (1)
{
unsigned char *bufferPtr = &buffer[i];
if (datalength > epMax)
{
/* PID Automatically toggled */
if ((result = XUD_SetBuffer(ep_in, bufferPtr, epMax)) != XUD_RES_OKAY)
return result;
datalength -= epMax;
i += epMax;
}
else
{
/* PID automatically toggled */
if ((result = XUD_SetBuffer(ep_in, bufferPtr, datalength)) != XUD_RES_OKAY)
return result;
break; //out of while loop
}
}
}
return XUD_RES_OKAY;
}

View File

@@ -0,0 +1,112 @@
// Copyright 2011-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/** @file XUD_EPFunctions.xc
* @brief Implementation of user API functions. See xud.h for documentation.
* @author Ross Owen, XMOS Limited
**/
#include <xs1.h>
#include "xud.h"
#include "XUD_USB_Defines.h"
static inline int min(int x, int y)
{
if (x < y)
return x;
return y;
}
void XUD_Kill(XUD_ep ep)
{
XUD_SetTestMode(ep, 0);
}
#ifndef EP0_MAX_PACKET_SIZE
#define EP0_MAX_PACKET_SIZE (64)
#endif
/* TODO Should take ep max length as a param - currently hardcoded as 64 (#11384) */
XUD_Result_t XUD_DoGetRequest(XUD_ep ep_out, XUD_ep ep_in, unsigned char buffer[], unsigned length, unsigned requested)
{
unsigned char tmpBuffer[1024];
unsigned rxlength;
unsigned sendLength = min(length, requested);
XUD_Result_t result;
if ((result = XUD_SetBuffer_EpMax(ep_in, buffer, sendLength, EP0_MAX_PACKET_SIZE)) != XUD_RES_OKAY)
{
return result;
}
/* USB 2.0 8.5.3.2: Send < 0 length packet when data-length % 64 is 0
* Note, we also don't want to try and send 2 zero-length packets i.e. if sendLength = 0 */
if ((requested > length) && ((length % EP0_MAX_PACKET_SIZE) == 0))
{
XUD_SetBuffer(ep_in, tmpBuffer, 0);
}
/* Status stage - this should return -1 for reset or 0 for 0 length status stage packet */
return XUD_GetBuffer(ep_out, tmpBuffer, rxlength);
}
void XUD_CloseEndpoint(XUD_ep one)
{
unsigned c1;
/* Input rst control token */
asm volatile("ldw %0, %1[2]":"=r"(c1):"r"(one)); // Load our chanend
asm volatile ("outct res[%0], 1":: "r"(c1)); // Close channel to other side
asm volatile ("chkct res[%0], 1":: "r"(c1)); // Close channel to this side
}
XUD_BusSpeed_t XUD_ResetEndpoint(XUD_ep one, XUD_ep &?two)
{
int busStateCt;
int busSpeed;
unsigned c1, c2, tmp;
/* Input rst control token */
asm volatile("ldw %0, %1[2]":"=r"(c1):"r"(one)); // Load our chanend
asm volatile ("inct %0, res[%1]": "=r"(busStateCt):"r"(c1)); // busStateCt = inct(one);
if (!isnull(two))
{
asm volatile("ldw %0, %1[2]":"=r"(c2):"r"(two));
asm volatile ("inct %0, res[%1]": "=r"(busStateCt):"r"(c2));
}
/* Clear ready flag (tidies small race where EP marked ready just after XUD clears ready due to reset */
asm volatile("ldw %0, %1[0]":"=r"(tmp):"r"(one)); // Load address of ep in XUD rdy table
asm volatile ("stw %0, %1[0]"::"r"(0), "r"(tmp));
/* Clear resetting flag */
asm volatile ("stw %0, %1[9]"::"r"(0), "r"(one));
if(!isnull(two))
{
asm volatile("ldw %0, %1[0]":"=r"(tmp):"r"(two)); // Load address of ep in XUD rdy table
asm volatile ("stw %0, %1[0]"::"r"(0), "r"(tmp));
/* Reset reseting flag */
asm volatile ("stw %0, %1[9]"::"r"(0), "r"(two));
}
/* Expect a word with speed */
asm volatile ("in %0, res[%1]": "=r"(busSpeed):"r"(c1));
if (!isnull(two))
{
asm volatile ("in %0, res[%1]": "=r"(busSpeed):"r"(c2));
}
return (XUD_BusSpeed_t) busSpeed;
}
XUD_ep XUD_InitEp(chanend c)
{
XUD_ep ep = inuint(c);
return ep;
}

View File

@@ -0,0 +1,637 @@
// Copyright 2015-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Implements USB Device standard requests
* @author Ross Owen, XMOS Limited
*/
#include "xud_device.h" /* Defines related to the USB 2.0 Spec */
#include "XUD_HAL.h"
#include <string.h>
#include <xs1.h>
#include <print.h>
#ifndef WINDOWS_OS_DESCRIPTOR_SUPPORT
#define WINDOWS_OS_DESCRIPTOR_SUPPORT
#endif
#ifndef MAX_INTS
/* Maximum number of interfaces supported */
#define MAX_INTS 16
#endif
#ifndef MAX_EPS
/* Maximum number of EP's supported */
#define MAX_EPS USB_MAX_NUM_EP
#endif
unsigned char g_currentConfig = 0;
unsigned char g_interfaceAlt[MAX_INTS]; /* Global endpoint status arrays */
unsigned short g_epStatusOut[MAX_EPS];
unsigned short g_epStatusIn[MAX_EPS];
#pragma unsafe arrays
XUD_Result_t USB_GetSetupPacket(XUD_ep ep_out, XUD_ep ep_in, USB_SetupPacket_t &sp)
{
unsigned char sbuffer[120];
unsigned length;
XUD_Result_t result;
if((result = XUD_GetSetupBuffer(ep_out, sbuffer, length)) != XUD_RES_OKAY)
{
return result;
}
/* Parse data buffer end populate SetupPacket struct */
USB_ParseSetupPacket(sbuffer, sp);
/* Return 0 for success */
return result;
}
/* Used when setting/clearing EP halt */
int SetEndpointHalt(unsigned epNum, unsigned halt)
{
/* Inspect for IN bit */
if(epNum & 0x80)
{
/* Range check */
if((epNum&0x7F) < MAX_EPS)
{
g_epStatusIn[epNum & 0x7F] = halt;
if(halt)
XUD_SetStallByAddr(epNum);
else
XUD_ClearStallByAddr(epNum);
return 0;
}
}
else
{
if(epNum < MAX_EPS)
{
g_epStatusOut[epNum] = halt;
if(halt)
XUD_SetStallByAddr(epNum);
else
XUD_ClearStallByAddr(epNum);
return 0;
}
}
return 1;
}
#pragma unsafe arrays
XUD_Result_t USB_StandardRequests(XUD_ep ep_out, XUD_ep ep_in,
NULLABLE_ARRAY_OF(unsigned char, devDesc_hs), int devDescLength_hs,
NULLABLE_ARRAY_OF(unsigned char, cfgDesc_hs), int cfgDescLength_hs,
NULLABLE_ARRAY_OF(unsigned char, devDesc_fs), int devDescLength_fs,
NULLABLE_ARRAY_OF(unsigned char, cfgDesc_fs), int cfgDescLength_fs,
char * unsafe strDescs[], int strDescsLength,
USB_SetupPacket_t &sp, XUD_BusSpeed_t usbBusSpeed)
{
/* Return value */
int datalength;
int stringID = 0;
/* Buffer for Setup data */
unsigned char buffer[120];
/* Stick bmRequest type back together for an easier parse... */
unsigned bmRequestType = (sp.bmRequestType.Direction<<7) | (sp.bmRequestType.Type<<5) | (sp.bmRequestType.Recipient);
switch(bmRequestType)
{
/* Standard Device Requests - To Device */
case USB_BMREQ_H2D_STANDARD_DEV:
/* Inspect for actual request */
switch(sp.bRequest)
{
/* Standard Device Request: ClearFeature (USB Spec 9.4.1) */
case USB_CLEAR_FEATURE:
/* Device Features than could potenially be cleared are as follows (See Figure 9-4)
* Self Powered: Cannot be changed by SetFeature() or ClearFeature()
* Remote Wakeup: Indicates if the device is currently enabled to request remote wakeup.
by default not implemented
*/
break;
/* Standard Device Request: Set Address (USB spec 9.6.4) */
/* This is a unique request since the operation is not completed until after the status stage */
case USB_SET_ADDRESS:
if((sp.wValue < 128) && (sp.wIndex == 0) && (sp.wLength == 0))
{
XUD_Result_t result;
/* Status stage: Send a zero length packet */
if((result = XUD_DoSetRequestStatus(ep_in)) != XUD_RES_OKAY)
{
return result;
}
/* Note: Really we should wait until ACK is received for status stage before changing address
* We will just wait some time... */
{
timer t;
unsigned time;
t :> time;
t when timerafter(time+50000) :> void;
}
/* Set the device address in XUD */
XUD_HAL_SetDeviceAddress(sp.wValue);
return XUD_RES_OKAY;
}
break;
/* Standard Device Request: SetConfiguration (USB Spec 9.4.7) */
case USB_SET_CONFIGURATION:
if((sp.wLength == 0) && (sp.wIndex == 0))
{
/* We can ignore sp.Direction if sp.wLength is 0. See USB Spec 9.3.1 */
/* USB 2.0 Spec 9.1.1.5 states that configuring a device should cause all
* the status and configuration values associated with the endpoints in the
* affected interfaces to be set to their default values. This includes setting
* the data toggle of any endpoint using data toggles to the value DATA0 */
/* Note: currently assume all EP's related to config (apart from 0) */
for(unsigned i = 1; i < USB_MAX_NUM_EP_IN; i++)
{
XUD_ResetEpStateByAddr(i | 0x80 );
}
for(unsigned i = 1; i < USB_MAX_NUM_EP_OUT; i++)
{
XUD_ResetEpStateByAddr(i);
}
/* Update global configuration value
* Note alot of devices maye wish to implement features here since this
* request indicates the device being placed into its "Configured" state
* i.e. the host has accepted the device */
g_currentConfig = sp.wValue;
/* No data stage for this request, just do status stage */
return XUD_DoSetRequestStatus(ep_in);
}
break;
/* Standard Device Request: SetDescriptor (USB Spec 9.4.8) */
case USB_SET_DESCRIPTOR:
/* Optional request for updating or adding new descriptors */
/* Not implemented by default */
break;
/* Standard Device Request: SetFeature (USB Spec 9.4.9) */
/* TODO only accept these requests in HS? */
case USB_SET_FEATURE:
if((sp.wValue == USB_TEST_MODE) && (sp.wLength == 0))
{
/* Inspect for Test Selector (high byte of wIndex, lower byte must be zero) */
switch(sp.wIndex)
{
case USB_WINDEX_TEST_J:
case USB_WINDEX_TEST_K:
case USB_WINDEX_TEST_SE0_NAK:
case USB_WINDEX_TEST_PACKET:
{
XUD_Result_t result;
if((result = XUD_DoSetRequestStatus(ep_in)) != XUD_RES_OKAY)
return result;
XUD_SetTestMode(ep_out, sp.wIndex);
}
break;
}
}
break;
}
break;
/* Standard Device Requests - To Host */
case USB_BMREQ_D2H_STANDARD_DEV:
switch(sp.bRequest)
{
/* Standard Device Request: GetStatus (USB Spec 9.4.5)*/
case USB_GET_STATUS:
/* Remote wakeup not supported (bit 1) */
buffer[1] = 0;
/* Pull self/bus powered bit from the config descriptor */
unsigned char self_powered = 0;
if((usbBusSpeed == XUD_SPEED_FS) && (cfgDescLength_fs != 0))
{
self_powered = (cfgDesc_fs[7] & 0x40) != 0;
}
else if(cfgDescLength_hs != 0)
{
self_powered = (cfgDesc_hs[7] & 0x40) != 0;
}
buffer[0] = self_powered;
return XUD_DoGetRequest(ep_out, ep_in, buffer, 2, sp.wLength);
/* Standard Device Request: GetConfiguration (USB Spec 9.4.2) */
case USB_GET_CONFIGURATION:
/* Return the current configuration of the device */
if((sp.wValue == 0) && (sp.wIndex == 0) && (sp.wLength == 1))
{
buffer[0] = (char)g_currentConfig;
return XUD_DoGetRequest(ep_out, ep_in, buffer, 1, sp.wLength);
}
break;
/* Standard Device Request: GetDescriptor (USB Spec 9.4.3)*/
case USB_GET_DESCRIPTOR:
/* Inspect for which Type of descriptor is required (high byte of wValue) */
switch(sp.wValue & 0xff00)
{
/* Device descriptor */
case (USB_DESCTYPE_DEVICE << 8):
/* Currently only 1 device descriptor supported */
if((sp.wValue & 0xff) == 0)
{
if((usbBusSpeed == XUD_SPEED_FS) && (devDescLength_fs != 0))
{
/* Return full-speed device descriptor */
return XUD_DoGetRequest(ep_out, ep_in, devDesc_fs, devDescLength_fs, sp.wLength);
}
else if(devDescLength_hs != 0)
{
/* Return high-speed device descriptor, if no FS desc, send the HS desc */
/* Do get request (send descriptor then 0 length status stage) */
return XUD_DoGetRequest(ep_out, ep_in, devDesc_hs, devDescLength_hs, sp.wLength);
}
}
break;
/* Configuration Descriptor */
case (USB_DESCTYPE_CONFIGURATION << 8):
/* Currently only 1 configuration descriptor supported */
/* TODO We currently return the same for all configs */
//if((sp.wValue & 0xff) == 0)
{
if((usbBusSpeed == XUD_SPEED_FS) && (cfgDescLength_fs != 0))
{
/* Return full-speed configuration descriptor */
cfgDesc_fs[1] = USB_DESCTYPE_CONFIGURATION;
return XUD_DoGetRequest(ep_out, ep_in, cfgDesc_fs, cfgDescLength_fs, sp.wLength);
}
else if(cfgDescLength_hs != 0)
{
/* Do get request (send descriptor then 0 length status stage) */
cfgDesc_hs[1] = USB_DESCTYPE_CONFIGURATION;
return XUD_DoGetRequest(ep_out, ep_in, cfgDesc_hs, cfgDescLength_hs, sp.wLength);
}
}
break;
/* Device qualifier descriptor */
case (USB_DESCTYPE_DEVICE_QUALIFIER << 8):
if((sp.wValue & 0xff) == 0)
{
/* Build a device qualifer descriptor from the device descriptor */
unsigned char devQualDesc[10];
if((usbBusSpeed == XUD_SPEED_HS) && (devDescLength_fs != 0))
{
/* Create devQual from FS Device Descriptor*/
devQualDesc[0] = 10; /* 0 bLength */
devQualDesc[1] = USB_DESCTYPE_DEVICE_QUALIFIER; /* 1 bDescriptorType */
devQualDesc[2] = devDesc_fs[2];
devQualDesc[3] = devDesc_fs[3];
devQualDesc[4] = devDesc_fs[4];
devQualDesc[5] = devDesc_fs[5];
devQualDesc[6] = devDesc_fs[6];
devQualDesc[7] = devDesc_fs[7];
devQualDesc[8] = devDesc_fs[17]; /* 8 bNumConfigurations */
devQualDesc[9] = 0;
/* Do get request (send descriptor then 0 length status stage) */
return XUD_DoGetRequest(ep_out, ep_in, devQualDesc, 10, sp.wLength);
}
else if(devDescLength_hs != 0)
{
/* Running in FS so create devQual from HS Device Descriptor */
devQualDesc[0] = 10; /* 0 bLength */
devQualDesc[1] = USB_DESCTYPE_DEVICE_QUALIFIER; /* 1 bDescriptorType */
devQualDesc[2] = devDesc_hs[2];
devQualDesc[3] = devDesc_hs[3];
devQualDesc[4] = devDesc_hs[4];
devQualDesc[5] = devDesc_hs[5];
devQualDesc[6] = devDesc_hs[6];
devQualDesc[7] = devDesc_hs[7];
devQualDesc[8] = devDesc_hs[17]; /* 8 bNumConfigurations */
devQualDesc[9] = 0;
/* Do get request (send descriptor then 0 length status stage) */
return XUD_DoGetRequest(ep_out, ep_in, devQualDesc, 10, sp.wLength);
}
/* Not handled if devDescLength_hs == 0 and running in full-speed.
* This should result in a STALL as per USB spec */
}
break;
/* Other Speed Configuration Descriptor */
case (USB_DESCTYPE_OTHER_SPEED << 8):
/* Accepts any configuration number */
//if((sp.wValue & 0xff) == 0)
{
if((usbBusSpeed == XUD_SPEED_HS) && (cfgDescLength_fs != 0))
{
cfgDesc_fs[1] = USB_DESCTYPE_OTHER_SPEED;
return XUD_DoGetRequest(ep_out, ep_in, cfgDesc_fs, cfgDescLength_fs, sp.wLength);
}
else if(cfgDescLength_hs != 0)
{
cfgDesc_hs[1] = USB_DESCTYPE_OTHER_SPEED;
return XUD_DoGetRequest(ep_out, ep_in, cfgDesc_hs, cfgDescLength_hs, sp.wLength);
}
/* Not handled if cfgDescLength_hs == 0 and running in full-speed.
* This should result in a STALL as per USB spec */
}
break;
/* String Descriptor */
case (USB_DESCTYPE_STRING << 8):
/* Set descriptor type */
buffer[1] = USB_DESCTYPE_STRING;
/* Send the string that was requested (low byte of wValue) */
/* First, generate valid descriptor from string */
stringID = sp.wValue & 0xff;
#ifdef WINDOWS_OS_DESCRIPTOR_SUPPORT
unsigned OS_STR_DESC[8] = {'M','S','F','T','1','0','0',0x01}; // GET_MS_DESCRIPTOR will use the same value as the OS_STR_DESC last byte in bRequest later.
#endif
/* String table bounds check */
#ifdef WINDOWS_OS_DESCRIPTOR_SUPPORT
if((stringID < strDescsLength) || (stringID == 0xEE))
#else
if(stringID < strDescsLength)
#endif
{
unsafe
{
#ifdef WINDOWS_OS_DESCRIPTOR_SUPPORT
datalength = (stringID == 0xEE) ? 8 : strlen((char*)strDescs[stringID]);
#else
datalength = strlen((char*)strDescs[stringID]);
#endif
/* String 0 (LangIDs) is a special case*/
if( stringID == 0 )
{
buffer[0] = datalength + 2;
if( sp.wLength < datalength + 2 )
{
datalength = sp.wLength - 2;
}
for(int i = 0; i < datalength; i += 1 )
{
buffer[i+2] = strDescs[stringID][i];
}
}
else
{
/* Datalength *= 2 due to unicode */
datalength <<= 1;
/* Set data length in descriptor (+2 due to 2 byte datalength)*/
buffer[0] = datalength + 2;
if(sp.wLength < datalength + 2)
{
datalength = sp.wLength - 2;
}
/* Add zero bytes for unicode.. */
for(int i = 0; i < datalength; i+=2)
{
#ifdef WINDOWS_OS_DESCRIPTOR_SUPPORT
buffer[i+2] = (stringID == 0xEE) ? OS_STR_DESC[i>>1] : strDescs[ stringID ][i>>1];
#else
buffer[i+2] = strDescs[ stringID ][i>>1];
#endif
buffer[i+3] = 0;
}
}
}
/* Send back string */
return XUD_DoGetRequest(ep_out, ep_in, buffer, datalength + 2, sp.wLength);
} /* if(stringID < stringDescs_length) */
break;
}
break;
} //switch(sp.bRequest)
break;
/* Direction: Host-to-device
* Type: Standard
* Recipient: Interface
*/
case USB_BMREQ_H2D_STANDARD_INT:
switch(sp.bRequest)
{
/* Standard Interface Request: SetInterface (USB Spec 9.4.10) */
case USB_SET_INTERFACE:
/* Note it is likely that a lot of devices will over-ride this request in their endpoint 0 code
* For example, in an audio device this request would show the intent of the host to start streaming
*/
if(sp.wLength == 0)
{
int numInterfaces = 0;
/* Pull number of interfaces from the Configuration Descriptor */
if((usbBusSpeed == XUD_SPEED_FS) && (cfgDescLength_fs != 0))
{
numInterfaces = cfgDesc_fs[4];
}
else if(cfgDescLength_hs != 0)
{
numInterfaces = cfgDesc_hs[4];
}
/* Record interface change */
if((sp.wIndex < numInterfaces) && (sp.wIndex < MAX_INTS))
{
/* Note here we assume the host has given us a valid Alternate setting
* It is hard for use to have a generic check for this here (without parsing the descriptors)
* If more robust checking is required this should be done in the endpoint 0 implementation
*/
g_interfaceAlt[sp.wIndex] = sp.wValue;
}
/* No data stage for this request, just do data stage */
return XUD_DoSetRequestStatus(ep_in);
}
break;
}
break;
/* Direction: Device-to-host
* Type: Standard
* Recipient: Interface
*/
case USB_BMREQ_D2H_STANDARD_INT:
switch(sp.bRequest)
{
case USB_GET_INTERFACE:
if((sp.wValue == 0) && (sp.wLength == 1))
{
int numInterfaces = 0;
/* Pull number of interfaces from the Configuration Descriptor */
if((usbBusSpeed == XUD_SPEED_FS) && (cfgDescLength_fs != 0))
{
numInterfaces = cfgDesc_fs[4];
}
else if(cfgDescLength_hs != 0)
{
numInterfaces = cfgDesc_hs[4];
}
if((sp.wIndex < numInterfaces) && (sp.wIndex < MAX_INTS))
{
buffer[0] = g_interfaceAlt[sp.wIndex];
return XUD_DoGetRequest(ep_out, ep_in, buffer, 1, sp.wLength);
}
}
break;
}
break;
/* Direction: Host-to-device
* Type: Standard
* Recipient: Endpoint
*/
case USB_BMREQ_H2D_STANDARD_EP:
switch(sp.bRequest)
{
/* Standard Endpoint Request: SetFeature (USB Spec 9.4.9) */
case USB_SET_FEATURE:
if(sp.wLength == 0)
{
/* The only Endpoint feature selector is HALT (bit 0) see figure 9-6 */
if(sp.wValue == USB_ENDPOINT_HALT)
{
/* Returns 0 on non-error */
if(!SetEndpointHalt(sp.wIndex, 1))
{
return XUD_DoSetRequestStatus(ep_in);
}
}
}
break;
/* Standard Endpoint Request: ClearFeature (USB Spec 9.4.1) */
case USB_CLEAR_FEATURE:
if(sp.wLength == 0)
{
/* The only feature selector for Endpoint is ENDPOINT_HALT */
if(sp.wValue == USB_ENDPOINT_HALT)
{
/* Returns 0 on non-error */
if(!SetEndpointHalt(sp.wIndex, 0))
{
return XUD_DoSetRequestStatus(ep_in);
}
}
}
break;
}
break;
/* Direction: Host-to-device
* Type: Standard
* Recipient: Endpoint
*/
case USB_BMREQ_D2H_STANDARD_EP:
switch(sp.bRequest)
{
/* Standard Endpoint Request: GetStatus (USB Spec 9.4.5) */
case USB_GET_STATUS:
/* Note: The only status for an EP is Halt (bit 0) */
/* Note: Without parsing the descriptors we don't know how many endpoints the device has... */
if((sp.wValue == 0) && (sp.wLength == 2))
{
buffer[0] = 0;
buffer[1] = 0;
if( sp.wIndex & 0x80 )
{
/* IN Endpoint */
if((sp.wIndex&0x7f) < MAX_EPS)
{
buffer[0] = ( g_epStatusIn[ sp.wIndex & 0x7F ] & 0xff );
buffer[1] = ( g_epStatusIn[ sp.wIndex & 0x7F ] >> 8 );
return XUD_DoGetRequest(ep_out, ep_in, buffer, 2, sp.wLength);
}
}
else
{
/* OUT Endpoint */
if(sp.wIndex < MAX_EPS)
{
buffer[0] = ( g_epStatusOut[ sp.wIndex ] & 0xff );
buffer[1] = ( g_epStatusOut[ sp.wIndex ] >> 8 );
return XUD_DoGetRequest(ep_out, ep_in, buffer, 2, sp.wLength);
}
}
}
break;
}
break;
} //switch(bmRequestType)
/* If we get this far we did not handle request - Protocol Stall Secion 8.4.5 of USB 2.0 spec
* Detailed in Section 8.5.3. Protocol stall is unique to control pipes.
* Protocol stall differs from functional stall in meaning and duration.
* A protocol STALL is returned during the Data or Status stage of a control
* transfer, and the STALL condition terminates at the beginning of the
* next control transfer (Setup). The remainder of this section refers to
* the general case of a functional stall */
XUD_SetStall(ep_out);
XUD_SetStall(ep_in);
return XUD_RES_ERR;
}

View File

@@ -0,0 +1,63 @@
// Copyright 2015-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <print.h>
#include "xud_std_requests.h"
void USB_ParseSetupPacket(unsigned char b[], USB_SetupPacket_t &p)
{
// Byte 0: bmRequestType.
p.bmRequestType.Recipient = b[0] & 0x1f;
p.bmRequestType.Type = (b[0] & 0x60) >> 5;
p.bmRequestType.Direction = b[0] >> 7;
// Byte 1: bRequest
p.bRequest = b[1];
// Bytes [2:3] wValue
p.wValue = (b[3] << 8) | (b[2]);
// Bytes [4:5] wIndex
p.wIndex = (b[5] << 8) | (b[4]);
// Bytes [6:7] wLength
p.wLength = (b[7] << 8) | (b[6]);
}
void USB_ComposeSetupBuffer(USB_SetupPacket_t sp, unsigned char buffer[])
{
buffer[0] = sp.bmRequestType.Recipient
| (sp.bmRequestType.Type << 5)
| (sp.bmRequestType.Direction << 7);
buffer[1] = sp.bRequest;
buffer[2] = sp.wValue & 0xff;
buffer[3] = (sp.wValue & 0xff00)>>8;
buffer[4] = sp.wIndex & 0xff;
buffer[5] = (sp.wIndex & 0xff00)>>8;
buffer[6] = sp.wLength & 0xff;
buffer[7] = (sp.wLength & 0xff00)>>8;
}
void USB_PrintSetupPacket(USB_SetupPacket_t sp)
{
printstr("Setup data\n"); //NOCOVER
printstr("bmRequestType.Recipient: "); //NOCOVER
printhexln(sp.bmRequestType.Recipient); //NOCOVER
printstr("bmRequestType.Type: "); //NOCOVER
printhexln(sp.bmRequestType.Type); //NOCOVER
printstr("bmRequestType.Direction: "); //NOCOVER
printhexln(sp.bmRequestType.Direction); //NOCOVER
printstr("bRequest: "); //NOCOVER
printhexln(sp.bRequest); //NOCOVER
printstr("bmRequestType.wValue: "); //NOCOVER
printhexln(sp.wValue); //NOCOVER
printstr("bmRequestType.wIndex: "); //NOCOVER
printhexln(sp.wIndex); //NOCOVER
printstr("bmRequestType.wLength: "); //NOCOVER
printhexln(sp.wLength); //NOCOVER
}

View File

@@ -0,0 +1,9 @@
// Copyright 2013-2022 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __xud_config_h__
#define __xud_config_h__
#define XUD_EP_COUNT_OUT 1
#define XUD_EP_COUNT_IN 1
#endif // __xud_config_h__