From 7c6b2019a302fb064665c1a69e559678c299e9bb Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Thu, 17 Sep 2009 13:12:21 +0000
Subject: [PATCH] Fix Mass Storage Host Class driver GetMaxLUN command -
 incorrect function return codes used in comparison to check for success.

Add HID Host Class driver functions to set the report protocol, add more class driver documentation.
---
 Demos/Host/ClassDriver/MouseHost/MouseHost.c  |  8 +++
 LUFA/Drivers/USB/Class/Device/HID.h           |  2 +-
 LUFA/Drivers/USB/Class/Host/CDC.h             |  4 ++
 LUFA/Drivers/USB/Class/Host/HID.c             | 58 ++++++++++++++++--
 LUFA/Drivers/USB/Class/Host/HID.h             | 59 ++++++++++++++++++-
 LUFA/Drivers/USB/Class/Host/MassStorage.c     | 16 +++--
 LUFA/Drivers/USB/Class/Host/MassStorage.h     |  2 +-
 LUFA/Drivers/USB/Class/Host/StillImage.h      |  2 +-
 LUFA/Drivers/USB/HighLevel/ConfigDescriptor.h |  1 +
 LUFA/ManPages/ChangeLog.txt                   |  2 +-
 10 files changed, 134 insertions(+), 20 deletions(-)

diff --git a/Demos/Host/ClassDriver/MouseHost/MouseHost.c b/Demos/Host/ClassDriver/MouseHost/MouseHost.c
index 844fa334c..5b9b4431e 100644
--- a/Demos/Host/ClassDriver/MouseHost/MouseHost.c
+++ b/Demos/Host/ClassDriver/MouseHost/MouseHost.c
@@ -98,6 +98,14 @@ int main(void)
 					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
 					break;
 				}
+
+				if (USB_HID_Host_SetBootProtocol(&Mouse_HID_Interface) != 0)
+				{
+					printf("Could not Set Boot Protocol Mode.\r\n");
+					LEDs_SetAllLEDs(LEDMASK_USB_ERROR);
+					USB_HostState = HOST_STATE_WaitForDeviceRemoval;
+					break;
+				}
 				
 				printf("Mouse Enumerated.\r\n");
 				USB_HostState = HOST_STATE_Configured;
diff --git a/LUFA/Drivers/USB/Class/Device/HID.h b/LUFA/Drivers/USB/Class/Device/HID.h
index ccd7426e1..faf9d5f72 100644
--- a/LUFA/Drivers/USB/Class/Device/HID.h
+++ b/LUFA/Drivers/USB/Class/Device/HID.h
@@ -137,7 +137,7 @@
 			 *
 			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class configuration and state.
 			 *  \param[in,out] ReportID  If preset to a non-zero value, this is the report ID being requested by the host. If zero, this should
-			 *                 be set to the report ID of the generated HID input report. If multiple reports are not sent via the
+			 *                 be set to the report ID of the generated HID input report (if any). If multiple reports are not sent via the
 			 *                 given HID interface, this parameter should be ignored.
 			 *  \param[out] ReportData  Pointer to a buffer where the generated HID report should be stored.
 			 *  \param[out] ReportSize  Number of bytes in the generated input report, or zero if no report is to be sent
diff --git a/LUFA/Drivers/USB/Class/Host/CDC.h b/LUFA/Drivers/USB/Class/Host/CDC.h
index de4b6afd4..df5a41ff0 100644
--- a/LUFA/Drivers/USB/Class/Host/CDC.h
+++ b/LUFA/Drivers/USB/Class/Host/CDC.h
@@ -145,6 +145,8 @@
 			 *  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* CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
 
@@ -154,6 +156,8 @@
 			 *  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* CDCInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
 			
diff --git a/LUFA/Drivers/USB/Class/Host/HID.c b/LUFA/Drivers/USB/Class/Host/HID.c
index 11dfb67ad..5a5ec484d 100644
--- a/LUFA/Drivers/USB/Class/Host/HID.c
+++ b/LUFA/Drivers/USB/Class/Host/HID.c
@@ -169,23 +169,73 @@ bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo)
 	return ReportReceived;
 }
 
