#include "USB.h"
#include <MC9S08JM60.h>  //映像寄存器地址头文件

static INT16U RxFlag;

/*****************************************************************************
 * Module variables.
 *****************************************************************************/
static volatile INT8U usb_current_config;
static volatile INT8U usb_state;
static volatile INT8U new_address;
static ep_info_t ep_info[NO_OF_HW_EP];

/*****************************************************************************
 * Function definitions.
 *****************************************************************************/
//字符串描述符
const INT8U string_descriptor0[4] = {4, 0x3, 0x09, 0x04 };
//供应商字符串描述符
const INT8U str_manufacturer[26] = { 
                                26, 0x3, 'C',0, 'M',0, 'X',0, 
                                ' ',0, 'S',0, 'y',0, 's',0, 
                                't',0, 'e',0, 'm',0, 's',0, 
                                ' ',0
                              };
//配置字符串描述符
const INT8U str_config[44] = { 
                          44, 0x3, 'D',0, 'e',0, 'f',0, 
                          'a',0, 'u',0, 'l',0, 't',0, 
                          ' ',0, 'c',0, 'o',0, 'n',0, 
                          'f',0, 'i',0, 'g',0, 'u',0, 
                          'r',0, 'a',0, 't',0, 'i',0, 
                          'o',0, 'n',0
                        };
//接口字符串描述符                        
const INT8U str_interface1[8] = { 
                             8, 0x3, 'C',0, 'D',0, 'C',0 
                           };
                           
const INT8U str_interface2[18] = { 
                            18, 0x3, 'C',0, 'D',0, 'C',0,
                            '-',0, 'D',0, 'a',0, 't',0,
                            'a',0
                            };
//设备序列号字符串描述符
const INT8U str_serail_number[10] = {
                            10, 0x3, 'V',0, '0',0, '.',0,
                            '1',0
                            };

//产品字符串描述符
const INT8U str_product[16] = { 
	                       16,0x03,'S',0,'U',0,'D',0,
	                       'A',0,'U',0,'S',0,'B',0
	                     };                            

const INT8U * const usb_string_descriptors[USB_NO_OF_STRING_DESC] = 
{
  string_descriptor0, 
  str_manufacturer,          //供应商字符串描述符,索引值=1 
  str_product,               //产品字符串描述符,索引值=2
  str_serail_number,         //设备序列号字符串描述符,索引值=3
  str_config,                //配置字符串描述符,索引值=4
  str_interface1,            //接口1字符串描述符,索引值=5
  str_interface2             //接口2字符串描述符,索引值=6
};

//设备描述符
const INT8U usb_device_descriptor[18] = {
    0x12, //bLength域，描述符的长度：18字节
    0x01, //bDescriptorType域，描述符类型（01H---表示本描述符为设备描述符）
    0x01,0x01, //bcdUSB域，符合USB1.1规范
    0x02, //bDeviceClass域，设备类
    0x00, //bDeviceSubClass域，设备子类
    0x00, //bDeviceProtocol域，设备协议（0表示不使用任何设备类协议）
    0x08, //bMaxPacketSize0域，端点0所支持的最大数据包长度高速8字节）  //-*USB1.1低速设备*-//
    0x00,0x15, //idVendor域，供应商ID（VID）
    0x20,0x00, //idProduct域，产品ID（PID）
    0x00,0x00, //bcdDevice域，设备版本号
    0x00, //iManufacturer域，供应商的字符串描述符索引
    0x00, //iProduct域，产品的字符串描述符索引
    0x00, //iSerialNumber域，设备序号的字符串描述符索引
    0x01  //bNumConfigurations域，该USB设备支持的配置数目为：1
};

