Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
source/usb/hid/usbd_hid.c
- Committer:
- Pawel Zarembski
- Date:
- 2020-04-07
- Revision:
- 0:01f31e923fe2
File content as of revision 0:01f31e923fe2:
/** * @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); }