summaryrefslogtreecommitdiff
path: root/LUFA/Drivers/USB/Class/Device
diff options
context:
space:
mode:
Diffstat (limited to 'LUFA/Drivers/USB/Class/Device')
-rw-r--r--LUFA/Drivers/USB/Class/Device/Audio.c98
-rw-r--r--LUFA/Drivers/USB/Class/Device/Audio.h336
-rw-r--r--LUFA/Drivers/USB/Class/Device/CDC.c332
-rw-r--r--LUFA/Drivers/USB/Class/Device/CDC.h342
-rw-r--r--LUFA/Drivers/USB/Class/Device/HID.c190
-rw-r--r--LUFA/Drivers/USB/Class/Device/HID.h222
-rw-r--r--LUFA/Drivers/USB/Class/Device/MIDI.c148
-rw-r--r--LUFA/Drivers/USB/Class/Device/MIDI.h189
-rw-r--r--LUFA/Drivers/USB/Class/Device/MassStorage.c247
-rw-r--r--LUFA/Drivers/USB/Class/Device/MassStorage.h177
-rw-r--r--LUFA/Drivers/USB/Class/Device/RNDIS.c496
-rw-r--r--LUFA/Drivers/USB/Class/Device/RNDIS.h186
12 files changed, 2963 insertions, 0 deletions
diff --git a/LUFA/Drivers/USB/Class/Device/Audio.c b/LUFA/Drivers/USB/Class/Device/Audio.c
new file mode 100644
index 0000000..cc847e5
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/Audio.c
@@ -0,0 +1,98 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_AUDIO_DRIVER
+#define __INCLUDE_FROM_AUDIO_DEVICE_C
+#include "Audio.h"
+
+void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+{
+ if (!(Endpoint_IsSETUPReceived()))
+ return;
+
+ if (USB_ControlRequest.wIndex != AudioInterfaceInfo->Config.StreamingInterfaceNumber)
+ return;
+
+ switch (USB_ControlRequest.bRequest)
+ {
+ case REQ_SetInterface:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ AudioInterfaceInfo->State.InterfaceEnabled = ((USB_ControlRequest.wValue & 0xFF) != 0);
+ }
+
+ break;
+ }
+}
+
+bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+{
+ memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State));
+
+ for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
+ {
+ uint16_t Size;
+ uint8_t Type;
+ uint8_t Direction;
+
+ if (EndpointNum == AudioInterfaceInfo->Config.DataINEndpointNumber)
+ {
+ Size = AudioInterfaceInfo->Config.DataINEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_ISOCHRONOUS;
+ }
+ else if (EndpointNum == AudioInterfaceInfo->Config.DataOUTEndpointNumber)
+ {
+ Size = AudioInterfaceInfo->Config.DataOUTEndpointSize;
+ Direction = ENDPOINT_DIR_OUT;
+ Type = EP_TYPE_ISOCHRONOUS;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size, ENDPOINT_BANK_DOUBLE)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#endif
diff --git a/LUFA/Drivers/USB/Class/Device/Audio.h b/LUFA/Drivers/USB/Class/Device/Audio.h
new file mode 100644
index 0000000..5ba688a
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/Audio.h
@@ -0,0 +1,336 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB Audio 1.0 Class driver.
+ *
+ * Device mode driver for the library USB Audio 1.0 Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassAudio
+ * @defgroup Group_USBClassAudioDevice Audio Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/Audio.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the Audio 1.0 USB Class driver.
+ *
+ * @{
+ */
+
+#ifndef _AUDIO_CLASS_DEVICE_H_
+#define _AUDIO_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/Audio.h"
+
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_AUDIO_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_AUDIO_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Defines: */
+ /** \brief Audio Class Device Mode Configuration and State Structure.
+ *
+ * Class state structure. An instance of this structure should be made for each Audio interface
+ * within the user application, and passed to each of the Audio class driver functions as the
+ * AudioInterfaceInfo parameter. This stores each Audio interface's configuration and state information.
+ */
+ typedef struct
+ {
+ const struct
+ {
+ uint8_t StreamingInterfaceNumber; /**< Index of the Audio Streaming interface within the device this
+ * structure controls.
+ */
+
+ uint8_t DataINEndpointNumber; /**< Endpoint number of the incoming Audio Streaming data, if available
+ * (zero if unused).
+ */
+ uint16_t DataINEndpointSize; /**< Size in bytes of the incoming Audio Streaming data endpoint, if available
+ * (zero if unused).
+ */
+
+ uint8_t DataOUTEndpointNumber; /**< Endpoint number of the outgoing Audio Streaming data, if available
+ * (zero if unused).
+ */
+ uint16_t DataOUTEndpointSize; /**< Size in bytes of the outgoing Audio Streaming data endpoint, if available
+ * (zero if unused).
+ */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ bool InterfaceEnabled; /**< Set and cleared by the class driver to indicate if the host has enabled the streaming endpoints
+ * of the Audio Streaming interface.
+ */
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_Audio_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given Audio interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration containing the
+ * given Audio interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Processes incoming control requests from the host, that are directed to the given Audio class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ */
+ void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /* Inline Functions: */
+ /** General management task for a given Audio class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ */
+ static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ (void)AudioInterfaceInfo;
+ }
+
+ /** Determines if the given audio interface is ready for a sample to be read from it, and selects the streaming
+ * OUT endpoint ready for reading.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Boolean true if the given Audio interface has a sample to be read, false otherwise.
+ */
+ static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled))
+ return false;
+
+ Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataOUTEndpointNumber);
+ return Endpoint_IsOUTReceived();
+ }
+
+ /** Determines if the given audio interface is ready to accept the next sample to be written to it, and selects
+ * the streaming IN endpoint ready for writing.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Boolean true if the given Audio interface is ready to accept the next sample, false otherwise.
+ */
+ static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled))
+ return false;
+
+ Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataINEndpointNumber);
+ return Endpoint_IsINReady();
+ }
+
+ /** Reads the next 8-bit audio sample from the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure
+ * ensure the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Signed 8-bit audio sample from the audio interface.
+ */
+ static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ int8_t Sample;
+
+ (void)AudioInterfaceInfo;
+
+ Sample = Endpoint_Read_Byte();
+
+ if (!(Endpoint_BytesInEndpoint()))
+ Endpoint_ClearOUT();
+
+ return Sample;
+ }
+
+ /** Reads the next 16-bit audio sample from the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure
+ * that the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Signed 16-bit audio sample from the audio interface.
+ */
+ static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ int16_t Sample;
+
+ (void)AudioInterfaceInfo;
+
+ Sample = (int16_t)Endpoint_Read_Word_LE();
+
+ if (!(Endpoint_BytesInEndpoint()))
+ Endpoint_ClearOUT();
+
+ return Sample;
+ }
+
+ /** Reads the next 24-bit audio sample from the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure
+ * that the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ *
+ * \return Signed 24-bit audio sample from the audio interface.
+ */
+ static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo)
+ {
+ int32_t Sample;
+
+ (void)AudioInterfaceInfo;
+
+ Sample = (((uint32_t)Endpoint_Read_Byte() << 16) | Endpoint_Read_Word_LE());
+
+ if (!(Endpoint_BytesInEndpoint()))
+ Endpoint_ClearOUT();
+
+ return Sample;
+ }
+
+ /** Writes the next 8-bit audio sample to the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to
+ * ensure that the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ * \param[in] Sample Signed 8-bit audio sample.
+ */
+ static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int8_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int8_t Sample)
+ {
+ Endpoint_Write_Byte(Sample);
+
+ if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpointSize)
+ Endpoint_ClearIN();
+ }
+
+ /** Writes the next 16-bit audio sample to the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to
+ * ensure that the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ * \param[in] Sample Signed 16-bit audio sample.
+ */
+ static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int16_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int16_t Sample)
+ {
+ Endpoint_Write_Word_LE(Sample);
+
+ if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpointSize)
+ Endpoint_ClearIN();
+ }
+
+ /** Writes the next 24-bit audio sample to the current audio interface.
+ *
+ * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to
+ * ensure that the correct endpoint is selected and ready for data.
+ *
+ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state.
+ * \param[in] Sample Signed 24-bit audio sample.
+ */
+ static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int32_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
+ static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
+ const int32_t Sample)
+ {
+ Endpoint_Write_Byte(Sample >> 16);
+ Endpoint_Write_Word_LE(Sample);
+
+ if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpointSize)
+ Endpoint_ClearIN();
+ }
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+
diff --git a/LUFA/Drivers/USB/Class/Device/CDC.c b/LUFA/Drivers/USB/Class/Device/CDC.c
new file mode 100644
index 0000000..0da5cc6
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/CDC.c
@@ -0,0 +1,332 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_CDC_DRIVER
+#define __INCLUDE_FROM_CDC_DEVICE_C
+#include "CDC.h"
+
+void CDC_Device_Event_Stub(void)
+{
+
+}
+
+void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if (!(Endpoint_IsSETUPReceived()))
+ return;
+
+ if (USB_ControlRequest.wIndex != CDCInterfaceInfo->Config.ControlInterfaceNumber)
+ return;
+
+ switch (USB_ControlRequest.bRequest)
+ {
+ case CDC_REQ_GetLineEncoding:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding));
+ Endpoint_ClearOUT();
+ }
+
+ break;
+ case CDC_REQ_SetLineEncoding:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding));
+ Endpoint_ClearIN();
+
+ EVENT_CDC_Device_LineEncodingChanged(CDCInterfaceInfo);
+ }
+
+ break;
+ case CDC_REQ_SetControlLineState:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue;
+
+ EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo);
+ }
+
+ break;
+ case CDC_REQ_SendBreak:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ EVENT_CDC_Device_BreakSent(CDCInterfaceInfo, (uint8_t)USB_ControlRequest.wValue);
+ }
+
+ break;
+ }
+}
+
+bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
+
+ for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
+ {
+ uint16_t Size;
+ uint8_t Type;
+ uint8_t Direction;
+ bool DoubleBanked;
+
+ if (EndpointNum == CDCInterfaceInfo->Config.DataINEndpointNumber)
+ {
+ Size = CDCInterfaceInfo->Config.DataINEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = CDCInterfaceInfo->Config.DataINEndpointDoubleBank;
+ }
+ else if (EndpointNum == CDCInterfaceInfo->Config.DataOUTEndpointNumber)
+ {
+ Size = CDCInterfaceInfo->Config.DataOUTEndpointSize;
+ Direction = ENDPOINT_DIR_OUT;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = CDCInterfaceInfo->Config.DataOUTEndpointDoubleBank;
+ }
+ else if (EndpointNum == CDCInterfaceInfo->Config.NotificationEndpointNumber)
+ {
+ Size = CDCInterfaceInfo->Config.NotificationEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_INTERRUPT;
+ DoubleBanked = CDCInterfaceInfo->Config.NotificationEndpointDoubleBank;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size,
+ DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return;
+
+ #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
+ CDC_Device_Flush(CDCInterfaceInfo);
+ #endif
+}
+
+uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const char* const Data,
+ const uint16_t Length)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return ENDPOINT_RWSTREAM_DeviceDisconnected;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber);
+ return Endpoint_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
+}
+
+uint8_t CDC_Device_SendByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const uint8_t Data)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return ENDPOINT_RWSTREAM_DeviceDisconnected;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber);
+
+ if (!(Endpoint_IsReadWriteAllowed()))
+ {
+ Endpoint_ClearIN();
+
+ uint8_t ErrorCode;
+
+ if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError)
+ return ErrorCode;
+ }
+
+ Endpoint_Write_Byte(Data);
+ return ENDPOINT_READYWAIT_NoError;
+}
+
+uint8_t CDC_Device_Flush(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return ENDPOINT_RWSTREAM_DeviceDisconnected;
+
+ uint8_t ErrorCode;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber);
+
+ if (!(Endpoint_BytesInEndpoint()))
+ return ENDPOINT_READYWAIT_NoError;
+
+ bool BankFull = !(Endpoint_IsReadWriteAllowed());
+
+ Endpoint_ClearIN();
+
+ if (BankFull)
+ {
+ if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError)
+ return ErrorCode;
+
+ Endpoint_ClearIN();
+ }
+
+ return ENDPOINT_READYWAIT_NoError;
+}
+
+uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return 0;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ if (Endpoint_IsOUTReceived())
+ {
+ if (!(Endpoint_BytesInEndpoint()))
+ {
+ Endpoint_ClearOUT();
+ return 0;
+ }
+ else
+ {
+ return Endpoint_BytesInEndpoint();
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return -1;
+
+ int16_t ReceivedByte = -1;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ if (Endpoint_IsOUTReceived())
+ {
+ if (Endpoint_BytesInEndpoint())
+ ReceivedByte = Endpoint_Read_Byte();
+
+ if (!(Endpoint_BytesInEndpoint()))
+ Endpoint_ClearOUT();
+ }
+
+ return ReceivedByte;
+}
+
+void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+{
+ if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
+ return;
+
+ Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.NotificationEndpointNumber);
+
+ USB_Request_Header_t Notification = (USB_Request_Header_t)
+ {
+ .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
+ .bRequest = CDC_NOTIF_SerialState,
+ .wValue = 0,
+ .wIndex = 0,
+ .wLength = sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
+ };
+
+ Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
+ sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
+ NO_STREAM_CALLBACK);
+ Endpoint_ClearIN();
+}
+
+void CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ FILE* const Stream)
+{
+ *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Device_putchar, CDC_Device_getchar, _FDEV_SETUP_RW);
+ fdev_set_udata(Stream, CDCInterfaceInfo);
+}
+
+void CDC_Device_CreateBlockingStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ FILE* const Stream)
+{
+ *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Device_putchar, CDC_Device_getchar_Blocking, _FDEV_SETUP_RW);
+ fdev_set_udata(Stream, CDCInterfaceInfo);
+}
+
+static int CDC_Device_putchar(char c,
+ FILE* Stream)
+{
+ return CDC_Device_SendByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
+}
+
+static int CDC_Device_getchar(FILE* Stream)
+{
+ int16_t ReceivedByte = CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream));
+
+ if (ReceivedByte < 0)
+ return _FDEV_EOF;
+
+ return ReceivedByte;
+}
+
+static int CDC_Device_getchar_Blocking(FILE* Stream)
+{
+ int16_t ReceivedByte;
+
+ while ((ReceivedByte = CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream))) < 0)
+ {
+ if (USB_DeviceState == DEVICE_STATE_Unattached)
+ return _FDEV_EOF;
+
+ CDC_Device_USBTask((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream));
+ USB_USBTask();
+ }
+
+ return ReceivedByte;
+}
+
+#endif
+
diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h
new file mode 100644
index 0000000..4fa823a
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/CDC.h
@@ -0,0 +1,342 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB CDC Class driver.
+ *
+ * Device mode driver for the library USB CDC Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassCDC
+ * @defgroup Group_USBClassCDCDevice CDC Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/CDC.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the CDC USB Class driver.
+ *
+ * \note There are several major drawbacks to the CDC-ACM standard USB class, however
+ * it is very standardized and thus usually available as a built-in driver on
+ * most platforms, and so is a better choice than a proprietary serial class.
+ *
+ * One major issue with CDC-ACM is that it requires two Interface descriptors,
+ * which will upset most hosts when part of a multi-function "Composite" USB
+ * device, as each interface will be loaded into a separate driver instance. To
+ * combat this, you should use the "Interface Association Descriptor" addendum to
+ * the USB standard which is available on most OSes when creating Composite devices.
+ *
+ * Another major oversight is that there is no mechanism for the host to notify the
+ * device that there is a data sink on the host side ready to accept data. This
+ * means that the device may try to send data while the host isn't listening, causing
+ * lengthy blocking timeouts in the transmission routines. To combat this, it is
+ * recommended that the virtual serial line DTR (Data Terminal Ready) be used where
+ * possible to determine if a host application is ready for data.
+ *
+ * @{
+ */
+
+#ifndef _CDC_CLASS_DEVICE_H_
+#define _CDC_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/CDC.h"
+
+ #include <stdio.h>
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_CDC_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_CDC_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Defines: */
+ /** \brief CDC Class Device Mode Configuration and State Structure.
+ *
+ * Class state structure. An instance of this structure should be made for each CDC interface
+ * within the user application, and passed to each of the CDC class driver functions as the
+ * CDCInterfaceInfo parameter. This stores each CDC interface's configuration and state information.
+ */
+ typedef struct
+ {
+ const 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. */
+ bool DataINEndpointDoubleBank; /**< Indicates if the CDC interface's IN data endpoint should use double banking. */
+
+ 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. */
+ bool DataOUTEndpointDoubleBank; /**< Indicates if the CDC interface's OUT data endpoint should use double banking. */
+
+ 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. */
+ bool NotificationEndpointDoubleBank; /**< Indicates if the CDC interface's notification endpoint should use double banking. */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ struct
+ {
+ uint8_t HostToDevice; /**< Control line states from the host to device, as a set of CDC_CONTROL_LINE_OUT_*
+ * masks. This value is updated each time \ref CDC_Device_USBTask() is called.
+ */
+ uint8_t DeviceToHost; /**< Control line states from the device to host, as a set of CDC_CONTROL_LINE_IN_*
+ * masks - to notify the host of changes to these values, call the
+ * \ref CDC_Device_SendControlLineStateChange() function.
+ */
+ } ControlLineStates; /**< Current states of the virtual serial port's control lines between the device and host. */
+
+ CDC_LineEncoding_t LineEncoding; /** Line encoding used in the virtual serial port, for the device's information.
+ * This is generally only used if the virtual serial port data is to be
+ * reconstructed on a physical UART.
+ */
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_CDC_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given CDC interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration containing
+ * the given CDC interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Processes incoming control requests from the host, that are directed to the given CDC class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ */
+ void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** General management task for a given CDC class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ */
+ void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** CDC class driver event for a line encoding change on a CDC interface. This event fires each time the host requests a
+ * line encoding change (containing the serial parity, baud and other configuration information) and may be hooked in the
+ * user program by declaring a handler function with the same name and parameters listed here. The new line encoding
+ * settings are available in the LineEncoding structure inside the CDC interface structure passed as a parameter.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ */
+ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** CDC class driver event for a control line state change on a CDC interface. This event fires each time the host requests a
+ * control line state change (containing the virtual serial control line states, such as DTR) and may be hooked in the
+ * user program by declaring a handler function with the same name and parameters listed here. The new control line states
+ * are available in the ControlLineStates.HostToDevice value inside the CDC interface structure passed as a parameter, set as
+ * a mask of CDC_CONTROL_LINE_OUT_* masks.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ */
+ void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** CDC class driver event for a send break request sent to the device from the host. This is generally used to separate
+ * data or to indicate a special condition to the receiving device.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ * \param[in] Duration Duration of the break that has been sent by the host, in milliseconds.
+ */
+ void EVENT_CDC_Device_BreakSent(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const uint8_t Duration) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Sends a given string to the attached USB host, if connected. If a host is not connected when the function is called, the
+ * string is discarded. Bytes will be queued for transmission to the host until either the endpoint bank becomes full, or the
+ * \ref CDC_Device_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
+ * packed into a single endpoint packet, increasing data throughput.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ * \param[in] Data Pointer to the string to send to the host.
+ * \param[in] Length Size in bytes of the string to send to the host.
+ *
+ * \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum.
+ */
+ uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const char* const Data,
+ const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
+
+ /** Sends a given byte to the attached USB host, if connected. If a host is not connected when the function is called, the
+ * byte is discarded. Bytes will be queued for transmission to the host until either the endpoint bank becomes full, or the
+ * \ref CDC_Device_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
+ * packed into a single endpoint packet, increasing data throughput.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ * \param[in] Data Byte of data to send to the host.
+ *
+ * \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum.
+ */
+ uint8_t CDC_Device_SendByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Determines the number of bytes received by the CDC interface from the host, waiting to be read. This indicates the number
+ * of bytes in the OUT endpoint bank only, and thus the number of calls to \ref CDC_Device_ReceiveByte() which are guaranteed to
+ * succeed immediately. If multiple bytes are to be received, they should be buffered by the user application, as the endpoint
+ * bank will not be released back to the USB controller until all bytes are read.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ *
+ * \return Total number of buffered bytes received from the host.
+ */
+ uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Reads a byte of data from the host. If no data is waiting to be read of if a USB host is not connected, the function
+ * returns a negative value. The \ref CDC_Device_BytesReceived() function may be queried in advance to determine how many
+ * bytes are currently buffered in the CDC interface's data receive endpoint bank, and thus how many repeated calls to this
+ * function which are guaranteed to succeed.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ *
+ * \return Next received byte from the host, or a negative value if no data received.
+ */
+ int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Flushes any data waiting to be sent, ensuring that the send buffer is cleared.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ *
+ * \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum.
+ */
+ uint8_t CDC_Device_Flush(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial
+ * control lines (DCD, DSR, etc.) have changed states, or to give BREAK notifications to the host. Line states persist
+ * until they are cleared via a second notification. This should be called each time the CDC class driver's
+ * ControlLineStates.DeviceToHost value is updated to push the new states to the USB host.
+ *
+ * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or
+ * the call will fail.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ */
+ void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Creates a standard character stream for the given CDC Device instance so that it can be used with all the regular
+ * functions in the avr-libc <stdio.h> library that accept a FILE stream as a destination (e.g. fprintf). The created
+ * stream is bidirectional and can be used for both input and output functions.
+ *
+ * Reading data from this stream is non-blocking, i.e. in most instances, complete strings cannot be read in by a single
+ * fetch, as the endpoint will not be ready at some point in the transmission, aborting the transfer. However, this may
+ * be used when the read data is processed byte-per-bye (via getc()) or when the user application will implement its own
+ * line buffering.
+ *
+ * \note The created stream can be given as stdout if desired to direct the standard output from all <stdio.h> functions
+ * to the given CDC interface.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed.
+ */
+ void CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
+
+ /** Identical to CDC_Device_CreateStream(), except that reads are blocking until the calling stream function terminates
+ * the transfer. While blocking, the USB and CDC service tasks are called repeatedly to maintain USB communications.
+ *
+ * \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class configuration and state.
+ * \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed.
+ */
+ void CDC_Device_CreateBlockingStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
+
+ /* Private Interface - For use in library only: */
+ #if !defined(__DOXYGEN__)
+ /* Function Prototypes: */
+ #if defined(__INCLUDE_FROM_CDC_DEVICE_C)
+ static int CDC_Device_putchar(char c,
+ FILE* Stream) ATTR_NON_NULL_PTR_ARG(2);
+ static int CDC_Device_getchar(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
+ static int CDC_Device_getchar_Blocking(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
+
+ void CDC_Device_Event_Stub(void);
+ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+ ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Device_Event_Stub);
+ void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
+ ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Device_Event_Stub);
+ void EVENT_CDC_Device_BreakSent(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
+ const uint8_t Duration) ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1)
+ ATTR_ALIAS(CDC_Device_Event_Stub);
+ #endif
+
+ #endif
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+
diff --git a/LUFA/Drivers/USB/Class/Device/HID.c b/LUFA/Drivers/USB/Class/Device/HID.c
new file mode 100644
index 0000000..f538610
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/HID.c
@@ -0,0 +1,190 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_HID_DRIVER
+#define __INCLUDE_FROM_HID_DEVICE_C
+#include "HID.h"
+
+void HID_Device_ProcessControlRequest(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo)
+{
+ if (!(Endpoint_IsSETUPReceived()))
+ return;
+
+ if (USB_ControlRequest.wIndex != HIDInterfaceInfo->Config.InterfaceNumber)
+ return;
+
+ switch (USB_ControlRequest.bRequest)
+ {
+ case HID_REQ_GetReport:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ uint16_t ReportSize = 0;
+ uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF);
+ uint8_t ReportType = (USB_ControlRequest.wValue >> 8) - 1;
+ uint8_t ReportData[HIDInterfaceInfo->Config.PrevReportINBufferSize];
+
+ memset(ReportData, 0, sizeof(ReportData));
+
+ CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportType, ReportData, &ReportSize);
+
+ if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL)
+ memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportData, HIDInterfaceInfo->Config.PrevReportINBufferSize);
+
+ Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
+
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
+ Endpoint_ClearOUT();
+ }
+
+ break;
+ case HID_REQ_SetReport:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ uint16_t ReportSize = USB_ControlRequest.wLength;
+ uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF);
+ uint8_t ReportType = (USB_ControlRequest.wValue >> 8) - 1;
+ uint8_t ReportData[ReportSize];
+
+ Endpoint_ClearSETUP();
+ Endpoint_Read_Control_Stream_LE(ReportData, ReportSize);
+ Endpoint_ClearIN();
+
+ CALLBACK_HID_Device_ProcessHIDReport(HIDInterfaceInfo, ReportID, ReportType, ReportData, ReportSize);
+ }
+
+ break;
+ case HID_REQ_GetProtocol:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Byte(HIDInterfaceInfo->State.UsingReportProtocol);
+ Endpoint_ClearIN();
+ Endpoint_ClearStatusStage();
+ }
+
+ break;
+ case HID_REQ_SetProtocol:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ HIDInterfaceInfo->State.UsingReportProtocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
+ }
+
+ break;
+ case HID_REQ_SetIdle:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ HIDInterfaceInfo->State.IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6);
+ }
+
+ break;
+ case HID_REQ_GetIdle:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Byte(HIDInterfaceInfo->State.IdleCount >> 2);
+ Endpoint_ClearIN();
+ Endpoint_ClearStatusStage();
+ }
+
+ break;
+ }
+}
+
+bool HID_Device_ConfigureEndpoints(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo)
+{
+ memset(&HIDInterfaceInfo->State, 0x00, sizeof(HIDInterfaceInfo->State));
+ HIDInterfaceInfo->State.UsingReportProtocol = true;
+ HIDInterfaceInfo->State.IdleCount = 500;
+
+ if (!(Endpoint_ConfigureEndpoint(HIDInterfaceInfo->Config.ReportINEndpointNumber, EP_TYPE_INTERRUPT,
+ ENDPOINT_DIR_IN, HIDInterfaceInfo->Config.ReportINEndpointSize,
+ HIDInterfaceInfo->Config.ReportINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void HID_Device_USBTask(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return;
+
+ Endpoint_SelectEndpoint(HIDInterfaceInfo->Config.ReportINEndpointNumber);
+
+ if (Endpoint_IsReadWriteAllowed())
+ {
+ uint8_t ReportINData[HIDInterfaceInfo->Config.PrevReportINBufferSize];
+ uint8_t ReportID = 0;
+ uint16_t ReportINSize = 0;
+
+ memset(ReportINData, 0, sizeof(ReportINData));
+
+ bool ForceSend = CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, HID_REPORT_ITEM_In,
+ ReportINData, &ReportINSize);
+ bool StatesChanged = false;
+ bool IdlePeriodElapsed = (HIDInterfaceInfo->State.IdleCount && !(HIDInterfaceInfo->State.IdleMSRemaining));
+
+ if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL)
+ {
+ StatesChanged = (memcmp(ReportINData, HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize) != 0);
+ memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINData, HIDInterfaceInfo->Config.PrevReportINBufferSize);
+ }
+
+ if (ReportINSize && (ForceSend || StatesChanged || IdlePeriodElapsed))
+ {
+ HIDInterfaceInfo->State.IdleMSRemaining = HIDInterfaceInfo->State.IdleCount;
+
+ Endpoint_SelectEndpoint(HIDInterfaceInfo->Config.ReportINEndpointNumber);
+
+ if (ReportID)
+ Endpoint_Write_Byte(ReportID);
+
+ Endpoint_Write_Stream_LE(ReportINData, ReportINSize, NO_STREAM_CALLBACK);
+
+ Endpoint_ClearIN();
+ }
+ }
+}
+
+#endif
+
diff --git a/LUFA/Drivers/USB/Class/Device/HID.h b/LUFA/Drivers/USB/Class/Device/HID.h
new file mode 100644
index 0000000..49358f5
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/HID.h
@@ -0,0 +1,222 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB HID Class driver.
+ *
+ * Device mode driver for the library USB HID Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassHID
+ * @defgroup Group_USBClassHIDDevice HID Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/HID.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the HID USB Class driver.
+ *
+ * @{
+ */
+
+#ifndef _HID_CLASS_DEVICE_H_
+#define _HID_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/HID.h"
+
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_HID_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_HID_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Defines: */
+ /** \brief HID Class Device Mode Configuration and State Structure.
+ *
+ * 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. This stores each HID interface's configuration and state information.
+ *
+ * \note Due to technical limitations, the HID device class driver does not utilize a separate OUT
+ * endpoint for host->device communications. Instead, the host->device data (if any) is sent to
+ * the device via the control endpoint.
+ */
+ typedef struct
+ {
+ const 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. */
+ bool ReportINEndpointDoubleBank; /**< Indicates if the HID interface's IN report endpoint should use double banking. */
+
+ void* PrevReportINBuffer; /**< Pointer to a buffer where the previously created HID input report can be
+ * stored by the driver, for comparison purposes to detect report changes that
+ * must be sent immediately to the host. This should point to a buffer big enough
+ * to hold the largest HID input report sent from the HID interface. If this is set
+ * to NULL, it is up to the user to force transfers when needed in the
+ * \ref CALLBACK_HID_Device_CreateHIDReport() callback function.
+ *
+ * \note Due to the single buffer, the internal driver can only correctly compare
+ * subsequent reports with identical report IDs. In multiple report devices,
+ * this buffer should be set to NULL and the decision to send reports made
+ * by the user application instead.
+ */
+ uint8_t PrevReportINBufferSize; /**< Size in bytes of the given input report buffer. This is used to create a
+ * second buffer of the same size within the driver so that subsequent reports
+ * can be compared. If the user app is to determine when reports are to be sent
+ * exclusively (i.e. \ref PrevReportINBuffer is NULL) this value must still be
+ * set to the size of the largest report the device can issue to the host.
+ */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ bool UsingReportProtocol; /**< Indicates if the HID interface is set to Boot or Report protocol mode. */
+ uint16_t IdleCount; /**< Report idle period, in milliseconds, set by the host. */
+ uint16_t IdleMSRemaining; /**< Total number of milliseconds remaining before the idle period elapsed - this
+ * should be decremented by the user application if non-zero each millisecond. */
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_HID_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given HID interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration
+ * containing the given HID interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool HID_Device_ConfigureEndpoints(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Processes incoming control requests from the host, that are directed to the given HID class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ */
+ void HID_Device_ProcessControlRequest(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** General management task for a given HID class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ */
+ void HID_Device_USBTask(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** HID class driver callback for the user creation of a HID IN report. This callback may fire in response to either
+ * HID class control requests from the host, or by the normal HID endpoint polling procedure. Inside this callback the
+ * user is responsible for the creation of the next HID input report to be sent to the host.
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ * \param[in,out] ReportID If preset to a non-zero value, this is the report ID being requested by the host. If zero,
+ * this should be set to the report ID of the generated HID input report (if any). If multiple
+ * reports are not sent via the given HID interface, this parameter should be ignored.
+ * \param[in] ReportType Type of HID report to generate, either \ref HID_REPORT_ITEM_In or \ref HID_REPORT_ITEM_Feature.
+ * \param[out] ReportData Pointer to a buffer where the generated HID report should be stored.
+ * \param[out] ReportSize Number of bytes in the generated input report, or zero if no report is to be sent.
+ *
+ * \return Boolean true to force the sending of the report even if it is identical to the previous report and still within
+ * the idle period (useful for devices which report relative movement), false otherwise.
+ */
+ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
+ uint8_t* const ReportID,
+ const uint8_t ReportType,
+ void* ReportData,
+ uint16_t* const ReportSize) ATTR_NON_NULL_PTR_ARG(1)
+ ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(4) ATTR_NON_NULL_PTR_ARG(5);
+
+ /** HID class driver callback for the user processing of a received HID OUT report. This callback may fire in response to
+ * either HID class control requests from the host, or by the normal HID endpoint polling procedure. Inside this callback
+ * the user is responsible for the processing of the received HID output report from the host.
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ * \param[in] ReportID Report ID of the received output report. If multiple reports are not received via the given HID
+ * interface, this parameter should be ignored.
+ * \param[in] ReportType Type of received HID report, either \ref HID_REPORT_ITEM_Out or \ref HID_REPORT_ITEM_Feature.
+ * \param[in] ReportData Pointer to a buffer where the received HID report is stored.
+ * \param[in] ReportSize Size in bytes of the received report from the host.
+ */
+ void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
+ const uint8_t ReportID,
+ const uint8_t ReportType,
+ const void* ReportData,
+ const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(4);
+
+ /* Inline Functions: */
+ /** Indicates that a millisecond of idle time has elapsed on the given HID interface, and the interface's idle count should be
+ * decremented. This should be called once per millisecond so that hardware key-repeats function correctly. It is recommended
+ * that this be called by the \ref EVENT_USB_Device_StartOfFrame() event, once SOF events have been enabled via
+ * \ref USB_Device_EnableSOFEvents().
+ *
+ * \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class configuration and state.
+ */
+ static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_ALWAYS_INLINE ATTR_NON_NULL_PTR_ARG(1);
+ static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo)
+ {
+ if (HIDInterfaceInfo->State.IdleMSRemaining)
+ HIDInterfaceInfo->State.IdleMSRemaining--;
+ }
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+
diff --git a/LUFA/Drivers/USB/Class/Device/MIDI.c b/LUFA/Drivers/USB/Class/Device/MIDI.c
new file mode 100644
index 0000000..9d2a1a8
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/MIDI.c
@@ -0,0 +1,148 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_MIDI_DRIVER
+#define __INCLUDE_FROM_MIDI_DEVICE_C
+#include "MIDI.h"
+
+bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
+{
+ memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State));
+
+ for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
+ {
+ uint16_t Size;
+ uint8_t Type;
+ uint8_t Direction;
+ bool DoubleBanked;
+
+ if (EndpointNum == MIDIInterfaceInfo->Config.DataINEndpointNumber)
+ {
+ Size = MIDIInterfaceInfo->Config.DataINEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = MIDIInterfaceInfo->Config.DataINEndpointDoubleBank;
+ }
+ else if (EndpointNum == MIDIInterfaceInfo->Config.DataOUTEndpointNumber)
+ {
+ Size = MIDIInterfaceInfo->Config.DataOUTEndpointSize;
+ Direction = ENDPOINT_DIR_OUT;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = MIDIInterfaceInfo->Config.DataOUTEndpointDoubleBank;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size,
+ DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return;
+
+ #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
+ MIDI_Device_Flush(MIDIInterfaceInfo);
+ #endif
+}
+
+uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo,
+ const MIDI_EventPacket_t* const Event)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return ENDPOINT_RWSTREAM_DeviceDisconnected;
+
+ uint8_t ErrorCode;
+
+ Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber);
+
+ if ((ErrorCode = Endpoint_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK)) != ENDPOINT_RWSTREAM_NoError)
+ return ErrorCode;
+
+ if (!(Endpoint_IsReadWriteAllowed()))
+ Endpoint_ClearIN();
+
+ return ENDPOINT_RWSTREAM_NoError;
+}
+
+uint8_t MIDI_Device_Flush(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return ENDPOINT_RWSTREAM_DeviceDisconnected;
+
+ uint8_t ErrorCode;
+
+ Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber);
+
+ if (Endpoint_BytesInEndpoint())
+ {
+ Endpoint_ClearIN();
+
+ if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError)
+ return ErrorCode;
+ }
+
+ return ENDPOINT_READYWAIT_NoError;
+}
+
+bool MIDI_Device_ReceiveEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo,
+ MIDI_EventPacket_t* const Event)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return false;
+
+ Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ if (!(Endpoint_IsReadWriteAllowed()))
+ return false;
+
+ Endpoint_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NO_STREAM_CALLBACK);
+
+ if (!(Endpoint_IsReadWriteAllowed()))
+ Endpoint_ClearOUT();
+
+ return true;
+}
+
+#endif
+
diff --git a/LUFA/Drivers/USB/Class/Device/MIDI.h b/LUFA/Drivers/USB/Class/Device/MIDI.h
new file mode 100644
index 0000000..8ac7146
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/MIDI.h
@@ -0,0 +1,189 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB MIDI Class driver.
+ *
+ * Device mode driver for the library USB MIDI Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassMIDI
+ * @defgroup Group_USBClassMIDIDevice MIDI Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/MIDI.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the MIDI USB Class driver.
+ *
+ * @{
+ */
+
+#ifndef _MIDI_CLASS_DEVICE_H_
+#define _MIDI_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/MIDI.h"
+
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_MIDI_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_MIDI_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Define: */
+ /** \brief MIDI Class Device Mode Configuration and State Structure.
+ *
+ * Class state structure. An instance of this structure should be made for each MIDI interface
+ * within the user application, and passed to each of the MIDI class driver functions as the
+ * MIDIInterfaceInfo parameter. This stores each MIDI interface's configuration and state information.
+ */
+ typedef struct
+ {
+ const struct
+ {
+ uint8_t StreamingInterfaceNumber; /**< Index of the Audio Streaming interface within the device this structure controls. */
+
+ uint8_t DataINEndpointNumber; /**< Endpoint number of the incoming MIDI data, if available (zero if unused). */
+ uint16_t DataINEndpointSize; /**< Size in bytes of the incoming MIDI data endpoint, if available (zero if unused). */
+ bool DataINEndpointDoubleBank; /**< Indicates if the MIDI interface's IN data endpoint should use double banking. */
+
+ uint8_t DataOUTEndpointNumber; /**< Endpoint number of the outgoing MIDI data, if available (zero if unused). */
+ uint16_t DataOUTEndpointSize; /**< Size in bytes of the outgoing MIDI data endpoint, if available (zero if unused). */
+ bool DataOUTEndpointDoubleBank; /**< Indicates if the MIDI interface's IN data endpoint should use double banking. */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ // No state information for this class
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_MIDI_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given MIDI interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration
+ * containing the given MIDI interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** General management task for a given MIDI class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ */
+ void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Sends a MIDI event packet to the host. If no host is connected, the event packet is discarded. Events are queued into the
+ * endpoint bank until either the endpoint bank is full, or \ref MIDI_Device_Flush() is called. This allows for multiple
+ * MIDI events to be packed into a single endpoint packet, increasing data throughput.
+ *
+ * \pre This function must only be called when the Host state machine is in the \ref HOST_STATE_Configured state or the
+ * call will fail.
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ * \param[in] Event Pointer to a populated \ref MIDI_EventPacket_t structure containing the MIDI event to send.
+ *
+ * \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum.
+ */
+ uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo,
+ const MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
+
+
+ /** Flushes the MIDI send buffer, sending any queued MIDI events to the host. This should be called to override the
+ * \ref MIDI_Device_SendEventPacket() function's packing behaviour, to flush queued events.
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ *
+ * \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum.
+ */
+ uint8_t MIDI_Device_Flush(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Receives a MIDI event packet from the host. Events are unpacked from the endpoint, thus if the endpoint bank contains
+ * multiple MIDI events from the host in the one packet, multiple calls to this function will return each individual event.
+ *
+ * \pre This function must only be called when the Host state machine is in the \ref HOST_STATE_Configured state or the
+ * call will fail.
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ * \param[out] Event Pointer to a USB_MIDI_EventPacket_t structure where the received MIDI event is to be placed.
+ *
+ * \return Boolean true if a MIDI event packet was received, false otherwise.
+ */
+ bool MIDI_Device_ReceiveEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo,
+ MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
+
+ /* Inline Functions: */
+ /** Processes incoming control requests from the host, that are directed to the given MIDI class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
+ */
+ static inline void MIDI_Device_ProcessControlRequest(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+ static inline void MIDI_Device_ProcessControlRequest(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
+ {
+ (void)MIDIInterfaceInfo;
+ }
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+
diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.c b/LUFA/Drivers/USB/Class/Device/MassStorage.c
new file mode 100644
index 0000000..64d61df
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/MassStorage.c
@@ -0,0 +1,247 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_MS_DRIVER
+#define __INCLUDE_FROM_MASSSTORAGE_DEVICE_C
+#include "MassStorage.h"
+
+static volatile bool* CallbackIsResetSource;
+
+void MS_Device_ProcessControlRequest(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+ if (!(Endpoint_IsSETUPReceived()))
+ return;
+
+ if (USB_ControlRequest.wIndex != MSInterfaceInfo->Config.InterfaceNumber)
+ return;
+
+ switch (USB_ControlRequest.bRequest)
+ {
+ case MS_REQ_MassStorageReset:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_ClearStatusStage();
+
+ MSInterfaceInfo->State.IsMassStoreReset = true;
+ }
+
+ break;
+ case MS_REQ_GetMaxLUN:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Byte(MSInterfaceInfo->Config.TotalLUNs - 1);
+ Endpoint_ClearIN();
+ Endpoint_ClearStatusStage();
+ }
+
+ break;
+ }
+}
+
+bool MS_Device_ConfigureEndpoints(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+ memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
+
+ for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
+ {
+ uint16_t Size;
+ uint8_t Type;
+ uint8_t Direction;
+ bool DoubleBanked;
+
+ if (EndpointNum == MSInterfaceInfo->Config.DataINEndpointNumber)
+ {
+ Size = MSInterfaceInfo->Config.DataINEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = MSInterfaceInfo->Config.DataINEndpointDoubleBank;
+ }
+ else if (EndpointNum == MSInterfaceInfo->Config.DataOUTEndpointNumber)
+ {
+ Size = MSInterfaceInfo->Config.DataOUTEndpointSize;
+ Direction = ENDPOINT_DIR_OUT;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = MSInterfaceInfo->Config.DataOUTEndpointDoubleBank;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size,
+ DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void MS_Device_USBTask(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return;
+
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ if (Endpoint_IsReadWriteAllowed())
+ {
+ if (MS_Device_ReadInCommandBlock(MSInterfaceInfo))
+ {
+ if (MSInterfaceInfo->State.CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN)
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber);
+
+ MSInterfaceInfo->State.CommandStatus.Status = CALLBACK_MS_Device_SCSICommandReceived(MSInterfaceInfo) ?
+ MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail;
+ MSInterfaceInfo->State.CommandStatus.Signature = MS_CSW_SIGNATURE;
+ MSInterfaceInfo->State.CommandStatus.Tag = MSInterfaceInfo->State.CommandBlock.Tag;
+ MSInterfaceInfo->State.CommandStatus.DataTransferResidue = MSInterfaceInfo->State.CommandBlock.DataTransferLength;
+
+ if ((MSInterfaceInfo->State.CommandStatus.Status == MS_SCSI_COMMAND_Fail) &&
+ (MSInterfaceInfo->State.CommandStatus.DataTransferResidue))
+ {
+ Endpoint_StallTransaction();
+ }
+
+ MS_Device_ReturnCommandStatus(MSInterfaceInfo);
+ }
+ }
+
+ if (MSInterfaceInfo->State.IsMassStoreReset)
+ {
+ Endpoint_ResetFIFO(MSInterfaceInfo->Config.DataOUTEndpointNumber);
+ Endpoint_ResetFIFO(MSInterfaceInfo->Config.DataINEndpointNumber);
+
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber);
+ Endpoint_ClearStall();
+ Endpoint_ResetDataToggle();
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber);
+ Endpoint_ClearStall();
+ Endpoint_ResetDataToggle();
+
+ MSInterfaceInfo->State.IsMassStoreReset = false;
+ }
+}
+
+static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset;
+ if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock,
+ (sizeof(MS_CommandBlockWrapper_t) - 16),
+ StreamCallback_MS_Device_AbortOnMassStoreReset))
+ {
+ return false;
+ }
+
+ if ((MSInterfaceInfo->State.CommandBlock.Signature != MS_CBW_SIGNATURE) ||
+ (MSInterfaceInfo->State.CommandBlock.LUN >= MSInterfaceInfo->Config.TotalLUNs) ||
+ (MSInterfaceInfo->State.CommandBlock.Flags & 0x1F) ||
+ (MSInterfaceInfo->State.CommandBlock.SCSICommandLength == 0) ||
+ (MSInterfaceInfo->State.CommandBlock.SCSICommandLength > 16))
+ {
+ Endpoint_StallTransaction();
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber);
+ Endpoint_StallTransaction();
+
+ return false;
+ }
+
+ CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset;
+ if (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock.SCSICommandData,
+ MSInterfaceInfo->State.CommandBlock.SCSICommandLength,
+ StreamCallback_MS_Device_AbortOnMassStoreReset))
+ {
+ return false;
+ }
+
+ Endpoint_ClearOUT();
+
+ return true;
+}
+
+static void MS_Device_ReturnCommandStatus(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ while (Endpoint_IsStalled())
+ {
+ #if !defined(INTERRUPT_CONTROL_ENDPOINT)
+ USB_USBTask();
+ #endif
+
+ if (MSInterfaceInfo->State.IsMassStoreReset)
+ return;
+ }
+
+ Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber);
+
+ while (Endpoint_IsStalled())
+ {
+ #if !defined(INTERRUPT_CONTROL_ENDPOINT)
+ USB_USBTask();
+ #endif
+
+ if (MSInterfaceInfo->State.IsMassStoreReset)
+ return;
+ }
+
+ CallbackIsResetSource = &MSInterfaceInfo->State.IsMassStoreReset;
+ if (Endpoint_Write_Stream_LE(&MSInterfaceInfo->State.CommandStatus, sizeof(MS_CommandStatusWrapper_t),
+ StreamCallback_MS_Device_AbortOnMassStoreReset))
+ {
+ return;
+ }
+
+ Endpoint_ClearIN();
+}
+
+static uint8_t StreamCallback_MS_Device_AbortOnMassStoreReset(void)
+{
+ #if !defined(INTERRUPT_CONTROL_ENDPOINT)
+ USB_USBTask();
+ #endif
+
+ if (*CallbackIsResetSource)
+ return STREAMCALLBACK_Abort;
+ else
+ return STREAMCALLBACK_Continue;
+}
+
+#endif
+
diff --git a/LUFA/Drivers/USB/Class/Device/MassStorage.h b/LUFA/Drivers/USB/Class/Device/MassStorage.h
new file mode 100644
index 0000000..31d3ba9
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/MassStorage.h
@@ -0,0 +1,177 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB Mass Storage Class driver.
+ *
+ * Device mode driver for the library USB Mass Storage Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassMS
+ * @defgroup Group_USBClassMSDevice Mass Storage Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/MassStorage.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the Mass Storage USB Class driver.
+ *
+ * @{
+ */
+
+#ifndef _MS_CLASS_DEVICE_H_
+#define _MS_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/MassStorage.h"
+
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_MS_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_MASSSTORAGE_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Defines: */
+ /** \brief Mass Storage Class Device Mode Configuration and State Structure.
+ *
+ * Class state structure. An instance of this structure should be made for each Mass Storage interface
+ * within the user application, and passed to each of the Mass Storage class driver functions as the
+ * MSInterfaceInfo parameter. This stores each Mass Storage interface's configuration and state information.
+ */
+ typedef struct
+ {
+ const 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. */
+ bool DataINEndpointDoubleBank; /**< Indicates if the Mass Storage interface's IN data endpoint should use double banking. */
+
+ 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. */
+ bool DataOUTEndpointDoubleBank; /**< Indicates if the Mass Storage interface's OUT data endpoint should use double banking. */
+
+ uint8_t TotalLUNs; /**< Total number of logical drives in the Mass Storage interface. */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ MS_CommandBlockWrapper_t CommandBlock; /**< Mass Storage class command block structure, stores the received SCSI
+ * command from the host which is to be processed.
+ */
+ MS_CommandStatusWrapper_t CommandStatus; /**< Mass Storage class command status structure, set elements to indicate
+ * the issued command's success or failure to the host.
+ */
+ volatile bool IsMassStoreReset; /**< Flag indicating that the host has requested that the Mass Storage interface be reset
+ * and that all current Mass Storage operations should immediately abort.
+ */
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_MS_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given Mass Storage interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration
+ * containing the given Mass Storage interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool MS_Device_ConfigureEndpoints(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Processes incoming control requests from the host, that are directed to the given Mass Storage class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state.
+ */
+ void MS_Device_ProcessControlRequest(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** General management task for a given Mass Storage class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a Mass Storage configuration and state.
+ */
+ void MS_Device_USBTask(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Mass Storage class driver callback for the user processing of a received SCSI command. This callback will fire each time the
+ * host sends a SCSI command which requires processing by the user application. Inside this callback the user is responsible
+ * for the processing of the received SCSI command from the host. The SCSI command is available in the CommandBlock structure
+ * inside the Mass Storage class state structure passed as a parameter to the callback function.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state.
+ *
+ * \return Boolean true if the SCSI command was successfully processed, false otherwise.
+ */
+ bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /* Private Interface - For use in library only: */
+ #if !defined(__DOXYGEN__)
+ /* Function Prototypes: */
+ #if defined(__INCLUDE_FROM_MASSSTORAGE_DEVICE_C)
+ static void MS_Device_ReturnCommandStatus(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+ static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+ static uint8_t StreamCallback_MS_Device_AbortOnMassStoreReset(void);
+ #endif
+
+ #endif
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+
diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.c b/LUFA/Drivers/USB/Class/Device/RNDIS.c
new file mode 100644
index 0000000..c6de9e5
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/RNDIS.c
@@ -0,0 +1,496 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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_USB_DRIVER
+#include "../../HighLevel/USBMode.h"
+#if defined(USB_CAN_BE_DEVICE)
+
+#define __INCLUDE_FROM_RNDIS_DRIVER
+#define __INCLUDE_FROM_RNDIS_DEVICE_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 RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
+{
+ if (!(Endpoint_IsSETUPReceived()))
+ return;
+
+ if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->Config.ControlInterfaceNumber)
+ return;
+
+ switch (USB_ControlRequest.bRequest)
+ {
+ case RNDIS_REQ_SendEncapsulatedCommand:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ Endpoint_ClearSETUP();
+ Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, USB_ControlRequest.wLength);
+ Endpoint_ClearIN();
+
+ RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo);
+ }
+
+ break;
+ case RNDIS_REQ_GetEncapsulatedResponse:
+ if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+ {
+ RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+
+ if (!(MessageHeader->MessageLength))
+ {
+ RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0;
+ MessageHeader->MessageLength = 1;
+ }
+
+ Endpoint_ClearSETUP();
+ Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, MessageHeader->MessageLength);
+ Endpoint_ClearOUT();
+
+ MessageHeader->MessageLength = 0;
+ }
+
+ break;
+ }
+}
+
+bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
+{
+ memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
+
+ for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
+ {
+ uint16_t Size;
+ uint8_t Type;
+ uint8_t Direction;
+ bool DoubleBanked;
+
+ if (EndpointNum == RNDISInterfaceInfo->Config.DataINEndpointNumber)
+ {
+ Size = RNDISInterfaceInfo->Config.DataINEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = RNDISInterfaceInfo->Config.DataINEndpointDoubleBank;
+ }
+ else if (EndpointNum == RNDISInterfaceInfo->Config.DataOUTEndpointNumber)
+ {
+ Size = RNDISInterfaceInfo->Config.DataOUTEndpointSize;
+ Direction = ENDPOINT_DIR_OUT;
+ Type = EP_TYPE_BULK;
+ DoubleBanked = RNDISInterfaceInfo->Config.DataOUTEndpointDoubleBank;
+ }
+ else if (EndpointNum == RNDISInterfaceInfo->Config.NotificationEndpointNumber)
+ {
+ Size = RNDISInterfaceInfo->Config.NotificationEndpointSize;
+ Direction = ENDPOINT_DIR_IN;
+ Type = EP_TYPE_INTERRUPT;
+ DoubleBanked = RNDISInterfaceInfo->Config.NotificationEndpointDoubleBank;
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size,
+ DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
+{
+ if (USB_DeviceState != DEVICE_STATE_Configured)
+ return;
+
+ RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+
+ Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber);
+
+ if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady)
+ {
+ USB_Request_Header_t Notification = (USB_Request_Header_t)
+ {
+ .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
+ .bRequest = RNDIS_NOTIF_ResponseAvailable,
+ .wValue = 0,
+ .wIndex = 0,
+ .wLength = 0,
+ };
+
+ Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
+
+ Endpoint_ClearIN();
+
+ RNDISInterfaceInfo->State.ResponseReady = false;
+ }
+
+ if ((RNDISInterfaceInfo->State.CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))
+ {
+ RNDIS_Packet_Message_t RNDISPacketHeader;
+
+ Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber);
+
+ if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->State.FrameIN.FrameInBuffer))
+ {
+ Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK);
+
+ if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
+ {
+ Endpoint_StallTransaction();
+ return;
+ }
+
+ Endpoint_Read_Stream_LE(RNDISInterfaceInfo->State.FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
+
+ Endpoint_ClearOUT();
+
+ RNDISInterfaceInfo->State.FrameIN.FrameLength = RNDISPacketHeader.DataLength;
+
+ RNDISInterfaceInfo->State.FrameIN.FrameInBuffer = true;
+ }
+
+ Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber);
+
+ if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer)
+ {
+ memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t));
+
+ RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;
+ RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + RNDISInterfaceInfo->State.FrameOUT.FrameLength);
+ RNDISPacketHeader.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
+ RNDISPacketHeader.DataLength = RNDISInterfaceInfo->State.FrameOUT.FrameLength;
+
+ Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_LE(RNDISInterfaceInfo->State.FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);
+ Endpoint_ClearIN();
+
+ RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer = false;
+ }
+ }
+}
+
+void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* const 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->State.RNDISMessageBuffer;
+
+ switch (MessageHeader->MessageType)
+ {
+ case REMOTE_NDIS_INITIALIZE_MSG:
+ RNDISInterfaceInfo->State.ResponseReady = true;
+
+ RNDIS_Initialize_Message_t* INITIALIZE_Message =
+ (RNDIS_Initialize_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ RNDIS_Initialize_Complete_t* INITIALIZE_Response =
+ (RNDIS_Initialize_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+
+ INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
+ INITIALIZE_Response->MessageLength = sizeof(RNDIS_Initialize_Complete_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_Message_t) + ETHERNET_FRAME_SIZE_MAX);
+ INITIALIZE_Response->PacketAlignmentFactor = 0;
+ INITIALIZE_Response->AFListOffset = 0;
+ INITIALIZE_Response->AFListSize = 0;
+
+ RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Initialized;
+
+ break;
+ case REMOTE_NDIS_HALT_MSG:
+ RNDISInterfaceInfo->State.ResponseReady = false;
+ MessageHeader->MessageLength = 0;
+
+ RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Uninitialized;
+
+ break;
+ case REMOTE_NDIS_QUERY_MSG:
+ RNDISInterfaceInfo->State.ResponseReady = true;
+
+ RNDIS_Query_Message_t* QUERY_Message = (RNDIS_Query_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ RNDIS_Query_Complete_t* QUERY_Response = (RNDIS_Query_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ uint32_t Query_Oid = QUERY_Message->Oid;
+
+ void* QueryData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
+ QUERY_Message->InformationBufferOffset];
+ void* ResponseData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Query_Complete_t)];
+ uint16_t ResponseSize;
+
+ QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
+ QUERY_Response->MessageLength = sizeof(RNDIS_Query_Complete_t);
+
+ if (RNDIS_Device_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_Complete_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->State.ResponseReady = true;
+
+ RNDIS_Set_Message_t* SET_Message = (RNDIS_Set_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ RNDIS_Set_Complete_t* SET_Response = (RNDIS_Set_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ uint32_t SET_Oid = SET_Message->Oid;
+
+ SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
+ SET_Response->MessageLength = sizeof(RNDIS_Set_Complete_t);
+ SET_Response->RequestId = SET_Message->RequestId;
+
+ void* SetData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
+ SET_Message->InformationBufferOffset];
+
+ SET_Response->Status = RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData,
+ SET_Message->InformationBufferLength) ?
+ REMOTE_NDIS_STATUS_SUCCESS : REMOTE_NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ case REMOTE_NDIS_RESET_MSG:
+ RNDISInterfaceInfo->State.ResponseReady = true;
+
+ RNDIS_Reset_Complete_t* RESET_Response = (RNDIS_Reset_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+
+ RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
+ RESET_Response->MessageLength = sizeof(RNDIS_Reset_Complete_t);
+ RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
+ RESET_Response->AddressingReset = 0;
+
+ break;
+ case REMOTE_NDIS_KEEPALIVE_MSG:
+ RNDISInterfaceInfo->State.ResponseReady = true;
+
+ RNDIS_KeepAlive_Message_t* KEEPALIVE_Message =
+ (RNDIS_KeepAlive_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+ RNDIS_KeepAlive_Complete_t* KEEPALIVE_Response =
+ (RNDIS_KeepAlive_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
+
+ KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
+ KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KeepAlive_Complete_t);
+ KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
+ KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
+
+ break;
+ }
+}
+
+static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
+ const uint32_t OId,
+ void* const QueryData,
+ const uint16_t QuerySize,
+ void* ResponseData,
+ uint16_t* const ResponseSize)
+{
+ (void)QueryData;
+ (void)QuerySize;
+
+ 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) = NDIS_HardwareStatus_Ready;
+
+ 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->Config.AdapterVendorDescription) + 1);
+
+ memcpy(ResponseData, RNDISInterfaceInfo->Config.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->Config.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->State.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 RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
+ const uint32_t OId,
+ const void* SetData,
+ const uint16_t SetSize)
+{
+ (void)SetSize;
+
+ switch (OId)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ RNDISInterfaceInfo->State.CurrPacketFilter = *((uint32_t*)SetData);
+ RNDISInterfaceInfo->State.CurrRNDISState = ((RNDISInterfaceInfo->State.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;
+ }
+}
+
+#endif
+
diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.h b/LUFA/Drivers/USB/Class/Device/RNDIS.h
new file mode 100644
index 0000000..9f24f29
--- /dev/null
+++ b/LUFA/Drivers/USB/Class/Device/RNDIS.h
@@ -0,0 +1,186 @@
+/*
+ LUFA Library
+ Copyright (C) Dean Camera, 2010.
+
+ dean [at] fourwalledcubicle [dot] com
+ www.lufa-lib.org
+*/
+
+/*
+ Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, 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
+ * \brief Device mode driver for the library USB RNDIS Class driver.
+ *
+ * Device mode driver for the library USB RNDIS Class driver.
+ *
+ * \note This file should not be included directly. It is automatically included as needed by the USB module driver
+ * dispatch header located in LUFA/Drivers/USB.h.
+ */
+
+/** \ingroup Group_USBClassRNDIS
+ * @defgroup Group_USBClassRNDISDevice RNDIS Class Device Mode Driver
+ *
+ * \section Sec_Dependencies Module Source Dependencies
+ * The following files must be built with any user project that uses this module:
+ * - LUFA/Drivers/USB/Class/Device/RNDIS.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
+ *
+ * \section Module Description
+ * Device Mode USB Class driver framework interface, for the RNDIS USB Class driver.
+ *
+ * @{
+ */
+
+#ifndef _RNDIS_CLASS_DEVICE_H_
+#define _RNDIS_CLASS_DEVICE_H_
+
+ /* Includes: */
+ #include "../../USB.h"
+ #include "../Common/RNDIS.h"
+
+ #include <string.h>
+
+ /* Enable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+
+ /* Preprocessor Checks: */
+ #if !defined(__INCLUDE_FROM_RNDIS_DRIVER)
+ #error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
+ #endif
+
+ #if defined(__INCLUDE_FROM_RNDIS_DEVICE_C) && defined(NO_STREAM_CALLBACKS)
+ #error The NO_STREAM_CALLBACKS compile time option cannot be used in projects using the library Class drivers.
+ #endif
+
+
+ /* Public Interface - May be used in end-application: */
+ /* Type Defines: */
+ /** \brief RNDIS Class Device Mode Configuration and State Structure.
+ *
+ * Class state structure. An instance of this structure should be made for each RNDIS interface
+ * within the user application, and passed to each of the RNDIS class driver functions as the
+ * RNDISInterfaceInfo parameter. This stores each RNDIS interface's configuration and state information.
+ */
+ typedef struct
+ {
+ const 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. */
+ bool DataINEndpointDoubleBank; /**< Indicates if the RNDIS interface's IN data endpoint should use double banking. */
+
+ 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. */
+ bool DataOUTEndpointDoubleBank; /**< Indicates if the RNDIS interface's OUT data endpoint should use double banking. */
+
+ 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. */
+ bool NotificationEndpointDoubleBank; /**< Indicates if the RNDIS interface's notification endpoint should use double banking. */
+
+ char* AdapterVendorDescription; /**< String description of the adapter vendor. */
+ MAC_Address_t AdapterMACAddress; /**< MAC address of the adapter. */
+ } Config; /**< Config data for the USB class interface within the device. All elements in this section.
+ * <b>must</b> be set or the interface will fail to enumerate and operate correctly.
+ */
+ struct
+ {
+ uint8_t RNDISMessageBuffer[RNDIS_MESSAGE_BUFFER_SIZE]; /**< Buffer to hold RNDIS messages to and from the host,
+ * managed by the class driver.
+ */
+ bool ResponseReady; /**< Internal flag indicating if a RNDIS message is waiting to be returned to the host. */
+ uint8_t CurrRNDISState; /**< Current RNDIS state of the adapter, a value from the \ref RNDIS_States_t enum. */
+ uint32_t CurrPacketFilter; /**< Current packet filter mode, used internally by the class driver. */
+ Ethernet_Frame_Info_t FrameIN; /**< Structure holding the last received Ethernet frame from the host, for user
+ * processing.
+ */
+ Ethernet_Frame_Info_t FrameOUT; /**< Structure holding the next Ethernet frame to send to the host, populated by the
+ * user application.
+ */
+ } State; /**< State data for the USB class interface within the device. All elements in this section
+ * are reset to their defaults when the interface is enumerated.
+ */
+ } USB_ClassInfo_RNDIS_Device_t;
+
+ /* Function Prototypes: */
+ /** Configures the endpoints of a given RNDIS interface, ready for use. This should be linked to the library
+ * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration
+ * containing the given HID interface is selected.
+ *
+ * \note The endpoint index numbers as given in the interface's configuration structure must not overlap with any other
+ * interface, or endpoint bank corruption will occur. Gaps in the allocated endpoint numbers or non-sequential indexes
+ * within a single interface is allowed, but no two interfaces of any type have have interleaved endpoint indexes.
+ *
+ * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing a RNDIS Class configuration and state.
+ *
+ * \return Boolean true if the endpoints were successfully configured, false otherwise.
+ */
+ bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** Processes incoming control requests from the host, that are directed to the given RNDIS class interface. This should be
+ * linked to the library \ref EVENT_USB_Device_ControlRequest() event.
+ *
+ * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing a RNDIS Class configuration and state.
+ */
+ void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /** General management task for a given HID class interface, required for the correct operation of the interface. This should
+ * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask().
+ *
+ * \param[in,out] RNDISInterfaceInfo Pointer to a structure containing a RNDIS Class configuration and state.
+ */
+ void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+ /* Private Interface - For use in library only: */
+ #if !defined(__DOXYGEN__)
+ /* Function Prototypes: */
+ #if defined(__INCLUDE_FROM_RNDIS_DEVICE_C)
+ static void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
+ ATTR_NON_NULL_PTR_ARG(1);
+ static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
+ const uint32_t OId,
+ void* const QueryData,
+ const uint16_t QuerySize,
+ void* ResponseData,
+ uint16_t* const ResponseSize) ATTR_NON_NULL_PTR_ARG(1)
+ ATTR_NON_NULL_PTR_ARG(5) ATTR_NON_NULL_PTR_ARG(6);
+ static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
+ const uint32_t OId,
+ const void* SetData,
+ const uint16_t SetSize) ATTR_NON_NULL_PTR_ARG(1)
+ ATTR_NON_NULL_PTR_ARG(3);
+ #endif
+
+ #endif
+
+ /* Disable C linkage for C++ Compilers: */
+ #if defined(__cplusplus)
+ }
+ #endif
+
+#endif
+
+/** @} */
+