//配置描述符
INT8U usb_config_descriptor[9+9+5+4+5+5+7+9+7+7] = {
    //配置描述符9字节-------------------------------------------------------
    //uin8 Configuration_Descriptor[9] = {
    //USB_FILL_CFG_DESC(9+9+5+4+5+5+7+9+7+7, 2, 1, 4, CFGD_ATTR_SELF_PWR, 0),
    0x09, //bLength域，配置描述符的长度：9字节
    0x02, //bDescriptorType域，（02H---表示本描述符为配置描述符）
    0x43,0x00, //wTotalLength域，配置信息的总长度，包括配置、接口和端点
    0x02, //bNumInterfaces域，该配置所支持的接口数，至少一个数据接口
    0x01, //bConfigurationValue域，配置值 
    0x04, //iConfiguration域，配置的字符串描述符索引
    0x40, //bmAttibutes域，配置的属性(具有总线供电、自供电及过程唤醒的特性) 
          //位7：1，必须为1，位6：0，自供电，位5：0，不支持远程唤醒
    0x00, //MaxPower域，设备从总线提取的最大电流以2mA为单位。该例中：50*2mA＝100mA
    //接口描述符9字节-------------------------------------------------------
    //USB_FILL_IFC_DESC(0, 0, 1, 2, 2, 1, 5),
    0x09, //bLength域，接口描述符长度：9
    0x04, //bDescriptorType域，（04H---表示本描述符为接口描述符）
    0x00, //bInterfaceNumber域，接口号
    0x00, //bAlternateSetting域，接口的可替换设置值
    0x01, //bNumEndpoints域，接口使用的端点数（除端点0）：2
    0x02, //bInterfaceClass域，接口所属的USB设备类（0xFF：供应商自定义）
    0x02, //bInterfaceSubClass域，接口所属的USB设备子类（0xFF：供应商自定义）
    0x01, //bInterfaceProtocol域，接口采用的USB设备类协议（0xFF：供应商自定义）
    0x05,  //iInterface域，接口字符串描述符的索引
    //
    0x05,
    0x24,
    0x00,
    0x10,
    0x01,
    //
    0x05,
    0x24,
    0x01,
    0x00,
    0x01,
    //
    0x04,
    0x24,
    0x02,
    0x00,
    //
    0x05,
    0x24,
    0x06,
    0x00,
    //
    0x01,
    //端点1描述符7字节------------------------------------------------------
    //uint8 endpoint_descriptor1[7] = { //IN端点描述符
    //USB_FILL_EP_DESC(0x1, EPD_DIR_TX, EPD_ATTR_INT, EP1_PACKET_SIZE, 0x2),
    0x07, //bLength域，端点描述符长度
    0x05, //bDescriptorType域，（05H---表示本描述符为端点描述符） 
    0x81, //bEndpointAddress域，端点1(IN)
    0x03, //bmAttributes域，0为控制传输，1为同步传输，2为块传输，3为中断传输
    0x20,0x00, //wMaxPacketSize域，端点支持最大数据包长度：32字节
    0x02, //bInterval域，轮询间隔，以ms为单位。    
    //接口描述符9字节-------------------------------------------------------
    //uint8 interface_descriptor[9] = {
    //USB_FILL_IFC_DESC(1, 0, 2, 10, 0, 0x0, 6),
    0x09, //bLength域，接口描述符长度：9
    0x04, //bDescriptorType域，（04H---表示本描述符为接口描述符）
    0x01, //bInterfaceNumber域，接口号
    0x00, //bAlternateSetting域，接口的可替换设置值
    0x02, //bNumEndpoints域，接口使用的端点数（除端点0）：2
    0x0A, //bInterfaceClass域，接口所属的USB设备类（0xFF：供应商自定义）
    0x00, //bInterfaceSubClass域，接口所属的USB设备子类（0xFF：供应商自定义）
    0x00, //bInterfaceProtocol域，接口采用的USB设备类协议（0xFF：供应商自定义）
    0x06,  //iInterface域，接口字符串描述符的索引
    
    //端点2描述符7字节------------------------------------------------------
    //uint8 endpoint_descriptor2[7] = { //IN端点描述符
    //USB_FILL_EP_DESC(0x2, EPD_DIR_TX, EPD_ATTR_BULK, EP2_PACKET_SIZE, 0x0),
    0x07, //bLength域，端点描述符长度
    0x05, //bDescriptorType域，（05H---表示本描述符为端点描述符） 
    0x82, //bEndpointAddress域，端点2(IN)
    0x02, //bmAttributes域，0为控制传输，1为同步传输，2为块传输，3为中断传输
    0x40,0x00, //wMaxPacketSize域，端点支持最大数据包长度：64字节
    0x00, //bInterval域，轮询间隔，以ms为单位。
    
    //端点3描述符7字节-------------------------------------------------------
    //uint8 endpoint_descriptor3[7] = { //OUT端点描述符
    //USB_FILL_EP_DESC(0x3, EPD_DIR_RX, EPD_ATTR_BULK, EP3_PACKET_SIZE, 0x0)
    0x07, //bLength域，端点描述符长度
    0x05, //bDescriptorType域，（05H---表示本描述符为端点描述符）
    0x03, //bEndpointAddress域，端点3(OUT)
    0x02, //bmAttributes域，0为控制传输，1为同步传输，2为块传输，3为中断传输
    0x40,0x00, //wMaxPacketSize域，端点支持最大数据包长度：64字节
    0x00  //bInterval域，轮询间隔，以ms为单位。
};
//-------------------------------------------------------------------------*
//函数名: USBInit                                                          *
//功  能: USB模块初始                                                      *
//参  数: 无                                                               *
//返  回: 成功返回0，不成功返回非0                                         *
//内部调用: usb_default                                                    *
//说  明: 先将MCF_USB_OTG_CTRL.DP位拉低,退出前再将该位拉高,这样才能在总线的*
//        D+,D-线上状态产生变化,主机才能识别到该USB设备                    *
//-------------------------------------------------------------------------*
INT8U USBInit(void)
{
  //检查设备ID,JM60的ID为0x04
  if (PERID != 0x04)
  {
    //未知USB设备
    return(1);
  }
  
  //PERID为设备ID寄存器,IDCOMP为(~设备ID)寄存器
  if (PERID != (INT8U) ~IDCOMP)
  {
    return(1);
  }
  
  // 复位USB模块。
  //USBCTL0寄存器的USBRESET置1
  USBCTL0_USBRESET = 1;
  
  //复位完成时USBRESET被置0
  while (USBCTL0_USBRESET)
    ;

  //使能设备，设备上电3.3V
  USBCTL0 = USBCTL0_USBPHYEN_MASK | USBCTL0_USBVREN_MASK;


  //清除除了复位以外的所有中断标志位
  INTSTAT = ~INTSTAT_USBRSTF_MASK;
  
  //禁止错误中断  
  ERRENB=0;
  
  //使能USB复位中断标志
  INTENB_USBRST=1;
  
  //使能USB模块
  CTL_USBEN=1;
  
  //使能上拉电阻
  USBCTL0_USBPU=1;
  
  //置USB未准备完成标志
  RxFlag = usb_unready;  
  return(0);
}

//-------------------------------------------------------------------------*
//函数名: USBReceiveData                                                   *
//功  能: USB数据发送                                                      *
//参  数: ep:  端点号                                                      *
//        * data:  待发数据地址                                            *
//返  回: 整型，所接受数据长度                                             *
//内部调用: USBReceive                                                     *
//说  明:USB Receive data ,max length = 63                                 *
//-------------------------------------------------------------------------*
INT8U USBReceiveData(INT8U ep,INT8U* data)
{
    return USBReceive(ep,data,64);
}

//-------------------------------------------------------------------------*
//函数名: USBSendData                                                      *
//功  能: USB发送数据                                                      *
//参  数:                                                                  *
//      ep:  端点号                                                        *                                                             *
//      * data:  数据缓冲区                                                *
//      length:  准备发送的字节数                                          *
//返  回: 无                                                               *
//内部调用: USBSend                                                        *
//说  明: USB Send Data ,max length = 63                                   *
//-------------------------------------------------------------------------*
void USBSendData(INT8U ep,INT8U* data,INT8U length)
{
    USBSend(ep,(void *)0,data,length,length);
}

//-------------------------------------------------------------------------*
//函数名: USBDefault                                                       *
//功  能: 使USB模块进入默认状态                                            *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: USBSetupEp, USBSetConfig                                       *
//说  明: 只对端点0进行配置,禁止其它端点                                   *
//-------------------------------------------------------------------------*
static void USBDefault(void)
{
  //配置端点0
  (void)USBSetupEp(0, EP_TYPE_CONTROL, 0, EP0_PACKET_SIZE);
  //关闭其他端点
  USBSetConfig(0);

  //设置地址为默认地址
  ADDR = 0;

  while(INTSTAT_TOKDNEF )         
        INTSTAT = 0xff;  
  usb_state=USBST_DEFAULT;
  new_address=0;
  
  //使能部分中断
  INTENB = INTENB_USBRST_MASK| INTENB_TOKDNE_MASK | INTENB_SLEEP_MASK;  
}
     
