找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7194|回复: 1
打印 上一主题 下一主题
收起左侧

usb_hid.c(usb复合设备驱动)

[复制链接]
跳转到指定楼层
楼主
ID:51024 发表于 2014-8-3 00:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//值得一提的是先检查你的遥控器电池电量,如果电量不足可能会自动断开与主机的通讯,或者反应不灵敏
/**

  ******************************************************************************
  * @file    usbh_hid_core.c
  * @author  MCD Application Team
  * @version V2.1.0
  * @date    19-March-2012
  * @brief   This file is the HID Layer Handlers for USB Host HID class.
  *
  * @verbatim
  *      
  *          ===================================================================      
  *                                HID Class  Description
  *          ===================================================================
  *           This module manages the MSC class V1.11 following the "Device Class Definition
  *           for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
  *           This driver implements the following aspects of the specification:
  *             - The Boot Interface Subclass
  *             - The Mouse and Keyboard protocols
  *      
  *  @endverbatim
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2
  *
  * 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.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usbh_hid_core.h"
#include "usbh_usr.h"
#include "ycc_host.h"
#include "main.h"
/** @addtogroup USBH_LIB
* @{
*/

/** @addtogroup USBH_CLASS
* @{
*/

/** @addtogroup USBH_HID_CLASS
* @{
*/

/** @defgroup USBH_HID_CORE
* @brief    This file includes HID Layer Handlers for USB Host HID class.
* @{
*/

/** @defgroup USBH_HID_CORE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/

/** @defgroup USBH_HID_CORE_Private_Defines
* @{
*/
/**
* @}
*/


/** @defgroup USBH_HID_CORE_Private_Macros
* @{
*/
/**
* @}
*/


/** @defgroup USBH_HID_CORE_Private_Variables
* @{
*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN HID_Machine_TypeDef        HID_KeyBoard __ALIGN_END ;
__ALIGN_BEGIN HID_Machine_TypeDef        HID_Mouse __ALIGN_END ;
__ALIGN_BEGIN HID_Machine_TypeDef* HIDP_Machine __ALIGN_END ;
/*定义一个 HIDP_Machine 是为了在HID_Mouse和HID_KeyBoard自由切换,以便于 HIDP_Machine->cb->Decode(HIDP_Machine->buff),正确解析的对应HID值。注意解析数据时只能是HID_Mouse和HID_KeyBoard其中一种。*/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN HID_Report_TypeDef         HID_Report __ALIGN_END ;

#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN USB_Setup_TypeDef          HID_Setup __ALIGN_END ;

#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
  #if defined ( __ICCARM__ ) /*!< IAR Compiler */
    #pragma data_alignment=4   
  #endif
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
__ALIGN_BEGIN USBH_HIDDesc_TypeDef       HID_Desc __ALIGN_END ;

/**
* @}
*/


/** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
* @{
*/

static USBH_Status USBH_HID_InterfaceInit  (USB_OTG_CORE_HANDLE *pdev ,
                                            void *phost);

static void  USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf);

static void USBH_HID_InterfaceDeInit  (USB_OTG_CORE_HANDLE *pdev ,
                                       void *phost);

static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
                                   void *phost);

static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
                                         void *phost);

static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
                                                  USBH_HOST *phost,
                                                  uint16_t length);

static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,\
                                            USBH_HOST *phost,  
                                            uint16_t length);

static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
                                  USBH_HOST *phost,
                                  uint8_t duration,
                                  uint8_t reportId);

static USBH_Status USBH_Set_Protocol (USB_OTG_CORE_HANDLE *pdev,
                                      USBH_HOST *phost,
                                      uint8_t protocol);


USBH_Class_cb_TypeDef  HID_cb =
{
  USBH_HID_InterfaceInit,
  USBH_HID_InterfaceDeInit,
  USBH_HID_ClassRequest,
  USBH_HID_Handle
};
/**
* @}
*/


/** @defgroup USBH_HID_CORE_Private_Functions
* @{
*/

