diff options
Diffstat (limited to 'lib/lufa/LUFA/Drivers/USB/Class/Device')
14 files changed, 3766 insertions, 0 deletions
| diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c new file mode 100644 index 0000000000..08cbeb7061 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c @@ -0,0 +1,197 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_AUDIO_DRIVER +#define  __INCLUDE_FROM_AUDIO_DEVICE_C +#include "AudioClassDevice.h" + +void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) +	{ +		uint8_t InterfaceIndex = (USB_ControlRequest.wIndex & 0xFF); + +		if ((InterfaceIndex != AudioInterfaceInfo->Config.ControlInterfaceNumber) && +		    (InterfaceIndex != AudioInterfaceInfo->Config.StreamingInterfaceNumber)) +		{ +			return; +		} +	} +	else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) +	{ +		uint8_t EndpointAddress = (USB_ControlRequest.wIndex & 0xFF); + +		if ((EndpointAddress != AudioInterfaceInfo->Config.DataINEndpoint.Address) && +		    (EndpointAddress != AudioInterfaceInfo->Config.DataOUTEndpoint.Address)) +		{ +			return; +		} +	} + +	switch (USB_ControlRequest.bRequest) +	{ +		case REQ_SetInterface: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				AudioInterfaceInfo->State.InterfaceEnabled = ((USB_ControlRequest.wValue & 0xFF) != 0); +				EVENT_Audio_Device_StreamStartStop(AudioInterfaceInfo); +			} + +			break; +		case AUDIO_REQ_GetStatus: +			if ((USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) || +			    (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT))) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); +			} + +			break; +		case AUDIO_REQ_SetCurrent: +		case AUDIO_REQ_SetMinimum: +		case AUDIO_REQ_SetMaximum: +		case AUDIO_REQ_SetResolution: +			if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) +			{ +				uint8_t EndpointProperty = USB_ControlRequest.bRequest; +				uint8_t EndpointAddress  = (uint8_t)USB_ControlRequest.wIndex; +				uint8_t EndpointControl  = (USB_ControlRequest.wValue >> 8); + +				if (CALLBACK_Audio_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, +				                                                 EndpointControl, NULL, NULL)) +				{ +					uint16_t ValueLength = USB_ControlRequest.wLength; +					uint8_t  Value[ValueLength]; + +					Endpoint_ClearSETUP(); +					Endpoint_Read_Control_Stream_LE(Value, ValueLength); +					Endpoint_ClearIN(); + +					CALLBACK_Audio_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, +					                                             EndpointControl, &ValueLength, Value); +				} +			} +			else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) +			{ +				uint8_t  Property  = USB_ControlRequest.bRequest; +				uint8_t  Entity    = (USB_ControlRequest.wIndex >> 8); +				uint16_t Parameter = USB_ControlRequest.wValue; + +				if (CALLBACK_Audio_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, +				                                                  Parameter, NULL, NULL)) +				{ +					uint16_t ValueLength = USB_ControlRequest.wLength; +					uint8_t  Value[ValueLength]; + +					Endpoint_ClearSETUP(); +					Endpoint_Read_Control_Stream_LE(Value, ValueLength); +					Endpoint_ClearIN(); + +					CALLBACK_Audio_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, +				                                                  Parameter, &ValueLength, Value); +				} +			} + +			break; +		case AUDIO_REQ_GetCurrent: +		case AUDIO_REQ_GetMinimum: +		case AUDIO_REQ_GetMaximum: +		case AUDIO_REQ_GetResolution: +			if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) +			{ +				uint8_t  EndpointProperty = USB_ControlRequest.bRequest; +				uint8_t  EndpointAddress  = (uint8_t)USB_ControlRequest.wIndex; +				uint8_t  EndpointControl  = (USB_ControlRequest.wValue >> 8); +				uint16_t ValueLength      = USB_ControlRequest.wLength; +				uint8_t  Value[ValueLength]; + +				if (CALLBACK_Audio_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, +				                                                 EndpointControl, &ValueLength, Value)) +				{ +					Endpoint_ClearSETUP(); +					Endpoint_Write_Control_Stream_LE(Value, ValueLength); +					Endpoint_ClearOUT(); +				} +			} +			else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) +			{ +				uint8_t  Property    = USB_ControlRequest.bRequest; +				uint8_t  Entity      = (USB_ControlRequest.wIndex >> 8); +				uint16_t Parameter   = USB_ControlRequest.wValue; +				uint16_t ValueLength = USB_ControlRequest.wLength; +				uint8_t  Value[ValueLength]; + +				if (CALLBACK_Audio_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, +				                                                  Parameter, &ValueLength, Value)) +				{ +					Endpoint_ClearSETUP(); +					Endpoint_Write_Control_Stream_LE(Value, ValueLength); +					Endpoint_ClearOUT(); +				} +			} + +			break; +	} +} + +bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +{ +	memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State)); + +	AudioInterfaceInfo->Config.DataINEndpoint.Type  = EP_TYPE_ISOCHRONOUS; +	AudioInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_ISOCHRONOUS; + +	if (!(Endpoint_ConfigureEndpointTable(&AudioInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&AudioInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  return false; + +	return true; +} + +void Audio_Device_Event_Stub(void) +{ + +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h new file mode 100644 index 0000000000..ca63511b20 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h @@ -0,0 +1,396 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB Audio 1.0 Class driver. + * + *  Device mode driver for the library USB Audio 1.0 Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassAudio + *  \defgroup Group_USBClassAudioDevice Audio 1.0 Class Device Mode Driver + * + *  \section Sec_USBClassAudioDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/AudioClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassAudioDevice_ModDescription Module Description + *  Device Mode USB Class driver framework interface, for the Audio 1.0 USB Class driver. + * + *  @{ + */ + +#ifndef _AUDIO_CLASS_DEVICE_H_ +#define _AUDIO_CLASS_DEVICE_H_ + +	/* Includes: */ +		#include "../../USB.h" +		#include "../Common/AudioClassCommon.h" + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_AUDIO_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			 *  \c AudioInterfaceInfo parameter. This stores each Audio interface's configuration and state information. +			 */ +			typedef struct +			{ +				struct +				{ +					uint8_t  ControlInterfaceNumber; /**< Index of the Audio Control interface within the device this +					                                  *   structure controls. +					                                  */ +					uint8_t  StreamingInterfaceNumber; /**< Index of the Audio Streaming interface within the device this +														*   structure controls. +														*/ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ +				} 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 \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given Audio class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 */ +			void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented +			 *  in the user application to handle property manipulations on streaming audio endpoints. +			 * +			 *  When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for +			 *  the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations +			 *  to indicate the size of the retrieved data. +			 * +			 *  \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value +			 *        of the \c DataLength parameter. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 *  \param[in]     EndpointProperty    Property of the endpoint to get or set, a value from \ref Audio_ClassRequests_t. +			 *  \param[in]     EndpointAddress     Address of the streaming endpoint whose property is being referenced. +			 *  \param[in]     EndpointControl     Parameter of the endpoint to get or set, a value from \ref Audio_EndpointControls_t. +			 *  \param[in,out] DataLength          For SET operations, the length of the parameter data to set. For GET operations, the maximum +			 *                                     length of the retrieved data. When NULL, the function should return whether the given property +			 *                                     and parameter is valid for the requested endpoint without reading or modifying the Data buffer. +			 *  \param[in,out] Data                Pointer to a location where the parameter data is stored for SET operations, or where +			 *                                     the retrieved data is to be stored for GET operations. +			 * +			 *  \return Boolean \c true if the property GET/SET was successful, \c false otherwise +			 */ +			bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                                  const uint8_t EndpointProperty, +			                                                  const uint8_t EndpointAddress, +			                                                  const uint8_t EndpointControl, +			                                                  uint16_t* const DataLength, +			                                                  uint8_t* Data) ATTR_NON_NULL_PTR_ARG(1); + +			/** Audio class driver callback for the setting and retrieval of streaming interface properties. This callback must be implemented +			 *  in the user application to handle property manipulations on streaming audio interfaces. +			 * +			 *  When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for +			 *  the given entity and should return as fast as possible. When non-NULL, this value may be altered for GET operations +			 *  to indicate the size of the retrieved data. +			 * +			 *  \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value +			 *        of the \c DataLength parameter. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 *  \param[in]     Property            Property of the interface to get or set, a value from \ref Audio_ClassRequests_t. +			 *  \param[in]     EntityAddress       Address of the audio entity whose property is being referenced. +			 *  \param[in]     Parameter           Parameter of the entity to get or set, specific to each type of entity (see USB Audio specification). +			 *  \param[in,out] DataLength          For SET operations, the length of the parameter data to set. For GET operations, the maximum +			 *                                     length of the retrieved data. When NULL, the function should return whether the given property +			 *                                     and parameter is valid for the requested endpoint without reading or modifying the Data buffer. +			 *  \param[in,out] Data                Pointer to a location where the parameter data is stored for SET operations, or where +			 *                                     the retrieved data is to be stored for GET operations. +			 * +			 *  \return Boolean \c true if the property GET/SET was successful, \c false otherwise +			 */ +			bool CALLBACK_Audio_Device_GetSetInterfaceProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                                   const uint8_t Property, +			                                                   const uint8_t EntityAddress, +			                                                   const uint16_t Parameter, +			                                                   uint16_t* const DataLength, +			                                                   uint8_t* Data) ATTR_NON_NULL_PTR_ARG(1); + +			/** Audio class driver event for an Audio Stream start/stop change. This event fires each time the device receives a stream enable or +			 *  disable control request from the host, to start and stop the audio stream. The current state of the stream can be determined by the +			 *  State.InterfaceEnabled value inside the Audio interface structure passed as a parameter. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 */ +			void EVENT_Audio_Device_StreamStartStop(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo); + +		/* Inline Functions: */ +			/** General management task for a given Audio class interface, required for the correct operation of the interface. This should +			 *  be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 */ +			static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			                                        ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				(void)AudioInterfaceInfo; +			} + +			/** Determines if the given audio interface is ready for a sample to be read from it, and selects the streaming +			 *  OUT endpoint ready for reading. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 * +			 *  \return Boolean \c true if the given Audio interface has a sample to be read, \c false otherwise. +			 */ +			static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			                                                 ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled)) +				  return false; + +				Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataOUTEndpoint.Address); +				return Endpoint_IsOUTReceived(); +			} + +			/** Determines if the given audio interface is ready to accept the next sample to be written to it, and selects +			 *  the streaming IN endpoint ready for writing. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 * +			 *  \return Boolean \c true if the given Audio interface is ready to accept the next sample, \c false otherwise. +			 */ +			static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			                                                     ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled)) +				  return false; + +				Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataINEndpoint.Address); +				return Endpoint_IsINReady(); +			} + +			/** Reads the next 8-bit audio sample from the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure +			 *       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_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				int8_t Sample; + +				(void)AudioInterfaceInfo; + +				Sample = Endpoint_Read_8(); + +				if (!(Endpoint_BytesInEndpoint())) +				  Endpoint_ClearOUT(); + +				return Sample; +			} + +			/** Reads the next 16-bit audio sample from the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure +			 *       that the correct endpoint is selected and ready for data. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 * +			 *  \return  Signed 16-bit audio sample from the audio interface. +			 */ +			static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			                                                ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				int16_t Sample; + +				(void)AudioInterfaceInfo; + +				Sample = (int16_t)Endpoint_Read_16_LE(); + +				if (!(Endpoint_BytesInEndpoint())) +				  Endpoint_ClearOUT(); + +				return Sample; +			} + +			/** Reads the next 24-bit audio sample from the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure +			 *       that the correct endpoint is selected and ready for data. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 * +			 *  \return Signed 24-bit audio sample from the audio interface. +			 */ +			static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			                                                ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +			{ +				int32_t Sample; + +				(void)AudioInterfaceInfo; + +				Sample = (((uint32_t)Endpoint_Read_8() << 16) | Endpoint_Read_16_LE()); + +				if (!(Endpoint_BytesInEndpoint())) +				  Endpoint_ClearOUT(); + +				return Sample; +			} + +			/** Writes the next 8-bit audio sample to the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to +			 *       ensure that the correct endpoint is selected and ready for data. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 *  \param[in]     Sample              Signed 8-bit audio sample. +			 */ +			static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                             const int8_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                             const int8_t Sample) +			{ +				Endpoint_Write_8(Sample); + +				if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) +				  Endpoint_ClearIN(); +			} + +			/** Writes the next 16-bit audio sample to the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to +			 *       ensure that the correct endpoint is selected and ready for data. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 *  \param[in]     Sample              Signed 16-bit audio sample. +			 */ +			static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                              const int16_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                              const int16_t Sample) +			{ +				Endpoint_Write_16_LE(Sample); + +				if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) +				  Endpoint_ClearIN(); +			} + +			/** Writes the next 24-bit audio sample to the current audio interface. +			 * +			 *  \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to +			 *       ensure that the correct endpoint is selected and ready for data. +			 * +			 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state. +			 *  \param[in]     Sample              Signed 24-bit audio sample. +			 */ +			static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                              const int32_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; +			static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, +			                                              const int32_t Sample) +			{ +				Endpoint_Write_16_LE(Sample); +				Endpoint_Write_8(Sample >> 16); + +				if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) +				  Endpoint_ClearIN(); +			} + +	/* Private Interface - For use in library only: */ +	#if !defined(__DOXYGEN__) +		/* Function Prototypes: */ +			#if defined(__INCLUDE_FROM_AUDIO_DEVICE_C) +				void Audio_Device_Event_Stub(void) ATTR_CONST; + +				void EVENT_Audio_Device_StreamStartStop(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +				                                        ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(Audio_Device_Event_Stub); +			#endif + +	#endif + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c new file mode 100644 index 0000000000..867548c00b --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c @@ -0,0 +1,362 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_CDC_DRIVER +#define  __INCLUDE_FROM_CDC_DEVICE_C +#include "CDCClassDevice.h" + +void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if (USB_ControlRequest.wIndex != CDCInterfaceInfo->Config.ControlInterfaceNumber) +	  return; + +	switch (USB_ControlRequest.bRequest) +	{ +		case CDC_REQ_GetLineEncoding: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); + +				while (!(Endpoint_IsINReady())); + +				Endpoint_Write_32_LE(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS); +				Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.CharFormat); +				Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.ParityType); +				Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.DataBits); + +				Endpoint_ClearIN(); +				Endpoint_ClearStatusStage(); +			} + +			break; +		case CDC_REQ_SetLineEncoding: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); + +				while (!(Endpoint_IsOUTReceived())) +				{ +					if (USB_DeviceState == DEVICE_STATE_Unattached) +					  return; +				} + +				CDCInterfaceInfo->State.LineEncoding.BaudRateBPS = Endpoint_Read_32_LE(); +				CDCInterfaceInfo->State.LineEncoding.CharFormat  = Endpoint_Read_8(); +				CDCInterfaceInfo->State.LineEncoding.ParityType  = Endpoint_Read_8(); +				CDCInterfaceInfo->State.LineEncoding.DataBits    = Endpoint_Read_8(); + +				Endpoint_ClearOUT(); +				Endpoint_ClearStatusStage(); + +				EVENT_CDC_Device_LineEncodingChanged(CDCInterfaceInfo); +			} + +			break; +		case CDC_REQ_SetControlLineState: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue; + +				EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo); +			} + +			break; +		case CDC_REQ_SendBreak: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				EVENT_CDC_Device_BreakSent(CDCInterfaceInfo, (uint8_t)USB_ControlRequest.wValue); +			} + +			break; +	} +} + +bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ +	memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State)); + +	CDCInterfaceInfo->Config.DataINEndpoint.Type       = EP_TYPE_BULK; +	CDCInterfaceInfo->Config.DataOUTEndpoint.Type      = EP_TYPE_BULK; +	CDCInterfaceInfo->Config.NotificationEndpoint.Type = EP_TYPE_INTERRUPT; + +	if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.NotificationEndpoint, 1))) +	  return false; + +	return true; +} + +void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return; + +	#if !defined(NO_CLASS_DRIVER_AUTOFLUSH) +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); + +	if (Endpoint_IsINReady()) +	  CDC_Device_Flush(CDCInterfaceInfo); +	#endif +} + +uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                              const char* const String) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_Stream_LE(String, strlen(String), NULL); +} + +uint8_t CDC_Device_SendString_P(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                              const char* const String) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_PStream_LE(String, strlen_P(String), NULL); +} + +uint8_t CDC_Device_SendData(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                            const void* const Buffer, +                            const uint16_t Length) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_Stream_LE(Buffer, Length, NULL); +} + +uint8_t CDC_Device_SendData_P(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                            const void* const Buffer, +                            const uint16_t Length) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_PStream_LE(Buffer, Length, NULL); +} + +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.DataINEndpoint.Address); + +	if (!(Endpoint_IsReadWriteAllowed())) +	{ +		Endpoint_ClearIN(); + +		uint8_t ErrorCode; + +		if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError) +		  return ErrorCode; +	} + +	Endpoint_Write_8(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.DataINEndpoint.Address); + +	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.DataOUTEndpoint.Address); + +	if (Endpoint_IsOUTReceived()) +	{ +		if (!(Endpoint_BytesInEndpoint())) +		{ +			Endpoint_ClearOUT(); +			return 0; +		} +		else +		{ +			return Endpoint_BytesInEndpoint(); +		} +	} +	else +	{ +		return 0; +	} +} + +int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return -1; + +	int16_t ReceivedByte = -1; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataOUTEndpoint.Address); + +	if (Endpoint_IsOUTReceived()) +	{ +		if (Endpoint_BytesInEndpoint()) +		  ReceivedByte = Endpoint_Read_8(); + +		if (!(Endpoint_BytesInEndpoint())) +		  Endpoint_ClearOUT(); +	} + +	return ReceivedByte; +} + +void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) +	  return; + +	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.NotificationEndpoint.Address); + +	USB_Request_Header_t Notification = (USB_Request_Header_t) +		{ +			.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), +			.bRequest      = CDC_NOTIF_SerialState, +			.wValue        = CPU_TO_LE16(0), +			.wIndex        = CPU_TO_LE16(0), +			.wLength       = CPU_TO_LE16(sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost)), +		}; + +	Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL); +	Endpoint_Write_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost, +	                         sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost), +	                         NULL); +	Endpoint_ClearIN(); +} + +#if defined(FDEV_SETUP_STREAM) +void CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                             FILE* const Stream) +{ +	*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Device_putchar, CDC_Device_getchar, _FDEV_SETUP_RW); +	fdev_set_udata(Stream, CDCInterfaceInfo); +} + +void CDC_Device_CreateBlockingStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +                                     FILE* const Stream) +{ +	*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Device_putchar, CDC_Device_getchar_Blocking, _FDEV_SETUP_RW); +	fdev_set_udata(Stream, CDCInterfaceInfo); +} + +static int CDC_Device_putchar(char c, +                              FILE* Stream) +{ +	return CDC_Device_SendByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0; +} + +static int CDC_Device_getchar(FILE* Stream) +{ +	int16_t ReceivedByte = CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)); + +	if (ReceivedByte < 0) +	  return _FDEV_EOF; + +	return ReceivedByte; +} + +static int CDC_Device_getchar_Blocking(FILE* Stream) +{ +	int16_t ReceivedByte; + +	while ((ReceivedByte = CDC_Device_ReceiveByte((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream))) < 0) +	{ +		if (USB_DeviceState == DEVICE_STATE_Unattached) +		  return _FDEV_EOF; + +		CDC_Device_USBTask((USB_ClassInfo_CDC_Device_t*)fdev_get_udata(Stream)); +		USB_USBTask(); +	} + +	return ReceivedByte; +} +#endif + +void CDC_Device_Event_Stub(void) +{ + +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.h new file mode 100644 index 0000000000..9d5c4e5a0a --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.h @@ -0,0 +1,386 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB CDC Class driver. + * + *  Device mode driver for the library USB CDC Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassCDC + *  \defgroup Group_USBClassCDCDevice CDC Class Device Mode Driver + * + *  \section Sec_USBClassCDCDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/CDCClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassCDCDevice_ModDescription 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. This is because each interface will be loaded into a separate driver + *        instance, causing the two interfaces be become unlinked. To prevent this, you + *        should use the "Interface Association Descriptor" addendum to the USB 2.0 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. It is thus highly recommended + *        that the virtual serial line DTR (Data Terminal Ready) signal 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/CDCClassCommon.h" + +		#include <stdio.h> + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_CDC_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			{ +				struct +				{ +					uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device. */ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ +					USB_Endpoint_Table_t NotificationEndpoint; /**< Notification IN Endpoint configuration table. */ +				} 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 +					{ +						uint16_t HostToDevice; /**< Control line states from the host to device, as a set of \c CDC_CONTROL_LINE_OUT_* +											    *   masks. This value is updated each time \ref CDC_Device_USBTask() is called. +											    */ +						uint16_t DeviceToHost; /**< Control line states from the device to host, as a set of \c CDC_CONTROL_LINE_IN_* +											    *   masks - to notify the host of changes to these values, call the +											    *   \ref CDC_Device_SendControlLineStateChange() function. +											    */ +					} ControlLineStates; /**< Current states of the virtual serial port's control lines between the device and host. */ + +					CDC_LineEncoding_t LineEncoding; /**< Line encoding used in the virtual serial port, for the device's information. +					                                  *   This is generally only used if the virtual serial port data is to be +					                                  *   reconstructed on a physical UART. +					                                  */ +				} State; /**< State data for the USB class interface within the device. All elements in this section +				          *   are reset to their defaults when the interface is enumerated. +				          */ +			} USB_ClassInfo_CDC_Device_t; + +		/* Function Prototypes: */ +			/** Configures the endpoints of a given CDC interface, ready for use. This should be linked to the library +			 *  \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration containing +			 *  the given CDC interface is selected. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 * +			 *  \return Boolean \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given CDC class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 */ +			void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given CDC class interface, required for the correct operation of the interface. This should +			 *  be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 */ +			void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** CDC class driver event for a line encoding change on a CDC interface. This event fires each time the host requests a +			 *  line encoding change (containing the serial parity, baud and other configuration information) and may be hooked in the +			 *  user program by declaring a handler function with the same name and parameters listed here. The new line encoding +			 *  settings are available in the \c 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 \c ControlLineStates.HostToDevice value inside the CDC interface structure passed as a parameter, set as +			 *  a mask of \c CDC_CONTROL_LINE_OUT_* masks. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 */ +			void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** CDC class driver event for a send break request sent to the device from the host. This is generally used to separate +			 *  data or to indicate a special condition to the receiving device. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     Duration          Duration of the break that has been sent by the host, in milliseconds. +			 */ +			void EVENT_CDC_Device_BreakSent(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                                const uint8_t Duration) ATTR_NON_NULL_PTR_ARG(1); + +			/** Sends a given data buffer to the attached USB host, if connected. If a host is not connected when the function is +			 *  called, the string is discarded. Bytes will be queued for transmission to the host until either the endpoint bank +			 *  becomes full, or the \ref CDC_Device_Flush() function is called to flush the pending data to the host. This allows +			 *  for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     Buffer            Pointer to a buffer containing the data to send to the device. +			 *  \param[in]     Length            Length of the data to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_SendData(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                            const void* const Buffer, +			                            const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Sends a given data buffer from PROGMEM space to the attached USB host, if connected. If a host is not connected when the +			 *  function is called, the string is discarded. Bytes will be queued for transmission to the host until either the endpoint +			 *  bank becomes full, or the \ref CDC_Device_Flush() function is called to flush the pending data to the host. This allows +			 *  for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     Buffer            Pointer to a buffer containing the data to send to the device. +			 *  \param[in]     Length            Length of the data to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_SendData_P(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                            const void* const Buffer, +			                            const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Sends a given null terminated string to the attached USB host, if connected. If a host is not connected when +			 *  the function is called, the string is discarded. Bytes will be queued for transmission to the host until either +			 *  the endpoint bank becomes full, or the \ref CDC_Device_Flush() function is called to flush the pending data to +			 *  the host. This allows for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     String            Pointer to the null terminated string to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                              const char* const String) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Sends a given null terminated string from PROGMEM space to the attached USB host, if connected. If a host is not connected +			 *  when the function is called, the string is discarded. Bytes will be queued for transmission to the host until either +			 *  the endpoint bank becomes full, or the \ref CDC_Device_Flush() function is called to flush the pending data to +			 *  the host. This allows for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     String            Pointer to the null terminated string to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_SendString_P(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                              const char* const String) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Sends a given byte to the attached USB host, if connected. If a host is not connected when the function is called, the +			 *  byte is discarded. Bytes will be queued for transmission to the host until either the endpoint bank becomes full, or the +			 *  \ref CDC_Device_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be +			 *  packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in]     Data              Byte of data to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_SendByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                            const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1); + +			/** Determines the number of bytes received by the CDC interface from the host, waiting to be read. This indicates the number +			 *  of bytes in the OUT endpoint bank only, and thus the number of calls to \ref CDC_Device_ReceiveByte() which are guaranteed to +			 *  succeed immediately. If multiple bytes are to be received, they should be buffered by the user application, as the endpoint +			 *  bank will not be released back to the USB controller until all bytes are read. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 * +			 *  \return Total number of buffered bytes received from the host. +			 */ +			uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Reads a byte of data from the host. If no data is waiting to be read of if a USB host is not connected, the function +			 *  returns a negative value. The \ref CDC_Device_BytesReceived() function may be queried in advance to determine how many +			 *  bytes are currently buffered in the CDC interface's data receive endpoint bank, and thus how many repeated calls to this +			 *  function which are guaranteed to succeed. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 * +			 *  \return Next received byte from the host, or a negative value if no data received. +			 */ +			int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Flushes any data waiting to be sent, ensuring that the send buffer is cleared. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 * +			 *  \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum. +			 */ +			uint8_t CDC_Device_Flush(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Sends a Serial Control Line State Change notification to the host. This should be called when the virtual serial +			 *  control lines (DCD, DSR, etc.) have changed states, or to give BREAK notifications to the host. Line states persist +			 *  until they are cleared via a second notification. This should be called each time the CDC class driver's +			 *  \c ControlLineStates.DeviceToHost value is updated to push the new states to the USB host. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 */ +			void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			#if defined(FDEV_SETUP_STREAM) || defined(__DOXYGEN__) +			/** Creates a standard character stream for the given CDC Device instance so that it can be used with all the regular +			 *  functions in the standard <stdio.h> library that accept a \c FILE stream as a destination (e.g. \c 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 \c getc()) or when the user application will implement its own +			 *  line buffering. +			 * +			 *  \note The created stream can be given as \c stdout if desired to direct the standard output from all \c <stdio.h> functions +			 *        to the given CDC interface. +			 *        \n\n +			 * +			 *  \note This function is not available on all microcontroller architectures. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in,out] Stream            Pointer to a FILE structure where the created stream should be placed. +			 */ +			void CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                             FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Identical to \ref 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. +			 * +			 *  \note This function is not available on all microcontroller architectures. +			 * +			 *  \param[in,out] CDCInterfaceInfo  Pointer to a structure containing a CDC Class configuration and state. +			 *  \param[in,out] Stream            Pointer to a FILE structure where the created stream should be placed. +			 */ +			void CDC_Device_CreateBlockingStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +			                                     FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); +			#endif + +	/* Private Interface - For use in library only: */ +	#if !defined(__DOXYGEN__) +		/* Function Prototypes: */ +			#if defined(__INCLUDE_FROM_CDC_DEVICE_C) +				#if defined(FDEV_SETUP_STREAM) +				static int CDC_Device_putchar(char c, +				                              FILE* Stream) ATTR_NON_NULL_PTR_ARG(2); +				static int CDC_Device_getchar(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1); +				static int CDC_Device_getchar_Blocking(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1); +				#endif + +				void CDC_Device_Event_Stub(void) ATTR_CONST; + +				void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +				                                          ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Device_Event_Stub); +				void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +				                                             ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Device_Event_Stub); +				void EVENT_CDC_Device_BreakSent(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, +				                                const uint8_t Duration) ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) +				                                ATTR_ALIAS(CDC_Device_Event_Stub); +			#endif + +	#endif + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.c new file mode 100644 index 0000000000..a8a6e8b50e --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.c @@ -0,0 +1,211 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_HID_DRIVER +#define  __INCLUDE_FROM_HID_DEVICE_C +#include "HIDClassDevice.h" + +void HID_Device_ProcessControlRequest(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if (USB_ControlRequest.wIndex != HIDInterfaceInfo->Config.InterfaceNumber) +	  return; + +	switch (USB_ControlRequest.bRequest) +	{ +		case HID_REQ_GetReport: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				uint16_t ReportSize = 0; +				uint8_t  ReportID   = (USB_ControlRequest.wValue & 0xFF); +				uint8_t  ReportType = (USB_ControlRequest.wValue >> 8) - 1; +				uint8_t  ReportData[HIDInterfaceInfo->Config.PrevReportINBufferSize]; + +				memset(ReportData, 0, sizeof(ReportData)); + +				CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, ReportType, ReportData, &ReportSize); + +				if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL) +				{ +					memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportData, +					       HIDInterfaceInfo->Config.PrevReportINBufferSize); +				} + +				Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP); + +				Endpoint_ClearSETUP(); + +				if (ReportID) +				  Endpoint_Write_8(ReportID); + +				Endpoint_Write_Control_Stream_LE(ReportData, ReportSize); +				Endpoint_ClearOUT(); +			} + +			break; +		case HID_REQ_SetReport: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				uint16_t ReportSize = USB_ControlRequest.wLength; +				uint8_t  ReportID   = (USB_ControlRequest.wValue & 0xFF); +				uint8_t  ReportType = (USB_ControlRequest.wValue >> 8) - 1; +				uint8_t  ReportData[ReportSize]; + +				Endpoint_ClearSETUP(); +				Endpoint_Read_Control_Stream_LE(ReportData, ReportSize); +				Endpoint_ClearIN(); + +				CALLBACK_HID_Device_ProcessHIDReport(HIDInterfaceInfo, ReportID, ReportType, +				                                     &ReportData[ReportID ? 1 : 0], ReportSize - (ReportID ? 1 : 0)); +			} + +			break; +		case HID_REQ_GetProtocol: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				while (!(Endpoint_IsINReady())); +				Endpoint_Write_8(HIDInterfaceInfo->State.UsingReportProtocol); +				Endpoint_ClearIN(); +				Endpoint_ClearStatusStage(); +			} + +			break; +		case HID_REQ_SetProtocol: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				HIDInterfaceInfo->State.UsingReportProtocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00); +			} + +			break; +		case HID_REQ_SetIdle: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				HIDInterfaceInfo->State.IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6); +			} + +			break; +		case HID_REQ_GetIdle: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				while (!(Endpoint_IsINReady())); +				Endpoint_Write_8(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; + +	HIDInterfaceInfo->Config.ReportINEndpoint.Type = EP_TYPE_INTERRUPT; + +	if (!(Endpoint_ConfigureEndpointTable(&HIDInterfaceInfo->Config.ReportINEndpoint, 1))) +	  return false; + +	return true; +} + +void HID_Device_USBTask(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return; + +	if (HIDInterfaceInfo->State.PrevFrameNum == USB_Device_GetFrameNumber()) +	{ +		#if defined(USB_DEVICE_OPT_LOWSPEED) +		if (!(USB_Options & USB_DEVICE_OPT_LOWSPEED)) +		  return; +		#else +		return; +		#endif +	} + +	Endpoint_SelectEndpoint(HIDInterfaceInfo->Config.ReportINEndpoint.Address); + +	if (Endpoint_IsReadWriteAllowed()) +	{ +		uint8_t  ReportINData[HIDInterfaceInfo->Config.PrevReportINBufferSize]; +		uint8_t  ReportID     = 0; +		uint16_t ReportINSize = 0; + +		memset(ReportINData, 0, sizeof(ReportINData)); + +		bool ForceSend         = CALLBACK_HID_Device_CreateHIDReport(HIDInterfaceInfo, &ReportID, HID_REPORT_ITEM_In, +		                                                             ReportINData, &ReportINSize); +		bool StatesChanged     = false; +		bool IdlePeriodElapsed = (HIDInterfaceInfo->State.IdleCount && !(HIDInterfaceInfo->State.IdleMSRemaining)); + +		if (HIDInterfaceInfo->Config.PrevReportINBuffer != NULL) +		{ +			StatesChanged = (memcmp(ReportINData, HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINSize) != 0); +			memcpy(HIDInterfaceInfo->Config.PrevReportINBuffer, ReportINData, HIDInterfaceInfo->Config.PrevReportINBufferSize); +		} + +		if (ReportINSize && (ForceSend || StatesChanged || IdlePeriodElapsed)) +		{ +			HIDInterfaceInfo->State.IdleMSRemaining = HIDInterfaceInfo->State.IdleCount; + +			Endpoint_SelectEndpoint(HIDInterfaceInfo->Config.ReportINEndpoint.Address); + +			if (ReportID) +			  Endpoint_Write_8(ReportID); + +			Endpoint_Write_Stream_LE(ReportINData, ReportINSize, NULL); + +			Endpoint_ClearIN(); +		} + +		HIDInterfaceInfo->State.PrevFrameNum = USB_Device_GetFrameNumber(); +	} +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.h new file mode 100644 index 0000000000..ae628c87d4 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/HIDClassDevice.h @@ -0,0 +1,210 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB HID Class driver. + * + *  Device mode driver for the library USB HID Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassHID + *  \defgroup Group_USBClassHIDDevice HID Class Device Mode Driver + * + *  \section Sec_USBClassHIDDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/HIDClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassHIDDevice_ModDescription 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/HIDClassCommon.h" + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_HID_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			 *  \c 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 +			{ +				struct +				{ +					uint8_t  InterfaceNumber; /**< Interface number of the HID interface within the device. */ + +					USB_Endpoint_Table_t ReportINEndpoint; /**< Data IN HID report endpoint configuration table. */ + +					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 \c 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 \c 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. \c PrevReportINBuffer is \c 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 PrevFrameNum; /**< Frame number of the previous HID report packet opportunity. */ +					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 \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool HID_Device_ConfigureEndpoints(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given HID class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state. +			 */ +			void HID_Device_ProcessControlRequest(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given HID class interface, required for the correct operation of the interface. This should +			 *  be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). +			 * +			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state. +			 */ +			void HID_Device_USBTask(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** HID class driver callback for the user creation of a HID IN report. This callback may fire in response to either +			 *  HID class control requests from the host, or by the normal HID endpoint polling procedure. Inside this callback the +			 *  user is responsible for the creation of the next HID input report to be sent to the host. +			 * +			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state. +			 *  \param[in,out] ReportID          If preset to a non-zero value, this is the report ID being requested by the host. If zero, +			 *                                   this should be set to the report ID of the generated HID input report (if any). If multiple +			 *                                   reports are not sent via the given HID interface, this parameter should be ignored. +			 *  \param[in]     ReportType        Type of HID report to generate, either \ref HID_REPORT_ITEM_In or \ref HID_REPORT_ITEM_Feature. +			 *  \param[out]    ReportData        Pointer to a buffer where the generated HID report should be stored. +			 *  \param[out]    ReportSize        Number of bytes in the generated input report, or zero if no report is to be sent. +			 * +			 *  \return Boolean \c 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), \c false otherwise. +			 */ +			bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, +			                                         uint8_t* const ReportID, +			                                         const uint8_t ReportType, +			                                         void* ReportData, +			                                         uint16_t* const ReportSize) ATTR_NON_NULL_PTR_ARG(1) +			                                         ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(4) ATTR_NON_NULL_PTR_ARG(5); + +			/** HID class driver callback for the user processing of a received HID OUT report. This callback may fire in response to +			 *  either HID class control requests from the host, or by the normal HID endpoint polling procedure. Inside this callback +			 *  the user is responsible for the processing of the received HID output report from the host. +			 * +			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state. +			 *  \param[in]     ReportID          Report ID of the received output report. If multiple reports are not received via the given HID +			 *                                   interface, this parameter should be ignored. +			 *  \param[in]     ReportType        Type of received HID report, either \ref HID_REPORT_ITEM_Out or \ref HID_REPORT_ITEM_Feature. +			 *  \param[in]     ReportData        Pointer to a buffer where the received HID report is stored. +			 *  \param[in]     ReportSize        Size in bytes of the received report from the host. +			 */ +			void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, +			                                          const uint8_t ReportID, +			                                          const uint8_t ReportType, +			                                          const void* ReportData, +			                                          const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(4); + +		/* Inline Functions: */ +			/** Indicates that a millisecond of idle time has elapsed on the given HID interface, and the interface's idle count should be +			 *  decremented. This should be called once per millisecond so that hardware key-repeats function correctly. It is recommended +			 *  that this be called by the \ref EVENT_USB_Device_StartOfFrame() event, once SOF events have been enabled via +			 *  \ref USB_Device_EnableSOFEvents(). +			 * +			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state. +			 */ +			static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) ATTR_ALWAYS_INLINE ATTR_NON_NULL_PTR_ARG(1); +			static inline void HID_Device_MillisecondElapsed(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo) +			{ +				if (HIDInterfaceInfo->State.IdleMSRemaining) +				  HIDInterfaceInfo->State.IdleMSRemaining--; +			} + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c new file mode 100644 index 0000000000..a35c4082bc --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c @@ -0,0 +1,131 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_MIDI_DRIVER +#define  __INCLUDE_FROM_MIDI_DEVICE_C +#include "MIDIClassDevice.h" + +bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) +{ +	memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State)); + +	MIDIInterfaceInfo->Config.DataINEndpoint.Type  = EP_TYPE_BULK; +	MIDIInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK; + +	if (!(Endpoint_ConfigureEndpointTable(&MIDIInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&MIDIInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  return false; + +	return true; +} + +void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return; + +	#if !defined(NO_CLASS_DRIVER_AUTOFLUSH) +	Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpoint.Address); + +	if (Endpoint_IsINReady()) +	  MIDI_Device_Flush(MIDIInterfaceInfo); +	#endif +} + +uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo, +                                    const MIDI_EventPacket_t* const Event) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	uint8_t ErrorCode; + +	Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpoint.Address); + +	if ((ErrorCode = Endpoint_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NULL)) != 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.DataINEndpoint.Address); + +	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.DataOUTEndpoint.Address); + +	if (!(Endpoint_IsOUTReceived())) +		return false; + +	if (!(Endpoint_IsReadWriteAllowed())) +	  return false; + +	Endpoint_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NULL); + +	if (!(Endpoint_IsReadWriteAllowed())) +	  Endpoint_ClearOUT(); + +	return true; +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.h new file mode 100644 index 0000000000..ee2efd7c18 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.h @@ -0,0 +1,175 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB MIDI Class driver. + * + *  Device mode driver for the library USB MIDI Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassMIDI + *  \defgroup Group_USBClassMIDIDevice MIDI Class Device Mode Driver + * + *  \section Sec_USBClassMIDIDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassMIDIDevice_ModDescription 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/MIDIClassCommon.h" + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_MIDI_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			 *  \c MIDIInterfaceInfo parameter. This stores each MIDI interface's configuration and state information. +			 */ +			typedef struct +			{ +				struct +				{ +					uint8_t  StreamingInterfaceNumber; /**< Index of the Audio Streaming interface within the device this structure controls. */ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ +				} 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 RESERVED; // No state information for this class +				} State; /**< State data for the USB class interface within the device. All elements in this section +				          *   are reset to their defaults when the interface is enumerated. +				          */ +			} USB_ClassInfo_MIDI_Device_t; + +		/* Function Prototypes: */ +			/** Configures the endpoints of a given MIDI interface, ready for use. This should be linked to the library +			 *  \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration +			 *  containing the given MIDI interface is selected. +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 * +			 *  \return Boolean \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool MIDI_Device_ConfigureEndpoints(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given MIDI class interface, required for the correct operation of the interface. This should +			 *  be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 */ +			void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Sends a MIDI event packet to the host. If no host is connected, the event packet is discarded. Events are queued into the +			 *  endpoint bank until either the endpoint bank is full, or \ref MIDI_Device_Flush() is called. This allows for multiple +			 *  MIDI events to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Host state machine is in the \ref HOST_STATE_Configured state or the +			 *       call will fail. +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 *  \param[in]     Event              Pointer to a populated \ref MIDI_EventPacket_t structure containing the MIDI event to send. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t MIDI_Device_SendEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo, +			                                    const MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + + +			/** Flushes the MIDI send buffer, sending any queued MIDI events to the host. This should be called to override the +			 *  \ref MIDI_Device_SendEventPacket() function's packing behavior, to flush queued events. +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 * +			 *  \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum. +			 */ +			uint8_t MIDI_Device_Flush(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Receives a MIDI event packet from the host. Events are unpacked from the endpoint, thus if the endpoint bank contains +			 *  multiple MIDI events from the host in the one packet, multiple calls to this function will return each individual event. +			 * +			 *  \pre This function must only be called when the Host state machine is in the \ref HOST_STATE_Configured state or the +			 *       call will fail. +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 *  \param[out]    Event              Pointer to a USB_MIDI_EventPacket_t structure where the received MIDI event is to be placed. +			 * +			 *  \return Boolean \c true if a MIDI event packet was received, \c false otherwise. +			 */ +			bool MIDI_Device_ReceiveEventPacket(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo, +			                                    MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +		/* Inline Functions: */ +			/** Processes incoming control requests from the host, that are directed to the given MIDI class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] MIDIInterfaceInfo  Pointer to a structure containing a MIDI Class configuration and state. +			 */ +			static inline void MIDI_Device_ProcessControlRequest(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); +			static inline void MIDI_Device_ProcessControlRequest(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) +			{ +				(void)MIDIInterfaceInfo; +			} + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.c new file mode 100644 index 0000000000..1ea30f7cbc --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.c @@ -0,0 +1,215 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_MS_DRIVER +#define  __INCLUDE_FROM_MASSSTORAGE_DEVICE_C +#include "MassStorageClassDevice.h" + +void MS_Device_ProcessControlRequest(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if (USB_ControlRequest.wIndex != MSInterfaceInfo->Config.InterfaceNumber) +	  return; + +	switch (USB_ControlRequest.bRequest) +	{ +		case MS_REQ_MassStorageReset: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				MSInterfaceInfo->State.IsMassStoreReset = true; +			} + +			break; +		case MS_REQ_GetMaxLUN: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				while (!(Endpoint_IsINReady())); +				Endpoint_Write_8(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)); + +	MSInterfaceInfo->Config.DataINEndpoint.Type  = EP_TYPE_BULK; +	MSInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK; + +	if (!(Endpoint_ConfigureEndpointTable(&MSInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&MSInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  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.DataOUTEndpoint.Address); + +	if (Endpoint_IsOUTReceived()) +	{ +		if (MS_Device_ReadInCommandBlock(MSInterfaceInfo)) +		{ +			if (MSInterfaceInfo->State.CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN) +			  Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpoint.Address); + +			bool SCSICommandResult = CALLBACK_MS_Device_SCSICommandReceived(MSInterfaceInfo); + +			MSInterfaceInfo->State.CommandStatus.Status              = (SCSICommandResult) ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail; +			MSInterfaceInfo->State.CommandStatus.Signature           = CPU_TO_LE32(MS_CSW_SIGNATURE); +			MSInterfaceInfo->State.CommandStatus.Tag                 = MSInterfaceInfo->State.CommandBlock.Tag; +			MSInterfaceInfo->State.CommandStatus.DataTransferResidue = MSInterfaceInfo->State.CommandBlock.DataTransferLength; + +			if (!(SCSICommandResult) && (le32_to_cpu(MSInterfaceInfo->State.CommandStatus.DataTransferResidue))) +			  Endpoint_StallTransaction(); + +			MS_Device_ReturnCommandStatus(MSInterfaceInfo); +		} +	} + +	if (MSInterfaceInfo->State.IsMassStoreReset) +	{ +		Endpoint_ResetEndpoint(MSInterfaceInfo->Config.DataOUTEndpoint.Address); +		Endpoint_ResetEndpoint(MSInterfaceInfo->Config.DataINEndpoint.Address); + +		Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpoint.Address); +		Endpoint_ClearStall(); +		Endpoint_ResetDataToggle(); +		Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpoint.Address); +		Endpoint_ClearStall(); +		Endpoint_ResetDataToggle(); + +		MSInterfaceInfo->State.IsMassStoreReset = false; +	} +} + +static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) +{ +	uint16_t BytesProcessed; + +	Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpoint.Address); + +	BytesProcessed = 0; +	while (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock, +	                               (sizeof(MS_CommandBlockWrapper_t) - 16), &BytesProcessed) == +	                               ENDPOINT_RWSTREAM_IncompleteTransfer) +	{ +		if (MSInterfaceInfo->State.IsMassStoreReset) +		  return false; +	} + +	if ((MSInterfaceInfo->State.CommandBlock.Signature         != CPU_TO_LE32(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.DataINEndpoint.Address); +		Endpoint_StallTransaction(); + +		return false; +	} + +	BytesProcessed = 0; +	while (Endpoint_Read_Stream_LE(&MSInterfaceInfo->State.CommandBlock.SCSICommandData, +	                                MSInterfaceInfo->State.CommandBlock.SCSICommandLength, &BytesProcessed) == +	                                ENDPOINT_RWSTREAM_IncompleteTransfer) +	{ +		if (MSInterfaceInfo->State.IsMassStoreReset) +		  return false; +	} + +	Endpoint_ClearOUT(); + +	return true; +} + +static void MS_Device_ReturnCommandStatus(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) +{ +	Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataOUTEndpoint.Address); + +	while (Endpoint_IsStalled()) +	{ +		#if !defined(INTERRUPT_CONTROL_ENDPOINT) +		USB_USBTask(); +		#endif + +		if (MSInterfaceInfo->State.IsMassStoreReset) +		  return; +	} + +	Endpoint_SelectEndpoint(MSInterfaceInfo->Config.DataINEndpoint.Address); + +	while (Endpoint_IsStalled()) +	{ +		#if !defined(INTERRUPT_CONTROL_ENDPOINT) +		USB_USBTask(); +		#endif + +		if (MSInterfaceInfo->State.IsMassStoreReset) +		  return; +	} + +	uint16_t BytesProcessed = 0; +	while (Endpoint_Write_Stream_LE(&MSInterfaceInfo->State.CommandStatus, +	                                sizeof(MS_CommandStatusWrapper_t), &BytesProcessed) == +	                                ENDPOINT_RWSTREAM_IncompleteTransfer) +	{ +		if (MSInterfaceInfo->State.IsMassStoreReset) +		  return; +	} + +	Endpoint_ClearIN(); +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.h new file mode 100644 index 0000000000..12b54f8dfb --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.h @@ -0,0 +1,161 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB Mass Storage Class driver. + * + *  Device mode driver for the library USB Mass Storage Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassMS + *  \defgroup Group_USBClassMSDevice Mass Storage Class Device Mode Driver + * + *  \section Sec_USBClassMSDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/MassStorageClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassMSDevice_ModDescription 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/MassStorageClassCommon.h" + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_MS_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			 *  \c MSInterfaceInfo parameter. This stores each Mass Storage interface's configuration and state information. +			 */ +			typedef struct +			{ +				struct +				{ +					uint8_t  InterfaceNumber; /**< Interface number of the Mass Storage interface within the device. */ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ + +					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 \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool MS_Device_ConfigureEndpoints(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given Mass Storage class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state. +			 */ +			void MS_Device_ProcessControlRequest(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given Mass Storage class interface, required for the correct operation of the interface. This should +			 *  be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). +			 * +			 *  \param[in,out] MSInterfaceInfo  Pointer to a structure containing a Mass Storage configuration and state. +			 */ +			void MS_Device_USBTask(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Mass Storage class driver callback for the user processing of a received SCSI command. This callback will fire each time the +			 *  host sends a SCSI command which requires processing by the user application. Inside this callback the user is responsible +			 *  for the processing of the received SCSI command from the host. The SCSI command is available in the CommandBlock structure +			 *  inside the Mass Storage class state structure passed as a parameter to the callback function. +			 * +			 *  \param[in,out] MSInterfaceInfo  Pointer to a structure containing a Mass Storage Class configuration and state. +			 * +			 *  \return Boolean \c true if the SCSI command was successfully processed, \c false otherwise. +			 */ +			bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +	/* Private Interface - For use in library only: */ +	#if !defined(__DOXYGEN__) +		/* Function Prototypes: */ +			#if defined(__INCLUDE_FROM_MASSSTORAGE_DEVICE_C) +				static void MS_Device_ReturnCommandStatus(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); +				static bool MS_Device_ReadInCommandBlock(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); +			#endif + +	#endif + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.c new file mode 100644 index 0000000000..7209c452dc --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.c @@ -0,0 +1,314 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_PRINTER_DRIVER +#define  __INCLUDE_FROM_PRINTER_DEVICE_C +#include "PrinterClassDevice.h" + +void PRNT_Device_ProcessControlRequest(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if (USB_ControlRequest.wIndex != PRNTInterfaceInfo->Config.InterfaceNumber) +	  return; + +	switch (USB_ControlRequest.bRequest) +	{ +		case PRNT_REQ_GetDeviceID: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); + +				while (!(Endpoint_IsINReady())) +				{ +					if (USB_DeviceState == DEVICE_STATE_Unattached) +					  return; +				} + +				uint16_t IEEEStringLen = strlen(PRNTInterfaceInfo->Config.IEEE1284String); +				Endpoint_Write_16_BE(IEEEStringLen); +				Endpoint_Write_Control_Stream_LE(PRNTInterfaceInfo->Config.IEEE1284String, IEEEStringLen); +				Endpoint_ClearStatusStage(); +			} + +			break; +		case PRNT_REQ_GetPortStatus: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); + +				while (!(Endpoint_IsINReady())) +				{ +					if (USB_DeviceState == DEVICE_STATE_Unattached) +					  return; +				} + +				Endpoint_Write_8(PRNTInterfaceInfo->State.PortStatus); +				Endpoint_ClearStatusStage(); +			} + +			break; +		case PRNT_REQ_SoftReset: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_ClearStatusStage(); + +				PRNTInterfaceInfo->State.IsPrinterReset = true; + +				EVENT_PRNT_Device_SoftReset(PRNTInterfaceInfo); +			} + +			break; +	} +} + +bool PRNT_Device_ConfigureEndpoints(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	memset(&PRNTInterfaceInfo->State, 0x00, sizeof(PRNTInterfaceInfo->State)); +	PRNTInterfaceInfo->State.PortStatus = PRNT_PORTSTATUS_NOTERROR | PRNT_PORTSTATUS_SELECT; + +	PRNTInterfaceInfo->Config.DataINEndpoint.Type  = EP_TYPE_BULK; +	PRNTInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK; + +	if (!(Endpoint_ConfigureEndpointTable(&PRNTInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&PRNTInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  return false; + +	return true; +} + +void PRNT_Device_USBTask(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return; + +	#if !defined(NO_CLASS_DRIVER_AUTOFLUSH) +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); + +	if (Endpoint_IsINReady()) +	  PRNT_Device_Flush(PRNTInterfaceInfo); +	#endif + +	if (PRNTInterfaceInfo->State.IsPrinterReset) +	{ +		Endpoint_ResetEndpoint(PRNTInterfaceInfo->Config.DataOUTEndpoint.Address); +		Endpoint_ResetEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); + +		Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataOUTEndpoint.Address); +		Endpoint_ClearStall(); +		Endpoint_ResetDataToggle(); +		Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); +		Endpoint_ClearStall(); +		Endpoint_ResetDataToggle(); + +		PRNTInterfaceInfo->State.IsPrinterReset = false; +	} +} + +uint8_t PRNT_Device_SendString(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +                               const char* const String) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_Stream_LE(String, strlen(String), NULL); +} + +uint8_t PRNT_Device_SendData(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +                             const void* const Buffer, +                             const uint16_t Length) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); +	return Endpoint_Write_Stream_LE(Buffer, Length, NULL); +} + +uint8_t PRNT_Device_SendByte(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +                             const uint8_t Data) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); + +	if (!(Endpoint_IsReadWriteAllowed())) +	{ +		Endpoint_ClearIN(); + +		uint8_t ErrorCode; + +		if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError) +		  return ErrorCode; +	} + +	Endpoint_Write_8(Data); +	return ENDPOINT_READYWAIT_NoError; +} + +uint8_t PRNT_Device_Flush(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return ENDPOINT_RWSTREAM_DeviceDisconnected; + +	uint8_t ErrorCode; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataINEndpoint.Address); + +	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 PRNT_Device_BytesReceived(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return 0; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataOUTEndpoint.Address); + +	if (Endpoint_IsOUTReceived()) +	{ +		if (!(Endpoint_BytesInEndpoint())) +		{ +			Endpoint_ClearOUT(); +			return 0; +		} +		else +		{ +			return Endpoint_BytesInEndpoint(); +		} +	} +	else +	{ +		return 0; +	} +} + +int16_t PRNT_Device_ReceiveByte(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return -1; + +	int16_t ReceivedByte = -1; + +	Endpoint_SelectEndpoint(PRNTInterfaceInfo->Config.DataOUTEndpoint.Address); + +	if (Endpoint_IsOUTReceived()) +	{ +		if (Endpoint_BytesInEndpoint()) +		  ReceivedByte = Endpoint_Read_8(); + +		if (!(Endpoint_BytesInEndpoint())) +		  Endpoint_ClearOUT(); +	} + +	return ReceivedByte; +} + +#if defined(FDEV_SETUP_STREAM) +void PRNT_Device_CreateStream(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +                              FILE* const Stream) +{ +	*Stream = (FILE)FDEV_SETUP_STREAM(PRNT_Device_putchar, PRNT_Device_getchar, _FDEV_SETUP_RW); +	fdev_set_udata(Stream, PRNTInterfaceInfo); +} + +void PRNT_Device_CreateBlockingStream(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +                                      FILE* const Stream) +{ +	*Stream = (FILE)FDEV_SETUP_STREAM(PRNT_Device_putchar, PRNT_Device_getchar_Blocking, _FDEV_SETUP_RW); +	fdev_set_udata(Stream, PRNTInterfaceInfo); +} + +static int PRNT_Device_putchar(char c, +                               FILE* Stream) +{ +	return PRNT_Device_SendByte((USB_ClassInfo_PRNT_Device_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0; +} + +static int PRNT_Device_getchar(FILE* Stream) +{ +	int16_t ReceivedByte = PRNT_Device_ReceiveByte((USB_ClassInfo_PRNT_Device_t*)fdev_get_udata(Stream)); + +	if (ReceivedByte < 0) +	  return _FDEV_EOF; + +	return ReceivedByte; +} + +static int PRNT_Device_getchar_Blocking(FILE* Stream) +{ +	int16_t ReceivedByte; + +	while ((ReceivedByte = PRNT_Device_ReceiveByte((USB_ClassInfo_PRNT_Device_t*)fdev_get_udata(Stream))) < 0) +	{ +		if (USB_DeviceState == DEVICE_STATE_Unattached) +		  return _FDEV_EOF; + +		PRNT_Device_USBTask((USB_ClassInfo_PRNT_Device_t*)fdev_get_udata(Stream)); +		USB_USBTask(); +	} + +	return ReceivedByte; +} +#endif + +void PRNT_Device_Event_Stub(void) +{ + +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.h new file mode 100644 index 0000000000..802c5912d3 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/PrinterClassDevice.h @@ -0,0 +1,293 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 Printer Class driver. + * + *  Device mode driver for the library USB Printer Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassPrinter + *  \defgroup Group_USBClassPrinterDevice Printer Class Device Mode Driver + * + *  \section Sec_USBClassPrinterDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/PrinterClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassPrinterDevice_ModDescription Module Description + *  Device Mode USB Class driver framework interface, for the Printer USB Class driver. + * + *  @{ + */ + +#ifndef _PRINTER_CLASS_DEVICE_H_ +#define _PRINTER_CLASS_DEVICE_H_ + +	/* Includes: */ +		#include "../../USB.h" +		#include "../Common/PrinterClassCommon.h" + +		#include <stdio.h> + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_PRINTER_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* Public Interface - May be used in end-application: */ +		/* Type Defines: */ +			/** \brief Printer Class Device Mode Configuration and State Structure. +			 * +			 *  Class state structure. An instance of this structure should be made for each Printer interface +			 *  within the user application, and passed to each of the Printer class driver functions as the +			 *  PRNTInterfaceInfo parameter. This stores each Printer interface's configuration and state information. +			 */ +			typedef struct +			{ +				struct +				{ +					uint8_t InterfaceNumber; /**< Interface number of the Printer interface within the device. */ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ + +					char* IEEE1284String; /**< IEEE 1284 identification string, sent to the host during enumeration +					                       *   to identify the printer model, manufacturer and other characteristics. +					                       */ +				} 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 PortStatus; /**< Current status of the Printer virtual port, a collection of \c PRNT_PORTSTATUS_* +					                     *   bitmask values. +					                     */ + +					volatile bool IsPrinterReset; /**< Flag indicating that the host has requested that the Printer 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_PRNT_Device_t; + +		/* Function Prototypes: */ +			/** Configures the endpoints of a given Printer 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 Printer interface is selected. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 * +			 *  \return Boolean \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool PRNT_Device_ConfigureEndpoints(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given Printer class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 */ +			void PRNT_Device_ProcessControlRequest(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given Printer 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] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 */ +			void PRNT_Device_USBTask(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Printer class driver event for a soft reset request on a Printer interface. This event fires each time the host +			 *  requests a reset of the printer interface's internal state, and may be hooked in the user program by declaring a +			 *  handler function with the same name and parameters listed here. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 */ +			void EVENT_PRNT_Device_SoftReset(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Sends a given data buffer 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 PRNT_Device_Flush() function is called to flush the pending data to the host. This allows +			 *  for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 *  \param[in]     Buffer            Pointer to a buffer containing the data to send to the device. +			 *  \param[in]     Length            Length of the data to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t PRNT_Device_SendData(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +			                             const void* const Buffer, +			                             const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Sends a given null terminated 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 PRNT_Device_Flush() function is called to flush the pending data to +			 *  the host. This allows for multiple bytes to be packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 *  \param[in]     String            Pointer to the null terminated string to send to the host. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t PRNT_Device_SendString(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +			                               const char* const String) 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 PRNT_Device_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be +			 *  packed into a single endpoint packet, increasing data throughput. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer 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 PRNT_Device_SendByte(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +			                             const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1); + +			/** Determines the number of bytes received by the Printer interface from the host, waiting to be read. This indicates the number +			 *  of bytes in the OUT endpoint bank only, and thus the number of calls to \ref PRNT_Device_ReceiveByte() which are guaranteed to +			 *  succeed immediately. If multiple bytes are to be received, they should be buffered by the user application, as the endpoint +			 *  bank will not be released back to the USB controller until all bytes are read. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 * +			 *  \return Total number of buffered bytes received from the host. +			 */ +			uint16_t PRNT_Device_BytesReceived(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Reads a byte of data from the host. If no data is waiting to be read of if a USB host is not connected, the function +			 *  returns a negative value. The \ref PRNT_Device_BytesReceived() function may be queried in advance to determine how many +			 *  bytes are currently buffered in the Printer interface's data receive endpoint bank, and thus how many repeated calls to this +			 *  function which are guaranteed to succeed. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 * +			 *  \return Next received byte from the host, or a negative value if no data received. +			 */ +			int16_t PRNT_Device_ReceiveByte(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Flushes any data waiting to be sent, ensuring that the send buffer is cleared. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or +			 *       the call will fail. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 * +			 *  \return A value from the \ref Endpoint_WaitUntilReady_ErrorCodes_t enum. +			 */ +			uint8_t PRNT_Device_Flush(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			#if defined(FDEV_SETUP_STREAM) || defined(__DOXYGEN__) +			/** Creates a standard character stream for the given Printer Device instance so that it can be used with all the regular +			 *  functions in the standard <stdio.h> library that accept a \c FILE stream as a destination (e.g. \c 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 \c getc()) or when the user application will implement its own +			 *  line buffering. +			 * +			 *  \note The created stream can be given as \c stdout if desired to direct the standard output from all \c <stdio.h> functions +			 *        to the given Printer interface. +			 *        \n\n +			 * +			 *  \note This function is not available on all microcontroller architectures. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 *  \param[in,out] Stream            Pointer to a FILE structure where the created stream should be placed. +			 */ +			void PRNT_Device_CreateStream(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +			                              FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); + +			/** Identical to \ref PRNT_Device_CreateStream(), except that reads are blocking until the calling stream function terminates +			 *  the transfer. While blocking, the USB and Printer service tasks are called repeatedly to maintain USB communications. +			 * +			 *  \note This function is not available on all microcontroller architectures. +			 * +			 *  \param[in,out] PRNTInterfaceInfo  Pointer to a structure containing a Printer Class configuration and state. +			 *  \param[in,out] Stream            Pointer to a FILE structure where the created stream should be placed. +			 */ +			void PRNT_Device_CreateBlockingStream(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo, +			                                      FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); +			#endif + +	/* Private Interface - For use in library only: */ +	#if !defined(__DOXYGEN__) +		/* Function Prototypes: */ +			#if defined(__INCLUDE_FROM_PRINTER_DEVICE_C) +				#if defined(FDEV_SETUP_STREAM) +				static int PRNT_Device_putchar(char c, +				                               FILE* Stream) ATTR_NON_NULL_PTR_ARG(2); +				static int PRNT_Device_getchar(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1); +				static int PRNT_Device_getchar_Blocking(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1); +				#endif + +				void PRNT_Device_Event_Stub(void) ATTR_CONST; + +				void EVENT_PRNT_Device_SoftReset(USB_ClassInfo_PRNT_Device_t* const PRNTInterfaceInfo) +				                                 ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(PRNT_Device_Event_Stub); + +			#endif + +	#endif + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.c new file mode 100644 index 0000000000..45293b12fc --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.c @@ -0,0 +1,508 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims 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 "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define  __INCLUDE_FROM_RNDIS_DRIVER +#define  __INCLUDE_FROM_RNDIS_DEVICE_C +#include "RNDISClassDevice.h" + +static const uint32_t PROGMEM AdapterSupportedOIDList[]  = +	{ +		CPU_TO_LE32(OID_GEN_SUPPORTED_LIST), +		CPU_TO_LE32(OID_GEN_PHYSICAL_MEDIUM), +		CPU_TO_LE32(OID_GEN_HARDWARE_STATUS), +		CPU_TO_LE32(OID_GEN_MEDIA_SUPPORTED), +		CPU_TO_LE32(OID_GEN_MEDIA_IN_USE), +		CPU_TO_LE32(OID_GEN_MAXIMUM_FRAME_SIZE), +		CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE), +		CPU_TO_LE32(OID_GEN_LINK_SPEED), +		CPU_TO_LE32(OID_GEN_TRANSMIT_BLOCK_SIZE), +		CPU_TO_LE32(OID_GEN_RECEIVE_BLOCK_SIZE), +		CPU_TO_LE32(OID_GEN_VENDOR_ID), +		CPU_TO_LE32(OID_GEN_VENDOR_DESCRIPTION), +		CPU_TO_LE32(OID_GEN_CURRENT_PACKET_FILTER), +		CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE), +		CPU_TO_LE32(OID_GEN_MEDIA_CONNECT_STATUS), +		CPU_TO_LE32(OID_GEN_XMIT_OK), +		CPU_TO_LE32(OID_GEN_RCV_OK), +		CPU_TO_LE32(OID_GEN_XMIT_ERROR), +		CPU_TO_LE32(OID_GEN_RCV_ERROR), +		CPU_TO_LE32(OID_GEN_RCV_NO_BUFFER), +		CPU_TO_LE32(OID_802_3_PERMANENT_ADDRESS), +		CPU_TO_LE32(OID_802_3_CURRENT_ADDRESS), +		CPU_TO_LE32(OID_802_3_MULTICAST_LIST), +		CPU_TO_LE32(OID_802_3_MAXIMUM_LIST_SIZE), +		CPU_TO_LE32(OID_802_3_RCV_ERROR_ALIGNMENT), +		CPU_TO_LE32(OID_802_3_XMIT_ONE_COLLISION), +		CPU_TO_LE32(OID_802_3_XMIT_MORE_COLLISIONS), +	}; + +void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ +	if (!(Endpoint_IsSETUPReceived())) +	  return; + +	if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->Config.ControlInterfaceNumber) +	  return; + +	switch (USB_ControlRequest.bRequest) +	{ +		case RNDIS_REQ_SendEncapsulatedCommand: +			if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				Endpoint_ClearSETUP(); +				Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->Config.MessageBuffer, USB_ControlRequest.wLength); +				Endpoint_ClearIN(); + +				RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo); +			} + +			break; +		case RNDIS_REQ_GetEncapsulatedResponse: +			if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) +			{ +				RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)RNDISInterfaceInfo->Config.MessageBuffer; + +				if (!(MessageHeader->MessageLength)) +				{ +					RNDISInterfaceInfo->Config.MessageBuffer[0] = 0; +					MessageHeader->MessageLength                = CPU_TO_LE32(1); +				} + +				Endpoint_ClearSETUP(); +				Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->Config.MessageBuffer, le32_to_cpu(MessageHeader->MessageLength)); +				Endpoint_ClearOUT(); + +				MessageHeader->MessageLength = CPU_TO_LE32(0); +			} + +			break; +	} +} + +bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ +	memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State)); + +	RNDISInterfaceInfo->Config.DataINEndpoint.Type       = EP_TYPE_BULK; +	RNDISInterfaceInfo->Config.DataOUTEndpoint.Type      = EP_TYPE_BULK; +	RNDISInterfaceInfo->Config.NotificationEndpoint.Type = EP_TYPE_INTERRUPT; + +	if (RNDISInterfaceInfo->Config.MessageBuffer == NULL) +	  return false; + +	if (RNDISInterfaceInfo->Config.MessageBufferLength < RNDIS_DEVICE_MIN_MESSAGE_BUFFER_LENGTH) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo->Config.DataINEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo->Config.DataOUTEndpoint, 1))) +	  return false; + +	if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo->Config.NotificationEndpoint, 1))) +	  return false; + +	return true; +} + +void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ +	if (USB_DeviceState != DEVICE_STATE_Configured) +	  return; + +	Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpoint.Address); + +	if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady) +	{ +		USB_Request_Header_t Notification = (USB_Request_Header_t) +			{ +				.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), +				.bRequest      = RNDIS_NOTIF_ResponseAvailable, +				.wValue        = CPU_TO_LE16(0), +				.wIndex        = CPU_TO_LE16(0), +				.wLength       = CPU_TO_LE16(0), +			}; + +		Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL); + +		Endpoint_ClearIN(); + +		RNDISInterfaceInfo->State.ResponseReady = 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->Config.MessageBuffer; + +	switch (le32_to_cpu(MessageHeader->MessageType)) +	{ +		case REMOTE_NDIS_INITIALIZE_MSG: +			RNDISInterfaceInfo->State.ResponseReady     = true; + +			RNDIS_Initialize_Message_t*  INITIALIZE_Message  = +			               (RNDIS_Initialize_Message_t*)RNDISInterfaceInfo->Config.MessageBuffer; +			RNDIS_Initialize_Complete_t* INITIALIZE_Response = +			               (RNDIS_Initialize_Complete_t*)RNDISInterfaceInfo->Config.MessageBuffer; + +			INITIALIZE_Response->MessageType            = CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_CMPLT); +			INITIALIZE_Response->MessageLength          = CPU_TO_LE32(sizeof(RNDIS_Initialize_Complete_t)); +			INITIALIZE_Response->RequestId              = INITIALIZE_Message->RequestId; +			INITIALIZE_Response->Status                 = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); + +			INITIALIZE_Response->MajorVersion           = CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR); +			INITIALIZE_Response->MinorVersion           = CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR); +			INITIALIZE_Response->DeviceFlags            = CPU_TO_LE32(REMOTE_NDIS_DF_CONNECTIONLESS); +			INITIALIZE_Response->Medium                 = CPU_TO_LE32(REMOTE_NDIS_MEDIUM_802_3); +			INITIALIZE_Response->MaxPacketsPerTransfer  = CPU_TO_LE32(1); +			INITIALIZE_Response->MaxTransferSize        = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) + ETHERNET_FRAME_SIZE_MAX); +			INITIALIZE_Response->PacketAlignmentFactor  = CPU_TO_LE32(0); +			INITIALIZE_Response->AFListOffset           = CPU_TO_LE32(0); +			INITIALIZE_Response->AFListSize             = CPU_TO_LE32(0); + +			RNDISInterfaceInfo->State.CurrRNDISState    = RNDIS_Initialized; +			break; +		case REMOTE_NDIS_HALT_MSG: +			RNDISInterfaceInfo->State.ResponseReady     = false; + +			MessageHeader->MessageLength                = CPU_TO_LE32(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->Config.MessageBuffer; +			RNDIS_Query_Complete_t* QUERY_Response      = (RNDIS_Query_Complete_t*)RNDISInterfaceInfo->Config.MessageBuffer; +			uint32_t                Query_Oid           = CPU_TO_LE32(QUERY_Message->Oid); + +			void*    QueryData    = &RNDISInterfaceInfo->Config.MessageBuffer[sizeof(RNDIS_Message_Header_t) + +			                                                                  le32_to_cpu(QUERY_Message->InformationBufferOffset)]; +			void*    ResponseData = &RNDISInterfaceInfo->Config.MessageBuffer[sizeof(RNDIS_Query_Complete_t)]; +			uint16_t ResponseSize; + +			QUERY_Response->MessageType                 = CPU_TO_LE32(REMOTE_NDIS_QUERY_CMPLT); + +			if (RNDIS_Device_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, le32_to_cpu(QUERY_Message->InformationBufferLength), +			                                  ResponseData, &ResponseSize)) +			{ +				QUERY_Response->Status                  = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); +				QUERY_Response->MessageLength           = cpu_to_le32(sizeof(RNDIS_Query_Complete_t) + ResponseSize); + +				QUERY_Response->InformationBufferLength = CPU_TO_LE32(ResponseSize); +				QUERY_Response->InformationBufferOffset = CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t) - sizeof(RNDIS_Message_Header_t)); +			} +			else +			{ +				QUERY_Response->Status                  = CPU_TO_LE32(REMOTE_NDIS_STATUS_NOT_SUPPORTED); +				QUERY_Response->MessageLength           = CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t)); + +				QUERY_Response->InformationBufferLength = CPU_TO_LE32(0); +				QUERY_Response->InformationBufferOffset = CPU_TO_LE32(0); +			} + +			break; +		case REMOTE_NDIS_SET_MSG: +			RNDISInterfaceInfo->State.ResponseReady     = true; + +			RNDIS_Set_Message_t*  SET_Message           = (RNDIS_Set_Message_t*)RNDISInterfaceInfo->Config.MessageBuffer; +			RNDIS_Set_Complete_t* SET_Response          = (RNDIS_Set_Complete_t*)RNDISInterfaceInfo->Config.MessageBuffer; +			uint32_t              SET_Oid               = le32_to_cpu(SET_Message->Oid); + +			SET_Response->MessageType                   = CPU_TO_LE32(REMOTE_NDIS_SET_CMPLT); +			SET_Response->MessageLength                 = CPU_TO_LE32(sizeof(RNDIS_Set_Complete_t)); +			SET_Response->RequestId                     = SET_Message->RequestId; + +			void* SetData = &RNDISInterfaceInfo->Config.MessageBuffer[sizeof(RNDIS_Message_Header_t) + +			                                                              le32_to_cpu(SET_Message->InformationBufferOffset)]; + +			SET_Response->Status = RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, +			                                                   le32_to_cpu(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->Config.MessageBuffer; + +			RESET_Response->MessageType                 = CPU_TO_LE32(REMOTE_NDIS_RESET_CMPLT); +			RESET_Response->MessageLength               = CPU_TO_LE32(sizeof(RNDIS_Reset_Complete_t)); +			RESET_Response->Status                      = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); +			RESET_Response->AddressingReset             = CPU_TO_LE32(0); + +			break; +		case REMOTE_NDIS_KEEPALIVE_MSG: +			RNDISInterfaceInfo->State.ResponseReady     = true; + +			RNDIS_KeepAlive_Message_t*  KEEPALIVE_Message  = +			                (RNDIS_KeepAlive_Message_t*)RNDISInterfaceInfo->Config.MessageBuffer; +			RNDIS_KeepAlive_Complete_t* KEEPALIVE_Response = +			                (RNDIS_KeepAlive_Complete_t*)RNDISInterfaceInfo->Config.MessageBuffer; + +			KEEPALIVE_Response->MessageType             = CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_CMPLT); +			KEEPALIVE_Response->MessageLength           = CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Complete_t)); +			KEEPALIVE_Response->RequestId               = KEEPALIVE_Message->RequestId; +			KEEPALIVE_Response->Status                  = CPU_TO_LE32(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) = CPU_TO_LE32(0); + +			return true; +		case OID_GEN_HARDWARE_STATUS: +			*ResponseSize = sizeof(uint32_t); + +			*((uint32_t*)ResponseData) = CPU_TO_LE32(NDIS_HardwareStatus_Ready); + +			return true; +		case OID_GEN_MEDIA_SUPPORTED: +		case OID_GEN_MEDIA_IN_USE: +			*ResponseSize = sizeof(uint32_t); + +			*((uint32_t*)ResponseData) = CPU_TO_LE32(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) = CPU_TO_LE32(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) = CPU_TO_LE32(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) = CPU_TO_LE32(REMOTE_NDIS_MEDIA_STATE_CONNECTED); + +			return true; +		case OID_GEN_LINK_SPEED: +			*ResponseSize = sizeof(uint32_t); + +			/* Indicate 10Mb/s link speed */ +			*((uint32_t*)ResponseData) = CPU_TO_LE32(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) = CPU_TO_LE32(1); + +			return true; +		case OID_GEN_CURRENT_PACKET_FILTER: +			*ResponseSize = sizeof(uint32_t); + +			*((uint32_t*)ResponseData) = cpu_to_le32(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) = CPU_TO_LE32(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) = CPU_TO_LE32(RNDISInterfaceInfo->Config.MessageBufferLength + ETHERNET_FRAME_SIZE_MAX); + +			return true; +		default: +			return false; +	} +} + +static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +                                        const uint32_t OId, +                                        const void* SetData, +                                        const uint16_t SetSize) +{ +	(void)SetSize; + +	switch (OId) +	{ +		case OID_GEN_CURRENT_PACKET_FILTER: +			RNDISInterfaceInfo->State.CurrPacketFilter = le32_to_cpu(*((uint32_t*)SetData)); +			RNDISInterfaceInfo->State.CurrRNDISState   = (RNDISInterfaceInfo->State.CurrPacketFilter) ? RNDIS_Data_Initialized : RNDIS_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; +	} +} + +bool RNDIS_Device_IsPacketReceived(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || +	    (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) +	{ +		return false; +	} + +	Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpoint.Address); +	return Endpoint_IsOUTReceived(); +} + +uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +                                void* Buffer, +                                uint16_t* const PacketLength) +{ +	if ((USB_DeviceState != DEVICE_STATE_Configured) || +	    (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) +	{ +		return ENDPOINT_RWSTREAM_DeviceDisconnected; +	} + +	Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpoint.Address); + +	*PacketLength = 0; + +	if (!(Endpoint_IsOUTReceived())) +		return ENDPOINT_RWSTREAM_NoError; + +	RNDIS_Packet_Message_t RNDISPacketHeader; +	Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); + +	if (le32_to_cpu(RNDISPacketHeader.DataLength) > ETHERNET_FRAME_SIZE_MAX) +	{ +		Endpoint_StallTransaction(); + +		return RNDIS_ERROR_LOGICAL_CMD_FAILED; +	} + +	*PacketLength = (uint16_t)le32_to_cpu(RNDISPacketHeader.DataLength); + +	Endpoint_Read_Stream_LE(Buffer, *PacketLength, NULL); +	Endpoint_ClearOUT(); + +	return ENDPOINT_RWSTREAM_NoError; +} + +uint8_t RNDIS_Device_SendPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +                                void* Buffer, +                                const uint16_t PacketLength) +{ +	uint8_t ErrorCode; + +	if ((USB_DeviceState != DEVICE_STATE_Configured) || +	    (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) +	{ +		return ENDPOINT_RWSTREAM_DeviceDisconnected; +	} + +	Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpoint.Address); + +	if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError) +	  return ErrorCode; + +	RNDIS_Packet_Message_t RNDISPacketHeader; + +	memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t)); + +	RNDISPacketHeader.MessageType   = CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG); +	RNDISPacketHeader.MessageLength = cpu_to_le32(sizeof(RNDIS_Packet_Message_t) + PacketLength); +	RNDISPacketHeader.DataOffset    = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)); +	RNDISPacketHeader.DataLength    = cpu_to_le32(PacketLength); + +	Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); +	Endpoint_Write_Stream_LE(Buffer, PacketLength, NULL); +	Endpoint_ClearIN(); + +	return ENDPOINT_RWSTREAM_NoError; +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.h new file mode 100644 index 0000000000..761bc2790f --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/RNDISClassDevice.h @@ -0,0 +1,207 @@ +/* +             LUFA Library +     Copyright (C) Dean Camera, 2017. + +  dean [at] fourwalledcubicle [dot] com +           www.lufa-lib.org +*/ + +/* +  Copyright 2017  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 disclaims all warranties with regard to this +  software, including all implied warranties of merchantability +  and fitness.  In no event shall the author be liable for any +  special, indirect or consequential damages or any damages +  whatsoever resulting from loss of use, data or profits, whether +  in an action of contract, negligence or other tortious action, +  arising out of or in connection with the use or performance of +  this software. +*/ + +/** \file + *  \brief Device mode driver for the library USB RNDIS Class driver. + * + *  Device mode driver for the library USB RNDIS Class driver. + * + *  \note This file should not be included directly. It is automatically included as needed by the USB module driver + *        dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassRNDIS + *  \defgroup Group_USBClassRNDISDevice RNDIS Class Device Mode Driver + * + *  \section Sec_USBClassRNDISDevice_Dependencies Module Source Dependencies + *  The following files must be built with any user project that uses this module: + *    - LUFA/Drivers/USB/Class/Device/RNDISClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + *  \section Sec_USBClassRNDISDevice_ModDescription 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/RNDISClassCommon.h" + +	/* Enable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			extern "C" { +		#endif + +	/* Preprocessor Checks: */ +		#if !defined(__INCLUDE_FROM_RNDIS_DRIVER) +			#error Do not include this file directly. Include LUFA/Drivers/USB.h instead. +		#endif + +	/* 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 +			 *  \c RNDISInterfaceInfo parameter. This stores each RNDIS interface's configuration and state information. +			 */ +			typedef struct +			{ +				struct +				{ +					uint8_t  ControlInterfaceNumber; /**< Interface number of the RNDIS control interface within the device. */ + +					USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ +					USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ +					USB_Endpoint_Table_t NotificationEndpoint; /**< Notification IN Endpoint configuration table. */ + +					char*         AdapterVendorDescription; /**< String description of the adapter vendor. */ +					MAC_Address_t AdapterMACAddress; /**< MAC address of the adapter. */ + +					uint8_t*      MessageBuffer; /**< Buffer where RNDIS messages can be stored by the internal driver. This +					                              *   should be at least 132 bytes in length for minimal functionality. */ +					uint16_t      MessageBufferLength; /**< Length in bytes of the \ref MessageBuffer RNDIS buffer. */ +				} 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     ResponseReady; /**< Internal flag indicating if a RNDIS message is waiting to be returned to the host. */ +					uint8_t  CurrRNDISState; /**< Current RNDIS state of the adapter, a value from the \ref RNDIS_States_t enum. */ +					uint32_t CurrPacketFilter; /**< Current packet filter mode, used internally by the class driver. */ +				} 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 RNDIS interface is selected. +			 * +			 *  \param[in,out] RNDISInterfaceInfo  Pointer to a structure containing a RNDIS Class configuration and state. +			 * +			 *  \return Boolean \c true if the endpoints were successfully configured, \c false otherwise. +			 */ +			bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Processes incoming control requests from the host, that are directed to the given RNDIS class interface. This should be +			 *  linked to the library \ref EVENT_USB_Device_ControlRequest() event. +			 * +			 *  \param[in,out] RNDISInterfaceInfo  Pointer to a structure containing a RNDIS Class configuration and state. +			 */ +			void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** General management task for a given RNDIS 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); + +			/** Determines if a packet is currently waiting for the device to read in and process. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or the +			 *       call will fail. +			 * +			 *  \param[in,out] RNDISInterfaceInfo  Pointer to a structure containing an RNDIS Class configuration and state. +			 * +			 *  \return Boolean \c true if a packet is waiting to be read in by the host, \c false otherwise. +			 */ +			bool RNDIS_Device_IsPacketReceived(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + +			/** Retrieves the next pending packet from the device, discarding the remainder of the RNDIS packet header to leave +			 *  only the packet contents for processing by the device in the nominated buffer. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or the +			 *       call will fail. +			 * +			 *  \param[in,out] RNDISInterfaceInfo  Pointer to a structure containing an RNDIS Class configuration and state. +			 *  \param[out]    Buffer              Pointer to a buffer where the packer data is to be written to. +			 *  \param[out]    PacketLength        Pointer to where the length in bytes of the read packet is to be stored. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +											void* Buffer, +											uint16_t* const PacketLength) ATTR_NON_NULL_PTR_ARG(1); + +			/** Sends the given packet to the attached RNDIS device, after adding a RNDIS packet message header. +			 * +			 *  \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or the +			 *       call will fail. +			 * +			 *  \param[in,out] RNDISInterfaceInfo  Pointer to a structure containing an RNDIS Class configuration and state. +			 *  \param[in]     Buffer              Pointer to a buffer where the packer data is to be read from. +			 *  \param[in]     PacketLength        Length in bytes of the packet to send. +			 * +			 *  \return A value from the \ref Endpoint_Stream_RW_ErrorCodes_t enum. +			 */ +			uint8_t RNDIS_Device_SendPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +											void* Buffer, +											const uint16_t PacketLength) ATTR_NON_NULL_PTR_ARG(1); + +	/* Private Interface - For use in library only: */ +	#if !defined(__DOXYGEN__) +		/* Macros: */ +			#define RNDIS_DEVICE_MIN_MESSAGE_BUFFER_LENGTH  sizeof(AdapterSupportedOIDList) + sizeof(RNDIS_Query_Complete_t) + +		/* Function Prototypes: */ +		#if defined(__INCLUDE_FROM_RNDIS_DEVICE_C) +			static void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +			                                                    ATTR_NON_NULL_PTR_ARG(1); +			static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +			                                          const uint32_t OId, +                                                      void* const QueryData, +                                                      const uint16_t QuerySize, +										              void* ResponseData, +                                                      uint16_t* const ResponseSize) ATTR_NON_NULL_PTR_ARG(1) +			                                          ATTR_NON_NULL_PTR_ARG(5) ATTR_NON_NULL_PTR_ARG(6); +			static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, +                                                    const uint32_t OId, +			                                        const void* SetData, +                                                    const uint16_t SetSize) ATTR_NON_NULL_PTR_ARG(1) +			                                        ATTR_NON_NULL_PTR_ARG(3); +		#endif + +	#endif + +	/* Disable C linkage for C++ Compilers: */ +		#if defined(__cplusplus) +			} +		#endif + +#endif + +/** @} */ + | 