//-------------------------------------------------------------------------*
//函数名: USBSetupEp                                                       *
//功  能: 设置端点                                                         *
//参  数: addr: 端点地址;type: 端点传输类型                                *
//        ep  : 端点号  ;psize: 端点传输的数据字节数                       *
//返  回: 0                                                                *
//内部调用: disable_ep_tx, disable_ep_rx, ready_ep_rx                      *
//说  明: 对指定的端点进行配置,将端点信息写入缓冲区描述符表及端点控制寄存器*
//-------------------------------------------------------------------------*
static INT8U USBSetupEp(INT8U addr, INT8U type, INT8U ep, INT16U psize)
{ 
  //如果以下几种有失败的，则需重新定义正确的端点
  CMX_ASSERT(ep < NO_OF_HW_EP);
  CMX_ASSERT((addr & (INT8U)~DIR_TX) < 0x10);
  CMX_ASSERT(psize <= 0xff);
   
  //关闭端点ep
  EPCTL[ep] = 0;

  if (ep_info[ep].state!=EPST_IDLE)
  {
    ep_info[ep].error=USBEPERR_HOST_ABORT;
  }
  else
  {
    ep_info[ep].error=USBEPERR_NONE;
  }

  ep_info[ep].state=EPST_IDLE;
  ep_info[ep].flags=0;
  ep_info[ep].data_func=(void*)0;
  ep_info[ep].address=0;
  ep_info[ep].tlength=0;
  ep_info[ep].maxlength=0;
  ep_info[ep].psize=psize;
  if (type == EP_TYPE_DISABLE)
  {
    return(0);
  }

  //配置端点0的TX BDT和RX BDT
  if (ep==0) 
  {
    //配置TX(IN)BDT
    BDT_ADDR(0)=(INT8U)(BDT_END>>2);
    BDT_LENGTH(0)=(INT8U)psize;    
    BDT_CTRL(0) = 0;
    //配置RX(OUT)BDT
    BDT_ADDR(1)=(INT8U)(ALIGN_RAM_BUF(BDT_END+psize)>>2);
    BDT_LENGTH(1)=(INT8U)psize;
    BDT_CTRL(1) = BDT_CTRL_OWN | BDT_CTRL_DTS;
    
    EPCTL[0]=EPCTL0_EPRXEN_MASK | EPCTL0_EPTXEN_MASK | EPCTL0_EPHSHK_MASK;
    //清除CTL_TSUSPEND，允许SIE继续令牌处理
    CTL_TSUSPEND=0;
    
  } 
  else 
  { 
    //非端点0的单缓冲区的端点配置
    INT8U ram_ofs;
    
    //获得下一个空的USB RAM的地址。读先前端点的BDT的值
    ram_ofs=(INT8U)(ALIGN_RAM_BUF((BDT_ADDR(ep)<<2)+BDT_LENGTH(ep)));
    
    //配置错误。使用一较小的包或移除一些端点
    CMX_ASSERT(ram_ofs+psize < EP_RAM_SIZE);
  
    BDT_ADDR(ep+1)=(INT8U)(ram_ofs>>2);
    BDT_LENGTH(ep+1)=(INT8U)psize;
    BDT_CTRL(ep+1)=0;
    if (addr & DIR_TX) 
    {
      EPCTL[ep]=EPCTL0_EPTXEN_MASK | EPCTL0_EPHSHK_MASK;
    }
    else 
    {
      EPCTL[ep]=EPCTL0_EPRXEN_MASK | EPCTL0_EPHSHK_MASK;
    }
  }
  return(0);
}

//-------------------------------------------------------------------------*
//函数名: USBSetConfig                                                     *
//功  能: 完成配置描述符配置                                               *
//参  数: cfg_index: 配置描述符索引                                        *
//返  回: 无                                                               *
//内部调用: GetEpDescriptor, USBSetupEp                                  *
//说  明: 对配置描述符中接口支持的所有端点进行配置                         *
//        本例只支持一个配置描述符,一个接口描述符                          *
//-------------------------------------------------------------------------*
static void USBSetConfig(INT8U cfg_ndx)
{
  INT8U cfg_ep=1;

  //所有的端点将会使用缓冲区0
  CTL_ODDRST=1;

  usb_current_config=cfg_ndx;

  CTL_ODDRST=0;
    
  if (cfg_ndx != 0)
  {
    //将配置描述符中的所有接口配置完成(多接口描述符)
    INT8U ifc=0;
    while(is_ifc_ndx(cfg_ndx, ifc, 0))
    { 
      
      INT8U ifc_ep=0;
      //将接口描述符中的所有端点配置完成
      while(is_ep_ndx(cfg_ndx, ifc, 0, ifc_ep))
      {
        const INT8U *epd = GetEpDescriptor(cfg_ndx, ifc, 0, ifc_ep);
        (void)USBSetupEp(epd[2], epd[3], (INT8U)(epd[2] & 0x7fu), RD_LE16(&epd[4]));
        ifc_ep++;
        cfg_ep++;
      }
      ifc++;
    }
    usb_state = USBST_CONFIGURED;
    RxFlag    = usb_ready;
  }
  else
  {
    //控制传输下，禁止除0号端点以外的所有端点
    usb_state=USBST_ADDRESSED;
  }

  //禁止其它的端点
  while(cfg_ep < NO_OF_HW_EP)
  {
    (void)USBSetupEp(0, EP_TYPE_DISABLE, cfg_ep++, 0);
  }
}

//-------------------------------------------------------------------------*
//函数名: USBStop                                                          *
//功  能: 停止USB设备                                                      *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: USBSetupEp                                                     *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void USBStop(void)
{
  //取消上拉电阻
  USBCTL0_USBPU=0;

  //重启USB模块
  USBCTL0_USBRESET = 1;
  while (USBCTL0_USBRESET)
    ;
    
  //取消USB模块  
  CTL_USBEN=0;

  //取消USBPHY
  USBCTL0_USBPHYEN=0;

  //取消3.3V电压
  USBCTL0_USBVREN=0;

  EnterDefaultState();
  (void)USBSetupEp(0, EP_TYPE_DISABLE, 0, 0);
  usb_state=USBST_DISABLED;
}

