(USB HID) In/Out Report 收發 Function
Posted ollie-lin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(USB HID) In/Out Report 收發 Function相关的知识,希望对你有一定的参考价值。
在紀錄 In/Out Report 收發之前先來看一下一個struct
1 typedef struct _Device_cb 2 { 3 uint8_t (*Init) (void *pdev , uint8_t cfgidx); 4 uint8_t (*DeInit) (void *pdev , uint8_t cfgidx); 5 /* Control Endpoints*/ 6 uint8_t (*Setup) (void *pdev , USB_SETUP_REQ *req); 7 uint8_t (*EP0_TxSent) (void *pdev ); 8 uint8_t (*EP0_RxReady) (void *pdev ); 9 /* Class Specific Endpoints*/ 10 uint8_t (*DataIn) (void *pdev , uint8_t epnum); 11 uint8_t (*DataOut) (void *pdev , uint8_t epnum); 12 uint8_t (*SOF) (void *pdev); 13 uint8_t (*IsoINIncomplete) (void *pdev); 14 uint8_t (*IsoOUTIncomplete) (void *pdev); 15 16 uint8_t *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length); 17 #ifdef USB_OTG_HS_CORE 18 uint8_t *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length); 19 #endif 20 21 #ifdef USB_SUPPORT_USER_STRING_DESC 22 uint8_t *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index, uint16_t *length); 23 #endif 24 25 } USBD_Class_cb_TypeDef;
這邊有特別註解 Control Endpoint, Class Specific Endpoint,理解翻譯就是Control Endpoint 即是所謂的Endpoint 0
在USB協定中,一定是透過Endpoint 0,而且一個裝置只能有一個,而且一定要支援。
它一次最大能傳的資料大小為64 bytes,並且是雙向傳輸。基本上一個USB裝置一插上電腦,電腦就會透過Endpoint 0來問一些資料。
根據USB2.0規格,Host必須保留10%的頻寬給Control傳輸。
而Class Specific Endpoint則是我定義 In/Out Report 需要使用的Function,在USB HID Init 時我會初始化我的Endpoint
1 static uint8_t USBD_HID_Init (void *pdev, 2 uint8_t cfgidx) 3 { 4 5 /* Open EP IN */ 6 DCD_EP_Open(pdev, 7 HID_IN_EP, 8 HID_IN_PACKET, 9 USB_OTG_EP_INT); 10 11 /* Open EP OUT */ 12 DCD_EP_Open(pdev, 13 HID_OUT_EP, 14 HID_OUT_PACKET, 15 USB_OTG_EP_INT); 16 17 DCD_EP_PrepareRx(pdev, HID_OUT_EP, WRReport_buf, USB_HID_RECEIVE_FRAME_SIZE); 18 19 return USBD_OK; 20 }
在Window API理頭,主要是利用 WriteFile/ReadFile 跟 HidD_GetInputReport / HidD_SetOutputReport 來收發資料。
在Firmware裡頭對應 WriteFile/ReadFile 的是 Class Specific Endpoint
而對應 HidD_GetInputReport / HidD_SetOutputReport 則是透過 Endpoint 0去對Firmware 做控制。
GetInputReport / SetOutputReport 在 Firmeware 需要在 USBD_HID_Setup 裡頭加上 Set/Get Report的Case
1 static uint8_t USBD_HID_Setup (void *pdev, USB_SETUP_REQ *req) 2 { 3 uint8_t USBD_HID_Report_LENGTH = 0; 4 uint16_t len = 0; 5 uint8_t *pbuf = NULL; 6 7 switch (req->bmRequest & USB_REQ_TYPE_MASK) 8 { 9 case USB_REQ_TYPE_CLASS : 10 switch (req->bRequest) 11 { 12 13 14 case HID_REQ_SET_PROTOCOL: 15 USBD_HID_Protocol = (uint8_t)(req->wValue); 16 break; 17 18 case HID_REQ_GET_PROTOCOL: 19 USBD_CtlSendData (pdev, 20 (uint8_t *)&USBD_HID_Protocol, 1); 21 break; 22 23 case HID_REQ_SET_IDLE: 24 USBD_HID_IdleState = (uint8_t)(req->wValue >> 8); 25 break; 26 27 case HID_REQ_GET_IDLE: 28 USBD_CtlSendData (pdev, (uint8_t *)&USBD_HID_IdleState, 1); 29 break; 30 31 case HID_REQ_SET_REPORT: 32 /* HidD_SetOutputReport 1-byte = Report ID (IN) */ 33 flag = 1; 34 USBD_HID_Report_ID = (uint8_t)(req->wValue); 35 USBD_HID_Report_LENGTH = (uint8_t)(req->wLength); 36 USBD_CtlPrepareRx (pdev, WRReport_buf, USBD_HID_Report_LENGTH); 37 break; 38 39 case HID_REQ_GET_REPORT: 40 /* HidD_GetInputReport 1-byte = Report ID (OUT) */ 41 flag = 1; 42 WRReport_buf[0] = 0x11; 43 WRReport_buf[1] = 0x22; 44 WRReport_buf[2] = 0x33; 45 WRReport_buf[3] = 0x44; 46 WRReport_buf[4] = 0x55; 47 WRReport_buf[5] = 0x66; 48 WRReport_buf[6] = 0x77; 49 WRReport_buf[7] = 0x88; 50 USBD_CtlSendData (pdev, (uint8_t *)&WRReport_buf, 8); // to pc 51 break; 52 53 default: 54 USBD_CtlError (pdev, req); 55 return USBD_FAIL; 56 } 57 break; 58 59 case USB_REQ_TYPE_STANDARD: 60 switch (req->bRequest) 61 { 62 case USB_REQ_GET_DESCRIPTOR: 63 if( req->wValue >> 8 == HID_REPORT_DESC) 64 { 65 len = MIN(CUSTOMHID_SIZ_REPORT_DESC , req->wLength); 66 pbuf = CustomHID_ReportDescriptor; 67 //pbuf = HID_MOUSE_ReportDesc; 68 69 } 70 else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE) 71 { 72 //#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED 73 // pbuf = USBD_HID_Desc; 74 //#else 75 // pbuf = USBD_HID_CfgDesc + 0x12; 76 //#endif 77 pbuf = USBD_HID_CfgDesc + 0x12; 78 len = MIN(USB_HID_DESC_SIZ , req->wLength); 79 } 80 USBD_CtlSendData (pdev, pbuf, len); 81 break; 82 case USB_REQ_GET_INTERFACE : 83 USBD_CtlSendData (pdev, (uint8_t *)&USBD_HID_AltSet, 1); 84 85 break; 86 87 case USB_REQ_SET_INTERFACE : 88 USBD_HID_AltSet = (uint8_t)(req->wValue); 89 break; 90 } 91 } 92 return USBD_OK; 93 }
這邊提及一下Firmware 發送 Class Specific Endpoint In/Out Report 是利用
DCD_EP_Tx (pdev, HID_IN_EP, report, len); // In Report DCD_EP_PrepareRx(pdev, HID_OUT_EP, WRReport_buf, HID_OUT_PACKET);
以上是关于(USB HID) In/Out Report 收發 Function的主要内容,如果未能解决你的问题,请参考以下文章
USB之HID类Set_Report Request[调试手记1]