Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbd_hid.c Source File

usbd_hid.c

Go to the documentation of this file.
00001 /**
00002  * @file    usbd_hid.c
00003  * @brief   Human Interface Device driver
00004  *
00005  * DAPLink Interface Firmware
00006  * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
00007  * SPDX-License-Identifier: Apache-2.0
00008  *
00009  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00010  * not use this file except in compliance with the License.
00011  * You may obtain a copy of the License at
00012  *
00013  * http://www.apache.org/licenses/LICENSE-2.0
00014  *
00015  * Unless required by applicable law or agreed to in writing, software
00016  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00017  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018  * See the License for the specific language governing permissions and
00019  * limitations under the License.
00020  */
00021 
00022 #include <string.h>
00023 
00024 #include "rl_usb.h"
00025 #include "usb_for_lib.h"
00026 
00027 
00028 U8 USBD_HID_Protocol;
00029 
00030 BOOL DataOutAsyncReq;
00031 U32 DataOutUpdateReqMask;
00032 U8 *ptrDataOut;
00033 volatile U16 DataOutToSendLen;
00034 U16 DataOutSentLen;
00035 BOOL DataOutEndWithShortPacket;
00036 
00037 U8 *ptrDataIn;
00038 U16 DataInReceMax;
00039 U16 DataInReceLen;
00040 
00041 U8 *ptrDataFeat;
00042 U16 DataFeatReceLen;
00043 
00044 
00045 /* Dummy Weak Functions that need to be provided by user */
00046 __weak void usbd_hid_init(void)
00047 {
00048 
00049 }
00050 __weak int usbd_hid_get_report(U8 rtype, U8 rid, U8 *buf, U8 req)
00051 {
00052     return (0);
00053 };
00054 __weak void usbd_hid_set_report(U8  rtype, U8 rid, U8 *buf, int len, U8 req)
00055 {
00056 
00057 }
00058 __weak U8 usbd_hid_get_protocol(void)
00059 {
00060     return (0);
00061 };
00062 __weak void usbd_hid_set_protocol(U8  protocol)
00063 {
00064 
00065 };
00066 
00067 
00068 /*
00069  *  USB Device HID Get Report Request Callback
00070  *   Called automatically on USB Device HID Get Report Request
00071  *    Parameters:      None
00072  *    Return Value:    TRUE - Success, FALSE - Error
00073  */
00074 
00075 BOOL USBD_HID_GetReport(void)
00076 {
00077     U8 *ptr_buf = 0;
00078 
00079     /* Report Type   = USBD_SetupPacket.wValueH */
00080     /* Report ID     = USBD_SetupPacket.wValueL */
00081     /* Report Length = USBD_SetupPacket.wLength */
00082     switch (USBD_SetupPacket.wValueH) {
00083         case HID_REPORT_INPUT:
00084             ptr_buf  = &USBD_HID_InReport[1];
00085             break;
00086 
00087         case HID_REPORT_OUTPUT:
00088             return (__FALSE);        /* Not Supported */
00089 
00090         case HID_REPORT_FEATURE:
00091             ptr_buf  = &USBD_HID_FeatReport[1];
00092             break;
00093     }
00094 
00095     usbd_hid_get_report(USBD_SetupPacket.wValueH, USBD_SetupPacket.wValueL, ptr_buf, USBD_HID_REQ_EP_CTRL);
00096     return (__TRUE);
00097 }
00098 
00099 
00100 /*
00101  *  USB Device HID Set Report Request Callback
00102  *   Called automatically on USB Device HID Set Report Request
00103  *    Parameters:      None
00104  *    Return Value:    TRUE - Success, FALSE - Error
00105  */
00106 
00107 BOOL USBD_HID_SetReport(void)
00108 {
00109     U8 *ptr_buf = 0;
00110 
00111     /* Report Type   = USBD_SetupPacket.wValueH */
00112     /* Report ID     = USBD_SetupPacket.wValueL */
00113     /* Report Length = USBD_SetupPacket.wLength */
00114     switch (USBD_SetupPacket.wValueH) {
00115         case HID_REPORT_INPUT:
00116             return (__FALSE);        /* Not Supported */
00117 
00118         case HID_REPORT_OUTPUT:
00119             ptr_buf  = &USBD_HID_OutReport[1];
00120             break;
00121 
00122         case HID_REPORT_FEATURE:
00123             ptr_buf  = &USBD_HID_FeatReport[1];
00124             break;
00125     }
00126 
00127     usbd_hid_set_report(USBD_SetupPacket.wValueH, USBD_SetupPacket.wValueL, ptr_buf, USBD_SetupPacket.wLength, USBD_HID_REQ_EP_CTRL);
00128     return (__TRUE);
00129 }
00130 
00131 
00132 /*
00133  *  USB Device HID Get Idle Request Callback
00134  *   Called automatically on USB Device HID Get Idle Request
00135  *    Parameters:      None
00136  *    Return Value:    TRUE - Success, FALSE - Error
00137  */
00138 
00139 BOOL USBD_HID_GetIdle(void)
00140 {
00141     USBD_EP0Buf[0] = USBD_HID_IdleSet[USBD_SetupPacket.wValueL];
00142     return (__TRUE);
00143 }
00144 
00145 
00146 /*
00147  *  USB Device HID Set Idle Request Callback
00148  *   Called automatically on USB Device HID Set Idle Request
00149  *    Parameters:      None
00150  *    Return Value:    TRUE - Success, FALSE - Error
00151  */
00152 
00153 BOOL USBD_HID_SetIdle(void)
00154 {
00155     U8 i;
00156 
00157     if (USBD_SetupPacket.wValueL) {       /* If  > 0 Report ID specified        */
00158         USBD_HID_IdleSet[USBD_SetupPacket.wValueL - 1] = USBD_SetupPacket.wValueH;
00159     } else {                              /* If == 0 all reports                */
00160         for (i = 0; i < usbd_hid_inreport_num; i++) {
00161             USBD_HID_IdleSet[i] = USBD_SetupPacket.wValueH;
00162         }
00163     }
00164 
00165     return (__TRUE);
00166 }
00167 
00168 
00169 /*
00170  *  USB Device HID Get Protocol Request Callback
00171  *   Called automatically on USB Device HID Get Protocol Request
00172  *    Parameters:      None
00173  *    Return Value:    TRUE - Success, FALSE - Error
00174  */
00175 
00176 BOOL USBD_HID_GetProtocol(void)
00177 {
00178     USBD_EP0Buf[0] = usbd_hid_get_protocol();
00179     return (__TRUE);
00180 }
00181 
00182 
00183 /*
00184  *  USB Device HID Set Protocol Request Callback
00185  *   Called automatically on USB Device HID Set Protocol Request
00186  *    Parameters:      None
00187  *    Return Value:    TRUE - Success, FALSE - Error
00188  */
00189 
00190 BOOL USBD_HID_SetProtocol(void)
00191 {
00192     usbd_hid_set_protocol(USBD_SetupPacket.wValueL);
00193     return (__TRUE);
00194 }
00195 
00196 
00197 /*
00198  *  USB Device HID Interrupt In Endpoint Event Callback
00199  *    Parameters:      event: not used (just for compatibility)
00200  *    Return Value:    None
00201  */
00202 
00203 void USBD_HID_EP_INTIN_Event(U32 event)
00204 {
00205     U8  i;
00206     U16 bytes_to_send;
00207 
00208     /* Check if sending is finished                                             */
00209     if ((DataOutSentLen >= DataOutToSendLen) &&
00210             !DataOutEndWithShortPacket) {     /* If all sent and short packet also  */
00211         ptrDataOut          = NULL;
00212         DataOutSentLen      = 0;
00213         DataOutToSendLen    = usbd_hid_get_report(HID_REPORT_INPUT, USBD_HID_InReport[0], &USBD_HID_InReport[1], USBD_HID_REQ_EP_INT);
00214 
00215         if (DataOutToSendLen) {             /* If new send should be started      */
00216             ptrDataOut        = USBD_HID_InReport;
00217 
00218             if (usbd_hid_inreport_num <= 1) { /* If only in 1 report skip ReportID  */
00219                 ptrDataOut++;
00220             } else {                          /* If more in reports, send ReportID  */
00221                 DataOutToSendLen++;
00222             }
00223         }
00224     }
00225 
00226     /* Check if new data out sending should be started                          */
00227     if (!DataOutToSendLen) {              /* If send not in progress            */
00228         if (DataOutAsyncReq) {              /* If asynchronous send requested     */
00229             DataOutAsyncReq = __FALSE;
00230         } else if (DataOutUpdateReqMask) {  /* If update requested                */
00231             if (usbd_hid_inreport_num <= 1) { /* If only one in report in system    */
00232                 if (DataOutUpdateReqMask) {
00233                     USBD_HID_InReport[0]  = 0;    /* ReportID = 0                       */
00234                     DataOutSentLen        = 0;
00235                     DataOutToSendLen      = usbd_hid_get_report(HID_REPORT_INPUT, 0, &USBD_HID_InReport[1], USBD_HID_REQ_PERIOD_UPDATE);
00236 
00237                     if (DataOutToSendLen) {
00238                         ptrDataOut          = &USBD_HID_InReport[1];
00239                     }
00240 
00241                     DataOutUpdateReqMask  = 0;
00242                 }
00243             } else {                          /* If multiple reports in system      */
00244                 for (i = USBD_HID_InReport[0]; ; i++) {
00245                     if (i >= 32) {
00246                         i = 0;
00247                     }
00248 
00249                     if (DataOutUpdateReqMask & (1 << i)) {
00250                         USBD_HID_InReport[0] = i + 1; /* ReportID                           */
00251                         DataOutSentLen      = 0;
00252                         DataOutToSendLen    = usbd_hid_get_report(HID_REPORT_INPUT, i + 1, &USBD_HID_InReport[1], USBD_HID_REQ_PERIOD_UPDATE);
00253 
00254                         if (DataOutToSendLen) {
00255                             ptrDataOut        = USBD_HID_InReport;
00256                             DataOutToSendLen++;
00257                         }
00258 
00259                         DataOutUpdateReqMask &= ~(1 << i);
00260                         break;
00261                     }
00262                 }
00263             }
00264         }
00265     }
00266 
00267     /* Check if data needs to be sent                                           */
00268     if (DataOutToSendLen ||
00269             DataOutEndWithShortPacket) {     /* If sending is in progress          */
00270         bytes_to_send = DataOutToSendLen - DataOutSentLen;
00271 
00272         if (bytes_to_send > usbd_hid_maxpacketsize[USBD_HighSpeed]) {
00273             bytes_to_send = usbd_hid_maxpacketsize[USBD_HighSpeed];
00274         }
00275 
00276         if (usbd_hid_ep_intin != 0) { //control ep does the sending to host
00277             USBD_WriteEP(usbd_hid_ep_intin | 0x80, ptrDataOut, bytes_to_send);
00278         }
00279 
00280         ptrDataOut     += bytes_to_send;
00281         DataOutSentLen += bytes_to_send;
00282 
00283         if ((DataOutSentLen < usbd_hid_inreport_max_sz) &&
00284                 (bytes_to_send == usbd_hid_maxpacketsize[USBD_HighSpeed])) {
00285             /* If short packet should be sent also*/
00286             DataOutEndWithShortPacket = __TRUE;
00287         } else {
00288             DataOutEndWithShortPacket = __FALSE;
00289         }
00290     }
00291 }
00292 
00293 
00294 /*
00295  *  USB Device HID Interrupt Out Endpoint Event Callback
00296  *    Parameters:      event: not used (just for compatibility)
00297  *    Return Value:    None
00298  */
00299 
00300 void USBD_HID_EP_INTOUT_Event(U32 event)
00301 {
00302     U16 bytes_rece;
00303 
00304     if (!DataInReceLen) {                 /* Check if new reception             */
00305         ptrDataIn     = USBD_HID_OutReport;
00306         DataInReceMax = usbd_hid_outreport_max_sz;
00307         DataInReceLen = 0;
00308     }
00309 
00310     bytes_rece      = USBD_ReadEP(usbd_hid_ep_intout, ptrDataIn, DataInReceMax - DataInReceLen);
00311     ptrDataIn      += bytes_rece;
00312     DataInReceLen  += bytes_rece;
00313 
00314     if (!bytes_rece ||
00315             (DataInReceLen >= usbd_hid_outreport_max_sz) ||
00316             (bytes_rece    <  usbd_hid_maxpacketsize[USBD_HighSpeed])) {
00317         if (usbd_hid_outreport_num <= 1) {  /* If only one out report in system   */
00318             usbd_hid_set_report(HID_REPORT_OUTPUT,                    0 ,  USBD_HID_OutReport   , DataInReceLen,   USBD_HID_REQ_EP_INT);
00319         } else {
00320             usbd_hid_set_report(HID_REPORT_OUTPUT, USBD_HID_OutReport[0], &USBD_HID_OutReport[1], DataInReceLen - 1, USBD_HID_REQ_EP_INT);
00321         }
00322 
00323         DataInReceLen = 0;
00324     }
00325 }
00326 
00327 
00328 /*
00329  *  USB Device HID Configure Callback
00330  *    Parameters:      None
00331  *    Return Value:    None
00332  */
00333 
00334 void USBD_HID_Configure_Event(void)
00335 {
00336     /* Reset all variables after connect event */
00337     USBD_HID_Protocol         = 0;
00338     DataOutAsyncReq           = __FALSE;
00339     DataOutUpdateReqMask      = __FALSE;
00340     ptrDataOut                = NULL;
00341     DataOutToSendLen          = 0;
00342     DataOutSentLen            = 0;
00343     DataOutEndWithShortPacket = __FALSE;
00344     ptrDataIn                 = NULL;
00345     DataInReceMax             = 0;
00346     DataInReceLen             = 0;
00347     ptrDataFeat               = NULL;
00348     DataFeatReceLen           = 0;
00349 }
00350 
00351 
00352 /*
00353  *  USB Device HID Interrupt In/Out Endpoint Event Callback
00354  *    Parameters:      event: USB Device Event
00355  *                       USBD_EVT_IN:  Input Event
00356  *                       USBD_EVT_OUT: Output Event
00357  *    Return Value:    None
00358  */
00359 
00360 void USBD_HID_EP_INT_Event(U32 event)
00361 {
00362     if (event & USBD_EVT_IN) {
00363         USBD_HID_EP_INTIN_Event(event);
00364     }
00365 
00366     if (event & USBD_EVT_OUT) {
00367         USBD_HID_EP_INTOUT_Event(event);
00368     }
00369 }
00370 
00371 
00372 /*
00373  *  USB Device HID SOF Handler (handles report timings: polling and idle times)
00374  *   Called automatically on USB Device Start of Frame
00375  *    Parameters:      None
00376  *    Return Value:    None
00377  */
00378 
00379 void USBD_HID_SOF_Event(void)
00380 {
00381     static U8   cnt_for_4ms = 0;
00382     U8   i;
00383     BOOL tick_4ms, do_polling, polling_reload, idle_reload;
00384 
00385     if (USBD_Configuration) {
00386         tick_4ms = __FALSE;
00387 
00388         if (cnt_for_4ms++ >= ((4 << (3 * USBD_HighSpeed))) - 1) {
00389             cnt_for_4ms = 0;
00390             tick_4ms    = __TRUE;
00391         }
00392 
00393         polling_reload = __FALSE;
00394 
00395         if (USBD_HID_PollingCnt < 255) {
00396             USBD_HID_PollingCnt++;
00397         }
00398 
00399         if (USBD_HID_PollingCnt == usbd_hid_interval[USBD_HighSpeed]) {
00400             polling_reload = __TRUE;          /* If polling interval expired        */
00401         }
00402 
00403         for (i = 0; i < usbd_hid_inreport_num; i++) {
00404             idle_reload = __FALSE;
00405 
00406             if (tick_4ms) {
00407                 if (USBD_HID_IdleCnt[i] < 255) {
00408                     USBD_HID_IdleCnt[i]++;
00409                 }
00410 
00411                 if (USBD_HID_IdleReload[i]) {
00412                     if (USBD_HID_IdleCnt[i] >= USBD_HID_IdleReload[i]) {
00413                         idle_reload = __TRUE;       /* If idle period expired             */
00414                     }
00415                 }
00416             }
00417 
00418             do_polling = (usbd_hid_interval[USBD_HighSpeed] > ((U16)(USBD_HID_IdleReload[i]) << (2 << (3 * USBD_HighSpeed)))) && (USBD_HID_IdleReload[i] != 0);
00419 
00420             if (polling_reload) {
00421                 if (do_polling) {
00422                     /* If polling is longer than idle     */
00423                     DataOutUpdateReqMask |= (1 << i);
00424                 }
00425             }
00426 
00427             if (USBD_HID_IdleReload[i] != USBD_HID_IdleSet[i]) {
00428                 if (USBD_HID_IdleCnt[i] >= USBD_HID_IdleSet[i]) {
00429                     DataOutUpdateReqMask |= (1 << i);
00430                     cnt_for_4ms = 0;
00431                 }
00432 
00433                 USBD_HID_IdleReload[i] = USBD_HID_IdleSet[i];
00434             }
00435 
00436             if (idle_reload) {
00437                 if (!do_polling) {
00438                     DataOutUpdateReqMask |= (1 << i);
00439                 }
00440 
00441                 USBD_HID_IdleCnt[i] = 0;
00442             }
00443         }
00444 
00445         if (polling_reload) {
00446             USBD_HID_PollingCnt = 0;
00447         }
00448 
00449         if (DataOutUpdateReqMask && !DataOutToSendLen) {        /* If pending     */
00450             /* refresh request and no active data */
00451             /* out then start data out            */
00452             USBD_HID_EP_INTIN_Event(0);
00453         }
00454     }
00455 }
00456 
00457 
00458 #ifdef __RTX                            /* RTX task for handling events */
00459 
00460 /*
00461  *  USB Device HID Interrupt In Endpoint Event Handler Task
00462  *    Parameters:      None
00463  *    Return Value:    None
00464  */
00465 
00466 void USBD_RTX_HID_EP_INTIN_Event(void)
00467 {
00468     for (;;) {
00469         usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
00470 
00471         if (usbd_os_evt_get() & USBD_EVT_IN) {
00472             USBD_HID_EP_INTIN_Event(0);
00473         }
00474     }
00475 }
00476 
00477 
00478 /*
00479  *  USB Device HID Interrupt Out Endpoint Event Handler Task
00480  *    Parameters:      None
00481  *    Return Value:    None
00482  */
00483 
00484 void USBD_RTX_HID_EP_INTOUT_Event(void)
00485 {
00486     for (;;) {
00487         usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
00488 
00489         if (usbd_os_evt_get() & USBD_EVT_OUT) {
00490             USBD_HID_EP_INTOUT_Event(0);
00491         }
00492     }
00493 }
00494 
00495 
00496 /*
00497  *  USB Device HID Interrupt In/Out Endpoint Event Handler Task
00498  *    Parameters:      None
00499  *    Return Value:    None
00500  */
00501 
00502 void USBD_RTX_HID_EP_INT_Event(void)
00503 {
00504     for (;;) {
00505         usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
00506         USBD_HID_EP_INT_Event(usbd_os_evt_get());
00507     }
00508 }
00509 #endif
00510 
00511 
00512 /*
00513  *  USB Device HID Get Report Trigger (asynchronous Get_Report request)
00514  *    Parameters:      rid: Report ID
00515  *                     buf: Pointer to data buffer
00516  *                     len: Number of bytes to be sent
00517  *    Return Value:    TRUE - Success, FALSE - Error
00518  */
00519 
00520 BOOL usbd_hid_get_report_trigger(U8 rid, U8 *buf, int len)
00521 {
00522     if (len > usbd_hid_inreport_max_sz) {
00523         return (__FALSE);
00524     }
00525 
00526     if (USBD_Configuration) {
00527         DataOutAsyncReq    = __TRUE;        /* Asynchronous data out request      */
00528 
00529         while (DataOutToSendLen) {
00530             if (!USBD_Configuration) {        /* If device not configured reject rq */
00531                 DataOutAsyncReq    = __FALSE;   /* Asynchronous data out request      */
00532                 ptrDataOut         = NULL;
00533                 DataOutSentLen     = 0;
00534                 DataOutToSendLen   = 0;
00535                 return (__FALSE);
00536             }
00537         }
00538 
00539         USBD_HID_InReport[0]   = rid;
00540         memcpy(&USBD_HID_InReport[1], buf, len);
00541         ptrDataOut             = USBD_HID_InReport;
00542         DataOutSentLen         = 0;
00543         DataOutToSendLen       = len;
00544 
00545         if (usbd_hid_inreport_num <= 1) {   /* If only 1 in report skip ReportID  */
00546             ptrDataOut ++;
00547         } else {                            /* If more in reports, send ReportID  */
00548             DataOutToSendLen ++;
00549         }
00550 
00551         USBD_HID_EP_INTIN_Event(0);
00552         USBD_HID_IdleCnt[rid]      = 0;
00553         return (__TRUE);
00554     }
00555 
00556     return (__FALSE);
00557 }