//-------------------------------------------------------------------------*
//函数名: USBResetEvent                                                    *
//功  能: USB复位事件                                                      *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void USBResetEvent(void)
{
  //空
}

//-------------------------------------------------------------------------*
//函数名: USBBusErrorEvent                                                 *
//功  能: USB总线错误事件                                                  *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void USBBusErrorEvent(void)
{
  //空
}

//-------------------------------------------------------------------------*
//函数名: USBSuspendEvent                                                  *
//功  能: USB暂停事件                                                      *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void USBSuspendEvent(void)
{
  //空
}

//-------------------------------------------------------------------------*
//函数名: USBWakeupEvent                                                   *
//功  能: USB唤醒事件                                                      *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void USBWakeupEvent(void)
{
  //空
}





//-------------------------------------------------------------------------*
//函数名: GetDeviceDescriptor                                              *
//功  能: 获得设备描述符                                                   *
//参  数: 无                                                               *
//返  回: 设备描述符数组的首地址                                           *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void *GetDeviceDescriptor(void)
{
  return((void*)usb_device_descriptor);
}

INT8U is_cfgd_index(INT16U cndx)
{
  return((INT8U)(cndx == 1 ? 1 : 0));
} 

//-------------------------------------------------------------------------*
//函数名: GetCfgDescriptor                                                 *
//功  能: 获得配置描述符                                                   *
//参  数: cndx：配置描述符索引                                             *
//返  回: 配置描述符数组的首地址                                           *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void *GetCfgDescriptor(INT8U cndx)
{
  cndx++;
  return((void*)usb_config_descriptor);
}


INT8U is_str_index(INT8U sndx)
{
  return((INT8U)(sndx < (sizeof(usb_string_descriptors)/sizeof(usb_string_descriptors[0]) ? 1 : 0)));
}

//-------------------------------------------------------------------------*
//函数名: GetStrDescriptor                                                 *
//功  能: 获得字符串描述符                                                 *
//参  数: ndx：字符串描述符索引                                            *
//返  回: 字符串描述符数组的首地址                                         *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void *GetStrDescriptor(INT8U sndx)
{
  return((void*)(usb_string_descriptors[sndx]));
}


INT8U is_ifc_ndx(INT8U c, INT8U i, INT8U is)
{
  if (c==1 &&  is == 0)
  {
    if (i==0 || i==1)
    {
      return(1);
    }
  }
  return(0);
}

INT8U is_ep_ndx(INT8U c, INT8U i, INT8U is, INT8U ep)
{
  if (c==1 && is==0)
  {
    if (i==0 && ep < 1)
    {
      return(1);
    }
    if (i==1 && ep < 2)
    {
      return(1);
    }
  }
  return(0);
}

//-------------------------------------------------------------------------*
//函数名: GetEpDescriptor                                                  *
//功  能: 获得字符串描述符                                                 *
//参  数: c:                                                               *
//        i:                                                               *
//        is:                                                              *
//        ep:                                                              *
//返  回: 字符串描述符数组的首地址                                         *
//内部调用:                                                                *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void * GetEpDescriptor(INT8U c, INT8U i, INT8U is, INT8U ep)
{
  c++;
  is++;
  if (i == 0)
  {
    return((void*)(&usb_config_descriptor[9+9+5+5+4+5]));
  }
  if (i == 1)
  {
    if (ep==0)
    {
      return((void*)(&usb_config_descriptor[9+9+5+5+4+5+7+9]));
    }
    else
    {
      return((void*)(&usb_config_descriptor[9+9+5+5+4+5+7+9+7]));
    }
  }
  return((void *)0);
}

//-------------------------------------------------------------------------*
//函数名: usb_cfg_init                                                     *
//功  能: 初始化USB配置                                                    *
//参  数: 无                                                               *
//返  回:                                                                  *
//内部调用: USBInit                                                        *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
void usb_cfg_init(void)
{
  (void)USBInit();
}

//-------------------------------------------------------------------------*
//函数名: usb_ep0_callback                                                 *
//功  能: 端点0状态回调                                                    *
//参  数: 无                                                               *
//返  回: clbst_ok                                                         *
//内部调用: 无                                                             *
//说  明: 无                                                               *
//-------------------------------------------------------------------------*
callback_state_t usb_ep0_callback(void)
{

   return clbst_ok;
   
}

//-------------------------------------------------------------------------*
//函数名: usb_get_done                                                     *
//功  能: 返回发送完成的字节数                                             *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 发送完成的字节数                                                 *
//-------------------------------------------------------------------------*
INT32U usb_get_done(INT8U ep)
{
  return(ep_info[ep].maxlength-ep_info[ep].tlength);
}

//-------------------------------------------------------------------------*
//函数名: usb_ep_is_busy                                                   *
//功  能: 判断USB模块是否忙                                                *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 0:空闲,1:忙                                                      *
//-------------------------------------------------------------------------*
INT8U usb_ep_is_busy(INT8U ep)
{
  return(ep_info[ep].state != EPST_IDLE ? (INT8U)1 : (INT8U)0);
}

//-------------------------------------------------------------------------*
//函数名: usb_get_state                                                    *
//功  能: 取得USB模块的当前状态                                            *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: USB模块的当前状态                                                *
//-------------------------------------------------------------------------*
INT8U usb_get_state(void)
{
  return(usb_state);
}

/*****************************************************************************
 * Name:
 *   ep2bdtndx
 * In:
 *   ep: number of endpoint.
 * Out:
 *   Pointer to the packet buffer containing data of the last received packet.
 *
 * Description:
 *   Returns te number of bytes that are left of the transfer. If
 *   usb_ep_is_busy returns false, then the transfer was aborted either
 *   by the host or by the application.
 *****************************************************************************/
static INT8U ep2bdtndx(INT8U ep, INT8U dirodd) 
{
  INT8U ndx;
  
  switch(ep) 
  {
    case 0:
      if (dirodd)  /* dirodd holds endpoint direction now */
      {
        ndx=1;     /* EP0 rx */
      }
      else 
      {
        ndx=0;     /* EP0 tx */
      }
      break;
    case 1:        /* value of dirodd is not used */
    case 2:
    case 3:
    case 4:
      ndx=ep+1;
      break;
    default:
      CMX_ASSERT(0);
  }
  return(ndx);
}

//=====内部函数=============================================================
//-------------------------------------------------------------------------*
//函数名: USBGetRxBDTAddr                                                  *
//功  能: 取得端点刚接收到数据的缓冲区地址,即该端点的BD.ADR_RX             *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 端点接收缓冲区的地址                                             *
//说  明: 由于端点有两个接收缓冲区EVEN和ODD，所以还要根据MCF_USB_STAT.ODD位*
//        判断上一个接收到的数据是存放在ODD还是EVEN中                      *
//-------------------------------------------------------------------------*
INT8U* USBGetRxBDTAddr(INT8U ep)
{
  INT8U dirodd=0;

  if (ep==0)
  {
    dirodd=1;
  }
  
  return((INT8U *)(BDT_BASE+(BDT_ADDR(ep2bdtndx(ep, dirodd))<<2)));
}


//-------------------------------------------------------------------------*
//函数名: send_zero_packet                                                 *
//功  能: 控制OUT传输状态阶段的响应                                        *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 无                                                               *
//内部调用: ready_ep_tx                                                    *
//说  明: 发送0长度的数据包说明设备的状态是OK的                            *
//-------------------------------------------------------------------------*
static void send_zero_packet(INT8U ep)
{ 
  if (ep < 7)
  {
    BDT_LENGTH(ep)  = 0;    
  }
  else
  {
    BDT_LENGTH(ep2bdtndx(ep, STAT_ODD ? 1 : 0)) = 0;
  }
  ready_ep_tx(ep, 0);  
}

//-------------------------------------------------------------------------*
//函数名: EnterDefaultState                                                *
//功  能: 进入默认状态                                                     *                                                          *
//参  数: 无                                                               *
//返  回: 无                                                               *
//内部调用: USBSetupEp，USBSetConfig                                       *
//说  明: 配置USB驱动返回默认状态。在默认状态时，只响应默认管道的标准请求。*
//-------------------------------------------------------------------------*
static void EnterDefaultState(void)
{
  //配置端点0
  (void)USBSetupEp(0, EP_TYPE_CONTROL, 0, EP0_PACKET_SIZE);
  //取消其他所有端点
  USBSetConfig(0);

  //设置地址为默认地址
  ADDR = 0;

  while(INTSTAT_TOKDNEF )
        INTSTAT = 0xff;  
  usb_state=USBST_DEFAULT;
  new_address=0;
  
  //使能部分中断
  INTENB = INTENB_USBRST_MASK| INTENB_TOKDNE_MASK | INTENB_SLEEP_MASK;  
}

//-------------------------------------------------------------------------*
//函数名: usb_stop_ep_tx                                                   *
//功  能: 产生STALL握手包                                                  *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 无                                                               *
//内部调用: _irq_disable, _irq_restore                                     *
//说  明: 被STALL的端点将不再发送任何包,所有的IN请求被取消                 *
//-------------------------------------------------------------------------*
void usb_stop_ep_tx(INT8U ep)
{
  hcc_imask im=_irq_disable();

  if (EPCTL[ep] & EPCTL1_EPTXEN_MASK)
  {    
    EPCTL[ep] |= EPCTL1_EPSTALL;
  }

  _irq_restore(im);
}

//-------------------------------------------------------------------------*
//函数名: usb_stop_ep_rx                                                   *
//功  能: 产生STALL握手包                                                  *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 无                                                               *
//内部调用: _irq_disable, _irq_restore                                     *
//说  明: 被STALL的端点将不再接收任何包,所有的OUT请求被取消                *
//-------------------------------------------------------------------------*
void usb_stop_ep_rx(INT8U ep)
{
  hcc_imask im=_irq_disable();

  if (EPCTL[ep] & EPCTL1_EPRXEN_MASK)
  {    
    EPCTL[ep] |= EPCTL1_EPSTALL;
  }

  _irq_restore(im);
}

//-------------------------------------------------------------------------*
//函数名: ready_ep_tx                                                      *
//功  能: 准备好端点发送                                                   *
//参  数: ep:  端点号; buf: 缓冲区(EVEN/BDD)                               *
//返  回: 无                                                               *
//说  明: 修改该端点的BD,使得tx端点准备好发送                              *
//-------------------------------------------------------------------------*
static void ready_ep_tx(INT8U ep, INT8U buf)
{
  INT32U ndx=ep2bdtndx(ep, buf);
  BDT_CTRL(ndx) = BDT_CTRL_OWN | ep_info[ep].data0 | BDT_CTRL_DTS;
}

//-------------------------------------------------------------------------*
//函数名: ready_ep_rx                                                      *
//功  能: 准备好端点接收                                                   *
//参  数: ep:  端点号; buf: 缓冲区(EVEN/BDD)                               *
//返  回: 无                                                               *
//说  明: 修改该端点的BD,使得rx端点准备好接收                              *
//-------------------------------------------------------------------------*
static void ready_ep_rx(INT8U ep, INT8U buf)
{
  INT32U ndx=ep2bdtndx(ep, buf);

  BDT_LENGTH(ndx)=(INT8U)ep_info[ep].psize;
  BDT_CTRL(ndx)= BDT_CTRL_OWN | ep_info[ep].data0 | BDT_CTRL_DTS;
}

//-------------------------------------------------------------------------*
//函数名: _usb_send                                                        *
//功  能: USB数据发送                                                      *
//参  数: ep:  端点号                                                      *
//返  回: 无                                                               *
//内部调用: select_tx_buf, send_zero_packet                                *
//说  明:                                                                  *
//-------------------------------------------------------------------------*
static void _usb_send(INT8U ep)
{
  INT32U l;
  INT8U x;
  INT8U bndx;

  switch (ep_info[ep].state)
  {
  case EPST_DATA_TX:
    l=MIN(ep_info[ep].tlength, ep_info[ep].psize);
    CMX_ASSERT(l == ep_info[ep].psize || l==ep_info[ep].tlength);      

    //选择下一个端点的缓冲区
    bndx=ep2bdtndx(ep, 0);
    
    //拷贝数据到信息包缓冲区
    for(x=0; x< l; x++)
    {
      ((INT8U*)(BDT_BASE+(BDT_ADDR(bndx)<<2)))[x]=*(INT8U*)ep_info[ep].address;
      ep_info[ep].address=((INT8U*)ep_info[ep].address)+1;      
    }
    
    //设置发送包长度
    BDT_LENGTH(bndx)=(INT8U)l;

    //使缓冲区准备好发送
    ready_ep_tx(ep, 0);
    
    //数据触发器位取反
    ep_info[ep].data0 ^= BDT_CTRL_DATA01;

    //计算发送状态
    ep_info[ep].tlength -= l;

    //判断是否为要发送的数据的最后一包，如果是最后一包时需发送一个0长度的包以结束数据发送。
    if (ep_info[ep].tlength == 0)
    { 
      if ((l == ep_info[ep].psize) && (ep_info[ep].flags & EPFL_ZPACKET))
      {
        ep_info[ep].state=EPST_TX_STOP;
      }
      else
      {
        ep_info[ep].state=EPST_DATA_TX_LAST;
      }
      break;
    }
    break;
  case EPST_TX_STOP:
    //发送0长度的数据包以结束数据阶段
    ep_info[ep].state=EPST_DATA_TX_LAST;
    send_zero_packet(ep);
    break;  
  case EPST_DATA_TX_LAST:
    //等待该端点的缓冲区发关完成
    ep_info[ep].state=EPST_IDLE;
    break;
  default:
    CMX_ASSERT(0);

  }
}
 
