From c68151698b7421abaa14622018ce8db27618be74 Mon Sep 17 00:00:00 2001 From: Robert Fisk Date: Sun, 4 Sep 2016 12:23:59 +1200 Subject: [PATCH] Bugfixes for keyboard support: works!!! --- Downstream/Inc/downstream_hid.h | 20 ++++++- .../Class/HID/Src/usbh_hid.c | 17 +++--- Downstream/Src/downstream_hid.c | 58 +++++++++---------- Upstream/Src/upstream_hid.c | 43 +++++++++----- 4 files changed, 84 insertions(+), 54 deletions(-) diff --git a/Downstream/Inc/downstream_hid.h b/Downstream/Inc/downstream_hid.h index 2a7bc6e..fee305d 100644 --- a/Downstream/Inc/downstream_hid.h +++ b/Downstream/Inc/downstream_hid.h @@ -15,9 +15,23 @@ #include "downstream_interface_def.h" #include "downstream_spi.h" +#include "usbh_def.h" +#define HID_MAX_REPORT_LEN 8 +//These defines are duplicated in upstream_hid.h. Keep them in sync! +#define HID_MOUSE_INPUT_DATA_LEN 4 +#define HID_MOUSE_OUTPUT_DATA_LEN 0 +#define HID_MOUSE_MAX_BUTTONS 3 + +#define HID_KEYBOARD_INPUT_DATA_LEN 8 +#define HID_KEYBOARD_OUTPUT_DATA_LEN 1 +#define HID_KEYBOARD_MAX_KEY 101 //Also set in Upstream's HID report descriptor +#define HID_KEYBOARD_MAX_LED 3 + + +//Stuff for parsing HID descriptors: #define HID_ITEM_LONG 0xFE #define HID_ITEM_LENGTH_MASK 0x03 @@ -42,12 +56,12 @@ #define HID_ITEM_INPUT_REL 0x06 -typedef void (*TransactionCompleteCallbackTypeDef)(void); +typedef void (*TransactionCompleteCallbackTypeDef)(USBH_StatusTypeDef result); InterfaceCommandClassTypeDef Downstream_HID_ApproveConnectedDevice(void); void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket); -void Downstream_HID_InterruptReportCallback(void); -void Downstream_HID_SendReportCallback(void); +void Downstream_HID_InterruptReportCallback(USBH_StatusTypeDef result); +void Downstream_HID_SendReportCallback(USBH_StatusTypeDef result); diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c index 49d9188..cbf4aa0 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/HID/Src/usbh_hid.c @@ -365,6 +365,9 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) HID_Handle->timer = phost->Timer; HID_Handle->state = HID_IDLE; break; + + case HID_IDLE: + break; case HID_GET_DATA: if ((int32_t)(phost->Timer - HID_Handle->timer) >= HID_Handle->poll) @@ -383,14 +386,15 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) if (urbStatus == USBH_URB_DONE) { - HID_Handle->ReportCallback(); + HID_Handle->ReportCallback(USBH_OK); HID_Handle->state = HID_IDLE; break; } if (urbStatus == USBH_URB_NOTREADY) { - HID_Handle->state = HID_GET_DATA; + HID_Handle->ReportCallback(USBH_BUSY); + HID_Handle->state = HID_IDLE; break; } @@ -400,7 +404,8 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) if(USBH_ClrFeature(phost, HID_Handle->ep_addr) == USBH_OK) { - HID_Handle->state = HID_GET_DATA; + HID_Handle->ReportCallback(USBH_BUSY); + HID_Handle->state = HID_IDLE; } } break; @@ -408,14 +413,10 @@ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) case HID_SET_DATA_POLL: if (USBH_CtlReq(phost, HID_Handle->Data, phost->Control.setup.b.wLength.w) == USBH_OK) { - HID_Handle->ReportCallback(); + HID_Handle->ReportCallback(USBH_OK); HID_Handle->state = HID_IDLE; } break; - - case HID_IDLE: - break; - default: break; diff --git a/Downstream/Src/downstream_hid.c b/Downstream/Src/downstream_hid.c index 0484ed2..3dff7f2 100644 --- a/Downstream/Src/downstream_hid.c +++ b/Downstream/Src/downstream_hid.c @@ -17,21 +17,6 @@ #include "stm32f4xx_hal.h" - -#define HID_MAX_REPORT_LEN 8 - -//These defines are duplicated in downstream_hid.c. Keep them in sync! -#define HID_MOUSE_INPUT_DATA_LEN 4 -#define HID_MOUSE_OUTPUT_DATA_LEN 0 -#define HID_MOUSE_MAX_BUTTONS 3 - -#define HID_KEYBOARD_INPUT_DATA_LEN 8 -#define HID_KEYBOARD_OUTPUT_DATA_LEN 1 -#define HID_KEYBOARD_MAX_KEY 101 //Also set in Upstream's HID report descriptor -#define HID_KEYBOARD_MAX_LED 3 - - - extern USBH_HandleTypeDef hUsbHostFS; //Hard-link ourselves to usb_host.c extern InterfaceCommandClassTypeDef ConfiguredDeviceClass; //Do a cheap hard-link to downstream_statemachine.c, rather than keep a duplicate here @@ -286,9 +271,10 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket) Downstream_PacketProcessor_FreakOut(); } Downstream_PacketProcessor_NotifyDisconnectReplyRequired(); + return; } - else if (receivedPacket->Command == COMMAND_HID_SET_REPORT) + if (receivedPacket->Command == COMMAND_HID_SET_REPORT) { if ((ConfiguredDeviceClass != COMMAND_CLASS_HID_KEYBOARD) || (receivedPacket->Length16 != ((HID_KEYBOARD_OUTPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16) || @@ -304,6 +290,7 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket) Downstream_HID_SendReportCallback); Downstream_ReleasePacket(receivedPacket); Downstream_PacketProcessor_NotifyDisconnectReplyRequired(); + return; } //else: @@ -311,27 +298,37 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket) } -void Downstream_HID_InterruptReportCallback(void) +void Downstream_HID_InterruptReportCallback(USBH_StatusTypeDef result) { DownstreamPacketTypeDef* freePacket; freePacket = Downstream_GetFreePacketImmediately(); - if (ConfiguredDeviceClass == COMMAND_CLASS_HID_MOUSE) - { - Downstream_HID_Mouse_ExtractDataFromReport(freePacket); - freePacket->Length16 = ((HID_MOUSE_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16; - } - else if (ConfiguredDeviceClass == COMMAND_CLASS_HID_KEYBOARD) + + if (result == USBH_OK) { - Downstream_HID_Keyboard_ExtractDataFromReport(freePacket); - freePacket->Length16 = ((HID_KEYBOARD_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16; - } - //else if... + //Data received from device + if (ConfiguredDeviceClass == COMMAND_CLASS_HID_MOUSE) + { + Downstream_HID_Mouse_ExtractDataFromReport(freePacket); + freePacket->Length16 = ((HID_MOUSE_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16; + } + else if (ConfiguredDeviceClass == COMMAND_CLASS_HID_KEYBOARD) + { + Downstream_HID_Keyboard_ExtractDataFromReport(freePacket); + freePacket->Length16 = ((HID_KEYBOARD_INPUT_DATA_LEN + 1) / 2) + DOWNSTREAM_PACKET_HEADER_LEN_16; + } + //else if... + else + { + Downstream_PacketProcessor_FreakOut(); + return; + } + } else { - Downstream_PacketProcessor_FreakOut(); - return; + //NAK received from device, return zero-length packet + freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16; } freePacket->CommandClass = ConfiguredDeviceClass; @@ -410,11 +407,12 @@ static void Downstream_HID_Keyboard_ExtractDataFromReport(DownstreamPacketTypeDe -void Downstream_HID_SendReportCallback(void) +void Downstream_HID_SendReportCallback(USBH_StatusTypeDef result) { DownstreamPacketTypeDef* freePacket; freePacket = Downstream_GetFreePacketImmediately(); + freePacket->Length16 = DOWNSTREAM_PACKET_HEADER_LEN_16; freePacket->CommandClass = ConfiguredDeviceClass; freePacket->Command = COMMAND_HID_SET_REPORT; Downstream_PacketProcessor_ClassReply(freePacket); diff --git a/Upstream/Src/upstream_hid.c b/Upstream/Src/upstream_hid.c index ac89ff5..6ac4960 100644 --- a/Upstream/Src/upstream_hid.c +++ b/Upstream/Src/upstream_hid.c @@ -25,6 +25,7 @@ uint8_t KeyboardOutData[HID_KEYBOARD_OUTPUT_DATA_LEN]; void Upstream_HID_GetNextInterruptReportReceiveCallback(UpstreamPacketTypeDef* receivedPacket); +void Upstream_HID_ReallySendControlReportReceiveCallback(UpstreamPacketTypeDef* receivedPacket); @@ -56,7 +57,14 @@ void Upstream_HID_GetNextInterruptReport(UpstreamHidGetReportCallback callback) if (callback != NULL) { - //This means we were called by the host (normal operation) + //This means we were called by the host + //Release packet used for last transaction (if any) + if (UpstreamHidPacket != NULL) + { + Upstream_ReleasePacket(UpstreamHidPacket); + UpstreamHidPacket = NULL; + } + if (KeyboardOutDataState == KEYBOARD_OUT_STATE_BUSY) { //Just save the callback, because we are still waiting for the OUT report to complete @@ -68,10 +76,11 @@ void Upstream_HID_GetNextInterruptReport(UpstreamHidGetReportCallback callback) //Just return if we already have an outstanding request return; } + GetReportCallback = callback; } else { - //This means were called on OUT report completion + //This means were called on OUT report completion, or retrying after a downstream NAK if (GetReportCallback == NULL) { //The host has not given us the callback yet, so we give up @@ -79,15 +88,6 @@ void Upstream_HID_GetNextInterruptReport(UpstreamHidGetReportCallback callback) } } - GetReportCallback = callback; - - //Release packet used for last transaction (if any) - if (UpstreamHidPacket != NULL) - { - Upstream_ReleasePacket(UpstreamHidPacket); - UpstreamHidPacket = NULL; - } - freePacket = Upstream_GetFreePacketImmediately(); if (freePacket == NULL) { @@ -138,6 +138,24 @@ void Upstream_HID_GetNextInterruptReportReceiveCallback(UpstreamPacketTypeDef* r return; //Just give up... } + if (receivedPacket->Length16 == UPSTREAM_PACKET_HEADER_LEN_16) + { + //Zero-length reply indicates no data from downstream device + Upstream_ReleasePacket(receivedPacket); + + //Check if we need to send OUT data to the keyboard before requesting next Interrupt IN data + if (KeyboardOutDataState == KEYBOARD_OUT_STATE_DATA_READY) + { + Upstream_HID_ReallySendControlReport(); + } + else + { + //Otherwise poll downstream again + Upstream_HID_GetNextInterruptReport(NULL); + } + return; + } + if (activeClass == COMMAND_CLASS_HID_MOUSE) { @@ -193,7 +211,6 @@ void Upstream_HID_GetNextInterruptReportReceiveCallback(UpstreamPacketTypeDef* r GetReportCallback = NULL; tempReportCallback(receivedPacket->Data, dataLength); - //Check if we need to send OUT data to the keyboard before requesting next Interrupt IN data if (KeyboardOutDataState == KEYBOARD_OUT_STATE_DATA_READY) { @@ -254,7 +271,7 @@ void Upstream_HID_ReallySendControlReport(void) if (Upstream_TransmitPacket(freePacket) == HAL_OK) { - Upstream_ReceivePacket(Upstream_HID_GetNextInterruptReportReceiveCallback); + Upstream_ReceivePacket(Upstream_HID_ReallySendControlReportReceiveCallback); } else {