From 7c6b2019a302fb064665c1a69e559678c299e9bb Mon Sep 17 00:00:00 2001 From: Dean Camera 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 844fa334c0..5b9b4431e2 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 ccd7426e19..faf9d5f72f 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 de4b6afd47..df5a41ff09 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 11dfb67adc..5a5ec484df 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 c1a68f819b..c0f67e7525 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 must 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 must 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 2d2f042b71..ead7768d6f 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 f6a1b61c2c..2395fcf1fe 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 fd67134c14..037ae6c019 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 be24debbab..c0ebe09567 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 be5251fa5f..b2e80da7af 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) * *