/**
* @brief  USBH_HID_InterfaceInit
*         The function init the HID class.
* @param  pdev: Selected device
* @param  hdev: Selected device property
* @retval  USBH_Status :Response for USB HID driver intialization
*/
static USBH_Status USBH_HID_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev,
                                           void *phost)
{
  uint8_t maxEP;
  USBH_HOST *pphost = phost;
uint8_t itf = 0;
  uint8_t num =0;
  USBH_Status status = USBH_BUSY ;

  HID_KeyBoard.state = HID_ERROR;
  HID_KeyBoard.cb = NULL;

HID_Mouse.state = HID_ERROR;
  HID_Mouse.cb = NULL;

  for (itf=0; itf<USBH_MAX_NUM_INTERFACES; itf++)
  {
  if(pphost->device_prop.Itf_Desc[itf].bInterfaceSubClass  == HID_BOOT_CODE)
  {
    /*Decode Bootclass Protocl: Mouse or Keyboard*/

    if(pphost->device_prop.Itf_Desc[itf].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE)
    {
      //key
HIDP_Machine = &HID_KeyBoard;
HIDP_Machine->cb = &HID_KeyBoard_cb;
    }
    else if(pphost->device_prop.Itf_Desc[itf].bInterfaceProtocol  == HID_MOUSE_BOOT_CODE)  
    {
//mouse
HIDP_Machine = &HID_Mouse;
HIDP_Machine->cb = &HID_Mouse_cb;
    }
else
{
continue;
}

HIDP_Machine->state  = HID_IDLE;
HIDP_Machine->ctl_state = HID_REQ_IDLE;
HIDP_Machine->ep_addr   = pphost->device_prop.Ep_Desc[itf][0].bEndpointAddress;
HIDP_Machine->length   = pphost->device_prop.Ep_Desc[itf][0].wMaxPacketSize;
HIDP_Machine->poll  = pphost->device_prop.Ep_Desc[itf][0].bInterval ;

if (HIDP_Machine->poll < HID_MIN_POLL)
{
HIDP_Machine->poll = HID_MIN_POLL;
}
   
    /* Check fo available number of endpoints */
    /* Find the number of EPs in the Interface Descriptor */      
    /* Choose the lower number in order not to overrun the buffer allocated */
    maxEP = ( (pphost->device_prop.Itf_Desc[itf].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
             pphost->device_prop.Itf_Desc[itf].bNumEndpoints :
                 USBH_MAX_NUM_ENDPOINTS);
   
   
    /* Decode endpoint IN and OUT address from interface descriptor */
    for (num=0; num < maxEP; num++)
    {
      if(pphost->device_prop.Ep_Desc[itf][num].bEndpointAddress & 0x80)
      {
        HIDP_Machine->HIDIntInEp = (pphost->device_prop.Ep_Desc[itf][num].bEndpointAddress);
        HIDP_Machine->hc_num_in  =\
               USBH_Alloc_Channel(pdev,
                                  pphost->device_prop.Ep_Desc[itf][num].bEndpointAddress);
        
        /* Open channel for IN endpoint */
        USBH_Open_Channel  (pdev,
                            HIDP_Machine->hc_num_in,
                            pphost->device_prop.address,
                            pphost->device_prop.speed,
                            EP_TYPE_INTR,
                            HIDP_Machine->length);
      }
      else
      {
        HIDP_Machine->HIDIntOutEp = (pphost->device_prop.Ep_Desc[itf][num].bEndpointAddress);
        HIDP_Machine->hc_num_out  =\
                USBH_Alloc_Channel(pdev,
                                   pphost->device_prop.Ep_Desc[itf][num].bEndpointAddress);
        
        /* Open channel for OUT endpoint */
        USBH_Open_Channel  (pdev,
                            HIDP_Machine->hc_num_out,
                            pphost->device_prop.address,
                            pphost->device_prop.speed,
                            EP_TYPE_INTR,
                            HIDP_Machine->length);
      }
      
    }   
   
    HIDP_Machine->start_toggle = 0;
     status = USBH_OK;
  }
  }

if (HID_KeyBoard.cb == NULL && HID_Mouse.cb == NULL)
  {
     pphost->usr_cb->DeviceNotSupported();   
  }

  return status;

}



/**
* @brief  USBH_HID_InterfaceDeInit
*         The function DeInit the Host Channels used for the HID class.
* @param  pdev: Selected device
* @param  hdev: Selected device property
* @retval None
*/
void USBH_HID_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
                               void *phost)
{
   //USBH_HOST *pphost = phost;
  uint8_t i = 0;

for (i=0; i<2; i++)
  {
    HIDP_Machine = (i==0) ? &HID_KeyBoard : &HID_Mouse;
  if(HIDP_Machine->hc_num_in != 0x00)
  {   
    USB_OTG_HC_Halt(pdev, HIDP_Machine->hc_num_in);
    USBH_Free_Channel  (pdev, HIDP_Machine->hc_num_in);
    HIDP_Machine->hc_num_in = 0;     /* Reset the Channel as Free */  
  }
  
  if(HIDP_Machine->hc_num_out != 0x00)
  {   
    USB_OTG_HC_Halt(pdev, HIDP_Machine->hc_num_out);
    USBH_Free_Channel  (pdev, HIDP_Machine->hc_num_out);
    HIDP_Machine->hc_num_out = 0;     /* Reset the Channel as Free */  
  }
  HIDP_Machine->start_toggle = 0;
  }
}

/**
* @brief  USBH_HID_ClassRequest
*         The function is responsible for handling HID Class requests
*         for HID class.
* @param  pdev: Selected device
* @param  hdev: Selected device property
* @retval  USBH_Status :Response for USB Set Protocol request
*/
static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
                                         void *phost)
{   
    USBH_HOST *pphost = phost;

  USBH_Status status         = USBH_BUSY;
  USBH_Status classReqStatus = USBH_BUSY;

//  HIDP_Machine = &HID_KeyBoard;
  /* Switch HID state machine */
  switch (HIDP_Machine->ctl_state)
  {
  case HID_IDLE:  
  case HID_REQ_GET_HID_DESC:

    /* Get HID Desc */
    if (USBH_Get_HID_Descriptor (pdev, pphost, USB_HID_DESC_SIZE)== USBH_OK)
    {

      USBH_ParseHIDDesc(&HID_Desc, pdev->host.Rx_Buffer);
      HIDP_Machine->ctl_state = HID_REQ_GET_REPORT_DESC;
    }

    break;     
  case HID_REQ_GET_REPORT_DESC:


    /* Get Report Desc */
    if (USBH_Get_HID_ReportDescriptor(pdev , pphost, HID_Desc.wItemLength) == USBH_OK)
    {
      HIDP_Machine->ctl_state = HID_REQ_SET_IDLE;
    }

    break;

  case HID_REQ_SET_IDLE:

    classReqStatus = USBH_Set_Idle (pdev, pphost, 0, 0);

    /* set Idle */
    if (classReqStatus == USBH_OK)
    {
      HIDP_Machine->ctl_state = HID_REQ_SET_PROTOCOL;  
    }
    else if(classReqStatus == USBH_NOT_SUPPORTED)
    {
      HIDP_Machine->ctl_state = HID_REQ_SET_PROTOCOL;        
    }
    break;

  case HID_REQ_SET_PROTOCOL:
    /* set protocol */
    if (USBH_Set_Protocol (pdev ,pphost, 0) == USBH_OK)
    {
      HIDP_Machine->ctl_state = HID_REQ_IDLE;

      /* all requests performed*/
      status = USBH_OK;
    }
    break;

  default:
    break;
  }

  return status;
}

/**
* @brief  USBH_HID_Handle
*         The function is for managing state machine for HID data transfers
* @param  pdev: Selected device
* @param  hdev: Selected device property
* @retval USBH_Status
*/
static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
                                   void   *phost)
{
USBH_HOST *pphost = phost;
USBH_Status status = USBH_OK;

switch (HIDP_Machine->state)
{
  
case HID_IDLE:
  if (HID_KeyBoard.cb != NULL)
   HID_KeyBoard.cb->Init();  
  if (HID_Mouse.cb != NULL)
   HID_Mouse.cb->Init();
  if (HID_KeyBoard.cb == NULL)
  HIDP_Machine = &HID_Mouse;
  else
    HIDP_Machine = &HID_KeyBoard;
  HIDP_Machine->state = HID_SYNC;
  
case HID_SYNC:

  /* Sync with start of Even Frame */
  if (USB_OTG_IsEvenFrame(pdev) != FALSE)
  {
  HIDP_Machine->state = HID_GET_DATA;  
  }
  break;
  
case HID_GET_DATA:

  USBH_InterruptReceiveData(pdev,
HIDP_Machine->buff,
HIDP_Machine->length,
   HIDP_Machine->hc_num_in);
  HIDP_Machine->start_toggle = 1;
  
  HIDP_Machine->state = HID_POLL;
  HIDP_Machine->timer = HCD_GetCurrentFrame(pdev);
//  if(HIDP_Machine == &HID_Mouse) HID_Mouse.cb->Init();
//  if(HIDP_Machine == &HID_KeyBoard) HID_KeyBoard.cb->Init();
  break;
  
case HID_POLL:
//SysTick_Delayms(1);
  if(( HCD_GetCurrentFrame(pdev) - HIDP_Machine->timer) >= HIDP_Machine->poll)
  {
if (HIDP_Machine == &HID_KeyBoard && HID_Mouse.cb != NULL)
HIDP_Machine = &HID_Mouse;
  else if (HIDP_Machine == &HID_Mouse && HID_KeyBoard.cb != NULL)
HIDP_Machine = &HID_KeyBoard;
  HIDP_Machine->state = HID_GET_DATA;
  }
  else if(HCD_GetURB_State(pdev , HIDP_Machine->hc_num_in) == URB_DONE)
  {
if(HIDP_Machine->start_toggle == 1) /* handle data once */
{
   HIDP_Machine->start_toggle = 0;
   HIDP_Machine->cb->Decode(HIDP_Machine->buff);//data is decoded here
}
  }
  else if(HCD_GetURB_State(pdev, HIDP_Machine->hc_num_in) == URB_STALL) /* IN Endpoint Stalled */
  {

/* Issue Clear Feature on interrupt IN endpoint */
if( (USBH_ClrFeature(pdev,
pphost,
HIDP_Machine->ep_addr,
HIDP_Machine->hc_num_in)) == USBH_OK)
{
/* Change state to issue next IN token */
HIDP_Machine->state = HID_GET_DATA;
}

  }  
  break;
  
default:
  break;
}
return status;
}


/**
* @brief  USBH_Get_HID_ReportDescriptor
*         Issue report Descriptor command to the device. Once the response
*         received, parse the report descriptor and update the status.
* @param  pdev   : Selected device
* @param  Length : HID Report Descriptor Length
* @retval USBH_Status : Response for USB HID Get Report Descriptor Request
*/
static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
                                                  USBH_HOST *phost,
                                                  uint16_t length)
{

  USBH_Status status;

  status = USBH_GetDescriptor(pdev,
                              phost,
                              USB_REQ_RECIPIENT_INTERFACE
                                | USB_REQ_TYPE_STANDARD,                                 
                                USB_DESC_HID_REPORT,
                                pdev->host.Rx_Buffer,
                                length);

  /* HID report descriptor is available in pdev->host.Rx_Buffer.
  In case of USB Boot Mode devices for In report handling ,
  HID report descriptor parsing is not required.
  In case, for supporting Non-Boot Protocol devices and output reports,
  user may parse the report descriptor*/


  return status;
}

