diff options
author | Dean Camera <dean@fourwalledcubicle.com> | 2010-05-08 03:12:14 +0000 |
---|---|---|
committer | Dean Camera <dean@fourwalledcubicle.com> | 2010-05-08 03:12:14 +0000 |
commit | 071e02c6b6b4837fa9cf0b6d4c749994e02638d7 (patch) | |
tree | 960446788703b69f0bb285450be80c5b3d8cc22c /LUFA/Drivers/USB/Class/Device | |
parent | e331b531c6e6d93eb0eee42b9002074e8090ad18 (diff) | |
download | lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.tar.gz lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.tar.bz2 lufa-071e02c6b6b4837fa9cf0b6d4c749994e02638d7.zip |
Add svn:eol-style property to source files, so that the line endings are correctly converted to the target system's native end of line style.
Diffstat (limited to 'LUFA/Drivers/USB/Class/Device')
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/Audio.c | 176 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/Audio.h | 638 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/CDC.c | 598 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/CDC.h | 662 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/HID.c | 388 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/HID.h | 412 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/MIDI.c | 248 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/MIDI.h | 368 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/MassStorage.c | 460 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/MassStorage.h | 336 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/RNDIS.c | 944 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Device/RNDIS.h | 342 |
12 files changed, 2786 insertions, 2786 deletions
diff --git a/LUFA/Drivers/USB/Class/Device/Audio.c b/LUFA/Drivers/USB/Class/Device/Audio.c index a10e6a5ae..241fd7f7e 100644 --- a/LUFA/Drivers/USB/Class/Device/Audio.c +++ b/LUFA/Drivers/USB/Class/Device/Audio.c @@ -1,89 +1,89 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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
-#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();
-
- AudioInterfaceInfo->State.InterfaceEnabled = ((USB_ControlRequest.wValue & 0xFF) != 0);
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- }
-}
-
-bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* AudioInterfaceInfo)
-{
- memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State));
-
- if (AudioInterfaceInfo->Config.DataINEndpointNumber)
- {
- if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_ISOCHRONOUS,
- ENDPOINT_DIR_IN, AudioInterfaceInfo->Config.DataINEndpointSize,
- ENDPOINT_BANK_DOUBLE)))
- {
- return false;
- }
- }
-
- if (AudioInterfaceInfo->Config.DataOUTEndpointNumber)
- {
- if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS,
- ENDPOINT_DIR_OUT, AudioInterfaceInfo->Config.DataOUTEndpointSize,
- ENDPOINT_BANK_DOUBLE)))
- {
- return false;
- }
- }
-
- return true;
-}
-
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 +#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(); + + AudioInterfaceInfo->State.InterfaceEnabled = ((USB_ControlRequest.wValue & 0xFF) != 0); + + Endpoint_ClearStatusStage(); + } + + break; + } +} + +bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* AudioInterfaceInfo) +{ + memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State)); + + if (AudioInterfaceInfo->Config.DataINEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_ISOCHRONOUS, + ENDPOINT_DIR_IN, AudioInterfaceInfo->Config.DataINEndpointSize, + ENDPOINT_BANK_DOUBLE))) + { + return false; + } + } + + if (AudioInterfaceInfo->Config.DataOUTEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(AudioInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_ISOCHRONOUS, + ENDPOINT_DIR_OUT, AudioInterfaceInfo->Config.DataOUTEndpointSize, + ENDPOINT_BANK_DOUBLE))) + { + return false; + } + } + + return true; +} + #endif
\ No newline at end of file diff --git a/LUFA/Drivers/USB/Class/Device/Audio.h b/LUFA/Drivers/USB/Class/Device/Audio.h index fd821e90c..45e267923 100644 --- a/LUFA/Drivers/USB/Class/Device/Audio.h +++ b/LUFA/Drivers/USB/Class/Device/Audio.h @@ -1,319 +1,319 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 Class driver.
- *
- * Device mode driver for the library USB Audio Class driver.
- *
- * \note This file should not be included directly. It is automatically included as needed by the class driver
- * dispatch header located in LUFA/Drivers/USB/Class/Audio.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
- *
- * \section Module Description
- * Device Mode USB Class driver framework interface, for the Audio 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/Class/Audio.h instead.
- #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.
- *
- * \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_UnhandledControlRequest() 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);
- 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.
- *
- * \note This function must only be called when the Device state machine is in the 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)
- {
- 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.
- *
- * \note This function must only be called when the Device state machine is in the 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)
- {
- 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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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 8-bit audio sample from the audio interface
- */
- static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) 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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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_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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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_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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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_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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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_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.
- *
- * \note This should be preceded immediately by a call to the USB_Audio_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_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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 Class driver. + * + * Device mode driver for the library USB Audio Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the class driver + * dispatch header located in LUFA/Drivers/USB/Class/Audio.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 + * + * \section Module Description + * Device Mode USB Class driver framework interface, for the Audio 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/Class/Audio.h instead. + #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. + * + * \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_UnhandledControlRequest() 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); + 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. + * + * \note This function must only be called when the Device state machine is in the 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) + { + 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. + * + * \note This function must only be called when the Device state machine is in the 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) + { + 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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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 8-bit audio sample from the audio interface + */ + static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) 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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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_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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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_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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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_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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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_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. + * + * \note This should be preceded immediately by a call to the USB_Audio_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_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 index f0c6edb12..69295e5e4 100644 --- a/LUFA/Drivers/USB/Class/Device/CDC.c +++ b/LUFA/Drivers/USB/Class/Device/CDC.c @@ -1,299 +1,299 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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_CLASS_DEVICE_C
-#define __INCLUDE_FROM_CDC_DRIVER
-#include "CDC.h"
-
-void CDC_Device_Event_Stub(void)
-{
-
-}
-
-void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
-{
- if (!(Endpoint_IsSETUPReceived()))
- return;
-
- if (USB_ControlRequest.wIndex != CDCInterfaceInfo->Config.ControlInterfaceNumber)
- return;
-
- switch (USB_ControlRequest.bRequest)
- {
- case REQ_GetLineEncoding:
- if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
- Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding));
- Endpoint_ClearOUT();
- }
-
- break;
- case REQ_SetLineEncoding:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
- Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding));
- EVENT_CDC_Device_LineEncodingChanged(CDCInterfaceInfo);
- Endpoint_ClearIN();
- }
-
- break;
- case REQ_SetControlLineState:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue;
- EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo);
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- case REQ_SendBreak:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- EVENT_CDC_Device_BreakSent(CDCInterfaceInfo, (uint8_t)USB_ControlRequest.wValue);
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- }
-}
-
-bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
-{
- memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
-
- if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_IN, CDCInterfaceInfo->Config.DataINEndpointSize,
- CDCInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_OUT, CDCInterfaceInfo->Config.DataOUTEndpointSize,
- CDCInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.NotificationEndpointNumber, EP_TYPE_INTERRUPT,
- ENDPOINT_DIR_IN, CDCInterfaceInfo->Config.NotificationEndpointSize,
- CDCInterfaceInfo->Config.NotificationEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- return true;
-}
-
-void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
-{
- if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
- return;
-
- Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber);
-
- if (Endpoint_IsOUTReceived() && !(Endpoint_BytesInEndpoint()))
- Endpoint_ClearOUT();
-
- CDC_Device_Flush(CDCInterfaceInfo);
-}
-
-uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, 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;
- }
-}
-
-uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo)
-{
- if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS))
- return 0;
-
- Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber);
-
- uint8_t DataByte = Endpoint_Read_Byte();
-
- if (!(Endpoint_BytesInEndpoint()))
- Endpoint_ClearOUT();
-
- return DataByte;
-}
-
-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 = 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* CDCInterfaceInfo, FILE* 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* CDCInterfaceInfo, FILE* 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)
-{
- if (!(CDC_Device_BytesReceived((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream))))
- return _FDEV_EOF;
-
- return CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream));
-}
-
-static int CDC_Device_getchar_Blocking(FILE* Stream)
-{
- while (!(CDC_Device_BytesReceived((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream))))
- {
- if (USB_DeviceState == DEVICE_STATE_Unattached)
- return _FDEV_EOF;
-
- CDC_Device_USBTask((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream));
- USB_USBTask();
- }
-
- return CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream));
-}
-
-#endif
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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_CLASS_DEVICE_C +#define __INCLUDE_FROM_CDC_DRIVER +#include "CDC.h" + +void CDC_Device_Event_Stub(void) +{ + +} + +void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != CDCInterfaceInfo->Config.ControlInterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case REQ_GetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding)); + Endpoint_ClearOUT(); + } + + break; + case REQ_SetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_Read_Control_Stream_LE(&CDCInterfaceInfo->State.LineEncoding, sizeof(CDCInterfaceInfo->State.LineEncoding)); + EVENT_CDC_Device_LineEncodingChanged(CDCInterfaceInfo); + Endpoint_ClearIN(); + } + + break; + case REQ_SetControlLineState: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue; + EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo); + + Endpoint_ClearStatusStage(); + } + + break; + case REQ_SendBreak: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + EVENT_CDC_Device_BreakSent(CDCInterfaceInfo, (uint8_t)USB_ControlRequest.wValue); + + Endpoint_ClearStatusStage(); + } + + break; + } +} + +bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo) +{ + memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State)); + + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, CDCInterfaceInfo->Config.DataINEndpointSize, + CDCInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, CDCInterfaceInfo->Config.DataOUTEndpointSize, + CDCInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(CDCInterfaceInfo->Config.NotificationEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, CDCInterfaceInfo->Config.NotificationEndpointSize, + CDCInterfaceInfo->Config.NotificationEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + return true; +} + +void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) + return; + + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber); + + if (Endpoint_IsOUTReceived() && !(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + CDC_Device_Flush(CDCInterfaceInfo); +} + +uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, 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; + } +} + +uint8_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* CDCInterfaceInfo) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) + return 0; + + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpointNumber); + + uint8_t DataByte = Endpoint_Read_Byte(); + + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + return DataByte; +} + +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 = 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* CDCInterfaceInfo, FILE* 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* CDCInterfaceInfo, FILE* 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) +{ + if (!(CDC_Device_BytesReceived((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)))) + return _FDEV_EOF; + + return CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)); +} + +static int CDC_Device_getchar_Blocking(FILE* Stream) +{ + while (!(CDC_Device_BytesReceived((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)))) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return _FDEV_EOF; + + CDC_Device_USBTask((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)); + USB_USBTask(); + } + + return CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)); +} + +#endif diff --git a/LUFA/Drivers/USB/Class/Device/CDC.h b/LUFA/Drivers/USB/Class/Device/CDC.h index 0b2c4c034..f0351f5d9 100644 --- a/LUFA/Drivers/USB/Class/Device/CDC.h +++ b/LUFA/Drivers/USB/Class/Device/CDC.h @@ -1,331 +1,331 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 class driver
- * dispatch header located in LUFA/Drivers/USB/Class/CDC.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
- *
- * \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
- * conbat 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/Class/CDC.h instead.
- #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. */
-
- struct
- {
- uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */
- uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the
- * CDCDevice_CDC_LineCodingFormats_t enum
- */
- uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the
- * CDCDevice_LineCodingParity_t enum
- */
- uint8_t DataBits; /**< Bits of data per character of the virtual serial port */
- } LineEncoding; /** 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.
- *
- * \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_UnhandledControlRequest() 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 seperate
- * 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, 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.
- *
- * \note This function must only be called when the Device state machine is in the 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, 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.
- *
- * \note This function must only be called when the Device state machine is in the 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.
- *
- * \note This function must only be called when the Device state machine is in the 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 0. The \ref CDC_Device_BytesReceived() function should be queried before data is received to ensure that no data
- * underflow occurs.
- *
- * \note This function must only be called when the Device state machine is in the 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 0 if no data received
- */
- uint8_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.
- *
- * \note This function must only be called when the Device state machine is in the 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.
- *
- * \note This function must only be called when the Device state machine is in the 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 characer 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* CDCInterfaceInfo, FILE* Stream);
-
- /** 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* CDCInterfaceInfo, FILE* Stream);
-
- /* Private Interface - For use in library only: */
- #if !defined(__DOXYGEN__)
- /* Function Prototypes: */
- #if defined(__INCLUDE_FROM_CDC_CLASS_DEVICE_C)
- static int CDC_Device_putchar(char c, FILE* Stream);
- static int CDC_Device_getchar(FILE* Stream);
- static int CDC_Device_getchar_Blocking(FILE* Stream);
-
- 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, 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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 class driver + * dispatch header located in LUFA/Drivers/USB/Class/CDC.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 + * + * \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 + * conbat 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/Class/CDC.h instead. + #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. */ + + struct + { + uint32_t BaudRateBPS; /**< Baud rate of the virtual serial port, in bits per second */ + uint8_t CharFormat; /**< Character format of the virtual serial port, a value from the + * CDCDevice_CDC_LineCodingFormats_t enum + */ + uint8_t ParityType; /**< Parity setting of the virtual serial port, a value from the + * CDCDevice_LineCodingParity_t enum + */ + uint8_t DataBits; /**< Bits of data per character of the virtual serial port */ + } LineEncoding; /** 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. + * + * \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_UnhandledControlRequest() 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 seperate + * 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, 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. + * + * \note This function must only be called when the Device state machine is in the 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, 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. + * + * \note This function must only be called when the Device state machine is in the 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. + * + * \note This function must only be called when the Device state machine is in the 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 0. The \ref CDC_Device_BytesReceived() function should be queried before data is received to ensure that no data + * underflow occurs. + * + * \note This function must only be called when the Device state machine is in the 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 0 if no data received + */ + uint8_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. + * + * \note This function must only be called when the Device state machine is in the 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. + * + * \note This function must only be called when the Device state machine is in the 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 characer 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* CDCInterfaceInfo, FILE* Stream); + + /** 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* CDCInterfaceInfo, FILE* Stream); + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_CDC_CLASS_DEVICE_C) + static int CDC_Device_putchar(char c, FILE* Stream); + static int CDC_Device_getchar(FILE* Stream); + static int CDC_Device_getchar_Blocking(FILE* Stream); + + 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, 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 index 676650976..88bb60993 100644 --- a/LUFA/Drivers/USB/Class/Device/HID.c +++ b/LUFA/Drivers/USB/Class/Device/HID.c @@ -1,194 +1,194 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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
-#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 REQ_GetReport:
- if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- uint16_t ReportINSize = 0;
- uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF);
- uint8_t ReportType = (USB_ControlRequest.wValue >> 8) - 1;
- uint8_t ReportINData[HIDInterfaceInfo->Config.PrevReportINBufferSize];
-
- memset(ReportINData, 0, sizeof(ReportINData));
-
- CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportType,
- HIDInterfaceInfo->Config.PrevReportINBuffer, &ReportINSize);
-
- if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL)
- memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINData, HIDInterfaceInfo->Config.PrevReportINBufferSize);
-
- Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
- Endpoint_Write_Control_Stream_LE(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize);
- Endpoint_ClearOUT();
- }
-
- break;
- case REQ_SetReport:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- uint16_t ReportOUTSize = USB_ControlRequest.wLength;
- uint8_t ReportOUTData[ReportOUTSize];
- uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF);
-
- Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize);
- CALLBACK_HID_Device_ProcessHIDReport(HIDInterfaceInfo, ReportID, ReportOUTData, ReportOUTSize);
- Endpoint_ClearIN();
- }
-
- break;
- case 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 REQ_SetProtocol:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- HIDInterfaceInfo->State.UsingReportProtocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- case REQ_SetIdle:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- HIDInterfaceInfo->State.IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6);
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- case 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, REPORT_ITEM_TYPE_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
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 +#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 REQ_GetReport: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + uint16_t ReportINSize = 0; + uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF); + uint8_t ReportType = (USB_ControlRequest.wValue >> 8) - 1; + uint8_t ReportINData[HIDInterfaceInfo->Config.PrevReportINBufferSize]; + + memset(ReportINData, 0, sizeof(ReportINData)); + + CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportType, + HIDInterfaceInfo->Config.PrevReportINBuffer, &ReportINSize); + + if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL) + memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINData, HIDInterfaceInfo->Config.PrevReportINBufferSize); + + Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP); + Endpoint_Write_Control_Stream_LE(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize); + Endpoint_ClearOUT(); + } + + break; + case REQ_SetReport: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + uint16_t ReportOUTSize = USB_ControlRequest.wLength; + uint8_t ReportOUTData[ReportOUTSize]; + uint8_t ReportID = (USB_ControlRequest.wValue & 0xFF); + + Endpoint_Read_Control_Stream_LE(ReportOUTData, ReportOUTSize); + CALLBACK_HID_Device_ProcessHIDReport(HIDInterfaceInfo, ReportID, ReportOUTData, ReportOUTSize); + Endpoint_ClearIN(); + } + + break; + case 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 REQ_SetProtocol: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + HIDInterfaceInfo->State.UsingReportProtocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00); + + Endpoint_ClearStatusStage(); + } + + break; + case REQ_SetIdle: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + HIDInterfaceInfo->State.IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6); + + Endpoint_ClearStatusStage(); + } + + break; + case 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, REPORT_ITEM_TYPE_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 index 92751241b..ac6ee4cb7 100644 --- a/LUFA/Drivers/USB/Class/Device/HID.h +++ b/LUFA/Drivers/USB/Class/Device/HID.h @@ -1,206 +1,206 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 class driver
- * dispatch header located in LUFA/Drivers/USB/Class/HID.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
- *
- * \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/Class/HID.h instead.
- #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.
- *
- * \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* 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_UnhandledControlRequest() 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* 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* 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 REPORT_ITEM_TYPE_In or \ref REPORT_ITEM_TYPE_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* 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] 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 void* ReportData, const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1)
- ATTR_NON_NULL_PTR_ARG(3);
-
- /* 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* HIDInterfaceInfo);
- static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* HIDInterfaceInfo)
- {
- if (HIDInterfaceInfo->State.IdleMSRemaining)
- HIDInterfaceInfo->State.IdleMSRemaining--;
- }
-
- /* Disable C linkage for C++ Compilers: */
- #if defined(__cplusplus)
- }
- #endif
-
-#endif
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 class driver + * dispatch header located in LUFA/Drivers/USB/Class/HID.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 + * + * \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/Class/HID.h instead. + #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. + * + * \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* 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_UnhandledControlRequest() 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* 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* 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 REPORT_ITEM_TYPE_In or \ref REPORT_ITEM_TYPE_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* 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] 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 void* ReportData, const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1) + ATTR_NON_NULL_PTR_ARG(3); + + /* 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* HIDInterfaceInfo); + static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* 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 index 1a66dc867..bf0f23c0d 100644 --- a/LUFA/Drivers/USB/Class/Device/MIDI.c +++ b/LUFA/Drivers/USB/Class/Device/MIDI.c @@ -1,124 +1,124 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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
-#include "MIDI.h"
-
-bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
-{
- memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State));
-
- if (MIDIInterfaceInfo->Config.DataINEndpointNumber)
- {
- if (!(Endpoint_ConfigureEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_IN, MIDIInterfaceInfo->Config.DataINEndpointSize,
- MIDIInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
- }
-
- if (MIDIInterfaceInfo->Config.DataOUTEndpointNumber)
- {
- if (!(Endpoint_ConfigureEndpoint(MIDIInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_OUT, MIDIInterfaceInfo->Config.DataOUTEndpointSize,
- MIDIInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
- }
-
- return true;
-}
-
-uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event)
-{
- if (USB_DeviceState != DEVICE_STATE_Configured)
- return ENDPOINT_RWSTREAM_DeviceDisconnected;
-
- Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber);
-
- if (Endpoint_IsReadWriteAllowed());
- {
- uint8_t ErrorCode;
-
- 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
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 +#include "MIDI.h" + +bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) +{ + memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State)); + + if (MIDIInterfaceInfo->Config.DataINEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, MIDIInterfaceInfo->Config.DataINEndpointSize, + MIDIInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + } + + if (MIDIInterfaceInfo->Config.DataOUTEndpointNumber) + { + if (!(Endpoint_ConfigureEndpoint(MIDIInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, MIDIInterfaceInfo->Config.DataOUTEndpointSize, + MIDIInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + } + + return true; +} + +uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo, MIDI_EventPacket_t* const Event) +{ + if (USB_DeviceState != DEVICE_STATE_Configured) + return ENDPOINT_RWSTREAM_DeviceDisconnected; + + Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpointNumber); + + if (Endpoint_IsReadWriteAllowed()); + { + uint8_t ErrorCode; + + 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 index 00d34e000..c4b871528 100644 --- a/LUFA/Drivers/USB/Class/Device/MIDI.h +++ b/LUFA/Drivers/USB/Class/Device/MIDI.h @@ -1,184 +1,184 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 class driver
- * dispatch header located in LUFA/Drivers/USB/Class/MIDI.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
- *
- * \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/Class/MIDI.h instead.
- #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 yet
- } 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.
- *
- * \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);
-
- /** 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.
- *
- * \note This function must only be called when the Device state machine is in the DEVICE_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 USB_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,
- 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);
-
- /** 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.
- *
- * \note This function must only be called when the Device state machine is in the DEVICE_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: */
- /** 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
- */
- static inline void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo);
- static inline void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo)
- {
- (void)MIDIInterfaceInfo;
- }
-
- /** 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_UnhandledControlRequest() 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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 class driver + * dispatch header located in LUFA/Drivers/USB/Class/MIDI.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 + * + * \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/Class/MIDI.h instead. + #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 yet + } 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. + * + * \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); + + /** 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. + * + * \note This function must only be called when the Device state machine is in the DEVICE_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 USB_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, + 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); + + /** 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. + * + * \note This function must only be called when the Device state machine is in the DEVICE_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: */ + /** 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 + */ + static inline void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo); + static inline void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) + { + (void)MIDIInterfaceInfo; + } + + /** 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_UnhandledControlRequest() 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 index a5ebab029..c31eb86cb 100644 --- a/LUFA/Drivers/USB/Class/Device/MassStorage.c +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.c @@ -1,230 +1,230 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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_CLASS_DEVICE_C
-#define __INCLUDE_FROM_MS_DRIVER
-#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 REQ_MassStorageReset:
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- MSInterfaceInfo->State.IsMassStoreReset = true;
-
- Endpoint_ClearStatusStage();
- }
-
- break;
- case 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));
-
- if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_IN, MSInterfaceInfo->Config.DataINEndpointSize,
- MSInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_OUT, MSInterfaceInfo->Config.DataOUTEndpointSize,
- MSInterfaceInfo->Config.DataOUTEndpointDoubleBank ? 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) ?
- SCSI_Command_Pass : 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 == 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
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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_CLASS_DEVICE_C +#define __INCLUDE_FROM_MS_DRIVER +#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 REQ_MassStorageReset: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + MSInterfaceInfo->State.IsMassStoreReset = true; + + Endpoint_ClearStatusStage(); + } + + break; + case 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)); + + if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, MSInterfaceInfo->Config.DataINEndpointSize, + MSInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(MSInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, MSInterfaceInfo->Config.DataOUTEndpointSize, + MSInterfaceInfo->Config.DataOUTEndpointDoubleBank ? 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) ? + SCSI_Command_Pass : 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 == 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 index 8eb150be9..00fd2e251 100644 --- a/LUFA/Drivers/USB/Class/Device/MassStorage.h +++ b/LUFA/Drivers/USB/Class/Device/MassStorage.h @@ -1,168 +1,168 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 class driver
- * dispatch header located in LUFA/Drivers/USB/Class/MassStorage.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
- *
- * \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/Class/MassStorage.h instead.
- #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.
- *
- * \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_UnhandledControlRequest() 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_MS_CLASS_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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 class driver + * dispatch header located in LUFA/Drivers/USB/Class/MassStorage.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 + * + * \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/Class/MassStorage.h instead. + #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. + * + * \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_UnhandledControlRequest() 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_MS_CLASS_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 index 69e8e677d..d71533bb4 100644 --- a/LUFA/Drivers/USB/Class/Device/RNDIS.c +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.c @@ -1,472 +1,472 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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_CLASS_DEVICE_C
-#define __INCLUDE_FROM_RNDIS_DRIVER
-#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 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);
- RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo);
- Endpoint_ClearIN();
- }
-
- break;
- case REQ_GetEncapsulatedResponse:
- if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
- {
- Endpoint_ClearSETUP();
-
- RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
-
- if (!(MessageHeader->MessageLength))
- {
- RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0;
- MessageHeader->MessageLength = 1;
- }
-
- 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));
-
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.DataINEndpointSize,
- RNDISInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK,
- ENDPOINT_DIR_OUT, RNDISInterfaceInfo->Config.DataOUTEndpointSize,
- RNDISInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
- {
- return false;
- }
-
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber, EP_TYPE_INTERRUPT,
- ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.NotificationEndpointSize,
- RNDISInterfaceInfo->Config.NotificationEndpointDoubleBank ? 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 = 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,
- 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
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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_CLASS_DEVICE_C +#define __INCLUDE_FROM_RNDIS_DRIVER +#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 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); + RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo); + Endpoint_ClearIN(); + } + + break; + case REQ_GetEncapsulatedResponse: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + if (!(MessageHeader->MessageLength)) + { + RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0; + MessageHeader->MessageLength = 1; + } + + 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)); + + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.DataINEndpointSize, + RNDISInterfaceInfo->Config.DataINEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK, + ENDPOINT_DIR_OUT, RNDISInterfaceInfo->Config.DataOUTEndpointSize, + RNDISInterfaceInfo->Config.DataOUTEndpointDoubleBank ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + + if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber, EP_TYPE_INTERRUPT, + ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.NotificationEndpointSize, + RNDISInterfaceInfo->Config.NotificationEndpointDoubleBank ? 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 = 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, + 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 index 5408ec70a..865eb0203 100644 --- a/LUFA/Drivers/USB/Class/Device/RNDIS.h +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.h @@ -1,171 +1,171 @@ -/*
- LUFA Library
- Copyright (C) Dean Camera, 2010.
-
- dean [at] fourwalledcubicle [dot] com
- www.fourwalledcubicle.com
-*/
-
-/*
- 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 class driver
- * dispatch header located in LUFA/Drivers/USB/Class/RNDIS.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
- *
- * \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/Class/RNDIS.h instead.
- #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 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.
- *
- * \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_UnhandledControlRequest() 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_CLASS_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,
- 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
-
-/** @} */
+/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + 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 class driver + * dispatch header located in LUFA/Drivers/USB/Class/RNDIS.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 + * + * \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/Class/RNDIS.h instead. + #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 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. + * + * \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_UnhandledControlRequest() 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_CLASS_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, + 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 + +/** @} */ |