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,422 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_AOA_DRIVER
|
||||
#define __INCLUDE_FROM_ANDROIDACCESSORY_HOST_C
|
||||
#include "AndroidAccessoryClassHost.h"
|
||||
|
||||
bool AOA_Host_ValidateAccessoryDevice(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const USB_Descriptor_Device_t* const DeviceDescriptor,
|
||||
bool* const NeedModeSwitch)
|
||||
{
|
||||
(void)AOAInterfaceInfo;
|
||||
|
||||
if (DeviceDescriptor->Header.Type != DTYPE_Device)
|
||||
return false;
|
||||
|
||||
*NeedModeSwitch = ((DeviceDescriptor->ProductID != ANDROID_ACCESSORY_PRODUCT_ID) &&
|
||||
(DeviceDescriptor->ProductID != ANDROID_ACCESSORY_ADB_PRODUCT_ID));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_ConfigurePipes(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* AOAInterface = NULL;
|
||||
|
||||
memset(&AOAInterfaceInfo->State, 0x00, sizeof(AOAInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return AOA_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_AOA_Host_NextAndroidAccessoryInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return AOA_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
AOAInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_AOA_Host_NextInterfaceBulkEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return AOA_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
AOAInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
AOAInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
AOAInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
AOAInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
AOAInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
AOAInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&AOAInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return AOA_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&AOAInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return AOA_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
AOAInterfaceInfo->State.IsActive = true;
|
||||
AOAInterfaceInfo->State.InterfaceNumber = AOAInterface->InterfaceNumber;
|
||||
|
||||
return AOA_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_AOA_Host_NextAndroidAccessoryInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == AOA_CSCP_AOADataClass) &&
|
||||
(Interface->SubClass == AOA_CSCP_AOADataSubclass) &&
|
||||
(Interface->Protocol == AOA_CSCP_AOADataProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_AOA_Host_NextInterfaceBulkEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
void AOA_Host_USBTask(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return;
|
||||
|
||||
#if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
|
||||
AOA_Host_Flush(AOAInterfaceInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_StartAccessoryMode(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
uint16_t AccessoryProtocol;
|
||||
if ((ErrorCode = AOA_Host_GetAccessoryProtocol(&AccessoryProtocol)) != HOST_WAITERROR_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
if ((AccessoryProtocol != CPU_TO_LE16(AOA_PROTOCOL_AccessoryV1)) && (AccessoryProtocol != CPU_TO_LE16(AOA_PROTOCOL_AccessoryV2)))
|
||||
return AOA_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
for (uint8_t PropertyIndex = 0; PropertyIndex < AOA_STRING_TOTAL_STRINGS; PropertyIndex++)
|
||||
{
|
||||
if ((ErrorCode = AOA_Host_SendPropertyString(AOAInterfaceInfo, PropertyIndex)) != HOST_WAITERROR_Successful)
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE),
|
||||
.bRequest = AOA_REQ_StartAccessoryMode,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
return USB_Host_SendControlRequest(NULL);
|
||||
}
|
||||
|
||||
static uint8_t AOA_Host_GetAccessoryProtocol(uint16_t* const Protocol)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE),
|
||||
.bRequest = AOA_REQ_GetAccessoryProtocol,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(uint16_t),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
return USB_Host_SendControlRequest(Protocol);
|
||||
}
|
||||
|
||||
static uint8_t AOA_Host_SendPropertyString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const uint8_t StringIndex)
|
||||
{
|
||||
const char* String = AOAInterfaceInfo->Config.PropertyStrings[StringIndex];
|
||||
|
||||
if (String == NULL)
|
||||
String = "";
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_VENDOR | REQREC_DEVICE),
|
||||
.bRequest = AOA_REQ_SendString,
|
||||
.wValue = 0,
|
||||
.wIndex = StringIndex,
|
||||
.wLength = (strlen(String) + 1),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
return USB_Host_SendControlRequest((char*)String);
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_SendData(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const void* const Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
|
||||
Pipe_Unfreeze();
|
||||
ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_SendString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const char* const String)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
|
||||
Pipe_Unfreeze();
|
||||
ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_SendByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const uint8_t Data)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_Write_8(Data);
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
uint16_t AOA_Host_BytesReceived(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return 0;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return Pipe_BytesInPipe();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t AOA_Host_ReceiveByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return -1;
|
||||
|
||||
int16_t ReceivedByte = -1;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (Pipe_BytesInPipe())
|
||||
ReceivedByte = Pipe_Read_8();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
|
||||
uint8_t AOA_Host_Flush(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AOAInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(AOAInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
return PIPE_READYWAIT_NoError;
|
||||
|
||||
bool BankFull = !(Pipe_IsReadWriteAllowed());
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if (BankFull)
|
||||
{
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
#if defined(FDEV_SETUP_STREAM)
|
||||
void AOA_Host_CreateStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
FILE* const Stream)
|
||||
{
|
||||
*Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar, _FDEV_SETUP_RW);
|
||||
fdev_set_udata(Stream, AOAInterfaceInfo);
|
||||
}
|
||||
|
||||
void AOA_Host_CreateBlockingStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
FILE* const Stream)
|
||||
{
|
||||
*Stream = (FILE)FDEV_SETUP_STREAM(AOA_Host_putchar, AOA_Host_getchar_Blocking, _FDEV_SETUP_RW);
|
||||
fdev_set_udata(Stream, AOAInterfaceInfo);
|
||||
}
|
||||
|
||||
static int AOA_Host_putchar(char c,
|
||||
FILE* Stream)
|
||||
{
|
||||
return AOA_Host_SendByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
|
||||
}
|
||||
|
||||
static int AOA_Host_getchar(FILE* Stream)
|
||||
{
|
||||
int16_t ReceivedByte = AOA_Host_ReceiveByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream));
|
||||
|
||||
if (ReceivedByte < 0)
|
||||
return _FDEV_EOF;
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
|
||||
static int AOA_Host_getchar_Blocking(FILE* Stream)
|
||||
{
|
||||
int16_t ReceivedByte;
|
||||
|
||||
while ((ReceivedByte = AOA_Host_ReceiveByte((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream))) < 0)
|
||||
{
|
||||
if (USB_HostState == HOST_STATE_Unattached)
|
||||
return _FDEV_EOF;
|
||||
|
||||
AOA_Host_USBTask((USB_ClassInfo_AOA_Host_t*)fdev_get_udata(Stream));
|
||||
USB_USBTask();
|
||||
}
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \brief Host mode driver for the library USB Android Open Accessory Class driver.
|
||||
*
|
||||
* Host mode driver for the library USB Android Open Accessory 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_USBClassAOA
|
||||
* \defgroup Group_USBClassAndroidAccessoryHost Android Open Accessory Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassAndroidAccessoryHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassAndroidAccessoryHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Android Open Accessory USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __AOA_CLASS_HOST_H__
|
||||
#define __AOA_CLASS_HOST_H__
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
#include "../Common/AndroidAccessoryClassCommon.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Preprocessor Checks: */
|
||||
#if !defined(__INCLUDE_FROM_AOA_DRIVER)
|
||||
#error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
|
||||
#endif
|
||||
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
/** Error code for some Android Open Accessory Host functions, indicating a logical (and not hardware) error. */
|
||||
#define AOA_ERROR_LOGICAL_CMD_FAILED 0x80
|
||||
|
||||
/* Type Defines: */
|
||||
/** \brief Android Open Accessory Class Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made within the user application,
|
||||
* and passed to each of the Android Open Accessory class driver functions as the \c AOAInterfaceInfo
|
||||
* parameter. This stores each Android Open Accessory interface's configuration and state information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe configuration table. */
|
||||
|
||||
char* PropertyStrings[AOA_STRING_TOTAL_STRINGS]; /**< Android Accessory property strings, sent to identify the accessory when the
|
||||
* Android device is switched into Open Accessory mode. */
|
||||
} 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref AOA_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the AOA interface within the attached device. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_AOA_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref AOA_Host_ConfigurePipes() function. */
|
||||
enum AOA_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
AOA_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
AOA_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
AOA_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible Android Open Accessory interface was not found in the device's Configuration Descriptor. */
|
||||
AOA_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** General management task for a given Android Open Accessory host 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] AOAInterfaceInfo Pointer to a structure containing an Android Open Accessory Class host configuration and state.
|
||||
*/
|
||||
void AOA_Host_USBTask(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Validates a device descriptor, to check if the device is a valid Android device, and if it is currently in Android Open Accessory mode.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing an AOA Class host configuration and state.
|
||||
* \param[in] DeviceDescriptor Pointer a buffer containing the attached device's Device Descriptor.
|
||||
* \param[out] NeedModeSwitch Pointer to a boolean where the mode switch requirement of the attached device is to be stored.
|
||||
*
|
||||
* \return Boolean \c true if the attached device is a valid Android device, \c false otherwise.
|
||||
*/
|
||||
bool AOA_Host_ValidateAccessoryDevice(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const USB_Descriptor_Device_t* const DeviceDescriptor,
|
||||
bool* const NeedModeSwitch) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Host interface configuration routine, to configure a given Android Open Accessory host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given Android Open Accessory Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the device. This should be
|
||||
* called once after the stack has enumerated the attached device, while the host state machine is in the Addressed state.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing an AOA Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref AOA_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t AOA_Host_ConfigurePipes(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Starts Accessory Mode in the attached Android device. This function will validate the device's Android Open Accessory protocol
|
||||
* version, send the configured property strings, and request a switch to Android Open Accessory mode.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing an AOA Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum, or \ref AOA_ERROR_LOGICAL_CMD_FAILED if a logical error occurred..
|
||||
*/
|
||||
uint8_t AOA_Host_StartAccessoryMode(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a given data buffer to the attached USB device, if connected. If a device is not connected when the function is
|
||||
* called, the data will be discarded. Bytes will be queued for transmission to the device until either the pipe bank
|
||||
* becomes full, or the \ref AOA_Host_Flush() function is called to flush the pending data to the device. This allows for
|
||||
* multiple bytes to be packed into a single pipe 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] AOAInterfaceInfo Pointer to a structure containing a AOA Class host 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 device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t AOA_Host_SendData(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const void* const Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a given null-terminated string to the attached USB device, if connected. If a device is not connected when the
|
||||
* function is called, the string is discarded. Bytes will be queued for transmission to the device until either the pipe
|
||||
* bank becomes full, or the \ref AOA_Host_Flush() function is called to flush the pending data to the device. This allows
|
||||
* for multiple bytes to be packed into a single pipe 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] AOAInterfaceInfo Pointer to a structure containing a AOA Class host configuration and state.
|
||||
* \param[in] String Pointer to the null terminated string to send to the device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t AOA_Host_SendString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const char* const String) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sends a given byte to the attached USB device, if connected. If a device is not connected when the function is called, the
|
||||
* byte is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the
|
||||
* \ref AOA_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
|
||||
* packed into a single pipe 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] AOAInterfaceInfo Pointer to a structure containing a AOA Class host configuration and state.
|
||||
* \param[in] Data Byte of data to send to the device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t AOA_Host_SendByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const uint8_t Data) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Determines the number of bytes received by the AOA interface from the device, waiting to be read. This indicates the number
|
||||
* of bytes in the IN pipe bank only, and thus the number of calls to \ref AOA_Host_ReceiveByte() which are guaranteed to succeed
|
||||
* immediately. If multiple bytes are to be received, they should be buffered by the user application, as the pipe bank will not be
|
||||
* released back to the USB controller until all bytes are read.
|
||||
*
|
||||
* \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] AOAInterfaceInfo Pointer to a structure containing a AOA Class host configuration and state.
|
||||
*
|
||||
* \return Total number of buffered bytes received from the device.
|
||||
*/
|
||||
uint16_t AOA_Host_BytesReceived(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Reads a byte of data from the device. If no data is waiting to be read of if a USB device is not connected, the function
|
||||
* returns a negative value. The \ref AOA_Host_BytesReceived() function may be queried in advance to determine how many bytes
|
||||
* are currently buffered in the AOA interface's data receive pipe.
|
||||
*
|
||||
* \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] AOAInterfaceInfo Pointer to a structure containing a AOA Class host configuration and state.
|
||||
*
|
||||
* \return Next received byte from the device, or a negative value if no data received.
|
||||
*/
|
||||
int16_t AOA_Host_ReceiveByte(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) 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 Host state machine is in the \ref HOST_STATE_Configured state or the
|
||||
* call will fail.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing a AOA Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t AOA_Host_Flush(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Creates a standard character stream for the given AOA Device instance so that it can be used with all the regular
|
||||
* functions in the standard \c <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 AOA interface.
|
||||
* \n\n
|
||||
*
|
||||
* \note This function is not available on all microcontroller architectures.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing a AOA Class configuration and state.
|
||||
* \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed.
|
||||
*/
|
||||
void AOA_Host_CreateStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Identical to \ref AOA_Host_CreateStream(), except that reads are blocking until the calling stream function terminates
|
||||
* the transfer. While blocking, the USB and AOA service tasks are called repeatedly to maintain USB communications.
|
||||
*
|
||||
* \note This function is not available on all microcontroller architectures.
|
||||
*
|
||||
* \param[in,out] AOAInterfaceInfo Pointer to a structure containing a AOA Class configuration and state.
|
||||
* \param[in,out] Stream Pointer to a FILE structure where the created stream should be placed.
|
||||
*/
|
||||
void AOA_Host_CreateBlockingStream(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_ANDROIDACCESSORY_HOST_C)
|
||||
#if defined(FDEV_SETUP_STREAM)
|
||||
static int AOA_Host_putchar(char c,
|
||||
FILE* Stream) ATTR_NON_NULL_PTR_ARG(2);
|
||||
static int AOA_Host_getchar(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
|
||||
static int AOA_Host_getchar_Blocking(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
|
||||
static uint8_t AOA_Host_GetAccessoryProtocol(uint16_t* const Protocol) ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t AOA_Host_SendPropertyString(USB_ClassInfo_AOA_Host_t* const AOAInterfaceInfo,
|
||||
const uint8_t StringIndex) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
static uint8_t DCOMP_AOA_Host_NextAndroidAccessoryInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_AOA_Host_NextInterfaceBulkEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_AUDIO_DRIVER
|
||||
#define __INCLUDE_FROM_AUDIO_HOST_C
|
||||
#include "AudioClassHost.h"
|
||||
|
||||
uint8_t Audio_Host_ConfigurePipes(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* AudioControlInterface = NULL;
|
||||
USB_Descriptor_Interface_t* AudioStreamingInterface = NULL;
|
||||
|
||||
memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return AUDIO_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while ((AudioInterfaceInfo->Config.DataINPipe.Address && !(DataINEndpoint)) ||
|
||||
(AudioInterfaceInfo->Config.DataOUTPipe.Address && !(DataOUTEndpoint)))
|
||||
{
|
||||
if (!(AudioControlInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_Audio_Host_NextAudioInterfaceDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (!(AudioControlInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_Audio_Host_NextAudioStreamInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_Audio_Host_NextAudioControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return AUDIO_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
AudioControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_Audio_Host_NextAudioStreamInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return AUDIO_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
}
|
||||
|
||||
AudioStreamingInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
AudioInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
AudioInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
AudioInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_ISOCHRONOUS;
|
||||
AudioInterfaceInfo->Config.DataINPipe.Banks = 2;
|
||||
|
||||
AudioInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
AudioInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
AudioInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_ISOCHRONOUS;
|
||||
AudioInterfaceInfo->Config.DataOUTPipe.Banks = 2;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&AudioInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return AUDIO_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&AudioInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return AUDIO_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
AudioInterfaceInfo->State.ControlInterfaceNumber = AudioControlInterface->InterfaceNumber;
|
||||
AudioInterfaceInfo->State.StreamingInterfaceNumber = AudioStreamingInterface->InterfaceNumber;
|
||||
AudioInterfaceInfo->State.EnabledStreamingAltIndex = AudioStreamingInterface->AlternateSetting;
|
||||
AudioInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return AUDIO_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioControlInterface(void* CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == AUDIO_CSCP_AudioClass) &&
|
||||
(Interface->SubClass == AUDIO_CSCP_ControlSubclass) &&
|
||||
(Interface->Protocol == AUDIO_CSCP_ControlProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioStreamInterface(void* CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == AUDIO_CSCP_AudioClass) &&
|
||||
(Interface->SubClass == AUDIO_CSCP_AudioStreamingSubclass) &&
|
||||
(Interface->Protocol == AUDIO_CSCP_StreamingProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioInterfaceDataEndpoint(void* CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((Endpoint->Attributes & EP_TYPE_MASK) == EP_TYPE_ISOCHRONOUS)
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
uint8_t Audio_Host_StartStopStreaming(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const bool EnableStreaming)
|
||||
{
|
||||
if (!(AudioInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
return USB_Host_SetInterfaceAltSetting(AudioInterfaceInfo->State.StreamingInterfaceNumber,
|
||||
EnableStreaming ? AudioInterfaceInfo->State.EnabledStreamingAltIndex : 0);
|
||||
}
|
||||
|
||||
uint8_t Audio_Host_GetSetEndpointProperty(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const uint8_t DataPipeIndex,
|
||||
const uint8_t EndpointProperty,
|
||||
const uint8_t EndpointControl,
|
||||
const uint16_t DataLength,
|
||||
void* const Data)
|
||||
{
|
||||
if (!(AudioInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
uint8_t RequestType;
|
||||
uint8_t EndpointAddress;
|
||||
|
||||
if (EndpointProperty & 0x80)
|
||||
RequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT);
|
||||
else
|
||||
RequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT);
|
||||
|
||||
Pipe_SelectPipe(DataPipeIndex);
|
||||
EndpointAddress = Pipe_GetBoundEndpointAddress();
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = RequestType,
|
||||
.bRequest = EndpointProperty,
|
||||
.wValue = ((uint16_t)EndpointControl << 8),
|
||||
.wIndex = EndpointAddress,
|
||||
.wLength = DataLength,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(Data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB Audio 1.0 Class driver.
|
||||
*
|
||||
* Host 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_USBClassAudioHost Audio 1.0 Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassAudioHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/AudioClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassAudioHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Audio 1.0 USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_CLASS_HOST_H__
|
||||
#define __AUDIO_CLASS_HOST_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 Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made 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
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref Audio_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t ControlInterfaceNumber; /**< Interface index of the Audio Control interface within the attached device. */
|
||||
uint8_t StreamingInterfaceNumber; /**< Interface index of the Audio Streaming interface within the attached device. */
|
||||
|
||||
uint8_t EnabledStreamingAltIndex; /**< Alternative setting index of the Audio Streaming interface when the stream is enabled. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_Audio_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref Audio_Host_ConfigurePipes() function. */
|
||||
enum AUDIO_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
AUDIO_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
AUDIO_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
AUDIO_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible AUDIO interface was not found in the device's Configuration Descriptor. */
|
||||
AUDIO_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given Audio host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given Audio Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the
|
||||
* device. This should be called once after the stack has enumerated the attached device, while the host state
|
||||
* machine is in the Addressed state.
|
||||
*
|
||||
* \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref AUDIO_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t Audio_Host_ConfigurePipes(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Starts or stops the audio streaming for the given configured Audio Host interface, allowing for audio samples to be
|
||||
* send and/or received.
|
||||
*
|
||||
* \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class host configuration and state.
|
||||
* \param[in] EnableStreaming Boolean true to enable streaming of the specified interface, \c false to disable
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t Audio_Host_StartStopStreaming(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const bool EnableStreaming) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Gets or sets the specified property of a streaming audio class endpoint that is bound to a pipe in the given
|
||||
* class instance.
|
||||
*
|
||||
* \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class host configuration and state.
|
||||
* \param[in] DataPipeIndex Index of the data pipe whose bound endpoint is to be altered.
|
||||
* \param[in] EndpointProperty Property of the endpoint to get or set, a value from \ref Audio_ClassRequests_t.
|
||||
* \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.
|
||||
* \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 A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t Audio_Host_GetSetEndpointProperty(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const uint8_t DataPipeIndex,
|
||||
const uint8_t EndpointProperty,
|
||||
const uint8_t EndpointControl,
|
||||
const uint16_t DataLength,
|
||||
void* const Data) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6);
|
||||
|
||||
/* Inline Functions: */
|
||||
/** General management task for a given Audio host 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 host configuration and state.
|
||||
*/
|
||||
static inline void Audio_Host_USBTask(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void Audio_Host_USBTask(USB_ClassInfo_Audio_Host_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
|
||||
* IN pipe ready for reading.
|
||||
*
|
||||
* \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] 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_Host_IsSampleReceived(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline bool Audio_Host_IsSampleReceived(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AudioInterfaceInfo->State.IsActive))
|
||||
return false;
|
||||
|
||||
bool SampleReceived = false;
|
||||
|
||||
Pipe_SelectPipe(AudioInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
SampleReceived = Pipe_IsINReceived();
|
||||
Pipe_Freeze();
|
||||
|
||||
return SampleReceived;
|
||||
}
|
||||
|
||||
/** Determines if the given audio interface is ready to accept the next sample to be written to it, and selects
|
||||
* the streaming OUT pipe ready for writing.
|
||||
*
|
||||
* \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] 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_Host_IsReadyForNextSample(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline bool Audio_Host_IsReadyForNextSample(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(AudioInterfaceInfo->State.IsActive))
|
||||
return false;
|
||||
|
||||
Pipe_SelectPipe(AudioInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
return Pipe_IsOUTReady();
|
||||
}
|
||||
|
||||
/** 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_Host_IsSampleReceived() function to ensure
|
||||
* that the correct pipe 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_Host_ReadSample8(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline int8_t Audio_Host_ReadSample8(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
{
|
||||
int8_t Sample;
|
||||
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Sample = Pipe_Read_8();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
|
||||
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_Host_IsSampleReceived() function to ensure
|
||||
* that the correct pipe 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_Host_ReadSample16(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline int16_t Audio_Host_ReadSample16(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
{
|
||||
int16_t Sample;
|
||||
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Sample = (int16_t)Pipe_Read_16_LE();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
|
||||
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_Host_IsSampleReceived() function to ensure
|
||||
* that the correct pipe 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_Host_ReadSample24(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline int32_t Audio_Host_ReadSample24(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo)
|
||||
{
|
||||
int32_t Sample;
|
||||
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Sample = (((uint32_t)Pipe_Read_8() << 16) | Pipe_Read_16_LE());
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
|
||||
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_Host_IsReadyForNextSample() function to
|
||||
* ensure that the correct pipe 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_Host_WriteSample8(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int8_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void Audio_Host_WriteSample8(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int8_t Sample)
|
||||
{
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Pipe_Write_8(Sample);
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearOUT();
|
||||
Pipe_WaitUntilReady();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
}
|
||||
|
||||
/** 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_Host_IsReadyForNextSample() function to
|
||||
* ensure that the correct pipe 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_Host_WriteSample16(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int16_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void Audio_Host_WriteSample16(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int16_t Sample)
|
||||
{
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Pipe_Write_16_LE(Sample);
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearOUT();
|
||||
Pipe_WaitUntilReady();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
}
|
||||
|
||||
/** 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_Host_IsReadyForNextSample() function to
|
||||
* ensure that the correct pipe 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_Host_WriteSample24(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int32_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void Audio_Host_WriteSample24(USB_ClassInfo_Audio_Host_t* const AudioInterfaceInfo,
|
||||
const int32_t Sample)
|
||||
{
|
||||
(void)AudioInterfaceInfo;
|
||||
|
||||
Pipe_Write_16_LE(Sample);
|
||||
Pipe_Write_8(Sample >> 16);
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_Unfreeze();
|
||||
Pipe_ClearOUT();
|
||||
Pipe_WaitUntilReady();
|
||||
Pipe_Freeze();
|
||||
}
|
||||
}
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_AUDIO_HOST_C)
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioControlInterface(void* CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioStreamInterface(void* CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_Audio_Host_NextAudioInterfaceDataEndpoint(void* CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,477 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_CDC_DRIVER
|
||||
#define __INCLUDE_FROM_CDC_HOST_C
|
||||
#include "CDCClassHost.h"
|
||||
|
||||
uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* NotificationEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* CDCControlInterface = NULL;
|
||||
|
||||
memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return CDC_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
|
||||
{
|
||||
if (!(CDCControlInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (NotificationEndpoint)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return CDC_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return CDC_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
CDCControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
NotificationEndpoint = NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
{
|
||||
if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
|
||||
NotificationEndpoint = EndpointData;
|
||||
else
|
||||
DataINEndpoint = EndpointData;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
}
|
||||
|
||||
CDCInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
CDCInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
CDCInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
CDCInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
CDCInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
CDCInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
CDCInterfaceInfo->Config.NotificationPipe.Size = le16_to_cpu(NotificationEndpoint->EndpointSize);
|
||||
CDCInterfaceInfo->Config.NotificationPipe.EndpointAddress = NotificationEndpoint->EndpointAddress;
|
||||
CDCInterfaceInfo->Config.NotificationPipe.Type = EP_TYPE_INTERRUPT;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return CDC_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return CDC_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.NotificationPipe, 1)))
|
||||
return CDC_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;
|
||||
CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
|
||||
CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD | CDC_CONTROL_LINE_IN_DSR);
|
||||
CDCInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return CDC_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == CDC_CSCP_CDCClass) &&
|
||||
(Interface->SubClass == CDC_CSCP_ACMSubclass) &&
|
||||
(Interface->Protocol == CDC_CSCP_ATCommandProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == CDC_CSCP_CDCDataClass) &&
|
||||
(Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
|
||||
(Interface->Protocol == CDC_CSCP_NoDataProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
|
||||
!(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
USB_Request_Header_t Notification;
|
||||
Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL);
|
||||
|
||||
if ((Notification.bRequest == CDC_NOTIF_SerialState) &&
|
||||
(Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
|
||||
{
|
||||
Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
|
||||
sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
|
||||
NULL);
|
||||
|
||||
Pipe_ClearIN();
|
||||
|
||||
EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
#if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
|
||||
CDC_Host_Flush(CDCInterfaceInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = CDC_REQ_SetLineEncoding,
|
||||
.wValue = 0,
|
||||
.wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
|
||||
.wLength = sizeof(CDCInterfaceInfo->State.LineEncoding),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = CDC_REQ_SetControlLineState,
|
||||
.wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
|
||||
.wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(NULL);
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const uint8_t Duration)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = CDC_REQ_SendBreak,
|
||||
.wValue = Duration,
|
||||
.wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(NULL);
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const void* const Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
|
||||
Pipe_Unfreeze();
|
||||
ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const char* const String)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
|
||||
Pipe_Unfreeze();
|
||||
ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const uint8_t Data)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_Write_8(Data);
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return 0;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return Pipe_BytesInPipe();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return -1;
|
||||
|
||||
int16_t ReceivedByte = -1;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (Pipe_BytesInPipe())
|
||||
ReceivedByte = Pipe_Read_8();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
|
||||
uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
return PIPE_READYWAIT_NoError;
|
||||
|
||||
bool BankFull = !(Pipe_IsReadWriteAllowed());
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if (BankFull)
|
||||
{
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
#if defined(FDEV_SETUP_STREAM)
|
||||
void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
FILE* const Stream)
|
||||
{
|
||||
*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
|
||||
fdev_set_udata(Stream, CDCInterfaceInfo);
|
||||
}
|
||||
|
||||
void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
FILE* const Stream)
|
||||
{
|
||||
*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
|
||||
fdev_set_udata(Stream, CDCInterfaceInfo);
|
||||
}
|
||||
|
||||
static int CDC_Host_putchar(char c,
|
||||
FILE* Stream)
|
||||
{
|
||||
return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
|
||||
}
|
||||
|
||||
static int CDC_Host_getchar(FILE* Stream)
|
||||
{
|
||||
int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
|
||||
|
||||
if (ReceivedByte < 0)
|
||||
return _FDEV_EOF;
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
|
||||
static int CDC_Host_getchar_Blocking(FILE* Stream)
|
||||
{
|
||||
int16_t ReceivedByte;
|
||||
|
||||
while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
|
||||
{
|
||||
if (USB_HostState == HOST_STATE_Unattached)
|
||||
return _FDEV_EOF;
|
||||
|
||||
CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
|
||||
USB_USBTask();
|
||||
}
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CDC_Host_Event_Stub(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB CDC Class driver.
|
||||
*
|
||||
* Host 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_USBClassCDCHost CDC Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassCDCHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/CDCClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassCDCHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the CDC USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __CDC_CLASS_HOST_H__
|
||||
#define __CDC_CLASS_HOST_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 Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made within the user application,
|
||||
* and passed to each of the CDC class driver functions as the \c CDCInterfaceInfo parameter. This
|
||||
* stores each CDC interface's configuration and state information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe configuration table. */
|
||||
USB_Pipe_Table_t NotificationPipe; /**< Notification IN Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref CDC_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t ControlInterfaceNumber; /**< Interface index of the CDC-ACM control interface within the attached device. */
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t HostToDevice; /**< Control line states from the host to device, as a set of \c CDC_CONTROL_LINE_OUT_*
|
||||
* masks - to notify the device of changes to these values, call the
|
||||
* \ref CDC_Host_SendControlLineStateChange() function.
|
||||
*/
|
||||
uint16_t DeviceToHost; /**< Control line states from the device to host, as a set of \c CDC_CONTROL_LINE_IN_*
|
||||
* masks. This value is updated each time \ref CDC_Host_USBTask() is called.
|
||||
*/
|
||||
} 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. When set by the host application, the
|
||||
* \ref CDC_Host_SetLineEncoding() function must be called to push the changes
|
||||
* to the device.
|
||||
*/
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_CDC_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref CDC_Host_ConfigurePipes() function. */
|
||||
enum CDC_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
CDC_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
CDC_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
CDC_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible CDC interface was not found in the device's Configuration Descriptor. */
|
||||
CDC_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** General management task for a given CDC host 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 an CDC Class host configuration and state.
|
||||
*/
|
||||
void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Host interface configuration routine, to configure a given CDC host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given CDC Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the device.
|
||||
* This should be called once after the stack has enumerated the attached device, while the host state machine is in
|
||||
* the Addressed state.
|
||||
*
|
||||
* \param[in,out] CDCInterfaceInfo Pointer to a structure containing an CDC Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref CDC_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Sets the line encoding for the attached device's virtual serial port. This should be called when the \c LineEncoding
|
||||
* values of the interface have been changed to push the new settings to the USB device.
|
||||
*
|
||||
* \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a Serial Control Line State Change notification to the device. This should be called when the virtual serial
|
||||
* control lines (DTR, RTS, etc.) have changed states. Line states persist until they are cleared via a second
|
||||
* notification. This should be called each time the CDC class driver's \c ControlLineStates.HostToDevice value is updated
|
||||
* to push the new states to the USB device.
|
||||
*
|
||||
* \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a Send Break request to the device. 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 host configuration and state.
|
||||
* \param[in] Duration Duration of the break, in milliseconds.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const uint8_t Duration) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a given data buffer to the attached USB device, if connected. If a device is not connected when the function is
|
||||
* called, the data will be discarded. Bytes will be queued for transmission to the device until either the pipe bank
|
||||
* becomes full, or the \ref CDC_Host_Flush() function is called to flush the pending data to the device. This allows for
|
||||
* multiple bytes to be packed into a single pipe 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] CDCInterfaceInfo Pointer to a structure containing a CDC Class host 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 device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
const void* const Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a given null-terminated string to the attached USB device, if connected. If a device is not connected when the
|
||||
* function is called, the string is discarded. Bytes will be queued for transmission to the device until either the pipe
|
||||
* bank becomes full, or the \ref CDC_Host_Flush() function is called to flush the pending data to the device. This allows
|
||||
* for multiple bytes to be packed into a single pipe 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] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
* \param[in] String Pointer to the null terminated string to send to the device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_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 device, if connected. If a device is not connected when the function is called, the
|
||||
* byte is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the
|
||||
* \ref CDC_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
|
||||
* packed into a single pipe 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] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
* \param[in] Data Byte of data to send to the device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_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 device, waiting to be read. This indicates the number
|
||||
* of bytes in the IN pipe bank only, and thus the number of calls to \ref CDC_Host_ReceiveByte() which are guaranteed to succeed
|
||||
* immediately. If multiple bytes are to be received, they should be buffered by the user application, as the pipe bank will not be
|
||||
* released back to the USB controller until all bytes are read.
|
||||
*
|
||||
* \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] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*
|
||||
* \return Total number of buffered bytes received from the device.
|
||||
*/
|
||||
uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Reads a byte of data from the device. If no data is waiting to be read of if a USB device is not connected, the function
|
||||
* returns a negative value. The \ref CDC_Host_BytesReceived() function may be queried in advance to determine how many bytes
|
||||
* are currently buffered in the CDC interface's data receive pipe.
|
||||
*
|
||||
* \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] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*
|
||||
* \return Next received byte from the device, or a negative value if no data received.
|
||||
*/
|
||||
int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_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 Host state machine is in the \ref HOST_STATE_Configured state or the
|
||||
* call will fail.
|
||||
*
|
||||
* \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_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 \c <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_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Identical to \ref CDC_Host_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_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
|
||||
FILE* const Stream) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
#endif
|
||||
|
||||
/** CDC class driver event for a control line state change on a CDC host interface. This event fires each time the device notifies
|
||||
* the host of a control line state change (containing the virtual serial control line states, such as DCD) 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.DeviceToHost value inside the CDC host interface structure passed as a parameter, set as
|
||||
* a mask of \c CDC_CONTROL_LINE_IN_* masks.
|
||||
*
|
||||
* \param[in,out] CDCInterfaceInfo Pointer to a structure containing a CDC Class host configuration and state.
|
||||
*/
|
||||
void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_CDC_HOST_C)
|
||||
#if defined(FDEV_SETUP_STREAM)
|
||||
static int CDC_Host_putchar(char c,
|
||||
FILE* Stream) ATTR_NON_NULL_PTR_ARG(2);
|
||||
static int CDC_Host_getchar(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
|
||||
static int CDC_Host_getchar_Blocking(FILE* Stream) ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
|
||||
void CDC_Host_Event_Stub(void) ATTR_CONST;
|
||||
|
||||
void EVENT_CDC_Host_ControLineStateChanged(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
|
||||
ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(CDC_Host_Event_Stub);
|
||||
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_HID_DRIVER
|
||||
#define __INCLUDE_FROM_HID_HOST_C
|
||||
#include "HIDClassHost.h"
|
||||
|
||||
uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* HIDInterface = NULL;
|
||||
USB_HID_Descriptor_HID_t* HIDDescriptor = NULL;
|
||||
|
||||
memset(&HIDInterfaceInfo->State, 0x00, sizeof(HIDInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return HID_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
||||
{
|
||||
if (!(HIDInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_HID_Host_NextHIDInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (DataINEndpoint)
|
||||
break;
|
||||
|
||||
do
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_HID_Host_NextHIDInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return HID_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
HIDInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
} while (HIDInterfaceInfo->Config.HIDInterfaceProtocol &&
|
||||
(HIDInterface->Protocol != HIDInterfaceInfo->Config.HIDInterfaceProtocol));
|
||||
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_HID_Host_NextHIDDescriptor) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return HID_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
HIDDescriptor = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_HID_Descriptor_HID_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
HIDInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
HIDInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
HIDInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_INTERRUPT;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return HID_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (DataOUTEndpoint)
|
||||
{
|
||||
HIDInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
HIDInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
HIDInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_INTERRUPT;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&HIDInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return HID_ENUMERROR_PipeConfigurationFailed;
|
||||
}
|
||||
|
||||
HIDInterfaceInfo->State.InterfaceNumber = HIDInterface->InterfaceNumber;
|
||||
HIDInterfaceInfo->State.HIDReportSize = LE16_TO_CPU(HIDDescriptor->HIDReportLength);
|
||||
HIDInterfaceInfo->State.SupportsBootProtocol = (HIDInterface->SubClass != HID_CSCP_NonBootProtocol);
|
||||
HIDInterfaceInfo->State.LargestReportSize = 8;
|
||||
HIDInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return HID_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if (Interface->Class == HID_CSCP_HIDClass)
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_HID_Host_NextHIDDescriptor(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == HID_DTYPE_HID)
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
else
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
void* Buffer)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = HID_REQ_SetReport,
|
||||
.wValue = ((HID_REPORT_ITEM_In + 1) << 8) | ReportID,
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, HID_REPORT_ITEM_In),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(Buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
void* Buffer)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
uint16_t ReportSize;
|
||||
uint8_t* BufferPos = Buffer;
|
||||
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
if (!(HIDInterfaceInfo->State.UsingBootProtocol))
|
||||
{
|
||||
uint8_t ReportID = 0;
|
||||
|
||||
if (HIDInterfaceInfo->Config.HIDParserData->UsingReportIDs)
|
||||
{
|
||||
ReportID = Pipe_Read_8();
|
||||
*(BufferPos++) = ReportID;
|
||||
}
|
||||
|
||||
ReportSize = USB_GetHIDReportSize(HIDInterfaceInfo->Config.HIDParserData, ReportID, HID_REPORT_ITEM_In);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ReportSize = Pipe_BytesInPipe();
|
||||
}
|
||||
|
||||
if ((ErrorCode = Pipe_Read_Stream_LE(BufferPos, ReportSize, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
const uint8_t ReportID,
|
||||
#endif
|
||||
const uint8_t ReportType,
|
||||
void* Buffer,
|
||||
const uint16_t ReportSize)
|
||||
{
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
|
||||
if (HIDInterfaceInfo->State.DeviceUsesOUTPipe && (ReportType == HID_REPORT_ITEM_Out))
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(HIDInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (ReportID)
|
||||
Pipe_Write_Stream_LE(&ReportID, sizeof(ReportID), NULL);
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(Buffer, ReportSize, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = HID_REQ_SetReport,
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
.wValue = ((ReportType + 1) << 8) | ReportID,
|
||||
#else
|
||||
.wValue = ((ReportType + 1) << 8),
|
||||
#endif
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = ReportSize,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
|
||||
return false;
|
||||
|
||||
bool ReportReceived;
|
||||
|
||||
Pipe_SelectPipe(HIDInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
ReportReceived = Pipe_IsINReceived();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ReportReceived;
|
||||
}
|
||||
|
||||
uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if (!(HIDInterfaceInfo->State.SupportsBootProtocol))
|
||||
return HID_ERROR_LOGICAL;
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = HID_REQ_SetProtocol,
|
||||
.wValue = 0,
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
HIDInterfaceInfo->State.LargestReportSize = 8;
|
||||
HIDInterfaceInfo->State.UsingBootProtocol = true;
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t HID_Host_SetIdlePeriod(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
const uint16_t MS)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = HID_REQ_SetIdle,
|
||||
.wValue = ((MS << 6) & 0xFF00),
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(NULL);
|
||||
}
|
||||
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
uint8_t HIDReportData[HIDInterfaceInfo->State.HIDReportSize];
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_INTERFACE),
|
||||
.bRequest = REQ_GetDescriptor,
|
||||
.wValue = (HID_DTYPE_Report << 8),
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = HIDInterfaceInfo->State.HIDReportSize,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(HIDReportData)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
if (HIDInterfaceInfo->State.UsingBootProtocol)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = HID_REQ_SetProtocol,
|
||||
.wValue = 1,
|
||||
.wIndex = HIDInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
HIDInterfaceInfo->State.UsingBootProtocol = false;
|
||||
}
|
||||
|
||||
if (HIDInterfaceInfo->Config.HIDParserData == NULL)
|
||||
return HID_ERROR_LOGICAL;
|
||||
|
||||
if ((ErrorCode = USB_ProcessHIDReport(HIDReportData, HIDInterfaceInfo->State.HIDReportSize,
|
||||
HIDInterfaceInfo->Config.HIDParserData)) != HID_PARSE_Successful)
|
||||
{
|
||||
return HID_ERROR_LOGICAL | ErrorCode;
|
||||
}
|
||||
|
||||
uint16_t LargestReportSizeBits = HIDInterfaceInfo->Config.HIDParserData->LargestReportSizeBits;
|
||||
HIDInterfaceInfo->State.LargestReportSize = (LargestReportSizeBits >> 3) + ((LargestReportSizeBits & 0x07) != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB HID Class driver.
|
||||
*
|
||||
* Host 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_USBClassHIDHost HID Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassHIDHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/HIDClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassHIDHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the HID USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __HID_CLASS_HOST_H__
|
||||
#define __HID_CLASS_HOST_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: */
|
||||
/* Macros: */
|
||||
/** Error code for some HID Host functions, indicating a logical (and not hardware) error. */
|
||||
#define HID_ERROR_LOGICAL 0x80
|
||||
|
||||
/* Type Defines: */
|
||||
/** \brief HID Class Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made 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.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe configuration table. */
|
||||
|
||||
uint8_t HIDInterfaceProtocol; /**< HID interface protocol value to match against if a specific
|
||||
* boot subclass protocol is required, a protocol value from the
|
||||
* \ref HID_Descriptor_ClassSubclassProtocol_t enum.
|
||||
*/
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
HID_ReportInfo_t* HIDParserData; /**< HID parser data to store the parsed HID report data, when boot protocol
|
||||
* is not used.
|
||||
*
|
||||
* \note When the \c HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined,
|
||||
* this field is unavailable.
|
||||
*/
|
||||
#endif
|
||||
} 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref HID_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the HID interface within the attached device. */
|
||||
|
||||
bool SupportsBootProtocol; /**< Indicates if the current interface instance supports the HID Boot
|
||||
* Protocol when enabled via \ref HID_Host_SetBootProtocol().
|
||||
*/
|
||||
bool DeviceUsesOUTPipe; /**< Indicates if the current interface instance uses a separate OUT data pipe for
|
||||
* OUT reports, or if OUT reports are sent via the control pipe instead.
|
||||
*/
|
||||
bool UsingBootProtocol; /**< Indicates that the interface is currently initialized in Boot Protocol mode */
|
||||
uint16_t HIDReportSize; /**< Size in bytes of the HID report descriptor in the device. */
|
||||
|
||||
uint8_t LargestReportSize; /**< Largest report the device will send, in bytes. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_HID_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref HID_Host_ConfigurePipes() function. */
|
||||
enum HID_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
HID_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
HID_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
HID_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible HID interface was not found in the device's Configuration Descriptor. */
|
||||
HID_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given HID host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given HID Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the
|
||||
* device. This should be called once after the stack has enumerated the attached device, while the host state
|
||||
* machine is in the Addressed state.
|
||||
*
|
||||
* \attention Once the device pipes are configured, the HID device's reporting protocol <b>must</b> be set via a call
|
||||
* to either the \ref HID_Host_SetBootProtocol() or \ref HID_Host_SetReportProtocol() function.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref HID_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
|
||||
/** Receives a HID IN report from the attached HID device, when a report has been received on the HID IN Data pipe.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \attention The destination buffer should be large enough to accommodate the largest report that the attached device
|
||||
* can generate.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
* \param[in] Buffer Buffer to store the received report into.
|
||||
*
|
||||
* \return An error code from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
void* Buffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
/** Receives a HID IN report from the attached device, by the report ID.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \note When the \c HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
* \param[in] ReportID Report ID of the received report if ControlRequest is false, set by the to the Report ID to fetch.
|
||||
* \param[in] Buffer Buffer to store the received report into.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
void* Buffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
#endif
|
||||
|
||||
/** Sends an OUT or FEATURE report to the currently attached HID device, using the device's OUT pipe if available,
|
||||
* or the device's Control pipe if not.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \note When the \c HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, the ReportID parameter is removed
|
||||
* from the parameter list of this function.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
* \param[in] ReportID Report ID of the report to send to the device, or 0 if the device does not use report IDs.
|
||||
* \param[in] ReportType Type of report to issue to the device, either \ref HID_REPORT_ITEM_Out or \ref HID_REPORT_ITEM_Feature.
|
||||
* \param[in] Buffer Buffer containing the report to send to the attached device.
|
||||
* \param[in] ReportSize Report size in bytes to send to the attached device.
|
||||
*
|
||||
* \return An error code from the \ref USB_Host_SendControlErrorCodes_t enum if the DeviceUsesOUTPipe flag is set in
|
||||
* the interface's state structure, a value from the \ref Pipe_Stream_RW_ErrorCodes_t enum otherwise.
|
||||
*/
|
||||
uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
const uint8_t ReportID,
|
||||
#endif
|
||||
const uint8_t ReportType,
|
||||
void* Buffer,
|
||||
const uint16_t ReportSize) ATTR_NON_NULL_PTR_ARG(1)
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
ATTR_NON_NULL_PTR_ARG(4);
|
||||
#else
|
||||
ATTR_NON_NULL_PTR_ARG(3);
|
||||
#endif
|
||||
|
||||
/** Determines if a HID IN report has been received from the attached device on the data IN pipe.
|
||||
*
|
||||
* \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] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
*
|
||||
* \return Boolean \c true if a report has been received, \c false otherwise.
|
||||
*/
|
||||
bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Switches the attached HID device's reporting protocol over to the Boot Report protocol mode, on supported devices.
|
||||
*
|
||||
* \note When the \c HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method must still be called
|
||||
* to explicitly place the attached device into boot protocol mode before use.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
*
|
||||
* \return \ref HID_ERROR_LOGICAL if the device does not support Boot Protocol mode, a value from the
|
||||
* \ref USB_Host_SendControlErrorCodes_t enum otherwise.
|
||||
*/
|
||||
uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sets the idle period for the attached HID device to the specified interval. The HID idle period determines the rate
|
||||
* at which the device should send a report, when no state changes have occurred; i.e. on HID keyboards, this sets the
|
||||
* hardware key repeat interval.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
* \param[in] MS Idle period as a multiple of four milliseconds, zero to disable hardware repeats
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t HID_Host_SetIdlePeriod(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo,
|
||||
const uint16_t MS) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
#if !defined(HID_HOST_BOOT_PROTOCOL_ONLY)
|
||||
/** Switches the attached HID device's reporting protocol over to the standard Report protocol mode. This also retrieves
|
||||
* and parses the device's HID report descriptor, so that the size of each report can be determined in advance.
|
||||
*
|
||||
* \attention Whether this function is used or not, the \ref CALLBACK_HIDParser_FilterHIDReportItem() callback from the HID
|
||||
* Report Parser this function references <b>must</b> be implemented in the user code.
|
||||
*
|
||||
* \note When the \c HID_HOST_BOOT_PROTOCOL_ONLY compile time token is defined, this method is unavailable.
|
||||
*
|
||||
* \param[in,out] HIDInterfaceInfo Pointer to a structure containing a HID Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum if an error occurs while retrieving the HID
|
||||
* Report descriptor or the setting of the Report protocol, \ref HID_ERROR_LOGICAL if the HID interface does
|
||||
* not have a valid \ref HID_ReportInfo_t structure set in its configuration, a mask of \ref HID_ERROR_LOGICAL
|
||||
* and a value from the \ref HID_Parse_ErrorCodes_t otherwise.
|
||||
*/
|
||||
uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
|
||||
/* Inline Functions: */
|
||||
/** General management task for a given Human Interface Class host 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 host configuration and state.
|
||||
*/
|
||||
static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
static inline void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* const HIDInterfaceInfo)
|
||||
{
|
||||
(void)HIDInterfaceInfo;
|
||||
}
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_HID_HOST_C)
|
||||
static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_HID_Host_NextHIDDescriptor(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_MIDI_DRIVER
|
||||
#define __INCLUDE_FROM_MIDI_HOST_C
|
||||
#include "MIDIClassHost.h"
|
||||
|
||||
uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* MIDIInterface = NULL;
|
||||
|
||||
memset(&MIDIInterfaceInfo->State, 0x00, sizeof(MIDIInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return MIDI_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
||||
{
|
||||
if (!(MIDIInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_MIDI_Host_NextMIDIStreamingDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_MIDI_Host_NextMIDIStreamingInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return MIDI_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
MIDIInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
MIDIInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
MIDIInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
MIDIInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
MIDIInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
MIDIInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
MIDIInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&MIDIInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return MIDI_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&MIDIInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return MIDI_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
MIDIInterfaceInfo->State.InterfaceNumber = MIDIInterface->InterfaceNumber;
|
||||
MIDIInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return MIDI_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == AUDIO_CSCP_AudioClass) &&
|
||||
(Interface->SubClass == AUDIO_CSCP_MIDIStreamingSubclass) &&
|
||||
(Interface->Protocol == AUDIO_CSCP_StreamingProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if ((EndpointType == EP_TYPE_BULK) && !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
|
||||
return;
|
||||
|
||||
#if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
|
||||
MIDI_Host_Flush(MIDIInterfaceInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_BytesInPipe())
|
||||
{
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return ErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
MIDI_EventPacket_t* const Event)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NULL)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
Pipe_ClearOUT();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
bool MIDI_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
MIDI_EventPacket_t* const Event)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MIDIInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
bool DataReady = false;
|
||||
|
||||
Pipe_SelectPipe(MIDIInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (Pipe_BytesInPipe())
|
||||
{
|
||||
Pipe_Read_Stream_LE(Event, sizeof(MIDI_EventPacket_t), NULL);
|
||||
DataReady = true;
|
||||
}
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return DataReady;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB MIDI Class driver.
|
||||
*
|
||||
* Host 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_USBClassMIDIHost MIDI Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassMIDIHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/MIDIClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassMIDIHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the MIDI USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __MIDI_CLASS_HOST_H__
|
||||
#define __MIDI_CLASS_HOST_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 Defines: */
|
||||
/** \brief MIDI Class Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made 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
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref MIDI_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the MIDI interface within the attached device. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_MIDI_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref MIDI_Host_ConfigurePipes() function. */
|
||||
enum MIDI_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
MIDI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
MIDI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
MIDI_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible MIDI interface was not found in the device's Configuration Descriptor. */
|
||||
MIDI_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given MIDI host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given MIDI Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the device.
|
||||
* This should be called once after the stack has enumerated the attached device, while the host state machine is in
|
||||
* the Addressed state.
|
||||
*
|
||||
* \param[in,out] MIDIInterfaceInfo Pointer to a structure containing an MIDI Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref MIDI_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MIDI_Host_ConfigurePipes(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** General management task for a given MIDI host 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 an MIDI Class host configuration and state.
|
||||
*/
|
||||
void MIDI_Host_USBTask(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a MIDI event packet to the device. If no device is connected, the event packet is discarded.
|
||||
*
|
||||
* \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 USB_MIDI_EventPacket_t structure containing the MIDI event to send.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MIDI_Host_SendEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Flushes the MIDI send buffer, sending any queued MIDI events to the device. This should be called to override the
|
||||
* \ref MIDI_Host_SendEventPacket() function's packing behavior, to flush queued events. Events are queued into the
|
||||
* pipe bank until either the pipe bank is full, or \ref MIDI_Host_Flush() is called. This allows for multiple MIDI
|
||||
* events to be packed into a single pipe packet, increasing data throughput.
|
||||
*
|
||||
* \param[in,out] MIDIInterfaceInfo Pointer to a structure containing a MIDI Class configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MIDI_Host_Flush(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Receives a MIDI event packet from the device.
|
||||
*
|
||||
* \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_Host_ReceiveEventPacket(USB_ClassInfo_MIDI_Host_t* const MIDIInterfaceInfo,
|
||||
MIDI_EventPacket_t* const Event) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_MIDI_HOST_C)
|
||||
static uint8_t DCOMP_MIDI_Host_NextMIDIStreamingInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_MIDI_Host_NextMIDIStreamingDataEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,579 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_MS_DRIVER
|
||||
#define __INCLUDE_FROM_MASSSTORAGE_HOST_C
|
||||
#include "MassStorageClassHost.h"
|
||||
|
||||
uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* MassStorageInterface = NULL;
|
||||
|
||||
memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return MS_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
||||
{
|
||||
if (!(MassStorageInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_MS_Host_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_MS_Host_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return MS_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
MassStorageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
MSInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
MSInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
MSInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
MSInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
MSInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
MSInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&MSInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return MS_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&MSInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return MS_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
|
||||
MSInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return MS_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == MS_CSCP_MassStorageClass) &&
|
||||
(Interface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
|
||||
(Interface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandBlockWrapper_t* const SCSICommandBlock,
|
||||
const void* const BufferPtr)
|
||||
{
|
||||
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
|
||||
|
||||
if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
|
||||
MSInterfaceInfo->State.TransactionTag = 1;
|
||||
|
||||
SCSICommandBlock->Signature = CPU_TO_LE32(MS_CBW_SIGNATURE);
|
||||
SCSICommandBlock->Tag = cpu_to_le32(MSInterfaceInfo->State.TransactionTag);
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
|
||||
NULL)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_ClearOUT();
|
||||
Pipe_WaitUntilReady();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
if (BufferPtr != NULL)
|
||||
{
|
||||
ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr);
|
||||
|
||||
if ((ErrorCode != PIPE_RWSTREAM_NoError) && (ErrorCode != PIPE_RWSTREAM_PipeStalled))
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return ErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
MS_CommandStatusWrapper_t SCSIStatusBlock;
|
||||
return MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSIStatusBlock);
|
||||
}
|
||||
|
||||
static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
|
||||
{
|
||||
uint16_t TimeoutMSRem = MS_COMMAND_DATA_TIMEOUT_MS;
|
||||
uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
while (!(Pipe_IsINReceived()))
|
||||
{
|
||||
uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
|
||||
|
||||
if (CurrentFrameNumber != PreviousFrameNumber)
|
||||
{
|
||||
PreviousFrameNumber = CurrentFrameNumber;
|
||||
|
||||
if (!(TimeoutMSRem--))
|
||||
return PIPE_RWSTREAM_Timeout;
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsStalled())
|
||||
{
|
||||
USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
|
||||
return PIPE_RWSTREAM_PipeStalled;
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsStalled())
|
||||
{
|
||||
USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
|
||||
return PIPE_RWSTREAM_PipeStalled;
|
||||
}
|
||||
|
||||
if (USB_HostState == HOST_STATE_Unattached)
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Freeze();
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandBlockWrapper_t* const SCSICommandBlock,
|
||||
void* BufferPtr)
|
||||
{
|
||||
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
|
||||
uint16_t BytesRem = le32_to_cpu(SCSICommandBlock->DataTransferLength);
|
||||
|
||||
if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
|
||||
{
|
||||
if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
while (!(Pipe_IsOUTReady()))
|
||||
{
|
||||
if (USB_HostState == HOST_STATE_Unattached)
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
}
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandStatusWrapper_t* const SCSICommandStatus)
|
||||
{
|
||||
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
|
||||
|
||||
if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
|
||||
NULL)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
|
||||
if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
|
||||
ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = MS_REQ_MassStorageReset,
|
||||
.wValue = 0,
|
||||
.wIndex = MSInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
|
||||
|
||||
if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
|
||||
if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
uint8_t* const MaxLUNIndex)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = MS_REQ_GetMaxLUN,
|
||||
.wValue = 0,
|
||||
.wIndex = MSInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 1,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
|
||||
{
|
||||
*MaxLUNIndex = 0;
|
||||
ErrorCode = HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Inquiry_Response_t* const InquiryData)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Inquiry_Response_t)),
|
||||
.Flags = MS_COMMAND_DIR_DATA_IN,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 6,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_INQUIRY,
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
sizeof(SCSI_Inquiry_Response_t), // Allocation Length
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData);
|
||||
}
|
||||
|
||||
uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = CPU_TO_LE32(0),
|
||||
.Flags = MS_COMMAND_DIR_DATA_IN,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 6,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_TEST_UNIT_READY,
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL);
|
||||
}
|
||||
|
||||
uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Capacity_t* const DeviceCapacity)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Capacity_t)),
|
||||
.Flags = MS_COMMAND_DIR_DATA_IN,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 10,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_READ_CAPACITY_10,
|
||||
0x00, // Reserved
|
||||
0x00, // MSB of Logical block address
|
||||
0x00,
|
||||
0x00,
|
||||
0x00, // LSB of Logical block address
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00, // Partial Medium Indicator
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
DeviceCapacity->Blocks = BE32_TO_CPU(DeviceCapacity->Blocks);
|
||||
DeviceCapacity->BlockSize = BE32_TO_CPU(DeviceCapacity->BlockSize);
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Request_Sense_Response_t* const SenseData)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Request_Sense_Response_t)),
|
||||
.Flags = MS_COMMAND_DIR_DATA_IN,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 6,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_REQUEST_SENSE,
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData);
|
||||
}
|
||||
|
||||
uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const bool PreventRemoval)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = CPU_TO_LE32(0),
|
||||
.Flags = MS_COMMAND_DIR_DATA_OUT,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 6,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
|
||||
0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
PreventRemoval, // Prevent flag
|
||||
0x00, // Reserved
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL);
|
||||
}
|
||||
|
||||
uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const uint32_t BlockAddress,
|
||||
const uint8_t Blocks,
|
||||
const uint16_t BlockSize,
|
||||
void* BlockBuffer)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
|
||||
.Flags = MS_COMMAND_DIR_DATA_IN,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 10,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_READ_10,
|
||||
0x00, // Unused (control bits, all off)
|
||||
(BlockAddress >> 24), // MSB of Block Address
|
||||
(BlockAddress >> 16),
|
||||
(BlockAddress >> 8),
|
||||
(BlockAddress & 0xFF), // LSB of Block Address
|
||||
0x00, // Reserved
|
||||
0x00, // MSB of Total Blocks to Read
|
||||
Blocks, // LSB of Total Blocks to Read
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer);
|
||||
}
|
||||
|
||||
uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const uint32_t BlockAddress,
|
||||
const uint8_t Blocks,
|
||||
const uint16_t BlockSize,
|
||||
const void* BlockBuffer)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
|
||||
return HOST_SENDCONTROL_DeviceDisconnected;
|
||||
|
||||
MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
|
||||
{
|
||||
.DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
|
||||
.Flags = MS_COMMAND_DIR_DATA_OUT,
|
||||
.LUN = LUNIndex,
|
||||
.SCSICommandLength = 10,
|
||||
.SCSICommandData =
|
||||
{
|
||||
SCSI_CMD_WRITE_10,
|
||||
0x00, // Unused (control bits, all off)
|
||||
(BlockAddress >> 24), // MSB of Block Address
|
||||
(BlockAddress >> 16),
|
||||
(BlockAddress >> 8),
|
||||
(BlockAddress & 0xFF), // LSB of Block Address
|
||||
0x00, // Reserved
|
||||
0x00, // MSB of Total Blocks to Write
|
||||
Blocks, // LSB of Total Blocks to Write
|
||||
0x00 // Unused (control)
|
||||
}
|
||||
};
|
||||
|
||||
return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB Mass Storage Class driver.
|
||||
*
|
||||
* Host 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_USBClassMassStorageHost Mass Storage Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassMassStorageHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/MassStorageClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassMassStorageHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Mass Storage USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __MS_CLASS_HOST_H__
|
||||
#define __MS_CLASS_HOST_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: */
|
||||
/* Macros: */
|
||||
/** Error code for some Mass Storage Host functions, indicating a logical (and not hardware) error. */
|
||||
#define MS_ERROR_LOGICAL_CMD_FAILED 0x80
|
||||
|
||||
/* Type Defines: */
|
||||
/** \brief Mass Storage Class Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made 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
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref MS_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the Mass Storage interface within the attached device. */
|
||||
|
||||
uint32_t TransactionTag; /**< Current transaction tag for data synchronizing of packets. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_MS_Host_t;
|
||||
|
||||
/** \brief SCSI Device LUN Capacity Structure.
|
||||
*
|
||||
* SCSI capacity structure, to hold the total capacity of the device in both the number
|
||||
* of blocks in the current LUN, and the size of each block. This structure is filled by
|
||||
* the device when the \ref MS_Host_ReadDeviceCapacity() function is called.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Blocks; /**< Number of blocks in the addressed LUN of the device. */
|
||||
uint32_t BlockSize; /**< Number of bytes in each block in the addressed LUN. */
|
||||
} SCSI_Capacity_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref MS_Host_ConfigurePipes() function. */
|
||||
enum MS_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
MS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
MS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
MS_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible Mass Storage interface was not found in the device's Configuration Descriptor. */
|
||||
MS_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given Mass Storage host interface instance using the
|
||||
* Configuration Descriptor read from an attached USB device. This function automatically updates the given Mass
|
||||
* Storage Host instance's state values and configures the pipes required to communicate with the interface if it
|
||||
* is found within the device. This should be called once after the stack has enumerated the attached device, while
|
||||
* the host state machine is in the Addressed state.
|
||||
*
|
||||
* \param[in,out] MSInterfaceInfo Pointer to a structure containing an MS Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] DeviceConfigDescriptor Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref MS_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Sends a MASS STORAGE RESET control request to the attached device, resetting the Mass Storage Interface
|
||||
* and readying it for the next Mass Storage command. This should be called after a failed SCSI request to
|
||||
* ensure the attached Mass Storage device is ready to receive the next command.
|
||||
*
|
||||
* \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a GET MAX LUN control request to the attached device, retrieving the index of the highest LUN (Logical
|
||||
* UNit, a logical drive) in the device. This value can then be used in the other functions of the Mass Storage
|
||||
* Host mode Class driver to address a specific LUN within the device.
|
||||
*
|
||||
* \note Some devices do not support this request, and will STALL it when issued. To get around this,
|
||||
* on unsupported devices the max LUN index will be reported as zero and no error will be returned
|
||||
* if the device STALLs the request.
|
||||
*
|
||||
* \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[out] MaxLUNIndex Pointer to a location where the highest LUN index value should be stored.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
uint8_t* const MaxLUNIndex) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Retrieves the Mass Storage device's inquiry data for the specified LUN, indicating the device characteristics and
|
||||
* properties.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[out] InquiryData Location where the read inquiry data should be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED.
|
||||
*/
|
||||
uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Inquiry_Response_t* const InquiryData) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Sends a TEST UNIT READY command to the device, to determine if it is ready to accept other SCSI commands.
|
||||
*
|
||||
* \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Retrieves the total capacity of the attached USB Mass Storage device, in blocks, and block size.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[out] DeviceCapacity Pointer to the location where the capacity information should be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Capacity_t* const DeviceCapacity) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Retrieves the device sense data, indicating the current device state and error codes for the previously
|
||||
* issued command.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[out] SenseData Pointer to the location where the sense information should be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
SCSI_Request_Sense_Response_t* const SenseData) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Issues a PREVENT MEDIUM REMOVAL command, to logically (or, depending on the type of device, physically) lock
|
||||
* the device from removal so that blocks of data on the medium can be read or altered.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[in] PreventRemoval Boolean \c true if the device should be locked from removal, \c false otherwise.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const bool PreventRemoval) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Reads blocks of data from the attached Mass Storage device's medium.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[in] BlockAddress Starting block address within the device to read from.
|
||||
* \param[in] Blocks Total number of blocks to read.
|
||||
* \param[in] BlockSize Size in bytes of each block within the device.
|
||||
* \param[out] BlockBuffer Pointer to where the read data from the device should be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const uint32_t BlockAddress,
|
||||
const uint8_t Blocks,
|
||||
const uint16_t BlockSize,
|
||||
void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6);
|
||||
|
||||
/** Writes blocks of data to the attached Mass Storage device's medium.
|
||||
*
|
||||
* \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] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state.
|
||||
* \param[in] LUNIndex LUN index within the device the command is being issued to.
|
||||
* \param[in] BlockAddress Starting block address within the device to write to.
|
||||
* \param[in] Blocks Total number of blocks to read.
|
||||
* \param[in] BlockSize Size in bytes of each block within the device.
|
||||
* \param[in] BlockBuffer Pointer to where the data to write should be sourced from.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or \ref MS_ERROR_LOGICAL_CMD_FAILED if not ready.
|
||||
*/
|
||||
uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
const uint8_t LUNIndex,
|
||||
const uint32_t BlockAddress,
|
||||
const uint8_t Blocks,
|
||||
const uint16_t BlockSize,
|
||||
const void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(6);
|
||||
|
||||
/* Inline Functions: */
|
||||
/** General management task for a given Mass Storage host 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 an Mass Storage Class host configuration and state.
|
||||
*/
|
||||
static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
|
||||
{
|
||||
(void)MSInterfaceInfo;
|
||||
}
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Macros: */
|
||||
#define MS_COMMAND_DATA_TIMEOUT_MS 10000
|
||||
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_MASSSTORAGE_HOST_C)
|
||||
static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandBlockWrapper_t* const SCSICommandBlock,
|
||||
const void* const BufferPtr) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandBlockWrapper_t* const SCSICommandBlock,
|
||||
void* BufferPtr) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
|
||||
MS_CommandStatusWrapper_t* const SCSICommandStatus)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_PRINTER_DRIVER
|
||||
#define __INCLUDE_FROM_PRINTER_HOST_C
|
||||
#include "PrinterClassHost.h"
|
||||
|
||||
uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* PrinterInterface = NULL;
|
||||
|
||||
memset(&PRNTInterfaceInfo->State, 0x00, sizeof(PRNTInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return PRNT_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint))
|
||||
{
|
||||
if (!(PrinterInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_PRNT_Host_NextPRNTInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_PRNT_Host_NextPRNTInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return PRNT_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
PrinterInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
DataINEndpoint = EndpointData;
|
||||
else
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
|
||||
PRNTInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
PRNTInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
PRNTInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
PRNTInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
PRNTInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
PRNTInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&PRNTInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return PRNT_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&PRNTInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return PRNT_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
PRNTInterfaceInfo->State.InterfaceNumber = PrinterInterface->InterfaceNumber;
|
||||
PRNTInterfaceInfo->State.AlternateSetting = PrinterInterface->AlternateSetting;
|
||||
PRNTInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return PRNT_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_PRNT_Host_NextPRNTInterface(void* CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == PRNT_CSCP_PrinterClass) &&
|
||||
(Interface->SubClass == PRNT_CSCP_PrinterSubclass) &&
|
||||
(Interface->Protocol == PRNT_CSCP_BidirectionalProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_PRNT_Host_NextPRNTInterfaceEndpoint(void* CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if (EndpointType == EP_TYPE_BULK)
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return;
|
||||
|
||||
#if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
|
||||
PRNT_Host_Flush(PRNTInterfaceInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
if (PRNTInterfaceInfo->State.AlternateSetting)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((ErrorCode = USB_Host_SetInterfaceAltSetting(PRNTInterfaceInfo->State.InterfaceNumber,
|
||||
PRNTInterfaceInfo->State.AlternateSetting)) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
uint8_t* const PortStatus)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = PRNT_REQ_GetPortStatus,
|
||||
.wValue = 0,
|
||||
.wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = sizeof(uint8_t),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
return USB_Host_SendControlRequest(PortStatus);
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = PRNT_REQ_SoftReset,
|
||||
.wValue = 0,
|
||||
.wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = 0,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
return USB_Host_SendControlRequest(NULL);
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_Flush(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
return PIPE_READYWAIT_NoError;
|
||||
|
||||
bool BankFull = !(Pipe_IsReadWriteAllowed());
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if (BankFull)
|
||||
{
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_SendByte(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
const uint8_t Data)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
Pipe_ClearOUT();
|
||||
|
||||
if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_Write_8(Data);
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_READYWAIT_NoError;
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_SendString(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
const char* const String)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
ErrorCode = Pipe_WaitUntilReady();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
const void* Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
Pipe_ClearOUT();
|
||||
|
||||
ErrorCode = Pipe_WaitUntilReady();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint16_t PRNT_Host_BytesReceived(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return 0;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
{
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
return Pipe_BytesInPipe();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Pipe_Freeze();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t PRNT_Host_ReceiveByte(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(PRNTInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
int16_t ReceivedByte = -1;
|
||||
|
||||
Pipe_SelectPipe(PRNTInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
{
|
||||
if (Pipe_BytesInPipe())
|
||||
ReceivedByte = Pipe_Read_8();
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ReceivedByte;
|
||||
}
|
||||
|
||||
uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
char* const DeviceIDString,
|
||||
const uint16_t BufferSize)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
uint16_t DeviceIDStringLength = 0;
|
||||
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = PRNT_REQ_GetDeviceID,
|
||||
.wValue = 0,
|
||||
.wIndex = PRNTInterfaceInfo->State.InterfaceNumber,
|
||||
.wLength = sizeof(DeviceIDStringLength),
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(&DeviceIDStringLength)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
if (!(DeviceIDStringLength))
|
||||
{
|
||||
DeviceIDString[0] = 0x00;
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
DeviceIDStringLength = be16_to_cpu(DeviceIDStringLength);
|
||||
|
||||
if (DeviceIDStringLength > BufferSize)
|
||||
DeviceIDStringLength = BufferSize;
|
||||
|
||||
USB_ControlRequest.wLength = DeviceIDStringLength;
|
||||
|
||||
if ((ErrorCode = USB_Host_SendControlRequest(DeviceIDString)) != HOST_SENDCONTROL_Successful)
|
||||
return ErrorCode;
|
||||
|
||||
memmove(&DeviceIDString[0], &DeviceIDString[2], DeviceIDStringLength - 2);
|
||||
|
||||
DeviceIDString[DeviceIDStringLength - 2] = 0x00;
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB Printer Class driver.
|
||||
*
|
||||
* Host 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_USBClassPrinterHost Printer Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassPrinterHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/PrinterClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassPrinterHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Printer USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __PRINTER_CLASS_HOST_H__
|
||||
#define __PRINTER_CLASS_HOST_H__
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
#include "../Common/PrinterClassCommon.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 Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made within the user application,
|
||||
* and passed to each of the Printer class driver functions as the \c PRNTInterfaceInfo parameter. This
|
||||
* stores each Printer interface's configuration and state information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref PRNT_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the Printer interface within the attached device. */
|
||||
uint8_t AlternateSetting; /**< Alternate setting within the Printer Interface in the attached device. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_PRNT_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref PRNT_Host_ConfigurePipes() function. */
|
||||
enum PRNT_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
PRNT_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
PRNT_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
PRNT_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible Printer interface was not found in the device's Configuration Descriptor. */
|
||||
PRNT_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given Printer host interface instance using the
|
||||
* Configuration Descriptor read from an attached USB device. This function automatically updates the given Printer
|
||||
* instance's state values and configures the pipes required to communicate with the interface if it is found within
|
||||
* the device. This should be called once after the stack has enumerated the attached device, while the host state
|
||||
* machine is in the Addressed state.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref PRNT_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_ConfigurePipes(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** General management task for a given Printer host 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 host configuration and state.
|
||||
*/
|
||||
void PRNT_Host_USBTask(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Configures the printer to enable Bidirectional mode, if it is not already in this mode. This should be called
|
||||
* once the connected device's configuration has been set, to ensure the printer is ready to accept commands.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_SetBidirectionalMode(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Retrieves the status of the virtual Printer port's inbound status lines. The result can then be masked against the
|
||||
* \c PRNT_PORTSTATUS_* macros to determine the printer port's status.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[out] PortStatus Location where the retrieved port status should be stored.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_GetPortStatus(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
uint8_t* const PortStatus)
|
||||
ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Soft-resets the attached printer, readying it for new commands.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_SoftReset(USB_ClassInfo_PRNT_Host_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 Host state machine is in the \ref HOST_STATE_Configured state or the
|
||||
* call will fail.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_Flush(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends the given null terminated string to the attached printer's input endpoint.
|
||||
*
|
||||
* \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] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[in] String Pointer to a null terminated string to send.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_SendString(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
const char* const String) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sends the given raw data stream to the attached printer's input endpoint. This should contain commands that the
|
||||
* printer is able to understand - for example, PCL data. Not all printers accept all printer languages; see
|
||||
* \ref PRNT_Host_GetDeviceID() for details on determining acceptable languages for an attached printer.
|
||||
*
|
||||
* \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] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[in] Buffer Pointer to a buffer containing the raw command stream to send to the printer.
|
||||
* \param[in] Length Size in bytes of the command stream to be sent.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_SendData(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
const void* Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sends a given byte to the attached USB device, if connected. If a device is not connected when the function is called, the
|
||||
* byte is discarded. Bytes will be queued for transmission to the device until either the pipe bank becomes full, or the
|
||||
* \ref PRNT_Host_Flush() function is called to flush the pending data to the host. This allows for multiple bytes to be
|
||||
* packed into a single pipe 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] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[in] Data Byte of data to send to the device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_WaitUntilReady_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_SendByte(USB_ClassInfo_PRNT_Host_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 device, waiting to be read. This indicates the number
|
||||
* of bytes in the IN pipe bank only, and thus the number of calls to \ref PRNT_Host_ReceiveByte() which are guaranteed to succeed
|
||||
* immediately. If multiple bytes are to be received, they should be buffered by the user application, as the pipe bank will not be
|
||||
* released back to the USB controller until all bytes are read.
|
||||
*
|
||||
* \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] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
*
|
||||
* \return Total number of buffered bytes received from the device.
|
||||
*/
|
||||
uint16_t PRNT_Host_BytesReceived(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Reads a byte of data from the device. If no data is waiting to be read of if a USB device is not connected, the function
|
||||
* returns a negative value. The \ref PRNT_Host_BytesReceived() function may be queried in advance to determine how many bytes
|
||||
* are currently buffered in the Printer interface's data receive pipe.
|
||||
*
|
||||
* \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] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
*
|
||||
* \return Next received byte from the device, or a negative value if no data received.
|
||||
*/
|
||||
int16_t PRNT_Host_ReceiveByte(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Retrieves the attached printer device's ID string, formatted according to IEEE 1284. This string is sent as a
|
||||
* Unicode string from the device and is automatically converted to an ASCII encoded C string by this function, thus
|
||||
* the maximum reportable string length is two less than the size given (to accommodate the Unicode string length
|
||||
* bytes which are removed).
|
||||
*
|
||||
* This string, when supported, contains the model, manufacturer and acceptable printer languages for the attached device.
|
||||
*
|
||||
* \param[in,out] PRNTInterfaceInfo Pointer to a structure containing a Printer Class host configuration and state.
|
||||
* \param[out] DeviceIDString Pointer to a buffer where the Device ID string should be stored, in ASCII format.
|
||||
* \param[in] BufferSize Size in bytes of the buffer allocated for the Device ID string.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t PRNT_Host_GetDeviceID(USB_ClassInfo_PRNT_Host_t* const PRNTInterfaceInfo,
|
||||
char* const DeviceIDString,
|
||||
const uint16_t BufferSize) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_PRINTER_HOST_C)
|
||||
static uint8_t DCOMP_PRNT_Host_NextPRNTInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_PRNT_Host_NextPRNTInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_RNDIS_DRIVER
|
||||
#define __INCLUDE_FROM_RNDIS_HOST_C
|
||||
#include "RNDISClassHost.h"
|
||||
|
||||
uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* NotificationEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* RNDISControlInterface = NULL;
|
||||
|
||||
memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return RNDIS_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
|
||||
{
|
||||
if (!(RNDISControlInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (NotificationEndpoint)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_RNDIS_Host_NextRNDISDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
NotificationEndpoint = NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
{
|
||||
if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
|
||||
NotificationEndpoint = EndpointData;
|
||||
else
|
||||
DataINEndpoint = EndpointData;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
}
|
||||
|
||||
RNDISInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
RNDISInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
RNDISInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
RNDISInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
RNDISInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
RNDISInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
RNDISInterfaceInfo->Config.NotificationPipe.Size = le16_to_cpu(NotificationEndpoint->EndpointSize);
|
||||
RNDISInterfaceInfo->Config.NotificationPipe.EndpointAddress = NotificationEndpoint->EndpointAddress;
|
||||
RNDISInterfaceInfo->Config.NotificationPipe.Type = EP_TYPE_INTERRUPT;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&RNDISInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return RNDIS_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&RNDISInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return RNDIS_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&RNDISInterfaceInfo->Config.NotificationPipe, 1)))
|
||||
return RNDIS_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
RNDISInterfaceInfo->State.ControlInterfaceNumber = RNDISControlInterface->InterfaceNumber;
|
||||
RNDISInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return RNDIS_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == CDC_CSCP_CDCClass) &&
|
||||
(Interface->SubClass == CDC_CSCP_ACMSubclass) &&
|
||||
(Interface->Protocol == CDC_CSCP_VendorSpecificProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor,
|
||||
USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == CDC_CSCP_CDCDataClass) &&
|
||||
(Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
|
||||
(Interface->Protocol == CDC_CSCP_NoDataProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
|
||||
!(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = RNDIS_REQ_SendEncapsulatedCommand,
|
||||
.wValue = 0,
|
||||
.wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
|
||||
.wLength = Length,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(Buffer);
|
||||
}
|
||||
|
||||
static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
USB_ControlRequest = (USB_Request_Header_t)
|
||||
{
|
||||
.bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
|
||||
.bRequest = RNDIS_REQ_GetEncapsulatedResponse,
|
||||
.wValue = 0,
|
||||
.wIndex = RNDISInterfaceInfo->State.ControlInterfaceNumber,
|
||||
.wLength = Length,
|
||||
};
|
||||
|
||||
Pipe_SelectPipe(PIPE_CONTROLPIPE);
|
||||
|
||||
return USB_Host_SendControlRequest(Buffer);
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
RNDIS_KeepAlive_Message_t KeepAliveMessage;
|
||||
RNDIS_KeepAlive_Complete_t KeepAliveMessageResponse;
|
||||
|
||||
KeepAliveMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_MSG);
|
||||
KeepAliveMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Message_t));
|
||||
KeepAliveMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
|
||||
|
||||
if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &KeepAliveMessage,
|
||||
sizeof(RNDIS_KeepAlive_Message_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &KeepAliveMessageResponse,
|
||||
sizeof(RNDIS_KeepAlive_Complete_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
RNDIS_Initialize_Message_t InitMessage;
|
||||
RNDIS_Initialize_Complete_t InitMessageResponse;
|
||||
|
||||
InitMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_MSG);
|
||||
InitMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Initialize_Message_t));
|
||||
InitMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
|
||||
|
||||
InitMessage.MajorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR);
|
||||
InitMessage.MinorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR);
|
||||
InitMessage.MaxTransferSize = cpu_to_le32(RNDISInterfaceInfo->Config.HostMaxPacketSize);
|
||||
|
||||
if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &InitMessage,
|
||||
sizeof(RNDIS_Initialize_Message_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &InitMessageResponse,
|
||||
sizeof(RNDIS_Initialize_Complete_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if (InitMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
|
||||
return RNDIS_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
RNDISInterfaceInfo->State.DeviceMaxPacketSize = le32_to_cpu(InitMessageResponse.MaxTransferSize);
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
const uint32_t Oid,
|
||||
void* Buffer,
|
||||
const uint16_t Length)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
struct
|
||||
{
|
||||
RNDIS_Set_Message_t SetMessage;
|
||||
uint8_t ContiguousBuffer[Length];
|
||||
} SetMessageData;
|
||||
|
||||
RNDIS_Set_Complete_t SetMessageResponse;
|
||||
|
||||
SetMessageData.SetMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_SET_MSG);
|
||||
SetMessageData.SetMessage.MessageLength = cpu_to_le32(sizeof(RNDIS_Set_Message_t) + Length);
|
||||
SetMessageData.SetMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
|
||||
|
||||
SetMessageData.SetMessage.Oid = cpu_to_le32(Oid);
|
||||
SetMessageData.SetMessage.InformationBufferLength = cpu_to_le32(Length);
|
||||
SetMessageData.SetMessage.InformationBufferOffset = CPU_TO_LE32(sizeof(RNDIS_Set_Message_t) - sizeof(RNDIS_Message_Header_t));
|
||||
SetMessageData.SetMessage.DeviceVcHandle = CPU_TO_LE32(0);
|
||||
|
||||
memcpy(&SetMessageData.ContiguousBuffer, Buffer, Length);
|
||||
|
||||
if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &SetMessageData,
|
||||
(sizeof(RNDIS_Set_Message_t) + Length))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &SetMessageResponse,
|
||||
sizeof(RNDIS_Set_Complete_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if (SetMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
|
||||
return RNDIS_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
const uint32_t Oid,
|
||||
void* Buffer,
|
||||
const uint16_t MaxLength)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
RNDIS_Query_Message_t QueryMessage;
|
||||
|
||||
struct
|
||||
{
|
||||
RNDIS_Query_Complete_t QueryMessageResponse;
|
||||
uint8_t ContiguousBuffer[MaxLength];
|
||||
} QueryMessageResponseData;
|
||||
|
||||
QueryMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_QUERY_MSG);
|
||||
QueryMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Query_Message_t));
|
||||
QueryMessage.RequestId = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
|
||||
|
||||
QueryMessage.Oid = cpu_to_le32(Oid);
|
||||
QueryMessage.InformationBufferLength = CPU_TO_LE32(0);
|
||||
QueryMessage.InformationBufferOffset = CPU_TO_LE32(0);
|
||||
QueryMessage.DeviceVcHandle = CPU_TO_LE32(0);
|
||||
|
||||
if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &QueryMessage,
|
||||
sizeof(RNDIS_Query_Message_t))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &QueryMessageResponseData,
|
||||
sizeof(QueryMessageResponseData))) != HOST_SENDCONTROL_Successful)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
if (QueryMessageResponseData.QueryMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
|
||||
return RNDIS_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
memcpy(Buffer, &QueryMessageResponseData.ContiguousBuffer, MaxLength);
|
||||
|
||||
return HOST_SENDCONTROL_Successful;
|
||||
}
|
||||
|
||||
bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
|
||||
{
|
||||
bool PacketWaiting;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
|
||||
return false;
|
||||
|
||||
Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipe.Address);
|
||||
|
||||
Pipe_Unfreeze();
|
||||
PacketWaiting = Pipe_IsINReceived();
|
||||
Pipe_Freeze();
|
||||
|
||||
return PacketWaiting;
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
uint16_t* const PacketLength)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (!(Pipe_IsReadWriteAllowed()))
|
||||
{
|
||||
if (Pipe_IsINReceived())
|
||||
Pipe_ClearIN();
|
||||
|
||||
*PacketLength = 0;
|
||||
Pipe_Freeze();
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
RNDIS_Packet_Message_t DeviceMessage;
|
||||
|
||||
if ((ErrorCode = Pipe_Read_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
|
||||
NULL)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
*PacketLength = (uint16_t)le32_to_cpu(DeviceMessage.DataLength);
|
||||
|
||||
Pipe_Discard_Stream(le32_to_cpu(DeviceMessage.DataOffset) -
|
||||
(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)),
|
||||
NULL);
|
||||
|
||||
Pipe_Read_Stream_LE(Buffer, *PacketLength, NULL);
|
||||
|
||||
if (!(Pipe_BytesInPipe()))
|
||||
Pipe_ClearIN();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t PacketLength)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
|
||||
return PIPE_READYWAIT_DeviceDisconnected;
|
||||
|
||||
RNDIS_Packet_Message_t DeviceMessage;
|
||||
|
||||
memset(&DeviceMessage, 0, sizeof(RNDIS_Packet_Message_t));
|
||||
DeviceMessage.MessageType = CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG);
|
||||
DeviceMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) + PacketLength);
|
||||
DeviceMessage.DataOffset = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
|
||||
DeviceMessage.DataLength = cpu_to_le32(PacketLength);
|
||||
|
||||
Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
|
||||
NULL)) != PIPE_RWSTREAM_NoError)
|
||||
{
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_Write_Stream_LE(Buffer, PacketLength, NULL);
|
||||
Pipe_ClearOUT();
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB RNDIS Class driver.
|
||||
*
|
||||
* Host 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_USBClassRNDISHost RNDIS Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassRNDISHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/RNDISClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassRNDISHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Microsoft RNDIS Ethernet
|
||||
* USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __RNDIS_CLASS_HOST_H__
|
||||
#define __RNDIS_CLASS_HOST_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 Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made 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
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe configuration table. */
|
||||
USB_Pipe_Table_t NotificationPipe; /**< Notification IN Pipe configuration table. */
|
||||
|
||||
uint32_t HostMaxPacketSize; /**< Maximum size of a packet which can be buffered by 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref RNDIS_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t ControlInterfaceNumber; /**< Interface index of the RNDIS control interface within the attached device. */
|
||||
|
||||
uint32_t DeviceMaxPacketSize; /**< Maximum size of a packet which can be buffered by the attached RNDIS device. */
|
||||
|
||||
uint32_t RequestID; /**< Request ID counter to give a unique ID for each command/response pair. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_RNDIS_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref RNDIS_Host_ConfigurePipes() function. */
|
||||
enum RNDIS_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
RNDIS_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
RNDIS_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
RNDIS_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible RNDIS interface was not found in the device's Configuration Descriptor. */
|
||||
RNDIS_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given RNDIS host interface instance using the Configuration
|
||||
* Descriptor read from an attached USB device. This function automatically updates the given RNDIS Host instance's
|
||||
* state values and configures the pipes required to communicate with the interface if it is found within the device.
|
||||
* This should be called once after the stack has enumerated the attached device, while the host state machine is in
|
||||
* the Addressed state.
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref RNDIS_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Sends a RNDIS KEEPALIVE command to the device, to ensure that it does not enter standby mode after periods
|
||||
* of long inactivity.
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum or \ref RNDIS_ERROR_LOGICAL_CMD_FAILED if the device returned a
|
||||
* logical command failure.
|
||||
*/
|
||||
uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Initializes the attached RNDIS device's RNDIS interface. This should be called after the device's pipes have been
|
||||
* configured via the call to \ref RNDIS_Host_ConfigurePipes().
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum or \ref RNDIS_ERROR_LOGICAL_CMD_FAILED if the
|
||||
* device returned a logical command failure.
|
||||
*/
|
||||
uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sets a given RNDIS property of an attached RNDIS device.
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
* \param[in] Oid OID number of the parameter to set.
|
||||
* \param[in] Buffer Pointer to where the property data is to be sourced from.
|
||||
* \param[in] Length Length in bytes of the property data to sent to the device.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum or \ref RNDIS_ERROR_LOGICAL_CMD_FAILED if the
|
||||
* device returned a logical command failure.
|
||||
*/
|
||||
uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
const uint32_t Oid,
|
||||
void* Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Gets a given RNDIS property of an attached RNDIS device.
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
* \param[in] Oid OID number of the parameter to get.
|
||||
* \param[in] Buffer Pointer to where the property data is to be written to.
|
||||
* \param[in] MaxLength Length in bytes of the destination buffer size.
|
||||
*
|
||||
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum or \ref RNDIS_ERROR_LOGICAL_CMD_FAILED if the
|
||||
* device returned a logical command failure.
|
||||
*/
|
||||
uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
const uint32_t Oid,
|
||||
void* Buffer,
|
||||
const uint16_t MaxLength) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Determines if a packet is currently waiting for the host to read in and process.
|
||||
*
|
||||
* \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] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host configuration and state.
|
||||
*
|
||||
* \return Boolean \c true if a packet is waiting to be read in by the host, \c false otherwise.
|
||||
*/
|
||||
bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_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 host in the nominated buffer.
|
||||
*
|
||||
* \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] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host 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 Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
uint16_t* const PacketLength) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2)
|
||||
ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** 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 Host state machine is in the \ref HOST_STATE_Configured state or the
|
||||
* call will fail.
|
||||
*
|
||||
* \param[in,out] RNDISInterfaceInfo Pointer to a structure containing an RNDIS Class host 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 Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t PacketLength) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/* Inline Functions: */
|
||||
/** General management task for a given RNDIS host 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 an RNDIS Class host configuration and state.
|
||||
*/
|
||||
static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void RNDIS_Host_USBTask(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
|
||||
{
|
||||
(void)RNDISInterfaceInfo;
|
||||
}
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_RNDIS_HOST_C)
|
||||
static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(2);
|
||||
static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Length) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
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_HOST)
|
||||
|
||||
#define __INCLUDE_FROM_SI_DRIVER
|
||||
#define __INCLUDE_FROM_STILLIMAGE_HOST_C
|
||||
#include "StillImageClassHost.h"
|
||||
|
||||
uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
|
||||
USB_Descriptor_Endpoint_t* EventsEndpoint = NULL;
|
||||
USB_Descriptor_Interface_t* StillImageInterface = NULL;
|
||||
|
||||
memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
|
||||
|
||||
if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
|
||||
return SI_ENUMERROR_InvalidConfigDescriptor;
|
||||
|
||||
while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(EventsEndpoint))
|
||||
{
|
||||
if (!(StillImageInterface) ||
|
||||
USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
|
||||
DCOMP_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
|
||||
{
|
||||
return SI_ENUMERROR_NoCompatibleInterfaceFound;
|
||||
}
|
||||
|
||||
StillImageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
|
||||
|
||||
DataINEndpoint = NULL;
|
||||
DataOUTEndpoint = NULL;
|
||||
EventsEndpoint = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
|
||||
|
||||
if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
|
||||
{
|
||||
if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
|
||||
EventsEndpoint = EndpointData;
|
||||
else
|
||||
DataINEndpoint = EndpointData;
|
||||
}
|
||||
else
|
||||
{
|
||||
DataOUTEndpoint = EndpointData;
|
||||
}
|
||||
}
|
||||
|
||||
SIInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
|
||||
SIInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
|
||||
SIInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
SIInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
|
||||
SIInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
|
||||
SIInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
|
||||
|
||||
SIInterfaceInfo->Config.EventsPipe.Size = le16_to_cpu(EventsEndpoint->EndpointSize);
|
||||
SIInterfaceInfo->Config.EventsPipe.EndpointAddress = EventsEndpoint->EndpointAddress;
|
||||
SIInterfaceInfo->Config.EventsPipe.Type = EP_TYPE_INTERRUPT;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&SIInterfaceInfo->Config.DataINPipe, 1)))
|
||||
return SI_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&SIInterfaceInfo->Config.DataOUTPipe, 1)))
|
||||
return SI_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
if (!(Pipe_ConfigurePipeTable(&SIInterfaceInfo->Config.EventsPipe, 1)))
|
||||
return SI_ENUMERROR_PipeConfigurationFailed;
|
||||
|
||||
SIInterfaceInfo->State.InterfaceNumber = StillImageInterface->InterfaceNumber;
|
||||
SIInterfaceInfo->State.IsActive = true;
|
||||
|
||||
return SI_ENUMERROR_NoError;
|
||||
}
|
||||
|
||||
uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
|
||||
|
||||
if ((Interface->Class == SI_CSCP_StillImageClass) &&
|
||||
(Interface->SubClass == SI_CSCP_StillImageSubclass) &&
|
||||
(Interface->Protocol == SI_CSCP_BulkOnlyProtocol))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
{
|
||||
USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
|
||||
|
||||
if (Header->Type == DTYPE_Endpoint)
|
||||
{
|
||||
USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
|
||||
|
||||
uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
|
||||
|
||||
if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
|
||||
(!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Found;
|
||||
}
|
||||
}
|
||||
else if (Header->Type == DTYPE_Interface)
|
||||
{
|
||||
return DESCRIPTOR_SEARCH_Fail;
|
||||
}
|
||||
|
||||
return DESCRIPTOR_SEARCH_NotFound;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
if (SIInterfaceInfo->State.IsSessionOpen)
|
||||
PIMAHeader->TransactionID = cpu_to_le32(SIInterfaceInfo->State.TransactionID++);
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
|
||||
|
||||
if (ParamBytes)
|
||||
{
|
||||
if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
Pipe_ClearOUT();
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader)
|
||||
{
|
||||
uint16_t TimeoutMSRem = SI_COMMAND_DATA_TIMEOUT_MS;
|
||||
uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
while (!(Pipe_IsINReceived()))
|
||||
{
|
||||
uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
|
||||
|
||||
if (CurrentFrameNumber != PreviousFrameNumber)
|
||||
{
|
||||
PreviousFrameNumber = CurrentFrameNumber;
|
||||
|
||||
if (!(TimeoutMSRem--))
|
||||
return PIPE_RWSTREAM_Timeout;
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsStalled())
|
||||
{
|
||||
USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
|
||||
return PIPE_RWSTREAM_PipeStalled;
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsStalled())
|
||||
{
|
||||
USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
|
||||
return PIPE_RWSTREAM_PipeStalled;
|
||||
}
|
||||
|
||||
if (USB_HostState == HOST_STATE_Unattached)
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
}
|
||||
|
||||
Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL);
|
||||
|
||||
if (PIMAHeader->Type == CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock))
|
||||
{
|
||||
uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
|
||||
|
||||
if (ParamBytes)
|
||||
Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL);
|
||||
|
||||
Pipe_ClearIN();
|
||||
}
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
const void* Buffer,
|
||||
const uint16_t Bytes)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NULL);
|
||||
|
||||
Pipe_ClearOUT();
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Bytes)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NULL);
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
|
||||
{
|
||||
bool IsEventReceived = false;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return false;
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
if (Pipe_IsINReceived())
|
||||
IsEventReceived = true;
|
||||
|
||||
Pipe_Freeze();
|
||||
|
||||
return IsEventReceived;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipe.Address);
|
||||
Pipe_Unfreeze();
|
||||
|
||||
ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(PIMA_Container_t), NULL);
|
||||
|
||||
Pipe_ClearIN();
|
||||
Pipe_Freeze();
|
||||
|
||||
return ErrorCode;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
SIInterfaceInfo->State.TransactionID = 0;
|
||||
SIInterfaceInfo->State.IsSessionOpen = false;
|
||||
|
||||
PIMA_Container_t PIMABlock = (PIMA_Container_t)
|
||||
{
|
||||
.DataLength = CPU_TO_LE32(PIMA_COMMAND_SIZE(1)),
|
||||
.Type = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
|
||||
.Code = CPU_TO_LE16(0x1002),
|
||||
.Params = {CPU_TO_LE32(1)},
|
||||
};
|
||||
|
||||
if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
|
||||
return SI_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
SIInterfaceInfo->State.IsSessionOpen = true;
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
PIMA_Container_t PIMABlock = (PIMA_Container_t)
|
||||
{
|
||||
.DataLength = CPU_TO_LE32(PIMA_COMMAND_SIZE(1)),
|
||||
.Type = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
|
||||
.Code = CPU_TO_LE16(0x1003),
|
||||
.Params = {CPU_TO_LE32(1)},
|
||||
};
|
||||
|
||||
if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
SIInterfaceInfo->State.IsSessionOpen = false;
|
||||
|
||||
if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
|
||||
return SI_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
const uint16_t Operation,
|
||||
const uint8_t TotalParams,
|
||||
uint32_t* const Params)
|
||||
{
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
uint8_t ErrorCode;
|
||||
|
||||
PIMA_Container_t PIMABlock = (PIMA_Container_t)
|
||||
{
|
||||
.DataLength = cpu_to_le32(PIMA_COMMAND_SIZE(TotalParams)),
|
||||
.Type = CPU_TO_LE16(PIMA_CONTAINER_CommandBlock),
|
||||
.Code = cpu_to_le16(Operation),
|
||||
};
|
||||
|
||||
memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams);
|
||||
|
||||
if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
|
||||
{
|
||||
uint8_t ErrorCode;
|
||||
PIMA_Container_t PIMABlock;
|
||||
|
||||
if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
|
||||
return PIPE_RWSTREAM_DeviceDisconnected;
|
||||
|
||||
if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
|
||||
return ErrorCode;
|
||||
|
||||
if ((PIMABlock.Type != CPU_TO_LE16(PIMA_CONTAINER_ResponseBlock)) || (PIMABlock.Code != CPU_TO_LE16(0x2001)))
|
||||
return SI_ERROR_LOGICAL_CMD_FAILED;
|
||||
|
||||
return PIPE_RWSTREAM_NoError;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
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 Host mode driver for the library USB Still Image Class driver.
|
||||
*
|
||||
* Host mode driver for the library USB Still Image 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_USBClassSI
|
||||
* \defgroup Group_USBClassStillImageHost Still Image Class Host Mode Driver
|
||||
*
|
||||
* \section Sec_USBClassStillImageHost_Dependencies Module Source Dependencies
|
||||
* The following files must be built with any user project that uses this module:
|
||||
* - LUFA/Drivers/USB/Class/Host/StillImageClassHost.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i>
|
||||
*
|
||||
* \section Sec_USBClassStillImageHost_ModDescription Module Description
|
||||
* Host Mode USB Class driver framework interface, for the Still Image USB Class driver.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __SI_CLASS_HOST_H__
|
||||
#define __SI_CLASS_HOST_H__
|
||||
|
||||
/* Includes: */
|
||||
#include "../../USB.h"
|
||||
#include "../Common/StillImageClassCommon.h"
|
||||
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Preprocessor Checks: */
|
||||
#if !defined(__INCLUDE_FROM_SI_DRIVER)
|
||||
#error Do not include this file directly. Include LUFA/Drivers/USB.h instead.
|
||||
#endif
|
||||
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
/** Error code for some Still Image Host functions, indicating a logical (and not hardware) error. */
|
||||
#define SI_ERROR_LOGICAL_CMD_FAILED 0x80
|
||||
|
||||
/* Type Defines: */
|
||||
/** \brief Still Image Class Host Mode Configuration and State Structure.
|
||||
*
|
||||
* Class state structure. An instance of this structure should be made within the user application,
|
||||
* and passed to each of the Still Image class driver functions as the \c SIInterfaceInfo parameter. This
|
||||
* stores each Still Image interface's configuration and state information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
USB_Pipe_Table_t DataINPipe; /**< Data IN Pipe configuration table. */
|
||||
USB_Pipe_Table_t DataOUTPipe; /**< Data OUT Pipe configuration table. */
|
||||
USB_Pipe_Table_t EventsPipe; /**< Event notification IN Pipe 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 IsActive; /**< Indicates if the current interface instance is connected to an attached device, valid
|
||||
* after \ref SI_Host_ConfigurePipes() is called and the Host state machine is in the
|
||||
* Configured state.
|
||||
*/
|
||||
uint8_t InterfaceNumber; /**< Interface index of the Still Image interface within the attached device. */
|
||||
|
||||
bool IsSessionOpen; /**< Indicates if a PIMA session is currently open with the attached device. */
|
||||
uint32_t TransactionID; /**< Transaction ID for the next transaction to send to the device. */
|
||||
} State; /**< State data for the USB class interface within the device. All elements in this section
|
||||
* <b>may</b> be set to initial values, but may also be ignored to default to sane values when
|
||||
* the interface is enumerated.
|
||||
*/
|
||||
} USB_ClassInfo_SI_Host_t;
|
||||
|
||||
/* Enums: */
|
||||
/** Enum for the possible error codes returned by the \ref SI_Host_ConfigurePipes() function. */
|
||||
enum SI_Host_EnumerationFailure_ErrorCodes_t
|
||||
{
|
||||
SI_ENUMERROR_NoError = 0, /**< Configuration Descriptor was processed successfully. */
|
||||
SI_ENUMERROR_InvalidConfigDescriptor = 1, /**< The device returned an invalid Configuration Descriptor. */
|
||||
SI_ENUMERROR_NoCompatibleInterfaceFound = 2, /**< A compatible Still Image interface was not found in the device's
|
||||
* Configuration Descriptor.
|
||||
*/
|
||||
SI_ENUMERROR_PipeConfigurationFailed = 3, /**< One or more pipes for the specified interface could not be configured correctly. */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
/** Host interface configuration routine, to configure a given Still Image host interface instance using the
|
||||
* Configuration Descriptor read from an attached USB device. This function automatically updates the given Still
|
||||
* Image Host instance's state values and configures the pipes required to communicate with the interface if it is
|
||||
* found within the device. This should be called once after the stack has enumerated the attached device, while
|
||||
* the host state machine is in the Addressed state.
|
||||
*
|
||||
* \param[in,out] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[in] ConfigDescriptorSize Length of the attached device's Configuration Descriptor.
|
||||
* \param[in] ConfigDescriptorData Pointer to a buffer containing the attached device's Configuration Descriptor.
|
||||
*
|
||||
* \return A value from the \ref SI_Host_EnumerationFailure_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
uint16_t ConfigDescriptorSize,
|
||||
void* ConfigDescriptorData) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
/** Opens a new PIMA session with the attached device. This should be used before any session-orientated PIMA commands
|
||||
* are issued to the device. Only one session can be open at the one time.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
|
||||
* returned a logical command failure.
|
||||
*/
|
||||
uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Closes an already opened PIMA session with the attached device. This should be used after all session-orientated
|
||||
* PIMA commands have been issued to the device.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
|
||||
* returned a logical command failure.
|
||||
*/
|
||||
uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Sends a raw PIMA block header to the device, filling out the transaction ID automatically. This can be used to send
|
||||
* arbitrary PIMA blocks to the device with or without parameters.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[in] PIMAHeader Pointer to a PIMA container structure that is to be sent.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Receives a raw PIMA block header from the device. This can be used to receive arbitrary PIMA blocks from the device with
|
||||
* or without parameters.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[out] PIMAHeader Pointer to a PIMA container structure where the received block is to be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sends a given PIMA command to the attached device, filling out the PIMA command header's Transaction ID automatically.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[in] Operation PIMA operation code to issue to the device.
|
||||
* \param[in] TotalParams Total number of 32-bit parameters to send to the device in the issued command block.
|
||||
* \param[in] Params Pointer to an array of 32-bit values containing the parameters to send in the command block.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
|
||||
* returned a logical command failure.
|
||||
*/
|
||||
uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
const uint16_t Operation,
|
||||
const uint8_t TotalParams,
|
||||
uint32_t* const Params) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Receives and checks a response block from the attached Still Image device, once a command has been issued and all data
|
||||
* associated with the command has been transferred.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
|
||||
* returned a logical command failure.
|
||||
*/
|
||||
uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Indicates if the device has issued a PIMA event block to the host via the asynchronous events pipe.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
*
|
||||
* \return Boolean \c true if an event is waiting to be read, \c false otherwise.
|
||||
*/
|
||||
bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
|
||||
|
||||
/** Receives an asynchronous event block from the device via the asynchronous events pipe.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[out] PIMAHeader Pointer to a PIMA container structure where the event should be stored.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum, or \ref SI_ERROR_LOGICAL_CMD_FAILED if the device
|
||||
* returned a logical command failure.
|
||||
*/
|
||||
uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
PIMA_Container_t* const PIMAHeader) ATTR_NON_NULL_PTR_ARG(1)
|
||||
ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Sends arbitrary data to the attached device, for use in the data phase of PIMA commands which require data
|
||||
* transfer beyond the regular PIMA command block parameters.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[in] Buffer Pointer to a buffer where the data to send has been stored.
|
||||
* \param[in] Bytes Length in bytes of the data in the buffer to send to the attached device.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
const void* Buffer,
|
||||
const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/** Receives arbitrary data from the attached device, for use in the data phase of PIMA commands which require data
|
||||
* transfer beyond the regular PIMA command block parameters.
|
||||
*
|
||||
* \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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
* \param[out] Buffer Pointer to a buffer where the received data is to be stored.
|
||||
* \param[in] Bytes Length in bytes of the data to read.
|
||||
*
|
||||
* \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum.
|
||||
*/
|
||||
uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
|
||||
void* Buffer,
|
||||
const uint16_t Bytes) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2);
|
||||
|
||||
/* Inline Functions: */
|
||||
/** General management task for a given Still Image host 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] SIInterfaceInfo Pointer to a structure containing a Still Image Class host configuration and state.
|
||||
*/
|
||||
static inline void SI_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE;
|
||||
static inline void SI_Host_USBTask(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
|
||||
{
|
||||
(void)SIInterfaceInfo;
|
||||
}
|
||||
|
||||
/* Private Interface - For use in library only: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Macros: */
|
||||
#define SI_COMMAND_DATA_TIMEOUT_MS 10000
|
||||
|
||||
/* Function Prototypes: */
|
||||
#if defined(__INCLUDE_FROM_STILLIMAGE_HOST_C)
|
||||
static uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
static uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue