原创 USB的“JoyStickMouse”源代码分析02

2010-4-23 21:20 4821 12 12 分类: MCU/ 嵌入式

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

 


二、USB函数库分析


3usb_mem.husb_mem.c


1usb_mem.h


这个头文件很简单,只声明了两个函数,供其它源文件使用。


void UserToPMABufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); 用户数据复制到端点对应的USB包缓冲区。


void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes);


2usb_mem.c


上述两个函数的实现。我这里将详细分析一个函数的代码。


void UserToPMABufferCopy(


u8 *pbUsrBuf,  //用户提供的数据缓冲区指针。


 u16 wPMABufAddr, //端点地址,这是包缓冲区内相对地址


 u16 wNBytes) //本次复制的字节数


{


  u32 n = (wNBytes + 1) >> 1;   /*用户提供的是字节个数,而包缓冲区每次处理一个字、两个字节,这里是进行转换,+1的目的是防止用户给出奇数。比如用户参数为9,则实际需要5个字 */


  u32 i, temp1, temp2;


  u16 *pdwVal;


  pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr); // wPMABufAddr实际是端点描述符表寄存器里对应的相对地址,两个字节对齐。而stm32内部实际是4个字节对齐。举个例子:端点0描述附表,在包缓冲区相对偏移0起始,占据8字节,分别为“0018,00080058,<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />00000-1字节存储发送缓冲区的相对地址,第4-5字节存储接收缓冲区的相对地址。


比如现在要将接收缓冲区的内容复制到用户缓冲区,首先要取得这个“0058”数值,获取的方法是 缓冲区相对偏移RxADDR =0058 = *u16*)(包缓冲区起始地址 + 4*2。这里4*2的意思是“0058”的相对偏移实际是第8个字节,而不是相对的偏移4字节。


然后获取接收缓冲区实际地址。 缓冲区实际地址 = 缓冲区起始地址 + 0058*2。这里乘以2的意思跟上述是一样的。


  for (i = n; i != 0; i--)


  {


    temp1 = (u16) * pbUsrBuf; //取得低字节


    pbUsrBuf++; //指向高字节


    temp2 = temp1 | (u16) * pbUsrBuf << 8; //高低组合成一个字


    *pdwVal++ = temp2; //写入包缓冲区的发送缓冲区。


    pdwVal++; //四字节对齐,跳过两个字节


    pbUsrBuf++; //指向下一个字节。


  }


}


 


4usb_init.cusb_init.h


1usb_init.h


主要是声明了函数ust_init()。


声明了一些外部变量。


extern USER_STANDARD_REQUESTS *pUser_Standard_Requests;


//有几个很重要的指针,在这个文件里作外部声明。


extern u16  SaveState ;


extern u16 wInterrupt_Mask;


3usb_init.c


DEVICE_INFO       Device_Info;//这个最重要的设备信息机构体在这里定义。


函数实现:


void USB_Init(void)


{


  pInformation = &Device_Info;  // pInformation是在usb控制传输处理核心usb_core.c中最重要的指针。


  pInformation->ControlState = 2; //2实际上代表IN_DATA状态,实际我觉得设置为0最好,代表WAIT_SETUP状态。


  pProperty = &Device_Property;  //这个结构体由用户提供,是一个函数指针结构体,大部分成员都是上层协议需要实现的操作函数。


  pUser_Standard_Requests = &User_Standard_Requests; //这个结构体跟上一个类似,主要是用户对标准请求的实现。


  /* Initialize devices one by one */


  pProperty->Init(); //调用用户提供的初始化函数。


}


 


5usb_int.cusb_int.h


1usb_int.h


主要是声明了函数void CTR_LP(void),这是数据传输完成处理的核心处理部分。


2usb_int.c


这个文件主要是实现了函数void CTR_LP(void)


 


开头:


u16 SaveRState;


u16 SaveTState; //这是中断处理时用于保存当时端点的状态


extern void (*pEpInt_IN[7])(void);    /*  Handles IN  interrupts   */


extern void (*pEpInt_OUT[7])(void);   /*  Handles OUT interrupts   */


这两个函数指针数组的定义在用户层usb_prop.c文件中。


 


void CTR_LP(void)


{


  u32 wEPVal = 0;


  while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)


  {


    _SetISTR((u16)CLR_CTR); /* clear CTR flag */


    EPindex = (u8)(wIstr & ISTR_EP_ID); //获取发生中断的端点号,分成0和非0端点两种情况。


    if (EPindex == 0)


    {


      SaveRState = _GetEPRxStatus(ENDP0);


      SaveTState = _GetEPTxStatus(ENDP0);


      _SetEPRxStatus(ENDP0, EP_RX_NAK);


      _SetEPTxStatus(ENDP0, EP_TX_NAK);


 


      if ((wIstr & ISTR_DIR) == 0)


      {


        _ClearEP_CTR_TX(ENDP0);


        In0_Process();   //取得方向标志,如果为0表示主机要“IN”数据。调用In0_Process()来处理。


          _SetEPRxStatus(ENDP0, SaveRState);


          _SetEPTxStatus(ENDP0, SaveTState);


          return;


      }


      Else  //DIR==1,有两种情况,可能是主要要“OUT”,也可能是在“SETUP”。


      {


        wEPVal = _GetENDPOINT(ENDP0);


        if ((wEPVal &EP_SETUP) != 0) //SETUP的情况


        {


          _ClearEP_CTR_RX(ENDP0);


          Setup0_Process(); //调用这个函数处理控制传输过程,这个函数的理解是理解USB工作最关键的。大部分usb_core.c文件里面的函数都是为它服务的。


          _SetEPRxStatus(ENDP0, SaveRState);


          _SetEPTxStatus(ENDP0, SaveTState);


          return;


        }


 


        else if ((wEPVal & EP_CTR_RX) != 0)//OUT的情况


        {


          _ClearEP_CTR_RX(ENDP0);


          Out0_Process(); //调用这个函数处理用户输出。


          _SetEPRxStatus(ENDP0, SaveRState);


          _SetEPTxStatus(ENDP0, SaveTState);


          return;


        }


      }


    }/* if(EPindex == 0) */


    Else  //这是非0端点的处理。在JoyStickMouse例程中几乎没什么作用。就是一个空架子。


    {


      wEPVal = _GetENDPOINT(EPindex);


      if ((wEPVal & EP_CTR_RX) != 0)


      {


        _ClearEP_CTR_RX(EPindex);


        (*pEpInt_OUT[EPindex-1])();


 


      } /* if((wEPVal & EP_CTR_RX) */


 


      if ((wEPVal & EP_CTR_TX) != 0)


      {


        _ClearEP_CTR_TX(EPindex);


        (*pEpInt_IN[EPindex-1])();


      } /* if((wEPVal & EP_CTR_TX) != 0) */


    }/* if(EPindex == 0) else */


  }/* while(...) */


}


 


6usb_def.h


主要是定义了与USB标志请求相关的一些常量。


typedef enum _RECIPIENT_TYPE


{


  DEVICE_RECIPIENT,     /* Recipient device */


  INTERFACE_RECIPIENT,  /* Recipient interface */


  ENDPOINT_RECIPIENT,   /* Recipient endpoint */


  OTHER_RECIPIENT


} RECIPIENT_TYPE;//请求发往的对象,可以是设备、接口、端点以及其它(这个需要用户特别实现)。


 


typedef enum _STANDARD_REQUESTS


{


  GET_STATUS = 0, //这个可以发给设备、接口和端点。


  CLEAR_FEATURE, //这个可以发给设备、接口和端点


  RESERVED1,


  SET_FEATURE, //这个可以发给设备、接口和端点


  RESERVED2,


  SET_ADDRESS,


  GET_DESCRIPTOR,//其余的全部都是发往设备处理。


  SET_DESCRIPTOR,


  GET_CONFIGURATION,


  SET_CONFIGURATION,


  GET_INTERFACE,//这个发往接口


  SET_INTERFACE,//这个也是发往接口。


  TOTAL_sREQUEST,  /* Total number of Standard request */


  SYNCH_FRAME = 12


} STANDARD_REQUESTS; //标志请求总共13种,USB实现11种。


 


typedef enum _DESCRIPTOR_TYPE


{


  DEVICE_DESCRIPTOR = 1,


  CONFIG_DESCRIPTOR,


  STRING_DESCRIPTOR,


  INTERFACE_DESCRIPTOR,


  ENDPOINT_DESCRIPTOR


} DESCRIPTOR_TYPE;  //描述符类型,这里都是标志描述符,类特殊描述符由用户程序支持。


typedef enum _FEATURE_SELECTOR


{


  ENDPOINT_STALL,


  DEVICE_REMOTE_WAKEUP


} FEATURE_SELECTOR;//这个是可以设置的特性,Get_Feature()和Set_Feature()请求所用。


 