/**
* @brief  USBH_Get_HID_Descriptor
*         Issue HID Descriptor command to the device. Once the response
*         received, parse the report descriptor and update the status.
* @param  pdev   : Selected device
* @param  Length : HID Descriptor Length
* @retval USBH_Status : Response for USB HID Get Report Descriptor Request
*/
static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,
                                            USBH_HOST *phost,
                                            uint16_t length)
{

  USBH_Status status;

  status = USBH_GetDescriptor(pdev,
                              phost,
                              USB_REQ_RECIPIENT_INTERFACE
                                | USB_REQ_TYPE_STANDARD,                                 
                                USB_DESC_HID,
                                pdev->host.Rx_Buffer,
                                length);

  return status;
}

/**
* @brief  USBH_Set_Idle
*         Set Idle State.
* @param  pdev: Selected device
* @param  duration: Duration for HID Idle request
* @param  reportID : Targetted report ID for Set Idle request
* @retval USBH_Status : Response for USB Set Idle request
*/
static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
                                  USBH_HOST *phost,
                                  uint8_t duration,
                                  uint8_t reportId)
{

  phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
    USB_REQ_TYPE_CLASS;


  phost->Control.setup.b.bRequest = USB_HID_SET_IDLE;
  phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId;

  phost->Control.setup.b.wIndex.w = 0;
  phost->Control.setup.b.wLength.w = 0;

  return USBH_CtlReq(pdev, phost, 0 , 0 );
}


/**
* @brief  USBH_Set_Report
*         Issues Set Report
* @param  pdev: Selected device
* @param  reportType  : Report type to be sent
* @param  reportID    : Targetted report ID for Set Report request
* @param  reportLen   : Length of data report to be send
* @param  reportBuff  : Report Buffer
* @retval USBH_Status : Response for USB Set Idle request
*/
USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pdev,
                                 USBH_HOST *phost,
                                    uint8_t reportType,
                                    uint8_t reportId,
                                    uint8_t reportLen,
                                    uint8_t* reportBuff)
{

  phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
    USB_REQ_TYPE_CLASS;


  phost->Control.setup.b.bRequest = USB_HID_SET_REPORT;
  phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;

  phost->Control.setup.b.wIndex.w = 0;
  phost->Control.setup.b.wLength.w = reportLen;

  return USBH_CtlReq(pdev, phost, reportBuff , reportLen );
}


/**
* @brief  USBH_Set_Protocol
*         Set protocol State.
* @param  pdev: Selected device
* @param  protocol : Set Protocol for HID : boot/report protocol
* @retval USBH_Status : Response for USB Set Protocol request
*/
static USBH_Status USBH_Set_Protocol(USB_OTG_CORE_HANDLE *pdev,
                                     USBH_HOST *phost,
                                     uint8_t protocol)
{


  phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
    USB_REQ_TYPE_CLASS;


  phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL;

  if(protocol != 0)
  {
    /* Boot Protocol */
    phost->Control.setup.b.wValue.w = 0;
  }
  else
  {
    /*Report Protocol*/
    phost->Control.setup.b.wValue.w = 1;
  }

  phost->Control.setup.b.wIndex.w = 0;
  phost->Control.setup.b.wLength.w = 0;

  return USBH_CtlReq(pdev, phost, 0 , 0 );

}

/**
* @brief  USBH_ParseHIDDesc
*         This function Parse the HID descriptor
* @param  buf: Buffer where the source descriptor is available
* @retval None
*/
static void  USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf)
{

  desc->bLength                  = *(uint8_t  *) (buf + 0);
  desc->bDescriptorType          = *(uint8_t  *) (buf + 1);
  desc->bcdHID                   =  LE16  (buf + 2);
  desc->bCountryCode             = *(uint8_t  *) (buf + 4);
  desc->bNumDescriptors          = *(uint8_t  *) (buf + 5);
  desc->bReportDescriptorType    = *(uint8_t  *) (buf + 6);
  desc->wItemLength              =  LE16  (buf + 7);

}
/**
* @}
*/

/**
* @}
*/

/**
* @}
*/


/**
* @}
*/


/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:79352 发表于 2015-7-12 14:28 | 只看该作者
来向大神学习学习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表