Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/usb/hid/usbd_hid.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/usb/hid/usbd_hid.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,557 @@ +/** + * @file usbd_hid.c + * @brief Human Interface Device driver + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> + +#include "rl_usb.h" +#include "usb_for_lib.h" + + +U8 USBD_HID_Protocol; + +BOOL DataOutAsyncReq; +U32 DataOutUpdateReqMask; +U8 *ptrDataOut; +volatile U16 DataOutToSendLen; +U16 DataOutSentLen; +BOOL DataOutEndWithShortPacket; + +U8 *ptrDataIn; +U16 DataInReceMax; +U16 DataInReceLen; + +U8 *ptrDataFeat; +U16 DataFeatReceLen; + + +/* Dummy Weak Functions that need to be provided by user */ +__weak void usbd_hid_init(void) +{ + +} +__weak int usbd_hid_get_report(U8 rtype, U8 rid, U8 *buf, U8 req) +{ + return (0); +}; +__weak void usbd_hid_set_report(U8 rtype, U8 rid, U8 *buf, int len, U8 req) +{ + +} +__weak U8 usbd_hid_get_protocol(void) +{ + return (0); +}; +__weak void usbd_hid_set_protocol(U8 protocol) +{ + +}; + + +/* + * USB Device HID Get Report Request Callback + * Called automatically on USB Device HID Get Report Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_GetReport(void) +{ + U8 *ptr_buf = 0; + + /* Report Type = USBD_SetupPacket.wValueH */ + /* Report ID = USBD_SetupPacket.wValueL */ + /* Report Length = USBD_SetupPacket.wLength */ + switch (USBD_SetupPacket.wValueH) { + case HID_REPORT_INPUT: + ptr_buf = &USBD_HID_InReport[1]; + break; + + case HID_REPORT_OUTPUT: + return (__FALSE); /* Not Supported */ + + case HID_REPORT_FEATURE: + ptr_buf = &USBD_HID_FeatReport[1]; + break; + } + + usbd_hid_get_report(USBD_SetupPacket.wValueH, USBD_SetupPacket.wValueL, ptr_buf, USBD_HID_REQ_EP_CTRL); + return (__TRUE); +} + + +/* + * USB Device HID Set Report Request Callback + * Called automatically on USB Device HID Set Report Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_SetReport(void) +{ + U8 *ptr_buf = 0; + + /* Report Type = USBD_SetupPacket.wValueH */ + /* Report ID = USBD_SetupPacket.wValueL */ + /* Report Length = USBD_SetupPacket.wLength */ + switch (USBD_SetupPacket.wValueH) { + case HID_REPORT_INPUT: + return (__FALSE); /* Not Supported */ + + case HID_REPORT_OUTPUT: + ptr_buf = &USBD_HID_OutReport[1]; + break; + + case HID_REPORT_FEATURE: + ptr_buf = &USBD_HID_FeatReport[1]; + break; + } + + usbd_hid_set_report(USBD_SetupPacket.wValueH, USBD_SetupPacket.wValueL, ptr_buf, USBD_SetupPacket.wLength, USBD_HID_REQ_EP_CTRL); + return (__TRUE); +} + + +/* + * USB Device HID Get Idle Request Callback + * Called automatically on USB Device HID Get Idle Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_GetIdle(void) +{ + USBD_EP0Buf[0] = USBD_HID_IdleSet[USBD_SetupPacket.wValueL]; + return (__TRUE); +} + + +/* + * USB Device HID Set Idle Request Callback + * Called automatically on USB Device HID Set Idle Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_SetIdle(void) +{ + U8 i; + + if (USBD_SetupPacket.wValueL) { /* If > 0 Report ID specified */ + USBD_HID_IdleSet[USBD_SetupPacket.wValueL - 1] = USBD_SetupPacket.wValueH; + } else { /* If == 0 all reports */ + for (i = 0; i < usbd_hid_inreport_num; i++) { + USBD_HID_IdleSet[i] = USBD_SetupPacket.wValueH; + } + } + + return (__TRUE); +} + + +/* + * USB Device HID Get Protocol Request Callback + * Called automatically on USB Device HID Get Protocol Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_GetProtocol(void) +{ + USBD_EP0Buf[0] = usbd_hid_get_protocol(); + return (__TRUE); +} + + +/* + * USB Device HID Set Protocol Request Callback + * Called automatically on USB Device HID Set Protocol Request + * Parameters: None + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL USBD_HID_SetProtocol(void) +{ + usbd_hid_set_protocol(USBD_SetupPacket.wValueL); + return (__TRUE); +} + + +/* + * USB Device HID Interrupt In Endpoint Event Callback + * Parameters: event: not used (just for compatibility) + * Return Value: None + */ + +void USBD_HID_EP_INTIN_Event(U32 event) +{ + U8 i; + U16 bytes_to_send; + + /* Check if sending is finished */ + if ((DataOutSentLen >= DataOutToSendLen) && + !DataOutEndWithShortPacket) { /* If all sent and short packet also */ + ptrDataOut = NULL; + DataOutSentLen = 0; + DataOutToSendLen = usbd_hid_get_report(HID_REPORT_INPUT, USBD_HID_InReport[0], &USBD_HID_InReport[1], USBD_HID_REQ_EP_INT); + + if (DataOutToSendLen) { /* If new send should be started */ + ptrDataOut = USBD_HID_InReport; + + if (usbd_hid_inreport_num <= 1) { /* If only in 1 report skip ReportID */ + ptrDataOut++; + } else { /* If more in reports, send ReportID */ + DataOutToSendLen++; + } + } + } + + /* Check if new data out sending should be started */ + if (!DataOutToSendLen) { /* If send not in progress */ + if (DataOutAsyncReq) { /* If asynchronous send requested */ + DataOutAsyncReq = __FALSE; + } else if (DataOutUpdateReqMask) { /* If update requested */ + if (usbd_hid_inreport_num <= 1) { /* If only one in report in system */ + if (DataOutUpdateReqMask) { + USBD_HID_InReport[0] = 0; /* ReportID = 0 */ + DataOutSentLen = 0; + DataOutToSendLen = usbd_hid_get_report(HID_REPORT_INPUT, 0, &USBD_HID_InReport[1], USBD_HID_REQ_PERIOD_UPDATE); + + if (DataOutToSendLen) { + ptrDataOut = &USBD_HID_InReport[1]; + } + + DataOutUpdateReqMask = 0; + } + } else { /* If multiple reports in system */ + for (i = USBD_HID_InReport[0]; ; i++) { + if (i >= 32) { + i = 0; + } + + if (DataOutUpdateReqMask & (1 << i)) { + USBD_HID_InReport[0] = i + 1; /* ReportID */ + DataOutSentLen = 0; + DataOutToSendLen = usbd_hid_get_report(HID_REPORT_INPUT, i + 1, &USBD_HID_InReport[1], USBD_HID_REQ_PERIOD_UPDATE); + + if (DataOutToSendLen) { + ptrDataOut = USBD_HID_InReport; + DataOutToSendLen++; + } + + DataOutUpdateReqMask &= ~(1 << i); + break; + } + } + } + } + } + + /* Check if data needs to be sent */ + if (DataOutToSendLen || + DataOutEndWithShortPacket) { /* If sending is in progress */ + bytes_to_send = DataOutToSendLen - DataOutSentLen; + + if (bytes_to_send > usbd_hid_maxpacketsize[USBD_HighSpeed]) { + bytes_to_send = usbd_hid_maxpacketsize[USBD_HighSpeed]; + } + + if (usbd_hid_ep_intin != 0) { //control ep does the sending to host + USBD_WriteEP(usbd_hid_ep_intin | 0x80, ptrDataOut, bytes_to_send); + } + + ptrDataOut += bytes_to_send; + DataOutSentLen += bytes_to_send; + + if ((DataOutSentLen < usbd_hid_inreport_max_sz) && + (bytes_to_send == usbd_hid_maxpacketsize[USBD_HighSpeed])) { + /* If short packet should be sent also*/ + DataOutEndWithShortPacket = __TRUE; + } else { + DataOutEndWithShortPacket = __FALSE; + } + } +} + + +/* + * USB Device HID Interrupt Out Endpoint Event Callback + * Parameters: event: not used (just for compatibility) + * Return Value: None + */ + +void USBD_HID_EP_INTOUT_Event(U32 event) +{ + U16 bytes_rece; + + if (!DataInReceLen) { /* Check if new reception */ + ptrDataIn = USBD_HID_OutReport; + DataInReceMax = usbd_hid_outreport_max_sz; + DataInReceLen = 0; + } + + bytes_rece = USBD_ReadEP(usbd_hid_ep_intout, ptrDataIn, DataInReceMax - DataInReceLen); + ptrDataIn += bytes_rece; + DataInReceLen += bytes_rece; + + if (!bytes_rece || + (DataInReceLen >= usbd_hid_outreport_max_sz) || + (bytes_rece < usbd_hid_maxpacketsize[USBD_HighSpeed])) { + if (usbd_hid_outreport_num <= 1) { /* If only one out report in system */ + usbd_hid_set_report(HID_REPORT_OUTPUT, 0 , USBD_HID_OutReport , DataInReceLen, USBD_HID_REQ_EP_INT); + } else { + usbd_hid_set_report(HID_REPORT_OUTPUT, USBD_HID_OutReport[0], &USBD_HID_OutReport[1], DataInReceLen - 1, USBD_HID_REQ_EP_INT); + } + + DataInReceLen = 0; + } +} + + +/* + * USB Device HID Configure Callback + * Parameters: None + * Return Value: None + */ + +void USBD_HID_Configure_Event(void) +{ + /* Reset all variables after connect event */ + USBD_HID_Protocol = 0; + DataOutAsyncReq = __FALSE; + DataOutUpdateReqMask = __FALSE; + ptrDataOut = NULL; + DataOutToSendLen = 0; + DataOutSentLen = 0; + DataOutEndWithShortPacket = __FALSE; + ptrDataIn = NULL; + DataInReceMax = 0; + DataInReceLen = 0; + ptrDataFeat = NULL; + DataFeatReceLen = 0; +} + + +/* + * USB Device HID Interrupt In/Out Endpoint Event Callback + * Parameters: event: USB Device Event + * USBD_EVT_IN: Input Event + * USBD_EVT_OUT: Output Event + * Return Value: None + */ + +void USBD_HID_EP_INT_Event(U32 event) +{ + if (event & USBD_EVT_IN) { + USBD_HID_EP_INTIN_Event(event); + } + + if (event & USBD_EVT_OUT) { + USBD_HID_EP_INTOUT_Event(event); + } +} + + +/* + * USB Device HID SOF Handler (handles report timings: polling and idle times) + * Called automatically on USB Device Start of Frame + * Parameters: None + * Return Value: None + */ + +void USBD_HID_SOF_Event(void) +{ + static U8 cnt_for_4ms = 0; + U8 i; + BOOL tick_4ms, do_polling, polling_reload, idle_reload; + + if (USBD_Configuration) { + tick_4ms = __FALSE; + + if (cnt_for_4ms++ >= ((4 << (3 * USBD_HighSpeed))) - 1) { + cnt_for_4ms = 0; + tick_4ms = __TRUE; + } + + polling_reload = __FALSE; + + if (USBD_HID_PollingCnt < 255) { + USBD_HID_PollingCnt++; + } + + if (USBD_HID_PollingCnt == usbd_hid_interval[USBD_HighSpeed]) { + polling_reload = __TRUE; /* If polling interval expired */ + } + + for (i = 0; i < usbd_hid_inreport_num; i++) { + idle_reload = __FALSE; + + if (tick_4ms) { + if (USBD_HID_IdleCnt[i] < 255) { + USBD_HID_IdleCnt[i]++; + } + + if (USBD_HID_IdleReload[i]) { + if (USBD_HID_IdleCnt[i] >= USBD_HID_IdleReload[i]) { + idle_reload = __TRUE; /* If idle period expired */ + } + } + } + + do_polling = (usbd_hid_interval[USBD_HighSpeed] > ((U16)(USBD_HID_IdleReload[i]) << (2 << (3 * USBD_HighSpeed)))) && (USBD_HID_IdleReload[i] != 0); + + if (polling_reload) { + if (do_polling) { + /* If polling is longer than idle */ + DataOutUpdateReqMask |= (1 << i); + } + } + + if (USBD_HID_IdleReload[i] != USBD_HID_IdleSet[i]) { + if (USBD_HID_IdleCnt[i] >= USBD_HID_IdleSet[i]) { + DataOutUpdateReqMask |= (1 << i); + cnt_for_4ms = 0; + } + + USBD_HID_IdleReload[i] = USBD_HID_IdleSet[i]; + } + + if (idle_reload) { + if (!do_polling) { + DataOutUpdateReqMask |= (1 << i); + } + + USBD_HID_IdleCnt[i] = 0; + } + } + + if (polling_reload) { + USBD_HID_PollingCnt = 0; + } + + if (DataOutUpdateReqMask && !DataOutToSendLen) { /* If pending */ + /* refresh request and no active data */ + /* out then start data out */ + USBD_HID_EP_INTIN_Event(0); + } + } +} + + +#ifdef __RTX /* RTX task for handling events */ + +/* + * USB Device HID Interrupt In Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +void USBD_RTX_HID_EP_INTIN_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + + if (usbd_os_evt_get() & USBD_EVT_IN) { + USBD_HID_EP_INTIN_Event(0); + } + } +} + + +/* + * USB Device HID Interrupt Out Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +void USBD_RTX_HID_EP_INTOUT_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + + if (usbd_os_evt_get() & USBD_EVT_OUT) { + USBD_HID_EP_INTOUT_Event(0); + } + } +} + + +/* + * USB Device HID Interrupt In/Out Endpoint Event Handler Task + * Parameters: None + * Return Value: None + */ + +void USBD_RTX_HID_EP_INT_Event(void) +{ + for (;;) { + usbd_os_evt_wait_or(0xFFFF, 0xFFFF); + USBD_HID_EP_INT_Event(usbd_os_evt_get()); + } +} +#endif + + +/* + * USB Device HID Get Report Trigger (asynchronous Get_Report request) + * Parameters: rid: Report ID + * buf: Pointer to data buffer + * len: Number of bytes to be sent + * Return Value: TRUE - Success, FALSE - Error + */ + +BOOL usbd_hid_get_report_trigger(U8 rid, U8 *buf, int len) +{ + if (len > usbd_hid_inreport_max_sz) { + return (__FALSE); + } + + if (USBD_Configuration) { + DataOutAsyncReq = __TRUE; /* Asynchronous data out request */ + + while (DataOutToSendLen) { + if (!USBD_Configuration) { /* If device not configured reject rq */ + DataOutAsyncReq = __FALSE; /* Asynchronous data out request */ + ptrDataOut = NULL; + DataOutSentLen = 0; + DataOutToSendLen = 0; + return (__FALSE); + } + } + + USBD_HID_InReport[0] = rid; + memcpy(&USBD_HID_InReport[1], buf, len); + ptrDataOut = USBD_HID_InReport; + DataOutSentLen = 0; + DataOutToSendLen = len; + + if (usbd_hid_inreport_num <= 1) { /* If only 1 in report skip ReportID */ + ptrDataOut ++; + } else { /* If more in reports, send ReportID */ + DataOutToSendLen ++; + } + + USBD_HID_EP_INTIN_Event(0); + USBD_HID_IdleCnt[rid] = 0; + return (__TRUE); + } + + return (__FALSE); +}