-uint8_t USB_HID_Host_SetProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo, bool UseReportProtocol)
+uint8_t USB_HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo)
 {
+	if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
+	  return false;
+
 	USB_ControlRequest = (USB_Request_Header_t)
 		{
 			.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
 			.bRequest      = REQ_SetProtocol,
-			.wValue        = UseReportProtocol,
+			.wValue        = 1,
 			.wIndex        = HIDInterfaceInfo->State.InterfaceNumber,
 			.wLength       = 0,
 		};
 
 	Pipe_SelectPipe(PIPE_CONTROLPIPE);
 	
-	if (UseReportProtocol && !(HIDInterfaceInfo->State.SupportsBootSubClass))
-	  return MS_ERROR_UNSUPPORTED;
+	if (!(HIDInterfaceInfo->State.SupportsBootSubClass))
+	  return HID_ERROR_LOGICAL;
 	
 	return USB_Host_SendControlRequest(NULL);
 }
 
+uint8_t USB_HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo)
+{
+	if ((USB_HostState != HOST_STATE_Configured) || !(HIDInterfaceInfo->State.IsActive))
+	  return false;
+
+	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        = (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;
+	  
+	USB_ControlRequest = (USB_Request_Header_t)
+		{
+			.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
+			.bRequest      = REQ_SetProtocol,
+			.wValue        = 0,
+			.wIndex        = HIDInterfaceInfo->State.InterfaceNumber,
+			.wLength       = 0,
+		};
+
+	if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
+	  return ErrorCode;
+
+	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;
+	}
+	
+	return 0;
+}
+
 #endif
diff --git a/LUFA/Drivers/USB/Class/Host/HID.h b/LUFA/Drivers/USB/Class/Host/HID.h
index c1a68f819..c0f67e752 100644
--- a/LUFA/Drivers/USB/Class/Host/HID.h
+++ b/LUFA/Drivers/USB/Class/Host/HID.h
@@ -34,6 +34,7 @@
  *  \section Sec_Dependencies Module Source Dependencies
  *  The following files must be built with any user project that uses this module:
  *    - LUFA/Drivers/USB/Class/Host/HID.c
+ *    - LUFA/Drivers/USB/Class/Host/HIDParser.c
  *
  *  \section Module Description
  *  Host Mode USB Class driver framework interface, for the HID USB Class driver.
@@ -57,7 +58,7 @@
 	/* Public Interface - May be used in end-application: */
 		/* Macros: */
 			/** Error code for some HID Host functions, indicating a logical (and not hardware) error */
-			#define MS_ERROR_UNSUPPORTED              0xC0
+			#define HID_ERROR_LOGICAL              0x80
 	
 		/* Type Defines: */
 			/** Class state structure. An instance of this structure should be made within the user application,
@@ -92,7 +93,7 @@
 					uint16_t DataOUTPipeSize;  /**< Size in bytes of the HID interface's OUT data pipe */
 					
 					bool SupportsBootSubClass; /**< Indicates if the current interface instance supports the HID Boot
-					                            *   Protocol when enabled via \ref USB_HID_Host_SetProtocol()
+					                            *   Protocol when enabled via \ref USB_HID_Host_SetBootProtocol()
 					                            */
 					uint16_t HIDReportSize; /**< Size in bytes of the HID report descriptor in the device */
 				} State; /**< State data for the USB class interface within the device. All elements in this section
@@ -102,6 +103,7 @@
 			} USB_ClassInfo_HID_Host_t;
 
 		/* Enums: */
+			/** Enum for the possible error codes returned by the \ref HID_Host_ConfigurePipes() function. */
 			enum HIDHost_EnumerationFailure_ErrorCodes_t
 			{
 				HID_ENUMERROR_NoError                    = 0, /**< Configuration Descriptor was processed successfully */
@@ -112,13 +114,64 @@
 			};
 	
 		/* Function Prototypes: */
+			/** 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
+			 */
 			void HID_Host_USBTask(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+			/** 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.
+			 *
+			 *  \note Once the device pipes are configured, the HID device's reporting protocol <b>must</b> be set via a call
+			 *        to either the \ref USB_HID_Host_SetBootProtocol() or \ref USB_HID_Host_SetReportProtocol() function.
+			 *
+			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class host configuration and state
+			 *  \param[in] ConfigDescriptorLength  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 HIDHost_EnumerationFailure_ErrorCodes_t enum
+			 */
 			uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo, uint16_t ConfigDescriptorLength,
 			                                uint8_t* DeviceConfigDescriptor) ATTR_NON_NULL_PTR_ARG(1, 3);
 