//-------------------------------------------------------------------------*
//函数名: USBSend                                                          *
//功  能: USB数据发送                                                      *
//参  数:                                                                  *
//      ep:  端点号                                                        *
//      f :                                                                *
//      * data:  数据缓冲区                                                *
//      tr_length:  从机准备发送的字节数                                   *
//      req_length: 主机要求接收的字节数                                   *
//返  回:无                                                                *
//说  明:                                                                  *
//     USB数据传输都是由主机发起,因此主机需告诉从机发送多少数据(req_length)*
//     而从机发送的数据(tr_length)不能超过主机要求的数据                   *
//-------------------------------------------------------------------------*
void USBSend(INT8U ep, usb_callback_t f, INT8U* data, INT32U tr_length, INT32U req_length)
{
  hcc_imask itst;

  ep_info[ep].tlength=tr_length <= req_length ? tr_length : req_length;
  ep_info[ep].maxlength=ep_info[ep].tlength;
  ep_info[ep].data_func=f;
  ep_info[ep].address=data;
  ep_info[ep].flags=req_length > tr_length ?   (INT8U)EPFL_ZPACKET : (INT8U)0;
  ep_info[ep].error = USBEPERR_NONE;
  ep_info[ep].state=EPST_DATA_TX;

  itst=_irq_disable();
  _usb_send(ep);
  _irq_restore(itst);
}

//-------------------------------------------------------------------------*
//函数名: _usb_receive                                                     *
//功  能: USB数据接收                                                      *
//参  数: ep:  端点号                                                      *
//返  回: 无                                                               *
//说  明:                                                                  *
//-------------------------------------------------------------------------*
void _usb_receive(INT8U ep)
{
  INT8U loops=0;
  int x;

  //拷贝数据到用户区
  do
  {
    INT8U odd=0;
    INT8U bndx;
    INT16U plength;

    if (ep==0)
    {
      odd=1;
    }
    
    bndx=ep2bdtndx(ep, odd);
    plength=BDT_LENGTH(bndx);

    //检查接受数据总数是否OK
    if (ep_info[ep].tlength < plength)
    { 
      //如果接受数据太多，则出现错误
      usb_stop_ep_rx(ep);
      ep_info[ep].error = USBEPERR_TO_MANY_DATA;
      return;
    }

    //拷贝数据到用户缓冲区
    for(x=0; x < plength; x++)
    {
      ((INT8U*)(ep_info[ep].address))[x]=((INT8U*)(BDT_BASE+(BDT_ADDR(bndx)<<2)))[x];
    }

    ep_info[ep].tlength -= plength;
    ep_info[ep].address = ((INT8U *)ep_info[ep].address) + plength;

    //判断是否为上一包数据
    if ((ep_info[ep].tlength == 0) || (ep_info[ep].psize != plength))
    {
      ep_info[ep].state=EPST_IDLE;

      if (ep)
      {
        //通知应用，传输完成
        if (ep_info[ep].data_func != (void *) 0)
        {
          (void)(*ep_info[ep].data_func)();
          ep_info[ep].data_func = (void *)0;      
        }
      }
    }
  }while(loops);
}

//-------------------------------------------------------------------------*
//函数名: USBReceive                                                       *
//功  能: USB接收数据                                                      *
//参  数:                                                                  *
//      ep:  端点号                                                        *                                                             *
//      * data:  数据缓冲区                                                *
//      tr_length:  从机准备发送的字节数                                   *
//返  回: 所接受数据长度                                                   *
//说  明:                                                                  *
//-------------------------------------------------------------------------*
INT8U USBReceive(INT8U ep,INT8U* data, INT32U tr_length)
{ 
  if(RxFlag == usb_ready)
  {
      RxFlag = usb_busy;
      ep_info[ep].tlength=tr_length;
      ep_info[ep].maxlength=ep_info[ep].tlength;
      ep_info[ep].data_func=(void*)0;
      ep_info[ep].address=data;
      ep_info[ep].state=EPST_DATA_RX;
      ep_info[ep].error=USBEPERR_NONE;
      ep_info[ep].flags=0;                 

      //使能下一个接受缓冲
      if (ep)
      {
        ready_ep_rx(ep, 0);
      }
      else
      {
        ready_ep_rx(ep, 1);    
      }
      ep_info[ep].data0 ^= BDT_CTRL_DATA01;
      
      return 0;
  }
  
  if(usb_ep_is_busy(ep) == 0)
  {
      RxFlag = usb_ready;
      return  ep_info[ep].maxlength-ep_info[ep].tlength;
  }
  return 0;
}


//-------------------------------------------------------------------------*
//函数名: USBSetAddress                                                    *
//功  能: 设置USB设备的地址                                                *
//参  数: 无                                                               *
//返  回: 状态机的值                                                       *
//说  明: 状态机使用该函数处理标准请求(set address),设定设备的地址         *
//-------------------------------------------------------------------------*
static callback_state_t USBSetAddress()
{
  if (new_address != 0)
  {
    usb_state=USBST_ADDRESSED;
    ADDR = new_address;
    new_address = 0;    
  }
  else
  {
    EnterDefaultState();
  }
  return(clbst_ok);
}

//-------------------------------------------------------------------------*
//函数名: USBDecodeSetup:对SETUP包解包                                     *
//功  能: 对SETUP包解包和处理                                              *
//参  数: 无                                                               *
//返  回: 状态机的值                                                       *
//说  明:                                                                  *
//   (1)只有接收到SETUP包才调用该函数                                      *
//   (2)SETUP包中8字节数据                                                 *
//    bmRequestType:1                                                      *
//    bRequest:1                                                           *
//    wValue.H:1 :描述符的类型                                             *
//    wValue.L:1 :描述符的索引                                             *
//    wIndex:2                                                             *
//    wLength:2                                                            *
//-------------------------------------------------------------------------*
static callback_state_t USBDecodeSetup()
{
  INT8U *pdata=(INT8U *)USBGetRxBDTAddr(0);//指向SETUP包

  //传输的方向
  callback_state_t r=(STP_REQU_TYPE(pdata) & 1u<<7) ? clbst_in: clbst_out; 

  
  switch (STP_REQU_TYPE(pdata) & 0x7f)
  {
    //标准设备请求
    case 0: 
    //判断请求类型
    //USB设备的11个标准请求，判断是什么请求
    switch (STP_REQUEST(pdata))
    {
      //1.设置地址请求
      case USBRQ_SET_ADDRESS:
      
        new_address=(INT8U)(STP_VALUE_LO(pdata) & 0x7f);
        ep_info[0].data_func=USBSetAddress;
        break;
        
      //2.读取描述符请求
      case USBRQ_GET_DESCRIPTOR:
        switch(STP_VALUE_HI(pdata))
        {
          //2.1 设备描述符
          case STDD_DEVICE:
            {
              INT8U *p=(INT8U*)GetDeviceDescriptor();
              USBSend(0, (void *) 0, p, p[0], STP_LENGTH(pdata));
            }
            break;
            
          //2.2 配置描述符  
          case STDD_CONFIG:
            {
              INT8U cfg=STP_VALUE_LO(pdata);
              if (cfg == 0)
              {
                cfg++;
              }
              if (is_cfgd_index(cfg))
              {
                const INT8U *cd;
                cd=GetCfgDescriptor(cfg);
                USBSend(0, (void *) 0, (void*)cd, RD_LE16(&cd[2])
                         , STP_LENGTH(pdata));
                break;
              }
            }
            //该字符串描述符不存在
            r=clbst_error;
            break;
            
          //2.3 字符串描述符
          case STDD_STRING:
            //该字符串描述符存在
            if (is_str_index(STP_VALUE_LO(pdata)))
            {
              USBSend(0, (void *) 0, (void *)GetStrDescriptor(STP_VALUE_LO(pdata))
                       , *(INT8U*)GetStrDescriptor(STP_VALUE_LO(pdata))
                       , STP_LENGTH(pdata));
              break;
            }
            //该字符串描述符不存在
            r=clbst_error;
            break;

          default:
            goto call_usercb;
        }
        break;
      case USBRQ_GET_CONFIGURATION:
        USBSend(0, (void *) 0, (void *)&usb_current_config
                   , 1
                   , STP_LENGTH(pdata));
        break;
      case USBRQ_SET_CONFIGURATION:
        if (STP_VALUE_LO(pdata) == 0 || is_cfgd_index(STP_VALUE_LO(pdata)))
        {

          USBSetConfig(STP_VALUE_LO(pdata));
          break;
        }
        r=clbst_error;
        break;
      case USBRQ_SYNCH_FRAME:
      case USBRQ_SET_FEATURE:
      case USBRQ_CLEAR_FEATURE:
      case USBRQ_GET_STATUS:
      case USBRQ_SET_DESCRIPTOR:
      default://未知请求
        goto call_usercb;
    }
    break;
  //标准的设备接口请求
  case 1:
      goto call_usercb;
  //标准的端点请求
  case 2: 
  
    switch(STP_REQUEST(pdata))
    {
    case USBRQ_CLEAR_FEATURE:
      switch(STP_VALUE(pdata))
      {
      case FEAT_ENDPOINT_HALT:
        {
          INT8U adr=STP_INDEX_LO(pdata) & 0x7f;
                   
          if (STP_INDEX_LO(pdata) & DIR_TX)
          {
            INT8U bndx=ep2bdtndx(adr, 0);
            ep_info[adr].data0=0;
            BDT_CTRL(bndx) = 0;
          }
          else
          {
            INT8U bndx;
            
            if(adr==0)
            {
              bndx=ep2bdtndx(adr, 1);
            }
            else
            {
              bndx=ep2bdtndx(adr, 0);              
            }
            ep_info[adr].data0=0;
            if (adr==0)
            {
              bndx++;
            }
            BDT_CTRL(bndx)=0;
          }
        }
        break;
      default:
        goto call_usercb;
      }
      break;
    default:
      goto call_usercb;
    }
    break;
  default:
  call_usercb:
    r=usb_ep0_callback();
  }

  return(r);
}
 
