Squashed 'tmk_core/' changes from caca2c0..dc0e46e
dc0e46e Rename LUFA to LUFA-git 3bfa7fa Remove LUFA-120730 215b764 Merge commit 'afa0f22a9299686fd88f58ce09c5b521ac917e8f' as 'protocol/lufa/LUFA' afa0f22 Squashed 'protocol/lufa/LUFA/' content from commit def7fca c0c42fa Remove submodule of LUFA 30f897d Merge commit '87ced33feb74e79c3281dda36eb6d6d153399b41' as 'protocol/usb_hid/USB_Host_Shield_2.0' 87ced33 Squashed 'protocol/usb_hid/USB_Host_Shield_2.0/' content from commit aab4a69 14f6d49 Remove submodule of USB_Host_Shield_2.0 git-subtree-dir: tmk_core git-subtree-split: dc0e46eaa4367d4e218f8816e3c117895820f07c
This commit is contained in:
parent
4d116a04e9
commit
f6d56675f9
1575 changed files with 421901 additions and 63190 deletions
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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_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_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
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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 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 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 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
|
||||
|
||||
/** @} */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue