Commit of new class abstraction APIs for all device demos other than the MIDI demo - not documented yet.
Removed scheduler and memory allocation libraries. Added new EVENT_USB_StartOfFrame event in the library to indicate the start of each USB frame (when generated). Removed Tx interrupt from the USBtoSerial demo; now sends characters via polling to ensure more time for the Rx interrupt.pull/1469/head
parent
2440ca268a
commit
d1e5266036
@ -1,394 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2009.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.fourwalledcubicle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software
|
|
||||||
and its documentation for any purpose and without fee is hereby
|
|
||||||
granted, provided that the above copyright notice appear in all
|
|
||||||
copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* RNDIS command handler functions. This handles RNDIS commands according to
|
|
||||||
* the Microsoft RNDIS specification, creating a USB Ethernet network adapter.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_RNDIS_C
|
|
||||||
#include "RNDIS.h"
|
|
||||||
|
|
||||||
/* Global Variables: */
|
|
||||||
/** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */
|
|
||||||
static MAC_Address_t PROGMEM AdapterMACAddress = {ADAPTER_MAC_ADDRESS};
|
|
||||||
|
|
||||||
/** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for
|
|
||||||
* the device, but may still be used by the OS in some circumstances.
|
|
||||||
*/
|
|
||||||
static char PROGMEM AdapterVendorDescription[] = "LUFA RNDIS Adapter";
|
|
||||||
|
|
||||||
/** List of RNDIS OID commands supported by this adapter. */
|
|
||||||
static const uint32_t PROGMEM AdapterSupportedOIDList[] =
|
|
||||||
{
|
|
||||||
OID_GEN_SUPPORTED_LIST,
|
|
||||||
OID_GEN_PHYSICAL_MEDIUM,
|
|
||||||
OID_GEN_HARDWARE_STATUS,
|
|
||||||
OID_GEN_MEDIA_SUPPORTED,
|
|
||||||
OID_GEN_MEDIA_IN_USE,
|
|
||||||
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
||||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
||||||
OID_GEN_LINK_SPEED,
|
|
||||||
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
||||||
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
||||||
OID_GEN_VENDOR_ID,
|
|
||||||
OID_GEN_VENDOR_DESCRIPTION,
|
|
||||||
OID_GEN_CURRENT_PACKET_FILTER,
|
|
||||||
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
||||||
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
||||||
OID_GEN_XMIT_OK,
|
|
||||||
OID_GEN_RCV_OK,
|
|
||||||
OID_GEN_XMIT_ERROR,
|
|
||||||
OID_GEN_RCV_ERROR,
|
|
||||||
OID_GEN_RCV_NO_BUFFER,
|
|
||||||
OID_802_3_PERMANENT_ADDRESS,
|
|
||||||
OID_802_3_CURRENT_ADDRESS,
|
|
||||||
OID_802_3_MULTICAST_LIST,
|
|
||||||
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
||||||
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
||||||
OID_802_3_XMIT_ONE_COLLISION,
|
|
||||||
OID_802_3_XMIT_MORE_COLLISIONS,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire
|
|
||||||
* Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this
|
|
||||||
* reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses.
|
|
||||||
*/
|
|
||||||
uint8_t RNDISMessageBuffer[sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_QUERY_CMPLT_t)];
|
|
||||||
|
|
||||||
/** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */
|
|
||||||
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISMessageBuffer;
|
|
||||||
|
|
||||||
/** Indicates if a RNDIS message response is ready to be sent back to the host. */
|
|
||||||
bool ResponseReady = false;
|
|
||||||
|
|
||||||
/** Current RNDIS adapter state, a value from the RNDIS_States_t enum. */
|
|
||||||
uint8_t CurrRNDISState = RNDIS_Uninitialized;
|
|
||||||
|
|
||||||
/** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */
|
|
||||||
uint32_t CurrPacketFilter = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is
|
|
||||||
* created, the ResponseReady global is updated so that the response is written back to the host upon request.
|
|
||||||
*/
|
|
||||||
void ProcessRNDISControlMessage(void)
|
|
||||||
{
|
|
||||||
/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
|
|
||||||
this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
|
|
||||||
|
|
||||||
switch (MessageHeader->MessageType)
|
|
||||||
{
|
|
||||||
case REMOTE_NDIS_INITIALIZE_MSG:
|
|
||||||
/* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */
|
|
||||||
|
|
||||||
ResponseReady = true;
|
|
||||||
|
|
||||||
RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISMessageBuffer;
|
|
||||||
RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISMessageBuffer;
|
|
||||||
|
|
||||||
INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
|
||||||
INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);
|
|
||||||
INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
|
|
||||||
INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
|
|
||||||
INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
|
|
||||||
INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
|
|
||||||
INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
|
|
||||||
INITIALIZE_Response->MaxPacketsPerTransfer = 1;
|
|
||||||
INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);
|
|
||||||
INITIALIZE_Response->PacketAlignmentFactor = 0;
|
|
||||||
INITIALIZE_Response->AFListOffset = 0;
|
|
||||||
INITIALIZE_Response->AFListSize = 0;
|
|
||||||
|
|
||||||
CurrRNDISState = RNDIS_Initialized;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case REMOTE_NDIS_HALT_MSG:
|
|
||||||
/* Halt the adapter, reset the adapter state - note that no response should be returned when completed */
|
|
||||||
|
|
||||||
ResponseReady = false;
|
|
||||||
MessageHeader->MessageLength = 0;
|
|
||||||
|
|
||||||
CurrRNDISState = RNDIS_Uninitialized;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case REMOTE_NDIS_QUERY_MSG:
|
|
||||||
/* Request for information about a parameter about the adapter, specified as an OID token */
|
|
||||||
|
|
||||||
ResponseReady = true;
|
|
||||||
|
|
||||||
RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISMessageBuffer;
|
|
||||||
RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISMessageBuffer;
|
|
||||||
uint32_t Query_Oid = QUERY_Message->Oid;
|
|
||||||
|
|
||||||
void* QueryData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
|
||||||
QUERY_Message->InformationBufferOffset];
|
|
||||||
void* ResponseData = &RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];
|
|
||||||
uint16_t ResponseSize;
|
|
||||||
|
|
||||||
QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
|
||||||
QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);
|
|
||||||
|
|
||||||
if (ProcessNDISQuery(Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
|
|
||||||
ResponseData, &ResponseSize))
|
|
||||||
{
|
|
||||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
|
||||||
QUERY_Response->MessageLength += ResponseSize;
|
|
||||||
|
|
||||||
QUERY_Response->InformationBufferLength = ResponseSize;
|
|
||||||
QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
QUERY_Response->InformationBufferLength = 0;
|
|
||||||
QUERY_Response->InformationBufferOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case REMOTE_NDIS_SET_MSG:
|
|
||||||
/* Request to set a parameter of the adapter, specified as an OID token */
|
|
||||||
|
|
||||||
ResponseReady = true;
|
|
||||||
|
|
||||||
RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISMessageBuffer;
|
|
||||||
RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISMessageBuffer;
|
|
||||||
uint32_t SET_Oid = SET_Message->Oid;
|
|
||||||
|
|
||||||
SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
|
|
||||||
SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);
|
|
||||||
SET_Response->RequestId = SET_Message->RequestId;
|
|
||||||
|
|
||||||
void* SetData = &RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
|
||||||
SET_Message->InformationBufferOffset];
|
|
||||||
|
|
||||||
if (ProcessNDISSet(SET_Oid, SetData, SET_Message->InformationBufferLength))
|
|
||||||
SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
|
||||||
else
|
|
||||||
SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case REMOTE_NDIS_RESET_MSG:
|
|
||||||
/* Soft reset the adapter */
|
|
||||||
|
|
||||||
ResponseReady = true;
|
|
||||||
|
|
||||||
RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISMessageBuffer;
|
|
||||||
|
|
||||||
RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
|
|
||||||
RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);
|
|
||||||
RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
|
||||||
RESET_Response->AddressingReset = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case REMOTE_NDIS_KEEPALIVE_MSG:
|
|
||||||
/* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */
|
|
||||||
|
|
||||||
ResponseReady = true;
|
|
||||||
|
|
||||||
RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISMessageBuffer;
|
|
||||||
RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISMessageBuffer;
|
|
||||||
|
|
||||||
KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
|
|
||||||
KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);
|
|
||||||
KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
|
|
||||||
KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested
|
|
||||||
* parameter is given as an OID value.
|
|
||||||
*
|
|
||||||
* \param OId OId value of the parameter being queried
|
|
||||||
* \param QueryData Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer
|
|
||||||
* \param QuerySize Size in bytes of the extra query data being sent by the host
|
|
||||||
* \param ResponseData Pointer to the start of the query response inside the RNDIS message buffer
|
|
||||||
* \param ResponseSize Pointer to the size in bytes of the response data being sent to the host
|
|
||||||
*
|
|
||||||
* \return Boolean true if the query was handled, false otherwise
|
|
||||||
*/
|
|
||||||
static bool ProcessNDISQuery(uint32_t OId, void* QueryData, uint16_t QuerySize,
|
|
||||||
void* ResponseData, uint16_t* ResponseSize)
|
|
||||||
{
|
|
||||||
/* Handler for REMOTE_NDIS_QUERY_MSG messages */
|
|
||||||
|
|
||||||
switch (OId)
|
|
||||||
{
|
|
||||||
case OID_GEN_SUPPORTED_LIST:
|
|
||||||
*ResponseSize = sizeof(AdapterSupportedOIDList);
|
|
||||||
|
|
||||||
/* Copy the list of supported NDIS OID tokens to the response buffer */
|
|
||||||
memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_PHYSICAL_MEDIUM:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate that the device is a true ethernet link */
|
|
||||||
*((uint32_t*)ResponseData) = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_HARDWARE_STATUS:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Always indicate hardware ready */
|
|
||||||
*((uint32_t*)ResponseData) = NdisHardwareStatusReady;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_MEDIA_SUPPORTED:
|
|
||||||
case OID_GEN_MEDIA_IN_USE:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate 802.3 (Ethernet) supported by the adapter */
|
|
||||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_VENDOR_ID:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
|
|
||||||
*((uint32_t*)ResponseData) = 0x00FFFFFF;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
||||||
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
||||||
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate that the maximum frame size is the size of the ethernet frame buffer */
|
|
||||||
*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_VENDOR_DESCRIPTION:
|
|
||||||
*ResponseSize = sizeof(AdapterVendorDescription);
|
|
||||||
|
|
||||||
/* Copy vendor description string to the response buffer */
|
|
||||||
memcpy_P(ResponseData, AdapterVendorDescription, sizeof(AdapterVendorDescription));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Always indicate that the adapter is connected to a network */
|
|
||||||
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_LINK_SPEED:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate 10Mb/s link speed */
|
|
||||||
*((uint32_t*)ResponseData) = 100000;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_802_3_PERMANENT_ADDRESS:
|
|
||||||
case OID_802_3_CURRENT_ADDRESS:
|
|
||||||
*ResponseSize = sizeof(MAC_Address_t);
|
|
||||||
|
|
||||||
/* Copy over the fixed adapter MAC to the response buffer */
|
|
||||||
memcpy_P(ResponseData, &AdapterMACAddress, sizeof(MAC_Address_t));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate only one multicast address supported */
|
|
||||||
*((uint32_t*)ResponseData) = 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate the current packet filter mask */
|
|
||||||
*((uint32_t*)ResponseData) = CurrPacketFilter;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_XMIT_OK:
|
|
||||||
case OID_GEN_RCV_OK:
|
|
||||||
case OID_GEN_XMIT_ERROR:
|
|
||||||
case OID_GEN_RCV_ERROR:
|
|
||||||
case OID_GEN_RCV_NO_BUFFER:
|
|
||||||
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
||||||
case OID_802_3_XMIT_ONE_COLLISION:
|
|
||||||
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Unused statistic OIDs - always return 0 for each */
|
|
||||||
*((uint32_t*)ResponseData) = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
||||||
*ResponseSize = sizeof(uint32_t);
|
|
||||||
|
|
||||||
/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
|
|
||||||
*((uint32_t*)ResponseData) = (sizeof(RNDISMessageBuffer) + ETHERNET_FRAME_SIZE_MAX);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given
|
|
||||||
* as an OID value.
|
|
||||||
*
|
|
||||||
* \param OId OId value of the parameter being set
|
|
||||||
* \param SetData Pointer to the parameter value in the RNDIS message buffer
|
|
||||||
* \param SetSize Size in bytes of the parameter value being sent by the host
|
|
||||||
*
|
|
||||||
* \return Boolean true if the set was handled, false otherwise
|
|
||||||
*/
|
|
||||||
static bool ProcessNDISSet(uint32_t OId, void* SetData, uint16_t SetSize)
|
|
||||||
{
|
|
||||||
/* Handler for REMOTE_NDIS_SET_MSG messages */
|
|
||||||
|
|
||||||
switch (OId)
|
|
||||||
{
|
|
||||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
||||||
/* Save the packet filter mask in case the host queries it again later */
|
|
||||||
CurrPacketFilter = *((uint32_t*)SetData);
|
|
||||||
|
|
||||||
/* Set the RNDIS state to initialized if the packet filter is non-zero */
|
|
||||||
CurrRNDISState = ((CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_Data_Initialized);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
case OID_802_3_MULTICAST_LIST:
|
|
||||||
/* Do nothing - throw away the value from the host as it is unused */
|
|
||||||
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Audio.h"
|
||||||
|
|
||||||
|
void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_IsSETUPReceived()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if (USB_ControlRequest.wIndex != AudioInterfaceInfo->InterfaceNumber)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
switch (USB_ControlRequest.bRequest)
|
||||||
|
{
|
||||||
|
case REQ_SetInterface:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
AudioInterfaceInfo->InterfaceEnabled = (USB_ControlRequest.wValue != 0);
|
||||||
|
|
||||||
|
while (!(Endpoint_IsINReady()));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (AudioInterfaceInfo->DataINEndpointNumber)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataINEndpointNumber, EP_TYPE_ISOCHRONOUS,
|
||||||
|
ENDPOINT_DIR_IN, AudioInterfaceInfo->DataINEndpointSize,
|
||||||
|
ENDPOINT_BANK_DOUBLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AudioInterfaceInfo->DataOUTEndpointNumber)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS,
|
||||||
|
ENDPOINT_DIR_OUT, AudioInterfaceInfo->DataOUTEndpointSize,
|
||||||
|
ENDPOINT_BANK_DOUBLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t USB_Audio_ReadSample8(void)
|
||||||
|
{
|
||||||
|
int8_t Sample;
|
||||||
|
|
||||||
|
Sample = Endpoint_Read_Byte();
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
return Sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t USB_Audio_ReadSample16(void)
|
||||||
|
{
|
||||||
|
int16_t Sample;
|
||||||
|
|
||||||
|
Sample = (int16_t)Endpoint_Read_Word_LE();
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
return Sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t USB_Audio_ReadSample24(void)
|
||||||
|
{
|
||||||
|
int32_t Sample;
|
||||||
|
|
||||||
|
Sample = (((uint32_t)Endpoint_Read_Byte() << 16) | Endpoint_Read_Word_LE());
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
return Sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_Audio_WriteSample8(int8_t Sample)
|
||||||
|
{
|
||||||
|
Endpoint_Write_Byte(Sample);
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_Audio_WriteSample16(int16_t Sample)
|
||||||
|
{
|
||||||
|
Endpoint_Write_Word_LE(Sample);
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_Audio_WriteSample24(int32_t Sample)
|
||||||
|
{
|
||||||
|
Endpoint_Write_Byte(Sample >> 16);
|
||||||
|
Endpoint_Write_Word_LE(Sample);
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(AudioInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
return Endpoint_IsOUTReceived();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(AudioInterfaceInfo->DataINEndpointNumber);
|
||||||
|
return Endpoint_IsINReady();
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AUDIO_CLASS_H_
|
||||||
|
#define _AUDIO_CLASS_H_
|
||||||
|
|
||||||
|
/* Includes: */
|
||||||
|
#include "../../USB.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Macros: */
|
||||||
|
|
||||||
|
/* Enums: */
|
||||||
|
|
||||||
|
/* Type Defines: */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t InterfaceNumber;
|
||||||
|
|
||||||
|
uint8_t DataINEndpointNumber;
|
||||||
|
uint16_t DataINEndpointSize;
|
||||||
|
|
||||||
|
uint8_t DataOUTEndpointNumber;
|
||||||
|
uint16_t DataOUTEndpointSize;
|
||||||
|
|
||||||
|
bool InterfaceEnabled;
|
||||||
|
} USB_ClassInfo_Audio_t;
|
||||||
|
|
||||||
|
/* Function Prototypes: */
|
||||||
|
bool USB_Audio_ConfigureEndpoints(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||||
|
void USB_Audio_ProcessControlPacket(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||||
|
void USB_Audio_USBTask(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||||
|
|
||||||
|
int8_t USB_Audio_ReadSample8(void);
|
||||||
|
int16_t USB_Audio_ReadSample16(void);
|
||||||
|
int32_t USB_Audio_ReadSample24(void);
|
||||||
|
void USB_Audio_WriteSample8(int8_t Sample);
|
||||||
|
void USB_Audio_WriteSample16(int16_t Sample);
|
||||||
|
void USB_Audio_WriteSample24(int32_t Sample);
|
||||||
|
bool USB_Audio_IsSampleReceived(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||||
|
bool USB_Audio_IsReadyForNextSample(USB_ClassInfo_Audio_t* AudioInterfaceInfo);
|
||||||
|
#endif
|
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INCLUDE_FROM_CDC_CLASS_C
|
||||||
|
#include "CDC.h"
|
||||||
|
|
||||||
|
void USB_CDC_Event_Stub(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_IsSETUPReceived()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (USB_ControlRequest.wIndex != CDCInterfaceInfo->ControlInterfaceNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (USB_ControlRequest.bRequest)
|
||||||
|
{
|
||||||
|
case REQ_GetLineEncoding:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding));
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_SetLineEncoding:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->LineEncoding, sizeof(CDCInterfaceInfo->LineEncoding));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
EVENT_USB_CDC_LineEncodingChanged(CDCInterfaceInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_SetControlLineState:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
CDCInterfaceInfo->ControlLineState = USB_ControlRequest.wValue;
|
||||||
|
|
||||||
|
EVENT_USB_CDC_ControLineStateChanged();
|
||||||
|
|
||||||
|
while (!(Endpoint_IsINReady()));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_IN, CDCInterfaceInfo->DataINEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_OUT, CDCInterfaceInfo->DataOUTEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT,
|
||||||
|
ENDPOINT_DIR_IN, CDCInterfaceInfo->NotificationEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(USB_IsConnected))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
if (!(Endpoint_BytesInEndpoint()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
{
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
while (!(Endpoint_IsReadWriteAllowed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||||
|
Endpoint_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
if (!(Endpoint_IsReadWriteAllowed()))
|
||||||
|
{
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
while (!(Endpoint_IsReadWriteAllowed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_Write_Byte(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
return Endpoint_BytesInEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
uint8_t DataByte = Endpoint_Read_Byte();
|
||||||
|
|
||||||
|
if (!(Endpoint_BytesInEndpoint()))
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
return DataByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(CDCInterfaceInfo->NotificationEndpointNumber);
|
||||||
|
|
||||||
|
USB_Request_Header_t Notification = (USB_Request_Header_t)
|
||||||
|
{
|
||||||
|
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||||
|
.bRequest = NOTIF_SerialState,
|
||||||
|
.wValue = 0,
|
||||||
|
.wIndex = 0,
|
||||||
|
.wLength = sizeof(uint16_t),
|
||||||
|
};
|
||||||
|
|
||||||
|
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);
|
||||||
|
Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask), NO_STREAM_CALLBACK);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CDC_CLASS_H_
|
||||||
|
#define _CDC_CLASS_H_
|
||||||
|
|
||||||
|
/* Includes: */
|
||||||
|
#include "../../USB.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Macros: */
|
||||||
|
/** CDC Class specific request to get the current virtual serial port configuration settings. */
|
||||||
|
#define REQ_GetLineEncoding 0x21
|
||||||
|
|
||||||
|
/** CDC Class specific request to set the current virtual serial port configuration settings. */
|
||||||
|
#define REQ_SetLineEncoding 0x20
|
||||||
|
|
||||||
|
/** CDC Class specific request to set the current virtual serial port handshake line states. */
|
||||||
|
#define REQ_SetControlLineState 0x22
|
||||||
|
|
||||||
|
/** Notification type constant for a change in the virtual serial port handshake line states, for
|
||||||
|
* use with a USB_Notification_Header_t notification structure when sent to the host via the CDC
|
||||||
|
* notification endpoint.
|
||||||
|
*/
|
||||||
|
#define NOTIF_SerialState 0x20
|
||||||
|
|
||||||
|
/** Mask for the DTR handshake line for use with the REQ_SetControlLineState class specific request
|
||||||
|
* from the host, to indicate that the DTR line state should be high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_OUT_DTR (1 << 0)
|
||||||
|
|
||||||
|
/** Mask for the RTS handshake line for use with the REQ_SetControlLineState class specific request
|
||||||
|
* from the host, to indicate that theRTS line state should be high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_OUT_RTS (1 << 1)
|
||||||
|
|
||||||
|
/** Mask for the DCD handshake line for use with the a NOTIF_SerialState class specific notification
|
||||||
|
* from the device to the host, to indicate that the DCD line state is currently high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_DCD (1 << 0)
|
||||||
|
|
||||||
|
/** Mask for the DSR handshake line for use with the a NOTIF_SerialState class specific notification
|
||||||
|
* from the device to the host, to indicate that the DSR line state is currently high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_DSR (1 << 1)
|
||||||
|
|
||||||
|
/** Mask for the BREAK handshake line for use with the a NOTIF_SerialState class specific notification
|
||||||
|
* from the device to the host, to indicate that the BREAK line state is currently high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_BREAK (1 << 2)
|
||||||
|
|
||||||
|
/** Mask for the RING handshake line for use with the a NOTIF_SerialState class specific notification
|
||||||
|
* from the device to the host, to indicate that the RING line state is currently high.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_RING (1 << 3)
|
||||||
|
|
||||||
|
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||||
|
* to indicate that a framing error has occurred on the virtual serial port.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_FRAMEERROR (1 << 4)
|
||||||
|
|
||||||
|
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||||
|
* to indicate that a parity error has occurred on the virtual serial port.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_PARITYERROR (1 << 5)
|
||||||
|
|
||||||
|
/** Mask for use with the a NOTIF_SerialState class specific notification from the device to the host,
|
||||||
|
* to indicate that a data overrun error has occurred on the virtual serial port.
|
||||||
|
*/
|
||||||
|
#define CONTROL_LINE_IN_OVERRUNERROR (1 << 6)
|
||||||
|
|
||||||
|
/** Macro to define a CDC class-specific functional descriptor. CDC functional descriptors have a
|
||||||
|
* uniform structure but variable sized data payloads, thus cannot be represented accurately by
|
||||||
|
* a single typedef struct. A macro is used instead so that functional descriptors can be created
|
||||||
|
* easily by specifying the size of the payload. This allows sizeof() to work correctly.
|
||||||
|
*
|
||||||
|
* \param DataSize Size in bytes of the CDC functional descriptor's data payload
|
||||||
|
*/
|
||||||
|
#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
|
||||||
|
struct \
|
||||||
|
{ \
|
||||||
|
USB_Descriptor_Header_t Header; \
|
||||||
|
uint8_t SubType; \
|
||||||
|
uint8_t Data[DataSize]; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enums: */
|
||||||
|
/** Enum for the possible line encoding formats of a virtual serial port. */
|
||||||
|
enum CDCDevice_CDC_LineCodingFormats_t
|
||||||
|
{
|
||||||
|
OneStopBit = 0, /**< Each frame contains one stop bit */
|
||||||
|
OneAndAHalfStopBits = 1, /**< Each frame contains one and a half stop bits */
|
||||||
|
TwoStopBits = 2, /**< Each frame contains two stop bits */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Enum for the possible line encoding parity settings of a virtual serial port. */
|
||||||
|
enum CDCDevice_LineCodingParity_t
|
||||||
|
{
|
||||||
|
Parity_None = 0, /**< No parity bit mode on each frame */
|
||||||
|
Parity_Odd = 1, /**< Odd parity bit mode on each frame */
|
||||||
|
Parity_Even = 2, /**< Even parity bit mode on each frame */
|
||||||
|
Parity_Mark = 3, /**< Mark parity bit mode on each frame */
|
||||||
|
Parity_Space = 4, /**< Space parity bit mode on each frame */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Type Defines: */
|
||||||
|
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||||
|
* as set by the host via a class specific request.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device */
|
||||||
|
|
||||||
|
uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint */
|
||||||
|
uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint */
|
||||||
|
|
||||||
|
uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint */
|
||||||
|
uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint */
|
||||||
|
|
||||||
|
uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used */
|
||||||
|
uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used */
|
||||||
|
|
||||||
|
uint8_t ControlLineState;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
|
||||||
|
uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the
|
||||||
|
* CDCDevice_CDC_LineCodingFormats_t enum
|
||||||
|
*/
|
||||||
|
uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the
|
||||||
|
* CDCDevice_LineCodingParity_t enum
|
||||||
|
*/
|
||||||
|
uint8_t DataBits; /**< Bits of data per character of the virtual serial port */
|
||||||
|
} LineEncoding;
|
||||||
|
} USB_ClassInfo_CDC_t;
|
||||||
|
|
||||||
|
/* Function Prototypes: */
|
||||||
|
#if defined(INCLUDE_FROM_CDC_CLASS_C)
|
||||||
|
void USB_CDC_Event_Stub(void);
|
||||||
|
void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo)
|
||||||
|
ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);
|
||||||
|
void EVENT_USB_CDC_ControLineStateChanged(void) ATTR_WEAK ATTR_ALIAS(USB_CDC_Event_Stub);;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
bool USB_CDC_ConfigureEndpoints(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
void USB_CDC_ProcessControlPacket(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
void USB_CDC_USBTask(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
|
||||||
|
void EVENT_USB_CDC_LineEncodingChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
void EVENT_USB_CDC_ControLineStateChanged(void);
|
||||||
|
|
||||||
|
void USB_CDC_SendString(USB_ClassInfo_CDC_t* CDCInterfaceInfo, char* Data, uint16_t Length);
|
||||||
|
void USB_CDC_SendByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint8_t Data);
|
||||||
|
uint16_t USB_CDC_BytesReceived(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
uint8_t USB_CDC_ReceiveByte(USB_ClassInfo_CDC_t* CDCInterfaceInfo);
|
||||||
|
void USB_CDC_SendSerialLineStateChanged(USB_ClassInfo_CDC_t* CDCInterfaceInfo, uint16_t LineStateMask);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HID.h"
|
||||||
|
|
||||||
|
void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_IsSETUPReceived()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (USB_ControlRequest.wIndex != HIDInterfaceInfo->InterfaceNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (USB_ControlRequest.bRequest)
|
||||||
|
{
|
||||||
|
case REQ_GetReport:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize];
|
||||||
|
uint16_t ReportINSize;
|
||||||
|
|
||||||
|
memset(ReportINData, 0, sizeof(ReportINData));
|
||||||
|
|
||||||
|
ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData);
|
||||||
|
|
||||||
|
Endpoint_Write_Control_Stream_LE(ReportINData, ReportINSize);
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_SetReport:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
uint16_t ReportOUTSize = USB_ControlRequest.wLength;
|
||||||
|
uint8_t ReportOUTData[ReportOUTSize];
|
||||||
|
|
||||||
|
Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_GetProtocol:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
Endpoint_Write_Byte(HIDInterfaceInfo->UsingReportProtocol);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
while (!(Endpoint_IsOUTReceived()));
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_SetProtocol:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
HIDInterfaceInfo->UsingReportProtocol = (USB_ControlRequest.wValue != 0x0000);
|
||||||
|
|
||||||
|
while (!(Endpoint_IsINReady()));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_SetIdle:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
HIDInterfaceInfo->IdleCount = ((USB_ControlRequest.wValue >> 8) << 2);
|
||||||
|
|
||||||
|
while (!(Endpoint_IsINReady()));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_GetIdle:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
Endpoint_Write_Byte(HIDInterfaceInfo->IdleCount >> 2);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
while (!(Endpoint_IsOUTReceived()));
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||||
|
{
|
||||||
|
HIDInterfaceInfo->UsingReportProtocol = true;
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportINEndpointNumber, EP_TYPE_INTERRUPT,
|
||||||
|
ENDPOINT_DIR_IN, HIDInterfaceInfo->ReportINEndpointSize, ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HIDInterfaceInfo->ReportOUTEndpointNumber)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber, EP_TYPE_INTERRUPT,
|
||||||
|
ENDPOINT_DIR_OUT, HIDInterfaceInfo->ReportOUTEndpointSize, ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (HIDInterfaceInfo->IdleMSRemaining)
|
||||||
|
HIDInterfaceInfo->IdleMSRemaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(USB_IsConnected))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportINEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsReadWriteAllowed() &&
|
||||||
|
!(HIDInterfaceInfo->IdleCount && HIDInterfaceInfo->IdleMSRemaining))
|
||||||
|
{
|
||||||
|
if (HIDInterfaceInfo->IdleCount && !(HIDInterfaceInfo->IdleMSRemaining))
|
||||||
|
HIDInterfaceInfo->IdleMSRemaining = HIDInterfaceInfo->IdleCount;
|
||||||
|
|
||||||
|
uint8_t ReportINData[HIDInterfaceInfo->ReportBufferSize];
|
||||||
|
uint16_t ReportINSize;
|
||||||
|
|
||||||
|
memset(ReportINData, 0, sizeof(ReportINData));
|
||||||
|
|
||||||
|
ReportINSize = CALLBACK_USB_HID_CreateNextHIDReport(HIDInterfaceInfo, ReportINData);
|
||||||
|
|
||||||
|
if (ReportINSize)
|
||||||
|
{
|
||||||
|
Endpoint_Write_Stream_LE(ReportINData, ReportINSize
|
||||||
|
#if !defined(NO_STREAM_CALLBACKS)
|
||||||
|
, NO_STREAM_CALLBACK
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HIDInterfaceInfo->ReportOUTEndpointNumber)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(HIDInterfaceInfo->ReportOUTEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsOUTReceived())
|
||||||
|
{
|
||||||
|
uint16_t ReportOUTSize = Endpoint_BytesInEndpoint();
|
||||||
|
uint8_t ReportOUTData[ReportOUTSize];
|
||||||
|
|
||||||
|
if (ReportOUTSize)
|
||||||
|
{
|
||||||
|
Endpoint_Read_Stream_LE(ReportOUTData, ReportOUTSize
|
||||||
|
#if !defined(NO_STREAM_CALLBACKS)
|
||||||
|
, NO_STREAM_CALLBACK
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK_USB_HID_ProcessReceivedHIDReport(HIDInterfaceInfo, ReportOUTData, ReportOUTSize);
|
||||||
|
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HID_CLASS_H_
|
||||||
|
#define _HID_CLASS_H_
|
||||||
|
|
||||||
|
/* Includes: */
|
||||||
|
#include "../../USB.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Macros: */
|
||||||
|
/** HID Class Specific Request to get the current HID report from the device. */
|
||||||
|
#define REQ_GetReport 0x01
|
||||||
|
|
||||||
|
/** HID Class Specific Request to get the current device idle count. */
|
||||||
|
#define REQ_GetIdle 0x02
|
||||||
|
|
||||||
|
/** HID Class Specific Request to set the current HID report to the device. */
|
||||||
|
#define REQ_SetReport 0x09
|
||||||
|
|
||||||
|
/** HID Class Specific Request to set the device's idle count. */
|
||||||
|
#define REQ_SetIdle 0x0A
|
||||||
|
|
||||||
|
/** HID Class Specific Request to get the current HID report protocol mode. */
|
||||||
|
#define REQ_GetProtocol 0x03
|
||||||
|
|
||||||
|
/** HID Class Specific Request to set the current HID report protocol mode. */
|
||||||
|
#define REQ_SetProtocol 0x0B
|
||||||
|
|
||||||
|
/** Descriptor header type value, to indicate a HID class HID descriptor. */
|
||||||
|
#define DTYPE_HID 0x21
|
||||||
|
|
||||||
|
/** Descriptor header type value, to indicate a HID class HID report descriptor. */
|
||||||
|
#define DTYPE_Report 0x22
|
||||||
|
|
||||||
|
/* Type Defines: */
|
||||||
|
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
|
||||||
|
* specification for details on the structure elements.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
USB_Descriptor_Header_t Header;
|
||||||
|
|
||||||
|
uint16_t HIDSpec;
|
||||||
|
uint8_t CountryCode;
|
||||||
|
|
||||||
|
uint8_t TotalReportDescriptors;
|
||||||
|
|
||||||
|
uint8_t HIDReportType;
|
||||||
|
uint16_t HIDReportLength;
|
||||||
|
} USB_Descriptor_HID_t;
|
||||||
|
|
||||||
|
/** Type define for the data type used to store HID report descriptor elements. */
|
||||||
|
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
|
||||||
|
|
||||||
|
/** Class state structure. An instance of this structure should be made for each HID interface
|
||||||
|
* within the user application, and passed to each of the HID class driver functions as the
|
||||||
|
* HIDInterfaceInfo parameter. The contents of this structure should be set to their correct
|
||||||
|
* values when used, or ommitted to force the library to use default values.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t InterfaceNumber; /**< Interface number of the HID interface within the device */
|
||||||
|
|
||||||
|
uint8_t ReportINEndpointNumber; /**< Endpoint number of the HID interface's IN report endpoint */
|
||||||
|
uint16_t ReportINEndpointSize; /**< Size in bytes of the HID interface's IN report endpoint */
|
||||||
|
|
||||||
|
uint8_t ReportOUTEndpointNumber; /**< Endpoint number of the HID interface's OUT report endpoint, if used */
|
||||||
|
uint16_t ReportOUTEndpointSize; /**< Size in bytes of the HID interface's OUT report endpoint, if used */
|
||||||
|
|
||||||
|
uint8_t ReportBufferSize;
|
||||||
|
|
||||||
|
bool UsingReportProtocol; /**< Indicates if the HID interface is set to Boot or Report protocol mode */
|
||||||
|
uint16_t IdleCount; /**< Report idle period, in ms, set by the host */
|
||||||
|
uint16_t IdleMSRemaining; /**< Total number of ms remaining before the idle period elapses */
|
||||||
|
} USB_ClassInfo_HID_t;
|
||||||
|
|
||||||
|
/* Function Prototypes: */
|
||||||
|
bool USB_HID_ConfigureEndpoints(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||||
|
void USB_HID_ProcessControlPacket(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||||
|
void USB_HID_RegisterStartOfFrame(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||||
|
void USB_HID_USBTask(USB_ClassInfo_HID_t* HIDInterfaceInfo);
|
||||||
|
|
||||||
|
uint16_t CALLBACK_USB_HID_CreateNextHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData);
|
||||||
|
void CALLBACK_USB_HID_ProcessReceivedHIDReport(USB_ClassInfo_HID_t* HIDInterfaceInfo, void* ReportData, uint16_t ReportSize);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INCLUDE_FROM_MS_CLASS_C
|
||||||
|
#include "MassStorage.h"
|
||||||
|
|
||||||
|
static USB_ClassInfo_MS_t* CallbackMSInterfaceInfo;
|
||||||
|
|
||||||
|
void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_IsSETUPReceived()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (USB_ControlRequest.wIndex != MSInterfaceInfo->InterfaceNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (USB_ControlRequest.bRequest)
|
||||||
|
{
|
||||||
|
case REQ_MassStorageReset:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
MSInterfaceInfo->IsMassStoreReset = true;
|
||||||
|
|
||||||
|
while (!(Endpoint_IsINReady()));
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_GetMaxLUN:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
Endpoint_Write_Byte(MSInterfaceInfo->TotalLUNs - 1);
|
||||||
|
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
while (!(Endpoint_IsOUTReceived()));
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_IN, MSInterfaceInfo->DataINEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_OUT, MSInterfaceInfo->DataOUTEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(USB_IsConnected))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsReadWriteAllowed())
|
||||||
|
{
|
||||||
|
if (USB_MS_ReadInCommandBlock(MSInterfaceInfo))
|
||||||
|
{
|
||||||
|
if (MSInterfaceInfo->CommandBlock.Flags & COMMAND_DIRECTION_DATA_IN)
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
MSInterfaceInfo->CommandStatus.Status = CALLBACK_USB_MS_SCSICommandReceived(MSInterfaceInfo) ?
|
||||||
|
Command_Pass : Command_Fail;
|
||||||
|
MSInterfaceInfo->CommandStatus.Signature = CSW_SIGNATURE;
|
||||||
|
MSInterfaceInfo->CommandStatus.Tag = MSInterfaceInfo->CommandBlock.Tag;
|
||||||
|
MSInterfaceInfo->CommandStatus.DataTransferResidue = MSInterfaceInfo->CommandBlock.DataTransferLength;
|
||||||
|
|
||||||
|
if ((MSInterfaceInfo->CommandStatus.Status == Command_Fail) && (MSInterfaceInfo->CommandStatus.DataTransferResidue))
|
||||||
|
Endpoint_StallTransaction();
|
||||||
|
|
||||||
|
USB_MS_ReturnCommandStatus(MSInterfaceInfo);
|
||||||
|
|
||||||
|
if (MSInterfaceInfo->IsMassStoreReset)
|
||||||
|
{
|
||||||
|
Endpoint_ResetFIFO(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
Endpoint_ResetFIFO(MSInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
Endpoint_ClearStall();
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||||
|
Endpoint_ClearStall();
|
||||||
|
|
||||||
|
MSInterfaceInfo->IsMassStoreReset = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||||
|
Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock,
|
||||||
|
(sizeof(CommandBlockWrapper_t) - MAX_SCSI_COMMAND_LENGTH),
|
||||||
|
StreamCallback_AbortOnMassStoreReset);
|
||||||
|
|
||||||
|
if ((MSInterfaceInfo->CommandBlock.Signature != CBW_SIGNATURE) ||
|
||||||
|
(MSInterfaceInfo->CommandBlock.LUN >= MSInterfaceInfo->TotalLUNs) ||
|
||||||
|
(MSInterfaceInfo->CommandBlock.SCSICommandLength > MAX_SCSI_COMMAND_LENGTH))
|
||||||
|
{
|
||||||
|
Endpoint_StallTransaction();
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||||
|
Endpoint_StallTransaction();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||||
|
Endpoint_Read_Stream_LE(&MSInterfaceInfo->CommandBlock.SCSICommandData,
|
||||||
|
MSInterfaceInfo->CommandBlock.SCSICommandLength,
|
||||||
|
StreamCallback_AbortOnMassStoreReset);
|
||||||
|
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
if (MSInterfaceInfo->IsMassStoreReset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo)
|
||||||
|
{
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
while (Endpoint_IsStalled())
|
||||||
|
{
|
||||||
|
USB_USBTask();
|
||||||
|
|
||||||
|
if (MSInterfaceInfo->IsMassStoreReset)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(MSInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
while (Endpoint_IsStalled())
|
||||||
|
{
|
||||||
|
USB_USBTask();
|
||||||
|
|
||||||
|
if (MSInterfaceInfo->IsMassStoreReset)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallbackMSInterfaceInfo = MSInterfaceInfo;
|
||||||
|
Endpoint_Write_Stream_LE(&MSInterfaceInfo->CommandStatus, sizeof(CommandStatusWrapper_t),
|
||||||
|
StreamCallback_AbortOnMassStoreReset);
|
||||||
|
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
if (MSInterfaceInfo->IsMassStoreReset)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t StreamCallback_AbortOnMassStoreReset(void)
|
||||||
|
{
|
||||||
|
USB_MS_USBTask(CallbackMSInterfaceInfo);
|
||||||
|
|
||||||
|
if (CallbackMSInterfaceInfo->IsMassStoreReset)
|
||||||
|
return STREAMCALLBACK_Abort;
|
||||||
|
else
|
||||||
|
return STREAMCALLBACK_Continue;
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MS_CLASS_H_
|
||||||
|
#define _MS_CLASS_H_
|
||||||
|
|
||||||
|
/* Includes: */
|
||||||
|
#include "../../USB.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Macros: */
|
||||||
|
/** Mass Storage Class specific request to reset the Mass Storage interface, ready for the next command. */
|
||||||
|
#define REQ_MassStorageReset 0xFF
|
||||||
|
|
||||||
|
/** Mass Storage Class specific request to retrieve the total number of Logical Units (drives) in the SCSI device. */
|
||||||
|
#define REQ_GetMaxLUN 0xFE
|
||||||
|
|
||||||
|
/** Maximum length of a SCSI command which can be issued by the device or host in a Mass Storage bulk wrapper. */
|
||||||
|
#define MAX_SCSI_COMMAND_LENGTH 16
|
||||||
|
|
||||||
|
/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||||
|
#define CBW_SIGNATURE 0x43425355UL
|
||||||
|
|
||||||
|
/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */
|
||||||
|
#define CSW_SIGNATURE 0x53425355UL
|
||||||
|
|
||||||
|
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */
|
||||||
|
#define COMMAND_DIRECTION_DATA_OUT (0 << 7)
|
||||||
|
|
||||||
|
/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */
|
||||||
|
#define COMMAND_DIRECTION_DATA_IN (1 << 7)
|
||||||
|
|
||||||
|
/* Type defines: */
|
||||||
|
/** Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t Signature; /**< Command block signature, must be CBW_SIGNATURE to indicate a valid Command Block */
|
||||||
|
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||||
|
uint32_t DataTransferLength; /** Length of the optional data portion of the issued command, in bytes */
|
||||||
|
uint8_t Flags; /**< Command block flags, indicating command data direction */
|
||||||
|
uint8_t LUN; /**< Logical Unit number this command is issued to */
|
||||||
|
uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array */
|
||||||
|
uint8_t SCSICommandData[MAX_SCSI_COMMAND_LENGTH]; /**< Issued SCSI command in the Command Block */
|
||||||
|
} CommandBlockWrapper_t;
|
||||||
|
|
||||||
|
/** Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t Signature; /**< Status block signature, must be CSW_SIGNATURE to indicate a valid Command Status */
|
||||||
|
uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper */
|
||||||
|
uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command */
|
||||||
|
uint8_t Status; /**< Status code of the issued command - a value from the MassStorage_CommandStatusCodes_t enum */
|
||||||
|
} CommandStatusWrapper_t;
|
||||||
|
|
||||||
|
/* Enums: */
|
||||||
|
/** Enum for the possible command status wrapper return status codes. */
|
||||||
|
enum MassStorage_CommandStatusCodes_t
|
||||||
|
{
|
||||||
|
Command_Pass = 0, /**< Command completed with no error */
|
||||||
|
Command_Fail = 1, /**< Command failed to complete - host may check the exact error via a SCSI REQUEST SENSE command */
|
||||||
|
Phase_Error = 2 /**< Command failed due to being invalid in the current phase */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Type Defines: */
|
||||||
|
/** Type define for the virtual serial port line encoding settings, for storing the current USART configuration
|
||||||
|
* as set by the host via a class specific request.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t InterfaceNumber; /**< Interface number of the Mass Storage interface within the device */
|
||||||
|
|
||||||
|
uint8_t DataINEndpointNumber; /**< Endpoint number of the Mass Storage interface's IN data endpoint */
|
||||||
|
uint16_t DataINEndpointSize; /**< Size in bytes of the Mass Storage interface's IN data endpoint */
|
||||||
|
|
||||||
|
uint8_t DataOUTEndpointNumber; /**< Endpoint number of the Mass Storage interface's OUT data endpoint */
|
||||||
|
uint16_t DataOUTEndpointSize; /**< Size in bytes of the Mass Storage interface's OUT data endpoint */
|
||||||
|
|
||||||
|
uint8_t TotalLUNs;
|
||||||
|
|
||||||
|
CommandBlockWrapper_t CommandBlock;
|
||||||
|
CommandStatusWrapper_t CommandStatus;
|
||||||
|
|
||||||
|
bool IsMassStoreReset;
|
||||||
|
} USB_ClassInfo_MS_t;
|
||||||
|
|
||||||
|
/* Function Prototypes: */
|
||||||
|
#if defined(INCLUDE_FROM_MS_CLASS_C)
|
||||||
|
static void USB_MS_ReturnCommandStatus(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
static bool USB_MS_ReadInCommandBlock(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
static uint8_t StreamCallback_AbortOnMassStoreReset(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void USB_MS_USBTask(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
bool USB_MS_ConfigureEndpoints(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
void USB_MS_ProcessControlPacket(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
|
||||||
|
bool CALLBACK_USB_MS_SCSICommandReceived(USB_ClassInfo_MS_t* MSInterfaceInfo);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,456 @@
|
|||||||
|
/*
|
||||||
|
LUFA Library
|
||||||
|
Copyright (C) Dean Camera, 2009.
|
||||||
|
|
||||||
|
dean [at] fourwalledcubicle [dot] com
|
||||||
|
www.fourwalledcubicle.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notice appear in all
|
||||||
|
copies and that both that the copyright notice and this
|
||||||
|
permission notice and warranty disclaimer appear in supporting
|
||||||
|
documentation, and that the name of the author not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the
|
||||||
|
software without specific, written prior permission.
|
||||||
|
|
||||||
|
The author disclaim all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability
|
||||||
|
and fitness. In no event shall the author be liable for any
|
||||||
|
special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
in an action of contract, negligence or other tortious action,
|
||||||
|
arising out of or in connection with the use or performance of
|
||||||
|
this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define INCLUDE_FROM_RNDIS_CLASS_C
|
||||||
|
#include "RNDIS.h"
|
||||||
|
|
||||||
|
static const uint32_t PROGMEM AdapterSupportedOIDList[] =
|
||||||
|
{
|
||||||
|
OID_GEN_SUPPORTED_LIST,
|
||||||
|
OID_GEN_PHYSICAL_MEDIUM,
|
||||||
|
OID_GEN_HARDWARE_STATUS,
|
||||||
|
OID_GEN_MEDIA_SUPPORTED,
|
||||||
|
OID_GEN_MEDIA_IN_USE,
|
||||||
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
||||||
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||||
|
OID_GEN_LINK_SPEED,
|
||||||
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
||||||
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
||||||
|
OID_GEN_VENDOR_ID,
|
||||||
|
OID_GEN_VENDOR_DESCRIPTION,
|
||||||
|
OID_GEN_CURRENT_PACKET_FILTER,
|
||||||
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||||||
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
||||||
|
OID_GEN_XMIT_OK,
|
||||||
|
OID_GEN_RCV_OK,
|
||||||
|
OID_GEN_XMIT_ERROR,
|
||||||
|
OID_GEN_RCV_ERROR,
|
||||||
|
OID_GEN_RCV_NO_BUFFER,
|
||||||
|
OID_802_3_PERMANENT_ADDRESS,
|
||||||
|
OID_802_3_CURRENT_ADDRESS,
|
||||||
|
OID_802_3_MULTICAST_LIST,
|
||||||
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
||||||
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
||||||
|
OID_802_3_XMIT_ONE_COLLISION,
|
||||||
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
||||||
|
};
|
||||||
|
|
||||||
|
void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_IsSETUPReceived()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->ControlInterfaceNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (USB_ControlRequest.bRequest)
|
||||||
|
{
|
||||||
|
case REQ_SendEncapsulatedCommand:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, USB_ControlRequest.wLength);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
USB_RNDIS_ProcessRNDISControlMessage(RNDISInterfaceInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REQ_GetEncapsulatedResponse:
|
||||||
|
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
|
||||||
|
{
|
||||||
|
Endpoint_ClearSETUP();
|
||||||
|
|
||||||
|
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
if (!(MessageHeader->MessageLength))
|
||||||
|
{
|
||||||
|
RNDISInterfaceInfo->RNDISMessageBuffer[0] = 0;
|
||||||
|
MessageHeader->MessageLength = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, MessageHeader->MessageLength);
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
MessageHeader->MessageLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_IN, RNDISInterfaceInfo->DataINEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,
|
||||||
|
ENDPOINT_DIR_OUT, RNDISInterfaceInfo->DataOUTEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT,
|
||||||
|
ENDPOINT_DIR_IN, RNDISInterfaceInfo->NotificationEndpointSize,
|
||||||
|
ENDPOINT_BANK_SINGLE)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (!(USB_IsConnected))
|
||||||
|
return;
|
||||||
|
|
||||||
|
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsINReady() && RNDISInterfaceInfo->ResponseReady)
|
||||||
|
{
|
||||||
|
USB_Request_Header_t Notification = (USB_Request_Header_t)
|
||||||
|
{
|
||||||
|
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||||
|
.bRequest = NOTIF_ResponseAvailable,
|
||||||
|
.wValue = 0,
|
||||||
|
.wIndex = 0,
|
||||||
|
.wLength = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);
|
||||||
|
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->ResponseReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((RNDISInterfaceInfo->CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
|
||||||
|
{
|
||||||
|
RNDIS_PACKET_MSG_t RNDISPacketHeader;
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->FrameIN.FrameInBuffer))
|
||||||
|
{
|
||||||
|
Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);
|
||||||
|
|
||||||
|
if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
|
||||||
|
{
|
||||||
|
Endpoint_StallTransaction();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_Read_Stream_LE(RNDISInterfaceInfo->FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
|
||||||
|
|
||||||
|
Endpoint_ClearOUT();
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->FrameIN.FrameLength = RNDISPacketHeader.DataLength;
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->FrameIN.FrameInBuffer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataINEndpointNumber);
|
||||||
|
|
||||||
|
if (Endpoint_IsINReady() && RNDISInterfaceInfo->FrameOUT.FrameInBuffer)
|
||||||
|
{
|
||||||
|
memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t));
|
||||||
|
|
||||||
|
RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;
|
||||||
|
RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->FrameOUT.FrameLength);
|
||||||
|
RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t));
|
||||||
|
RNDISPacketHeader.DataLength = RNDISInterfaceInfo->FrameOUT.FrameLength;
|
||||||
|
|
||||||
|
Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);
|
||||||
|
Endpoint_Write_Stream_LE(RNDISInterfaceInfo->FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
|
||||||
|
Endpoint_ClearIN();
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->FrameOUT.FrameInBuffer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)
|
||||||
|
{
|
||||||
|
/* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
|
||||||
|
this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
|
||||||
|
|
||||||
|
RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
switch (MessageHeader->MessageType)
|
||||||
|
{
|
||||||
|
case REMOTE_NDIS_INITIALIZE_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = true;
|
||||||
|
|
||||||
|
RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
|
||||||
|
INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);
|
||||||
|
INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
|
||||||
|
INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
|
||||||
|
INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
|
||||||
|
INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
|
||||||
|
INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
|
||||||
|
INITIALIZE_Response->MaxPacketsPerTransfer = 1;
|
||||||
|
INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);
|
||||||
|
INITIALIZE_Response->PacketAlignmentFactor = 0;
|
||||||
|
INITIALIZE_Response->AFListOffset = 0;
|
||||||
|
INITIALIZE_Response->AFListSize = 0;
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->CurrRNDISState = RNDIS_Initialized;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REMOTE_NDIS_HALT_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = false;
|
||||||
|
MessageHeader->MessageLength = 0;
|
||||||
|
|
||||||
|
RNDISInterfaceInfo->CurrRNDISState = RNDIS_Uninitialized;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REMOTE_NDIS_QUERY_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = true;
|
||||||
|
|
||||||
|
RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
uint32_t Query_Oid = QUERY_Message->Oid;
|
||||||
|
|
||||||
|
void* QueryData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||||
|
QUERY_Message->InformationBufferOffset];
|
||||||
|
void* ResponseData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)];
|
||||||
|
uint16_t ResponseSize;
|
||||||
|
|
||||||
|
QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
|
||||||
|
QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);
|
||||||
|
|
||||||
|
if (USB_RNDIS_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
|
||||||
|
ResponseData, &ResponseSize))
|
||||||
|
{
|
||||||
|
QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||||
|
QUERY_Response->MessageLength += ResponseSize;
|
||||||
|
|
||||||
|
QUERY_Response->InformationBufferLength = ResponseSize;
|
||||||
|
QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
QUERY_Response->InformationBufferLength = 0;
|
||||||
|
QUERY_Response->InformationBufferOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REMOTE_NDIS_SET_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = true;
|
||||||
|
|
||||||
|
RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
uint32_t SET_Oid = SET_Message->Oid;
|
||||||
|
|
||||||
|
SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
|
||||||
|
SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);
|
||||||
|
SET_Response->RequestId = SET_Message->RequestId;
|
||||||
|
|
||||||
|
void* SetData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
|
||||||
|
SET_Message->InformationBufferOffset];
|
||||||
|
|
||||||
|
if (USB_RNDIS_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength))
|
||||||
|
SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||||
|
else
|
||||||
|
SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REMOTE_NDIS_RESET_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = true;
|
||||||
|
|
||||||
|
RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
|
||||||
|
RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);
|
||||||
|
RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||||
|
RESET_Response->AddressingReset = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case REMOTE_NDIS_KEEPALIVE_MSG:
|
||||||
|
RNDISInterfaceInfo->ResponseReady = true;
|
||||||
|
|
||||||
|
RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;
|
||||||
|
|
||||||
|
KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
|
||||||
|
KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);
|
||||||
|
KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
|
||||||
|
KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo,
|
||||||
|
uint32_t OId, void* QueryData, uint16_t QuerySize,
|
||||||
|
void* ResponseData, uint16_t* ResponseSize)
|
||||||
|
{
|
||||||
|
switch (OId)
|
||||||
|
{
|
||||||
|
case OID_GEN_SUPPORTED_LIST:
|
||||||
|
*ResponseSize = sizeof(AdapterSupportedOIDList);
|
||||||
|
|
||||||
|
memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_PHYSICAL_MEDIUM:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Indicate that the device is a true ethernet link */
|
||||||
|
*((uint32_t*)ResponseData) = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_HARDWARE_STATUS:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
*((uint32_t*)ResponseData) = NdisHardwareStatusReady;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_MEDIA_SUPPORTED:
|
||||||
|
case OID_GEN_MEDIA_IN_USE:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_VENDOR_ID:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
|
||||||
|
*((uint32_t*)ResponseData) = 0x00FFFFFF;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
||||||
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
||||||
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
*((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_VENDOR_DESCRIPTION:
|
||||||
|
*ResponseSize = (strlen(RNDISInterfaceInfo->AdapterVendorDescription) + 1);
|
||||||
|
|
||||||
|
memcpy(ResponseData, RNDISInterfaceInfo->AdapterVendorDescription, *ResponseSize);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
*((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_LINK_SPEED:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Indicate 10Mb/s link speed */
|
||||||
|
*((uint32_t*)ResponseData) = 100000;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_802_3_PERMANENT_ADDRESS:
|
||||||
|
case OID_802_3_CURRENT_ADDRESS:
|
||||||
|
*ResponseSize = sizeof(MAC_Address_t);
|
||||||
|
|
||||||
|
memcpy(ResponseData, &RNDISInterfaceInfo->AdapterMACAddress, sizeof(MAC_Address_t));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Indicate only one multicast address supported */
|
||||||
|
*((uint32_t*)ResponseData) = 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
*((uint32_t*)ResponseData) = RNDISInterfaceInfo->CurrPacketFilter;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_XMIT_OK:
|
||||||
|
case OID_GEN_RCV_OK:
|
||||||
|
case OID_GEN_XMIT_ERROR:
|
||||||
|
case OID_GEN_RCV_ERROR:
|
||||||
|
case OID_GEN_RCV_NO_BUFFER:
|
||||||
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
||||||
|
case OID_802_3_XMIT_ONE_COLLISION:
|
||||||
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Unused statistic OIDs - always return 0 for each */
|
||||||
|
*((uint32_t*)ResponseData) = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
||||||
|
*ResponseSize = sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
|
||||||
|
*((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, uint16_t SetSize)
|
||||||
|
{
|
||||||
|
switch (OId)
|
||||||
|
{
|
||||||
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||||
|
RNDISInterfaceInfo->CurrPacketFilter = *((uint32_t*)SetData);
|
||||||
|
RNDISInterfaceInfo->CurrRNDISState = ((RNDISInterfaceInfo->CurrPacketFilter) ?
|
||||||
|
RNDIS_Data_Initialized : RNDIS_Data_Initialized);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case OID_802_3_MULTICAST_LIST:
|
||||||
|
/* Do nothing - throw away the value from the host as it is unused */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1,226 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2009.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.fourwalledcubicle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software
|
|
||||||
and its documentation for any purpose and without fee is hereby
|
|
||||||
granted, provided that the above copyright notice appear in all
|
|
||||||
copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define INCLUDE_FROM_DYNALLOC_C
|
|
||||||
#include "DynAlloc.h"
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char Mem_Heap[NUM_BLOCKS * BLOCK_SIZE];
|
|
||||||
void* Mem_Handles[NUM_HANDLES];
|
|
||||||
uint8_t Mem_Block_Flags[(NUM_BLOCKS / 4) + ((NUM_BLOCKS % 4) ? 1 : 0)];
|
|
||||||
uint8_t FlagMaskLookupMask[4];
|
|
||||||
uint8_t FlagMaskLookupNum[4];
|
|
||||||
} Mem_MemData = {.FlagMaskLookupMask = {(3 << 0), (3 << 2), (3 << 4), (3 << 6)},
|
|
||||||
.FlagMaskLookupNum = { 0, 2, 4, 6}};
|
|
||||||
|
|
||||||
static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum)
|
|
||||||
{
|
|
||||||
const Block_Number_t BlockIndex = (BlockNum >> 2);
|
|
||||||
const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03];
|
|
||||||
const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03];
|
|
||||||
|
|
||||||
return ((Mem_MemData.Mem_Block_Flags[BlockIndex] & FlagMask) >> FlagMaskShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags)
|
|
||||||
{
|
|
||||||
const Block_Number_t BlockIndex = (BlockNum >> 2);
|
|
||||||
const uint8_t FlagMask = Mem_MemData.FlagMaskLookupMask[BlockNum & 0x03];
|
|
||||||
const uint8_t FlagMaskShift = Mem_MemData.FlagMaskLookupNum[BlockNum & 0x03];
|
|
||||||
|
|
||||||
Mem_MemData.Mem_Block_Flags[BlockIndex] &= ~FlagMask;
|
|
||||||
Mem_MemData.Mem_Block_Flags[BlockIndex] |= (Flags << FlagMaskShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void Mem_Defrag(void)
|
|
||||||
{
|
|
||||||
Block_Number_t FreeStartBlock = 0;
|
|
||||||
char* FreeStartPtr = NULL;
|
|
||||||
char* UsedStartPtr = NULL;
|
|
||||||
Block_Number_t CurrBlock;
|
|
||||||
|
|
||||||
for (CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
|
||||||
{
|
|
||||||
if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK))
|
|
||||||
{
|
|
||||||
FreeStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE];
|
|
||||||
FreeStartBlock = CurrBlock;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FreeStartPtr == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (++CurrBlock < NUM_BLOCKS)
|
|
||||||
{
|
|
||||||
uint8_t CurrBlockFlags = Mem_GetBlockFlags(CurrBlock);
|
|
||||||
|
|
||||||
if (CurrBlockFlags & BLOCK_USED_MASK)
|
|
||||||
{
|
|
||||||
UsedStartPtr = &Mem_MemData.Mem_Heap[CurrBlock * BLOCK_SIZE];
|
|
||||||
|
|
||||||
for (Handle_Number_t HandleNum = 0; HandleNum < NUM_HANDLES; HandleNum++)
|
|
||||||
{
|
|
||||||
if (Mem_MemData.Mem_Handles[HandleNum] == UsedStartPtr)
|
|
||||||
{
|
|
||||||
Mem_MemData.Mem_Handles[HandleNum] = FreeStartPtr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(FreeStartPtr, UsedStartPtr, BLOCK_SIZE);
|
|
||||||
FreeStartPtr += BLOCK_SIZE;
|
|
||||||
|
|
||||||
Mem_SetBlockFlags(FreeStartBlock++, CurrBlockFlags);
|
|
||||||
Mem_SetBlockFlags(CurrBlock, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool Mem_FindFreeBlocks(Block_Number_t* const RetStartPtr, const Block_Number_t Blocks)
|
|
||||||
{
|
|
||||||
Block_Number_t FreeInCurrSec = 0;
|
|
||||||
|
|
||||||
for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
|
||||||
{
|
|
||||||
if (Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK)
|
|
||||||
FreeInCurrSec = 0;
|
|
||||||
else
|
|
||||||
FreeInCurrSec++;
|
|
||||||
|
|
||||||
if (FreeInCurrSec >= Blocks)
|
|
||||||
{
|
|
||||||
*RetStartPtr = CurrBlock;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes)
|
|
||||||
{
|
|
||||||
Block_Number_t ReqBlocks = (Bytes / BLOCK_SIZE);
|
|
||||||
Block_Number_t StartBlock;
|
|
||||||
|
|
||||||
if (Bytes % BLOCK_SIZE)
|
|
||||||
ReqBlocks++;
|
|
||||||
|
|
||||||
if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks)))
|
|
||||||
{
|
|
||||||
Mem_Defrag();
|
|
||||||
|
|
||||||
if (!(Mem_FindFreeBlocks(&StartBlock, ReqBlocks)))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Block_Number_t UsedBlock = 0; UsedBlock < (ReqBlocks - 1); UsedBlock++)
|
|
||||||
Mem_SetBlockFlags((StartBlock + UsedBlock), (BLOCK_USED_MASK | BLOCK_LINKED_MASK));
|
|
||||||
|
|
||||||
Mem_SetBlockFlags((StartBlock + (ReqBlocks - 1)), BLOCK_USED_MASK);
|
|
||||||
|
|
||||||
for (Handle_Number_t AllocEntry = 0; AllocEntry < NUM_HANDLES; AllocEntry++)
|
|
||||||
{
|
|
||||||
Mem_Handle_t CurrHdl = (Mem_Handle_t)&Mem_MemData.Mem_Handles[AllocEntry];
|
|
||||||
|
|
||||||
if (DEREF(CurrHdl, void*) == NULL)
|
|
||||||
{
|
|
||||||
DEREF(CurrHdl, void*) = &Mem_MemData.Mem_Heap[StartBlock * BLOCK_SIZE];
|
|
||||||
return CurrHdl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes)
|
|
||||||
{
|
|
||||||
Mem_Free(CurrAllocHdl);
|
|
||||||
return Mem_Alloc(Bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes)
|
|
||||||
{
|
|
||||||
Mem_Handle_t AllocHdl = Mem_Alloc(Bytes);
|
|
||||||
|
|
||||||
if (AllocHdl != NULL)
|
|
||||||
memset(DEREF(AllocHdl, void*), 0x00, Bytes);
|
|
||||||
|
|
||||||
return AllocHdl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mem_Free(Mem_Handle_t CurrAllocHdl)
|
|
||||||
{
|
|
||||||
char* MemBlockPtr = DEREF(CurrAllocHdl, char*);
|
|
||||||
Block_Number_t CurrBlock = ((uint16_t)(MemBlockPtr - Mem_MemData.Mem_Heap) / BLOCK_SIZE);
|
|
||||||
uint8_t CurrBlockFlags;
|
|
||||||
|
|
||||||
if ((CurrAllocHdl == NULL) || (MemBlockPtr == NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
CurrBlockFlags = Mem_GetBlockFlags(CurrBlock);
|
|
||||||
Mem_SetBlockFlags(CurrBlock, 0);
|
|
||||||
|
|
||||||
CurrBlock++;
|
|
||||||
}
|
|
||||||
while (CurrBlockFlags & BLOCK_LINKED_MASK);
|
|
||||||
|
|
||||||
DEREF(CurrAllocHdl, void*) = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block_Number_t Mem_TotalFreeBlocks(void)
|
|
||||||
{
|
|
||||||
Block_Number_t FreeBlocks = 0;
|
|
||||||
|
|
||||||
for (Block_Number_t CurrBlock = 0; CurrBlock < NUM_BLOCKS; CurrBlock++)
|
|
||||||
{
|
|
||||||
if (!(Mem_GetBlockFlags(CurrBlock) & BLOCK_USED_MASK))
|
|
||||||
FreeBlocks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FreeBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle_Number_t Mem_TotalFreeHandles(void)
|
|
||||||
{
|
|
||||||
Handle_Number_t FreeHandles = 0;
|
|
||||||
|
|
||||||
for (Handle_Number_t CurrHandle = 0; CurrHandle < NUM_HANDLES; CurrHandle++)
|
|
||||||
{
|
|
||||||
if (Mem_MemData.Mem_Handles[CurrHandle] == NULL)
|
|
||||||
FreeHandles++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FreeHandles;
|
|
||||||
}
|
|
@ -1,198 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2009.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.fourwalledcubicle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software
|
|
||||||
and its documentation for any purpose and without fee is hereby
|
|
||||||
granted, provided that the above copyright notice appear in all
|
|
||||||
copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for
|
|
||||||
* the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the
|
|
||||||
* management memory overhead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup Group_MemoryAllocator Dynamic Block Memory Allocator - LUFA/MemoryAllocator/DynAlloc.h
|
|
||||||
*
|
|
||||||
* \section Sec_Dependencies Module Source Dependencies
|
|
||||||
* The following files must be built with any user project that uses this module:
|
|
||||||
* - LUFA/MemoryAllocator/DynAlloc.c
|
|
||||||
*
|
|
||||||
* \section Module Description
|
|
||||||
* Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for
|
|
||||||
* the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the
|
|
||||||
* management memory overhead.
|
|
||||||
*
|
|
||||||
* Unlike the normal memory allocation routines, this library gives out handles to memory which must be dereferenced
|
|
||||||
* at the exact time of use, rather than handing back direct memory pointers. By using library managed handles
|
|
||||||
* instead of pointers, allocated memory blocks can be shifted around as needed transparently to defragment the
|
|
||||||
* memory as more blocks are requested.
|
|
||||||
*
|
|
||||||
* The memory heap is static, thus the total memory usage of the compiled application (as reported by the avr-size
|
|
||||||
* tool of the AVR-GCC toolchain) includes the dynamic memory heap.
|
|
||||||
*
|
|
||||||
* The constants NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined in the project makefile (and passed to the
|
|
||||||
* preprocessor via the -D GCC switch) for this library to compile.
|
|
||||||
*
|
|
||||||
* NUM_BLOCKS indicates the number of memory blocks in the memory psudoheap which can be chained together and handed
|
|
||||||
* to the application via a memory handle. NUM_HANDLES is the maximum number of memory handles (pointing to one or
|
|
||||||
* more chained memory blocks) which can be handed out simultaneously before requiring a handle (and its associated
|
|
||||||
* memory) to be freed. BLOCK_SIZE gives the number of bytes in each memory block.
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DYN_ALLOC__
|
|
||||||
#define __DYN_ALLOC__
|
|
||||||
|
|
||||||
/* Includes : */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Preprocessor Checks: */
|
|
||||||
#if (!defined(NUM_BLOCKS) || !defined(BLOCK_SIZE) || !defined(NUM_HANDLES))
|
|
||||||
#error NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined before use via makefile.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Public Interface - May be used in end-application: */
|
|
||||||
/* Macros: */
|
|
||||||
/** Macro to dereference a given memory handle into the given type. The given type should be a pointer
|
|
||||||
* if the memory is to contain an array of items, or should be a standard type (such as a primitive or
|
|
||||||
* structure) if the memory is to hold a single item of a single type. */
|
|
||||||
#define DEREF(handle, type) (*(type*)handle)
|
|
||||||
|
|
||||||
/** Constant, giving the total heap size in bytes. */
|
|
||||||
#define ALLOCABLE_BYTES (1UL * NUM_BLOCKS * BLOCK_SIZE)
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Memory handle type, used to store handles given by the library functions. */
|
|
||||||
typedef const void** Mem_Handle_t;
|
|
||||||
|
|
||||||
#if (ALLOCABLE_BYTES > 0xFFFF) || defined(__DOXYGEN__)
|
|
||||||
/** Type define for the size (in bytes) for an allocation for passing to the library functions.
|
|
||||||
* The exact type width varies depending on the value of ALLOCABLE_BYTES to ensure that a single
|
|
||||||
* allocation can request the entire heap if needed.
|
|
||||||
*/
|
|
||||||
typedef uint32_t Alloc_Size_t;
|
|
||||||
#elif (ALLOCABLE_BYTES > 0xFF)
|
|
||||||
typedef uint16_t Alloc_Size_t;
|
|
||||||
#else
|
|
||||||
typedef uint8_t Alloc_Size_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (NUM_BLOCKS > 0xFFFF) || defined(__DOXYGEN__)
|
|
||||||
/** Type define for a block number in the heap. The exact type width varies depending on the
|
|
||||||
* value of NUM_BLOCKS to ensure that the type can store an index to any block in the block pool.
|
|
||||||
*/
|
|
||||||
typedef uint32_t Block_Number_t;
|
|
||||||
#elif (NUM_BLOCKS > 0xFF)
|
|
||||||
typedef uint16_t Block_Number_t;
|
|
||||||
#else
|
|
||||||
typedef uint8_t Block_Number_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (NUM_HANDLES > 0xFFFF) || defined(__DOXYGEN__)
|
|
||||||
/** Type define for a handle number. The exact type width varies depending on the value of NUM_HANDLES
|
|
||||||
* to ensure that the type can store the index of any handle in the handle pool.
|
|
||||||
*/
|
|
||||||
typedef uint32_t Handle_Number_t;
|
|
||||||
#elif (NUM_HANDLES > 0xFF)
|
|
||||||
typedef uint16_t Handle_Number_t;
|
|
||||||
#else
|
|
||||||
typedef uint8_t Handle_Number_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
|
|
||||||
* returns a handle to the newly allocated memory.
|
|
||||||
*
|
|
||||||
* \param Bytes The number of bytes requested to be allocated from the heap
|
|
||||||
*
|
|
||||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
|
||||||
*/
|
|
||||||
Mem_Handle_t Mem_Alloc(const Alloc_Size_t Bytes);
|
|
||||||
|
|
||||||
/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
|
|
||||||
* returns a handle to the newly allocated memory. Calloced memory is automatically cleared to all 0x00
|
|
||||||
* values at the time of allocation.
|
|
||||||
*
|
|
||||||
* \param Bytes The number of pre-cleared bytes requested to be allocated from the heap
|
|
||||||
*
|
|
||||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
|
||||||
*/
|
|
||||||
Mem_Handle_t Mem_Calloc(const Alloc_Size_t Bytes);
|
|
||||||
|
|
||||||
/** Deallocates a given memory handle, and attempts to allocates the given number of blocks from the heap
|
|
||||||
* (calculated from the requested number of bytes) immediately following the deallocation. The new memory
|
|
||||||
* may be located in the same area as the previous memory, but this is not guaranteed.
|
|
||||||
*
|
|
||||||
* \param CurrAllocHdl Handle to an already allocated section of memory in the heap to deallocate
|
|
||||||
* \param Bytes The number of bytes requested to be allocated from the heap following the
|
|
||||||
* deallocation
|
|
||||||
*
|
|
||||||
* \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
|
|
||||||
*
|
|
||||||
* \warning Even if the allocation fails, the deallocation will still occur. Care should be taken to ensure
|
|
||||||
* that the previously allocated memory is not used following an unsuccessful realloc().
|
|
||||||
*/
|
|
||||||
Mem_Handle_t Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes);
|
|
||||||
|
|
||||||
/** Deallocates a given previously allocated section of memory from the heap.
|
|
||||||
*
|
|
||||||
* \param CurrAllocHdl Handle to a previously allocated section of memory in the heap
|
|
||||||
*/
|
|
||||||
void Mem_Free(Mem_Handle_t CurrAllocHdl);
|
|
||||||
|
|
||||||
/** Returns the total number of unallocated blocks in the heap.
|
|
||||||
*
|
|
||||||
* \return Number of free blocks in the heap, as a Block_Number_t integer
|
|
||||||
*/
|
|
||||||
Block_Number_t Mem_TotalFreeBlocks(void);
|
|
||||||
|
|
||||||
/** Returns the total number of unallocated handles in the handle pool.
|
|
||||||
*
|
|
||||||
* \return Number of free handles in the handle pool, as a Handle_Number_t integer
|
|
||||||
*/
|
|
||||||
Handle_Number_t Mem_TotalFreeHandles(void);
|
|
||||||
|
|
||||||
/* Private Interface - For use in library only: */
|
|
||||||
#if !defined(__DOXYGEN__)
|
|
||||||
/* Macros: */
|
|
||||||
#define BLOCK_USED_MASK (1 << 0)
|
|
||||||
#define BLOCK_LINKED_MASK (1 << 1)
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
#if defined(INCLUDE_FROM_DYNALLOC_C)
|
|
||||||
static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum);
|
|
||||||
static void Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags);
|
|
||||||
static void Mem_Defrag(void);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @} */
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2009.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.fourwalledcubicle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software
|
|
||||||
and its documentation for any purpose and without fee is hereby
|
|
||||||
granted, provided that the above copyright notice appear in all
|
|
||||||
copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Scheduler.h"
|
|
||||||
|
|
||||||
volatile SchedulerDelayCounter_t Scheduler_TickCounter;
|
|
||||||
volatile uint8_t Scheduler_TotalTasks;
|
|
||||||
|
|
||||||
bool Scheduler_HasDelayElapsed(const uint16_t Delay, SchedulerDelayCounter_t* const DelayCounter)
|
|
||||||
{
|
|
||||||
SchedulerDelayCounter_t CurrentTickValue_LCL;
|
|
||||||
SchedulerDelayCounter_t DelayCounter_LCL;
|
|
||||||
|
|
||||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
|
||||||
{
|
|
||||||
CurrentTickValue_LCL = Scheduler_TickCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
DelayCounter_LCL = *DelayCounter;
|
|
||||||
|
|
||||||
if (CurrentTickValue_LCL >= DelayCounter_LCL)
|
|
||||||
{
|
|
||||||
if ((CurrentTickValue_LCL - DelayCounter_LCL) >= Delay)
|
|
||||||
{
|
|
||||||
*DelayCounter = CurrentTickValue_LCL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (((MAX_DELAYCTR_COUNT - DelayCounter_LCL) + CurrentTickValue_LCL) >= Delay)
|
|
||||||
{
|
|
||||||
*DelayCounter = CurrentTickValue_LCL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus)
|
|
||||||
{
|
|
||||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
|
||||||
|
|
||||||
while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks])
|
|
||||||
{
|
|
||||||
if (CurrTask->Task == Task)
|
|
||||||
{
|
|
||||||
CurrTask->TaskStatus = TaskStatus;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrTask++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus)
|
|
||||||
{
|
|
||||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
|
||||||
|
|
||||||
while (CurrTask != &Scheduler_TaskList[Scheduler_TotalTasks])
|
|
||||||
{
|
|
||||||
if (CurrTask->GroupID == GroupID)
|
|
||||||
CurrTask->TaskStatus = TaskStatus;
|
|
||||||
|
|
||||||
CurrTask++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,285 +0,0 @@
|
|||||||
/*
|
|
||||||
LUFA Library
|
|
||||||
Copyright (C) Dean Camera, 2009.
|
|
||||||
|
|
||||||
dean [at] fourwalledcubicle [dot] com
|
|
||||||
www.fourwalledcubicle.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software
|
|
||||||
and its documentation for any purpose and without fee is hereby
|
|
||||||
granted, provided that the above copyright notice appear in all
|
|
||||||
copies and that both that the copyright notice and this
|
|
||||||
permission notice and warranty disclaimer appear in supporting
|
|
||||||
documentation, and that the name of the author not be used in
|
|
||||||
advertising or publicity pertaining to distribution of the
|
|
||||||
software without specific, written prior permission.
|
|
||||||
|
|
||||||
The author disclaim all warranties with regard to this
|
|
||||||
software, including all implied warranties of merchantability
|
|
||||||
and fitness. In no event shall the author be liable for any
|
|
||||||
special, indirect or consequential damages or any damages
|
|
||||||
whatsoever resulting from loss of use, data or profits, whether
|
|
||||||
in an action of contract, negligence or other tortious action,
|
|
||||||
arising out of or in connection with the use or performance of
|
|
||||||
this software.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need
|
|
||||||
* to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h
|
|
||||||
*
|
|
||||||
* \section Sec_Dependencies Module Source Dependencies
|
|
||||||
* The following files must be built with any user project that uses this module:
|
|
||||||
* - LUFA/Scheduler/Scheduler.c
|
|
||||||
*
|
|
||||||
* \section Module Description
|
|
||||||
* Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need
|
|
||||||
* to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group.
|
|
||||||
*
|
|
||||||
* For a task to yield it must return, thus each task should have persistent data marked with the static attribute.
|
|
||||||
*
|
|
||||||
* Usage Example:
|
|
||||||
* \code
|
|
||||||
* #include <LUFA/Scheduler/Scheduler.h>
|
|
||||||
*
|
|
||||||
* TASK(MyTask1);
|
|
||||||
* TASK(MyTask2);
|
|
||||||
*
|
|
||||||
* TASK_LIST
|
|
||||||
* {
|
|
||||||
* { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
|
||||||
* { .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* int main(void)
|
|
||||||
* {
|
|
||||||
* Scheduler_Start();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* TASK(MyTask1)
|
|
||||||
* {
|
|
||||||
* // Implementation Here
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* TASK(MyTask2)
|
|
||||||
* {
|
|
||||||
* // Implementation Here
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SCHEDULER_H__
|
|
||||||
#define __SCHEDULER_H__
|
|
||||||
|
|
||||||
/* Includes: */
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <util/atomic.h>
|
|
||||||
|
|
||||||
#include "../Common/Common.h"
|
|
||||||
|
|
||||||
/* Enable C linkage for C++ Compilers: */
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Public Interface - May be used in end-application: */
|
|
||||||
/* Macros: */
|
|
||||||
/** Creates a new scheduler task body or prototype. Should be used in the form:
|
|
||||||
* \code
|
|
||||||
* TASK(TaskName); // Prototype
|
|
||||||
*
|
|
||||||
* TASK(TaskName)
|
|
||||||
* {
|
|
||||||
* // Task body
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
#define TASK(name) void name (void)
|
|
||||||
|
|
||||||
/** Defines a task list array, containing one or more task entries of the type TaskEntry_t. Each task list
|
|
||||||
* should be encased in curly braces and ended with a comma.
|
|
||||||
*
|
|
||||||
* Usage Example:
|
|
||||||
* \code
|
|
||||||
* TASK_LIST
|
|
||||||
* {
|
|
||||||
* { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 },
|
|
||||||
* // More task entries here
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
#define TASK_LIST TaskEntry_t Scheduler_TaskList[] =
|
|
||||||
|
|
||||||
/** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type
|
|
||||||
* SchedulerDelayCounter_t.
|
|
||||||
*/
|
|
||||||
#define TASK_MAX_DELAY (MAX_DELAYCTR_COUNT - 1)
|
|
||||||
|
|
||||||
/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */
|
|
||||||
#define TASK_RUN true
|
|
||||||
|
|
||||||
/** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */
|
|
||||||
#define TASK_STOP false
|
|
||||||
|
|
||||||
/* Pseudo-Function Macros: */
|
|
||||||
#if defined(__DOXYGEN__)
|
|
||||||
/** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end
|
|
||||||
* of the user application's main() function, as it can never return to the calling function.
|
|
||||||
*/
|
|
||||||
void Scheduler_Start(void);
|
|
||||||
|
|
||||||
/** Initializes the scheduler so that the scheduler functions can be called before the scheduler itself
|
|
||||||
* is started. This must be executed before any scheduler function calls other than Scheduler_Start(),
|
|
||||||
* and can be omitted if no such functions could be called before the scheduler is started.
|
|
||||||
*/
|
|
||||||
void Scheduler_Init(void);
|
|
||||||
#else
|
|
||||||
#define Scheduler_Start() Scheduler_GoSchedule(TOTAL_TASKS);
|
|
||||||
|
|
||||||
#define Scheduler_Init() Scheduler_InitScheduler(TOTAL_TASKS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Type Defines: */
|
|
||||||
/** Type define for a pointer to a scheduler task. */
|
|
||||||
typedef void (*TaskPtr_t)(void);
|
|
||||||
|
|
||||||
/** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay
|
|
||||||
* possible.
|
|
||||||
*/
|
|
||||||
typedef uint16_t SchedulerDelayCounter_t;
|
|
||||||
|
|
||||||
/** Structure for holding a single task's information in the scheduler task list. */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
TaskPtr_t Task; /**< Pointer to the task to execute. */
|
|
||||||
bool TaskStatus; /**< Status of the task (either TASK_RUN or TASK_STOP). */
|
|
||||||
uint8_t GroupID; /**< Group ID of the task so that its status can be changed as a group. */
|
|
||||||
} TaskEntry_t;
|
|
||||||
|
|
||||||
/* Global Variables: */
|
|
||||||
/** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type
|
|
||||||
* TaskEntry_t and can be manipulated as desired, although it is preferential that the proper Scheduler
|
|
||||||
* functions should be used instead of direct manipulation.
|
|
||||||
*/
|
|
||||||
extern TaskEntry_t Scheduler_TaskList[];
|
|
||||||
|
|
||||||
/** Contains the total number of tasks in the task list, irrespective of if the task's status is set to
|
|
||||||
* TASK_RUN or TASK_STOP.
|
|
||||||
*
|
|
||||||
* \note This value should be treated as read-only, and never altered in user-code.
|
|
||||||
*/
|
|
||||||
extern volatile uint8_t Scheduler_TotalTasks;
|
|
||||||
|
|
||||||
/** Contains the current scheduler tick count, for use with the delay functions. If the delay functions
|
|
||||||
* are used in the user code, this should be incremented each tick period so that the delays can be
|
|
||||||
* calculated.
|
|
||||||
*/
|
|
||||||
extern volatile SchedulerDelayCounter_t Scheduler_TickCounter;
|
|
||||||
|
|
||||||
/* Inline Functions: */
|
|
||||||
/** Resets the delay counter value to the current tick count. This should be called to reset the period
|
|
||||||
* for a delay in a task which is dependant on the current tick value.
|
|
||||||
*
|
|
||||||
* \param DelayCounter Counter which is storing the starting tick count for a given delay.
|
|
||||||
*/
|
|
||||||
static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter)
|
|
||||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
|
||||||
static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t* const DelayCounter)
|
|
||||||
{
|
|
||||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
|
||||||
{
|
|
||||||
*DelayCounter = Scheduler_TickCounter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Function Prototypes: */
|
|
||||||
/** Determines if the given tick delay has elapsed, based on the given .
|
|
||||||
*
|
|
||||||
* \param Delay The delay to test for, measured in ticks
|
|
||||||
* \param DelayCounter The counter which is storing the starting tick value for the delay
|
|
||||||
*
|
|
||||||
* \return Boolean true if the delay has elapsed, false otherwise
|
|
||||||
*
|
|
||||||
* Usage Example:
|
|
||||||
* \code
|
|
||||||
* static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up
|
|
||||||
*
|
|
||||||
* // Task runs every 10000 ticks, 10 seconds for this demo
|
|
||||||
* if (Scheduler_HasDelayElapsed(10000, &DelayCounter))
|
|
||||||
* {
|
|
||||||
* // Code to execute after delay interval elapsed here
|
|
||||||
* }
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
bool Scheduler_HasDelayElapsed(const uint16_t Delay,
|
|
||||||
SchedulerDelayCounter_t* const DelayCounter)
|
|
||||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(2);
|
|
||||||
|
|
||||||
/** Sets the task mode for a given task.
|
|
||||||
*
|
|
||||||
* \param Task Name of the task whose status is to be changed
|
|
||||||
* \param TaskStatus New task status for the task (TASK_RUN or TASK_STOP)
|
|
||||||
*/
|
|
||||||
void Scheduler_SetTaskMode(const TaskPtr_t Task, const bool TaskStatus);
|
|
||||||
|
|
||||||
/** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their
|
|
||||||
* statuses changed at once.
|
|
||||||
*
|
|
||||||
* \param GroupID Value of the task group ID whose status is to be changed
|
|
||||||
* \param TaskStatus New task status for tasks in the specified group (TASK_RUN or TASK_STOP)
|
|
||||||
*/
|
|
||||||
void Scheduler_SetGroupTaskMode(const uint8_t GroupID, const bool TaskStatus);
|
|
||||||
|
|
||||||
/* Private Interface - For use in library only: */
|
|
||||||
#if !defined(__DOXYGEN__)
|
|
||||||
/* Macros: */
|
|
||||||
#define TOTAL_TASKS (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t))
|
|
||||||
#define MAX_DELAYCTR_COUNT 0xFFFF
|
|
||||||
|
|
||||||
/* Inline Functions: */
|
|
||||||
static inline void Scheduler_InitScheduler(const uint8_t TotalTasks) ATTR_ALWAYS_INLINE;
|
|
||||||
static inline void Scheduler_InitScheduler(const uint8_t TotalTasks)
|
|
||||||
{
|
|
||||||
Scheduler_TotalTasks = TotalTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void Scheduler_GoSchedule(const uint8_t TotalTasks) ATTR_NO_RETURN ATTR_ALWAYS_INLINE;
|
|
||||||
static inline void Scheduler_GoSchedule(const uint8_t TotalTasks)
|
|
||||||
{
|
|
||||||
Scheduler_InitScheduler(TotalTasks);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
TaskEntry_t* CurrTask = &Scheduler_TaskList[0];
|
|
||||||
|
|
||||||
while (CurrTask != &Scheduler_TaskList[TotalTasks])
|
|
||||||
{
|
|
||||||
if (CurrTask->TaskStatus == TASK_RUN)
|
|
||||||
CurrTask->Task();
|
|
||||||
|
|
||||||
CurrTask++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Disable C linkage for C++ Compilers: */
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @} */
|
|
@ -1,31 +0,0 @@
|
|||||||
/** \file
|
|
||||||
*
|
|
||||||
* This file contains special DoxyGen information for the generation of the main page and other special
|
|
||||||
* documentation pages. It is not a project source file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \page Page_SchedulerOverview LUFA Scheduler Overview
|
|
||||||
*
|
|
||||||
* The LUFA library comes with a small, basic round-robbin scheduler which allows for small "tasks" to be executed
|
|
||||||
* continuously in sequence, and enabled/disabled at runtime. Unlike a conventional, complex RTOS scheduler, the
|
|
||||||
* LUFA scheduler is very simple in design and operation and is essentially a loop conditionally executing a series
|
|
||||||
* of functions.
|
|
||||||
*
|
|
||||||
* Each LUFA scheduler task should be written similar to an ISR; it should execute quickly (so that no one task
|
|
||||||
* hogs the processor, preventing another from running before some sort of timeout is exceeded). Unlike normal RTOS
|
|
||||||
* tasks, each LUFA scheduler task is a regular function, and thus must be designed to be called, and designed to
|
|
||||||
* return to the calling scheduler function repeatedly. Data which must be preserved between task calls should be
|
|
||||||
* declared as global or (preferably) as a static local variable inside the task.
|
|
||||||
*
|
|
||||||
* The scheduler consists of a task list, listing all the tasks which can be executed by the scheduler. Once started,
|
|
||||||
* each task is then called one after another, unless the task is stopped by another running task or interrupt.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* If desired, the LUFA scheduler <b>does not need to be used</b> in a LUFA powered application. A more conventional
|
|
||||||
* approach to application design can be used, or a proper scheduling RTOS inserted in the place of the LUFA scheduler.
|
|
||||||
* In the case of the former the USB task must be run manually repeatedly to maintain USB communications, and in the
|
|
||||||
* case of the latter a proper RTOS task must be set up to do the same.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* For more information on the LUFA scheduler, see the Scheduler.h file documentation.
|
|
||||||
*/
|
|
Loading…
Reference in new issue