Squashed 'lib/lufa/' content from commit 385d40300
git-subtree-dir: lib/lufa git-subtree-split: 385d4030035dbaf41591309dbde47653bd03841b
This commit is contained in:
		
						commit
						60b30c0363
					
				
					 1455 changed files with 394541 additions and 0 deletions
				
			
		
							
								
								
									
										422
									
								
								LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,422 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										314
									
								
								LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								LUFA/Drivers/USB/Class/Host/AndroidAccessoryClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,314 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										223
									
								
								LUFA/Drivers/USB/Class/Host/AudioClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								LUFA/Drivers/USB/Class/Host/AudioClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,223 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										411
									
								
								LUFA/Drivers/USB/Class/Host/AudioClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								LUFA/Drivers/USB/Class/Host/AudioClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,411 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										512
									
								
								LUFA/Drivers/USB/Class/Host/CDCClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								LUFA/Drivers/USB/Class/Host/CDCClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,512 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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_SendData_P(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_PStream_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_SendString_P(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_PStream_LE(String, strlen_P(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 | ||||
| 
 | ||||
							
								
								
									
										385
									
								
								LUFA/Drivers/USB/Class/Host/CDCClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								LUFA/Drivers/USB/Class/Host/CDCClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,385 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 data buffer from PROGMEM space 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 host 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 host. | ||||
| 			 * | ||||
| 			 *  \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum. | ||||
| 			 */ | ||||
| 			uint8_t CDC_Host_SendData_P(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 null terminated string from PROGMEM space 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 host. | ||||
| 			 * | ||||
| 			 *  \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum. | ||||
| 			 */ | ||||
| 			uint8_t CDC_Host_SendString_P(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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										399
									
								
								LUFA/Drivers/USB/Class/Host/HIDClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								LUFA/Drivers/USB/Class/Host/HIDClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,399 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										313
									
								
								LUFA/Drivers/USB/Class/Host/HIDClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								LUFA/Drivers/USB/Class/Host/HIDClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,313 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										231
									
								
								LUFA/Drivers/USB/Class/Host/MIDIClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								LUFA/Drivers/USB/Class/Host/MIDIClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,231 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										190
									
								
								LUFA/Drivers/USB/Class/Host/MIDIClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								LUFA/Drivers/USB/Class/Host/MIDIClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,190 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										579
									
								
								LUFA/Drivers/USB/Class/Host/MassStorageClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								LUFA/Drivers/USB/Class/Host/MassStorageClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,579 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										335
									
								
								LUFA/Drivers/USB/Class/Host/MassStorageClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								LUFA/Drivers/USB/Class/Host/MassStorageClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,335 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										400
									
								
								LUFA/Drivers/USB/Class/Host/PrinterClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								LUFA/Drivers/USB/Class/Host/PrinterClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,400 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										285
									
								
								LUFA/Drivers/USB/Class/Host/PrinterClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								LUFA/Drivers/USB/Class/Host/PrinterClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,285 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										476
									
								
								LUFA/Drivers/USB/Class/Host/RNDISClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										476
									
								
								LUFA/Drivers/USB/Class/Host/RNDISClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,476 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										270
									
								
								LUFA/Drivers/USB/Class/Host/RNDISClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								LUFA/Drivers/USB/Class/Host/RNDISClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,270 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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 | ||||
| 
 | ||||
| /** @} */ | ||||
| 
 | ||||
							
								
								
									
										436
									
								
								LUFA/Drivers/USB/Class/Host/StillImageClassHost.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								LUFA/Drivers/USB/Class/Host/StillImageClassHost.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,436 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| #define  __INCLUDE_FROM_USB_DRIVER | ||||
| #include "../../Core/USBMode.h" | ||||
| 
 | ||||
| #if defined(USB_CAN_BE_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 | ||||
| 
 | ||||
							
								
								
									
										317
									
								
								LUFA/Drivers/USB/Class/Host/StillImageClassHost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								LUFA/Drivers/USB/Class/Host/StillImageClassHost.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,317 @@ | |||
| /*
 | ||||
|              LUFA Library | ||||
|      Copyright (C) Dean Camera, 2017. | ||||
| 
 | ||||
|   dean [at] fourwalledcubicle [dot] com | ||||
|            www.lufa-lib.org | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|   Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||||
| 
 | ||||
|   Permission to use, copy, modify, distribute, and sell this | ||||
|   software and its documentation for any purpose is hereby granted | ||||
|   without fee, provided that the above copyright notice appear in | ||||
|   all copies and that both that the copyright notice and this | ||||
|   permission notice and warranty disclaimer appear in supporting | ||||
|   documentation, and that the name of the author not be used in | ||||
|   advertising or publicity pertaining to distribution of the | ||||
|   software without specific, written prior permission. | ||||
| 
 | ||||
|   The author disclaims all warranties with regard to this | ||||
|   software, including all implied warranties of merchantability | ||||
|   and fitness.  In no event shall the author be liable for any | ||||
|   special, indirect or consequential damages or any damages | ||||
|   whatsoever resulting from loss of use, data or profits, whether | ||||
|   in an action of contract, negligence or other tortious action, | ||||
|   arising out of or in connection with the use or performance of | ||||
|   this software. | ||||
| */ | ||||
| 
 | ||||
| /** \file
 | ||||
|  *  \brief 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
	
	 Jack Humbert
						Jack Humbert