#define REQUEST_TYPE      0x60  /* 请求发送方屏蔽位,可能是标准请求、类请求和厂商请求。 */


#define STANDARD_REQUEST  0x00  /* Standard request */


#define CLASS_REQUEST     0x20  /* Class request */


#define VENDOR_REQUEST    0x40  /* Vendor request */


 


#define RECIPIENT         0x1F  /* 请求接收对象的屏蔽位 */


 


 


7usb_core.h


一些核心处理结构体就是在这个头文件中定义的。


typedef enum _CONTROL_STATE


{


  WAIT_SETUP,       /* 0 */初始状态是等待SETUP


  SETTING_UP,       /* 1 */收到SETUP后是建立中


  IN_DATA,          /* 2 */


  OUT_DATA,         /* 3 */


  LAST_IN_DATA,     /* 4 */


  LAST_OUT_DATA,    /* 5 */


  WAIT_STATUS_IN,   /* 7 */数据阶段是OUT,则状态阶段主机发IN


  WAIT_STATUS_OUT,  /* 8 */


  STALLED,          /* 9 */用户请求不支持,等待下一个SETUP


  PAUSE             /* 10 */这个可能表示出错了。


} CONTROL_STATE;    /* 控制传输阶段对主机信号的处理,是以状态机类似的处理方式,这个就是设备可能的状态。*/


 


typedef struct _ENDPOINT_INFO


{//端点传输信息结构体,前面本来有一段很长的英文注释,重点讲解CopyData的作用。实际它不是用于复制的,主要是指明数据长度、返回数据缓冲指针的。


  u16  Usb_wLength; //还有多少数据需要操作。


  u16  Usb_wOffset; //当前数据缓冲的偏移


  u16  PacketSize; //端点支持的包长度。


  u8   *(*CopyData)(u16 Length); //这是一个函数指针定义。


}ENDPOINT_INFO;


 


typedef struct _DEVICE_INFO


{


  u8 USBbmRequestType;       /* bmRequestType */


  u8 USBbRequest;            /* bRequest */


  u16_u8 USBwValues;         /* wValue */


  u16_u8 USBwIndexs;         /* wIndex */


  u16_u8 USBwLengths;        /* wLength */


以上部分从SETUP包后面跟的数据包中获得。


  u8 ControlState;           /* of type CONTROL_STATE */


  u8 Current_Feature;


  u8 Current_Configuration;   /* Selected configuration */


  u8 Current_Interface;    /* Selected interface of current configuration


  u8 Current_AlternateSetting;/ */


 


  ENDPOINT_INFO Ctrl_Info;


}DEVICE_INFO;


这个就是控制传输最重要的结构体定义。


 


typedef struct _DEVICE_PROP


{


  void (*Init)(void);        /* Initialize the device */


  void (*Reset)(void);       /* Reset routine of this device */


 


  void (*Process_Status_IN)(void);


  void (*Process_Status_OUT)(void);//用户对状态过程的特殊处理


  RESULT (*Class_Data_Setup)(u8 RequestNo);


  RESULT (*Class_NoData_Setup)(u8 RequestNo); //有些类特殊请求,usb_core.c并不会支持,而交由上层用户处理。


  RESULT(*Class_Get_Interface_Setting)(u8 Interface,u8 lternateSetting);


 


  u8* (*GetDeviceDescriptor)(u16 Length);


  u8* (*GetConfigDescriptor)(u16 Length);


  u8* (*GetStringDescriptor)(u16 Length);  //描述符都是与具体功能设备相关的,上层用户要提供给底层“usb_core.c”统一的操作模式


  u8* RxEP_buffer;


  u8 MaxPacketSize;


}DEVICE_PROP;


 


 


对四个最重要函数的声明:


u8 Setup0_Process(void);


u8 Post0_Process(void);


u8 Out0_Process(void);


u8 In0_Process(void);


 


对四个最重要结构体的声明:


extern DEVICE_PROP Device_Property;


extern  USER_STANDARD_REQUESTS User_Standard_Requests;


extern  DEVICE  Device_Table;


extern DEVICE_INFO Device_Info;


这四个结构体前三个由用户定义和实现,第四个结构体由“usb_init.c”定义和初始化,主要在“usb_core.c”中起作用。


 


 


今天的分析就先到这儿,明天再详细分析一下“usb_core.c”。


 


 


 

文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /2 下一条