+			/** Determines if a report has been received on the HID interface's IN report pipe, when the device is initialized
+			 *  into Report Protocol mode.
+			 *
+			 *  \param[in,out] HIDInterfaceInfo  Pointer to a structure containing a HID Class host configuration and state
+			 *
+			 *  \return Boolean true if a report has been received, false otherwise
+			 */
 			bool    HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
 			
-			uint8_t USB_HID_Host_SetProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo, bool UseReportProtocol) ATTR_NON_NULL_PTR_ARG(1);
+			/** Switches the attached HID device's reporting protocol over to the Boot Report protocol mode, on supported devices.
+			 *
+			 *  \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 USB_HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
+
+			/** 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.
+			 *
+			 *  \note 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.
+			 *
+			 *  \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 USB_HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t* HIDInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1);
 		
 	/* Private Interface - For use in library only: */
 	#if !defined(__DOXYGEN__)
diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.c b/LUFA/Drivers/USB/Class/Host/MassStorage.c
index 2d2f042b7..ead7768d6 100644
--- a/LUFA/Drivers/USB/Class/Host/MassStorage.c
+++ b/LUFA/Drivers/USB/Class/Host/MassStorage.c
@@ -274,8 +274,10 @@ static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* MSInterfaceInf
 	
 	if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
 	                                     NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
-	  return ErrorCode;
-	  
+	{
+		return ErrorCode;
+	}
+	
 	Pipe_ClearIN();
 	Pipe_Freeze();
 	
@@ -322,14 +324,10 @@ uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t* Max
 		
 	Pipe_SelectPipe(PIPE_CONTROLPIPE);
 
-	if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
-	{
-		Pipe_ClearStall();
-
-		*MaxLUNIndex = 0;
-	}
+	if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
+	  *MaxLUNIndex = 0;
 	
-	return HOST_SENDCONTROL_SetupStalled;
+	return ErrorCode;
 }
 
 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, SCSI_Inquiry_Response_t* InquiryData)
diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.h b/LUFA/Drivers/USB/Class/Host/MassStorage.h
index f6a1b61c2..2395fcf1f 100644
--- a/LUFA/Drivers/USB/Class/Host/MassStorage.h
+++ b/LUFA/Drivers/USB/Class/Host/MassStorage.h
@@ -56,7 +56,7 @@
 	/* 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              0xC0
+			#define MS_ERROR_LOGICAL_CMD_FAILED              0x80
 	
 		/* Type Defines: */
 			/** Class state structure. An instance of this structure should be made within the user application,
diff --git a/LUFA/Drivers/USB/Class/Host/StillImage.h b/LUFA/Drivers/USB/Class/Host/StillImage.h
index fd67134c1..037ae6c01 100644
--- a/LUFA/Drivers/USB/Class/Host/StillImage.h
+++ b/LUFA/Drivers/USB/Class/Host/StillImage.h
@@ -56,7 +56,7 @@
 	/* 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              0xC0
+			#define SI_ERROR_LOGICAL_CMD_FAILED              0x80
 
 		/* Type Defines: */
 			typedef struct
diff --git a/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.h b/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.h
index be24debba..c0ebe0956 100644
--- a/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.h
+++ b/LUFA/Drivers/USB/HighLevel/ConfigDescriptor.h
@@ -155,6 +155,7 @@
 			uint8_t USB_GetNextDescriptorComp(uint16_t* BytesRem, uint8_t** CurrConfigLoc, ConfigComparatorPtr_t ComparatorRoutine);
 			
 		/* Enums: */
+			/** Enum for the possible return codes of the \ref USB_GetDeviceConfigDescriptor() function. */
 			enum USB_Host_GetConfigDescriptor_ErrorCodes_t
 			{
 				HOST_GETCONFIG_Successful       = 0, /**< No error occurred while retrieving the configuration descriptor */
diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index be5251fa5..b2e80da7a 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -65,7 +65,7 @@
   *  - Fix allowable F_CPU values comment in project makefiles to more accurately reflect the allowable values on the USB AVRs
   *  - Fixed DFU and CDC class bootloaders on the series 2 USB AVRs, corrected invalid signatures, added support for the new
   *    ATMEGAxxx2 series 2 variant AVRs to the DFU bootloader
-  *  - Fixed Low Level USBtoSerial demo not storing received characters (thanks to Michael from DirectAid.ca)
+  *  - Fixed Low Level USBtoSerial demo not storing received characters (thanks to Michael Cooper)
   *  - Fixed MIDI Device Class driver not sending/receiving MIDI packets of the correct size (thanks to Thomas Bleeker)
   *
   *
-- 
GitLab