//-------------------------------------------------------------------------*
//函数名: USBInterrupt                                                     *
//功  能: USB模块中断处理                                                  *
//参  数:无                                                                *
//返  回:无                                                                *
//说  明:                                                                  *
//     (1)缓冲区描述符字段                                                 *
//        BD[5:2]为当前令牌的PID                                           *
//        BD[5:2]=0x01 OUT                                                 *
//        BD[5:2]=0x09 IN                                                  *
//        BD[5:2]=0x0d SETUP                                               *
//     (2)控制传输的阶段                                                   *
//        建立阶段主机发出SETUP包和8字节数据(data0),从机给出握手包         *
//        数据阶段主机发出IN令牌,从机以DATA1响应，主机给出握手包           *
//        状态阶段主机发出OUT令牌,从机以0长度数据包响应,主机给出握手包     *
//-------------------------------------------------------------------------*
interrupt void USBInterrupt(void)
{
  INT8U istr;

  //保存USB的中断状态寄存器的值
  istr=INTSTAT & INTENB;
  
  //1.非令牌完成中断,清除相应的中断标识位
  if(istr & ~INTSTAT_TOKDNEF_MASK)
  {
    if (istr & INTSTAT_USBRSTF_MASK)
    {
      INTSTAT_USBRSTF=1;
      //进入默认状态
      USBDefault();
      USBResetEvent();
      goto it_exit;
    }

    if (istr & INTSTAT_ERRORF_MASK)
    {
      INTSTAT_ERRORF=0;
      USBBusErrorEvent();
    }
    
    if (istr & INTSTAT_RESUMEF_MASK)
    {
      INTENB_RESUME=0;
      
      INTSTAT_RESUMEF=1;
      INTENB_SLEEP=1;
      USBWakeupEvent();
    }
    
    if (istr & INTSTAT_SLEEPF_MASK)
    {
      INTENB_SLEEP=0;

      INTSTAT_SLEEPF=0;
      INTENB_RESUME=1;
      USBSuspendEvent();
    }

    if (istr & INTSTAT_STALLF_MASK)
    {
      INTSTAT_STALLF=1;
    }
  }

  if (istr & INTSTAT_TOKDNEF_MASK)
  {
    INT8U ep=(INT8U)(STAT_ENDP);
    int is_rx;
    int is_stp=0;

    if (STAT_IN)
    { //OUT包
      is_rx=0;
    }
    else
    { //IN包
      is_rx=1;      
    }

    //判断是否是端点0
    if (ep==0)
    {      
      //判断是否是SETUP包
      is_stp=(BDT_CTRL(1) & BDT_CTRL_BDTKPID) == SOF_PID_VALUE<<2 ? 1 : 0;
      
      switch(ep_info[ep].state)
      {
      default:
        break;
      case EPST_IDLE:
idle:   if (is_stp)
        {
          BDT_CTRL(0)=0;
          BDT_CTRL(1)=0;
           
          CTL_TSUSPEND=0;   //将该位清0以允许SIE继续处理令牌

          ep_info[ep].data_func = (void*)0;
          ep_info[ep].flags=0;
          ep_info[ep].error=USBEPERR_NONE;
          ep_info[ep].data0 = BDT_CTRL_DATA01;

          switch(USBDecodeSetup())
          {
            case clbst_error:
              usb_stop_ep_tx(0);
              usb_stop_ep_rx(0);
              ep_info[0].state = EPST_IDLE;
              ep_info[0].error = USBEPERR_USER_ABORT;
              break;
            case clbst_not_ready:
              break;
            case clbst_in:
              ready_ep_rx(0, 1);
              break;
            case clbst_out:
              if (ep_info[0].state == EPST_IDLE)
              {
                goto send_status;
              }
              break;
            default:
              break;
          }
        }
        else
        {
          ep_info[0].error = USBEPERR_TO_MANY_DATA;

          usb_stop_ep_rx(0);
          usb_stop_ep_tx(0);
          CTL_TSUSPEND=0;
        }
        break;
      //数据阶段(IN令牌)
      case EPST_DATA_TX:
      case EPST_DATA_TX_LAST:
      case EPST_TX_STOP:

        //如果有RX中断，停止传输
        if (is_rx)
        {
          ep_info[0].state=EPST_IDLE;
          if (ep_info[0].data_func != (void *)0)
          {
            (void)(*ep_info[0].data_func)();
            ep_info[0].data_func=(void *) 0;
          }
          goto idle;
        }
        
        if (ep_info[ep].state == EPST_DATA_TX_LAST)
        {
          break;          
        }
        
        _usb_send(0);

        if (ep_info[0].state == EPST_IDLE)
        {
          ep_info[0].state=EPST_STATUS_TX;
        }
        break;
      //状态阶段  
      case EPST_STATUS_TX:
        CMX_ASSERT(is_rx);
        //在IN传输阶段，接受0长度的DATA1包
        ep_info[0].state=EPST_IDLE;

        if (ep_info[0].data_func != (void *) 0)
        {

          (void)(*ep_info[0].data_func)();
          ep_info[0].data_func = (void *)0;
        }
        ready_ep_rx(0, 1);
        break;
        
      //数据阶段(OUT令牌)  
      case EPST_DATA_RX:
        _usb_receive(0);
send_status:
        if(ep_info[0].state == EPST_IDLE)
        {
          //如果有错误则返回STALL的握手包
          if (ep_info[0].flags & EPFL_ERROR)
          {
            usb_stop_ep_tx(0);
          }
          else
          {
            //握手信号永远是DATA1包
            ep_info[0].data0 = BDT_CTRL_DATA01;
            //如果一切OK，发送握手信号
            ep_info[0].state=EPST_STATUS_RX;
            //发送0字节长度DATA1包作为回答
            send_zero_packet(0);
          }
        }
        break;
      //状态阶段
      case EPST_STATUS_RX:
        //在OUT传输阶段，发送0字节长度的DATA0包
        ep_info[0].state=EPST_IDLE;
        
        if (ep_info[0].data_func != (void *) 0)
        {
          (void)(*ep_info[0].data_func)();
          ep_info[0].data_func = (void *)0;
        }
        ready_ep_rx(0, 1);
        break;
      }
    }
    else
    {
      //如果刚完成的事务为OUT(RX)，则将BDT中端点缓冲区的内容复制到端点的用户缓冲区中
      if(is_rx)
      {
        _usb_receive(ep);
      }
      else
      { 
        //如果刚完成的事务为IN(TX)，则要将TX缓冲区的内容发送出去
        _usb_send(ep);
        if (ep_info[ep].state==EPST_IDLE)
        {
          if (ep_info[ep].data_func != (void *)0)
          {
            (void)(*ep_info[ep].data_func)();
            ep_info[ep].data_func = (void *)0;
          }
        }
      }
    }
	  //清除中断标志位
    INTSTAT_TOKDNEF=1;

  }
  it_exit:
  	;
}
void _irq_restore (hcc_imask ip)
{
  if(ip)
  {
    /* Disable interrupts */
    asm ("sei");
  }
  else
  { 
    /* Enable interrupts */
    asm("cli");
  }
}

//-------------------------------------------------------------------------*
// 函数名:  _irq_disable()                                                 *
// 功  能:  初始化SCM模块                                                  *
//          设置基址、允许片上模块访问内部SRAM                             *
// 参  数:  无                                                             *
// 返  回:  无                                                             *
//-------------------------------------------------------------------------*
hcc_imask _irq_disable (void)
{
  INT8U r;
  asm ("tpa;");     /* transfer CCR to A */
  asm ("sei;");     /* disable interrupts */
  asm ("and #8;");  /* mask I bit of CCR */
  asm ("sta r;");
  return(r);
}
/****************************** END OF FILE **********************************/


